1 // This is a part of the Active Template Library.
2 // Copyright (C) Microsoft Corporation
3 // All rights reserved.
5 // This source code is only intended as a supplement to the
6 // Active Template Library Reference and related
7 // electronic documentation provided with the library.
8 // See these sources for detailed information regarding the
9 // Active Template Library product.
11 #ifndef __ATLSESSION_H__
12 #define __ATLSESSION_H__
16 #pragma warning(disable: 4702) // unreachable code
29 #include <atlsiface.h>
31 #pragma warning(disable: 4625) // copy constructor could not be generated because a base class copy constructor is inaccessible
32 #pragma warning(disable: 4626) // assignment operator could not be generated because a base class assignment operator is inaccessible
34 #ifndef MAX_SESSION_KEY_LEN
35 #define MAX_SESSION_KEY_LEN 128
38 #ifndef MAX_VARIABLE_NAME_LENGTH
39 #define MAX_VARIABLE_NAME_LENGTH 50
42 #ifndef MAX_VARIABLE_VALUE_LENGTH
43 #define MAX_VARIABLE_VALUE_LENGTH 1024
46 #ifndef MAX_CONNECTION_STRING_LEN
47 #define MAX_CONNECTION_STRING_LEN 2048
50 #ifndef SESSION_COOKIE_NAME
51 #define SESSION_COOKIE_NAME "SESSIONID"
54 #ifndef ATL_SESSION_TIMEOUT
55 #define ATL_SESSION_TIMEOUT 600000 //10 min
58 #ifndef ATL_SESSION_SWEEPER_TIMEOUT
59 #define ATL_SESSION_SWEEPER_TIMEOUT 1000 // 1sec
62 #define INVALID_DB_SESSION_POS 0x0
63 #define ATL_DBSESSION_ID _T("__ATL_SESSION_DB_CONNECTION")
65 #pragma pack(push,_ATL_PACKING)
68 // CSessionNameGenerator
69 // This is a helper class that generates random data for session key
70 // names. This class tries to use the CryptoApi to generate random
71 // bytes for the session key name. If the CryptoApi isn't available
72 // then the CRT rand() is used to generate the random bytes. This
73 // class's GetNewSessionName member function is used to actually
74 // generate the session name.
75 class CSessionNameGenerator
:
79 bool m_bCryptNotAvailable
;
80 enum {MIN_SESSION_KEY_LEN
=5};
82 CSessionNameGenerator() throw() :
83 m_bCryptNotAvailable(false)
85 // Note that the crypto api is being
86 // initialized with no private key
88 HRESULT hr
= InitVerifyContext();
89 m_bCryptNotAvailable
= FAILED(hr
) ? true : false;
92 // This function creates a new session name and base64 encodes it.
93 // The base64 encoding algorithm used needs at least MIN_SESSION_KEY_LEN
94 // bytes to work correctly. Since we stack allocate the temporary
95 // buffer that holds the key name, the buffer must be less than or equal to
96 // the MAX_SESSION_KEY_LEN in size.
97 HRESULT
GetNewSessionName(__out_ecount_part_z(*pdwSize
, *pdwSize
) LPSTR szNewID
, __inout DWORD
*pdwSize
) throw()
104 if (*pdwSize
< MIN_SESSION_KEY_LEN
||
105 *pdwSize
> MAX_SESSION_KEY_LEN
)
111 BYTE key
[MAX_SESSION_KEY_LEN
] = {0x0};
114 // calculate the number of bytes that will fit in the
115 // buffer we've been passed
116 DWORD dwDataSize
= CalcMaxInputSize(*pdwSize
);
118 if (dwDataSize
&& *pdwSize
>= (DWORD
)(Base64EncodeGetRequiredLength(dwDataSize
,
119 ATL_BASE64_FLAG_NOCRLF
)))
121 int dwKeySize
= *pdwSize
;
122 hr
= GenerateRandomName(key
, dwDataSize
);
125 if( Base64Encode(key
,
129 ATL_BASE64_FLAG_NOCRLF
) )
132 szNewID
[dwKeySize
]=0;
133 *pdwSize
= dwKeySize
+1;
140 *pdwSize
= (DWORD
)(Base64EncodeGetRequiredLength(dwDataSize
,
141 ATL_BASE64_FLAG_NOCRLF
));
142 return E_OUTOFMEMORY
;
148 DWORD
CalcMaxInputSize(DWORD nOutputSize
) throw()
150 if (nOutputSize
< (DWORD
)MIN_SESSION_KEY_LEN
)
152 // subtract one from the output size to make room
153 // for the NULL terminator in the output then
154 // calculate the biggest number of input bytes that
155 // when base64 encoded will fit in a buffer of size
156 // nOutputSize (including base64 padding)
157 int nInputSize
= ((nOutputSize
-1)*3)/4;
158 int factor
= ((nInputSize
*4)/3)%4;
160 nInputSize
-= factor
;
165 HRESULT
GenerateRandomName(BYTE
*pBuff
, DWORD dwBuffSize
) throw()
173 if (!m_bCryptNotAvailable
&& GetHandle())
175 // Use the crypto api to generate random data.
176 return GenRandom(dwBuffSize
, pBuff
);
179 // CryptoApi isn't available so we generate
180 // random data using rand. We seed the random
181 // number generator with a seed that is a combination
182 // of bytes from an arbitrary number and the system
183 // time which changes every millisecond so it will
184 // be different for every call to this function.
186 GetSystemTimeAsFileTime(&ft
);
187 static DWORD dwVal
= 0x21;
188 DWORD dwSeed
= (dwVal
++ << 0x18) | (ft
.dwLowDateTime
& 0x00ffff00) | dwVal
++ & 0x000000ff;
191 // fill buffer with random bytes
192 for (int i
=0; i
< (int)dwBuffSize
; i
++)
194 *pCurr
= (BYTE
) (rand() & 0x000000ff);
203 // CDefaultQueryClass
204 // returns Query strings for use in SQL queries used
205 // by the database persisted session service.
206 class CDefaultQueryClass
209 LPCTSTR
GetSessionRefDelete() throw()
211 return _T("DELETE FROM SessionReferences ")
212 _T("WHERE SessionID=? AND RefCount <= 0 ")
213 _T("AND DATEDIFF(millisecond, LastAccess, getdate()) > TimeoutMs");
216 LPCTSTR
GetSessionRefIsExpired() throw()
218 return _T("SELECT SessionID FROM SessionReferences ")
219 _T("WHERE (SessionID=?) AND (DATEDIFF(millisecond, LastAccess, getdate()) > TimeoutMs)");
222 LPCTSTR
GetSessionRefDeleteFinal() throw()
224 return _T("DELETE FROM SessionReferences ")
225 _T("WHERE SessionID=?");
228 LPCTSTR
GetSessionRefCreate() throw()
230 return _T("INSERT INTO SessionReferences ")
231 _T("(SessionID, LastAccess, RefCount, TimeoutMs) ")
232 _T("VALUES (?, getdate(), 1, ?)");
235 LPCTSTR
GetSessionRefUpdateTimeout() throw()
237 return _T("UPDATE SessionReferences ")
238 _T("SET TimeoutMs=? WHERE SessionID=?");
241 LPCTSTR
GetSessionRefAddRef() throw()
243 return _T("UPDATE SessionReferences ")
244 _T("SET RefCount=RefCount+1, ")
245 _T("LastAccess=getdate() ")
246 _T("WHERE SessionID=?");
249 LPCTSTR
GetSessionRefRemoveRef() throw()
251 return _T("UPDATE SessionReferences ")
252 _T("SET RefCount=RefCount-1, ")
253 _T("LastAccess=getdate() ")
254 _T("WHERE SessionID=?");
257 LPCTSTR
GetSessionRefAccess() throw()
259 return _T("UPDATE SessionReferences ")
260 _T("SET LastAccess=getdate() ")
261 _T("WHERE SessionID=?");
264 LPCTSTR
GetSessionRefSelect() throw()
266 return _T("SELECT * FROM SessionReferences ")
267 _T("WHERE SessionID=?");
270 LPCTSTR
GetSessionRefGetCount() throw()
272 return _T("SELECT COUNT(*) FROM SessionReferences");
276 LPCTSTR
GetSessionVarCount() throw()
278 return _T("SELECT COUNT(*) FROM SessionVariables WHERE SessionID=?");
281 LPCTSTR
GetSessionVarInsert() throw()
283 return _T("INSERT INTO SessionVariables ")
284 _T("(VariableValue, SessionID, VariableName) ")
285 _T("VALUES (?, ?, ?)");
288 LPCTSTR
GetSessionVarUpdate() throw()
290 return _T("UPDATE SessionVariables ")
291 _T("SET VariableValue=? ")
292 _T("WHERE SessionID=? AND VariableName=?");
295 LPCTSTR
GetSessionVarDeleteVar() throw()
297 return _T("DELETE FROM SessionVariables ")
298 _T("WHERE SessionID=? AND VariableName=?");
301 LPCTSTR
GetSessionVarDeleteAllVars() throw()
303 return _T("DELETE FROM SessionVariables WHERE (SessionID=?)");
306 LPCTSTR
GetSessionVarSelectVar()throw()
308 return _T("SELECT SessionID, VariableName, VariableValue ")
309 _T("FROM SessionVariables ")
310 _T("WHERE SessionID=? AND VariableName=?");
313 LPCTSTR
GetSessionVarSelectAllVars() throw()
315 return _T("SELECT SessionID, VariableName, VariableValue ")
316 _T("FROM SessionVariables ")
317 _T("WHERE SessionID=?");
320 LPCTSTR
GetSessionReferencesSet() throw()
322 return _T("UPDATE SessionReferences SET TimeoutMs=?");
327 // Contains the data for the session variable accessors
328 class CSessionDataBase
331 TCHAR m_szSessionID
[MAX_SESSION_KEY_LEN
];
332 TCHAR m_VariableName
[MAX_VARIABLE_NAME_LENGTH
];
333 BYTE m_VariableValue
[MAX_VARIABLE_VALUE_LENGTH
];
334 DBLENGTH m_VariableLen
;
335 CSessionDataBase() throw()
337 m_szSessionID
[0] = '\0';
338 m_VariableName
[0] = '\0';
339 m_VariableValue
[0] = '\0';
342 HRESULT
Assign(LPCTSTR szSessionID
, LPCTSTR szVarName
, VARIANT
*pVal
) throw()
345 CVariantStream stream
;
348 if (Checked::tcsnlen(szSessionID
, MAX_SESSION_KEY_LEN
)< MAX_SESSION_KEY_LEN
)
349 Checked::tcscpy_s(m_szSessionID
, _countof(m_szSessionID
), szSessionID
);
356 if (hr
== S_OK
&& szVarName
)
357 if (Checked::tcsnlen(szVarName
, MAX_VARIABLE_NAME_LENGTH
) < MAX_VARIABLE_NAME_LENGTH
)
358 Checked::tcscpy_s(m_VariableName
, _countof(m_VariableName
), szVarName
);
362 if (hr
== S_OK
&& pVal
)
364 hr
= stream
.InsertVariant(pVal
);
367 BYTE
*pBytes
= stream
.m_stream
;
368 size_t size
= stream
.GetVariantSize();
369 if (pBytes
&& size
&& size
< MAX_VARIABLE_VALUE_LENGTH
)
371 Checked::memcpy_s(m_VariableValue
, MAX_VARIABLE_VALUE_LENGTH
, pBytes
, size
);
372 m_VariableLen
= static_cast<DBLENGTH
>(size
);
383 // Use to select a session variable given the name
384 // of a session and the name of a variable.
385 class CSessionDataSelector
: public CSessionDataBase
388 BEGIN_COLUMN_MAP(CSessionDataSelector
)
389 COLUMN_ENTRY(1, m_szSessionID
)
390 COLUMN_ENTRY(2, m_VariableName
)
391 COLUMN_ENTRY_LENGTH(3, m_VariableValue
, m_VariableLen
)
393 BEGIN_PARAM_MAP(CSessionDataSelector
)
394 SET_PARAM_TYPE(DBPARAMIO_INPUT
)
395 COLUMN_ENTRY(1, m_szSessionID
)
396 COLUMN_ENTRY(2, m_VariableName
)
400 // Use to select all session variables given the name of
402 class CAllSessionDataSelector
: public CSessionDataBase
405 BEGIN_COLUMN_MAP(CAllSessionDataSelector
)
406 COLUMN_ENTRY(1, m_szSessionID
)
407 COLUMN_ENTRY(2, m_VariableName
)
408 COLUMN_ENTRY_LENGTH(3, m_VariableValue
, m_VariableLen
)
410 BEGIN_PARAM_MAP(CAllSessionDataSelector
)
411 SET_PARAM_TYPE(DBPARAMIO_INPUT
)
412 COLUMN_ENTRY(1, m_szSessionID
)
416 // Use to update the value of a session variable
417 class CSessionDataUpdator
: public CSessionDataBase
420 BEGIN_PARAM_MAP(CSessionDataUpdator
)
421 SET_PARAM_TYPE(DBPARAMIO_INPUT
)
422 COLUMN_ENTRY_LENGTH(1, m_VariableValue
, m_VariableLen
)
423 COLUMN_ENTRY(2, m_szSessionID
)
424 COLUMN_ENTRY(3, m_VariableName
)
428 // Use to delete a session variable given the
429 // session name and the name of the variable
430 class CSessionDataDeletor
433 CSessionDataDeletor()
435 m_szSessionID
[0] = '\0';
436 m_VariableName
[0] = '\0';
439 TCHAR m_szSessionID
[MAX_SESSION_KEY_LEN
];
440 TCHAR m_VariableName
[MAX_VARIABLE_NAME_LENGTH
];
441 HRESULT
Assign(LPCTSTR szSessionID
, LPCTSTR szVarName
) throw()
445 if (Checked::tcsnlen(szSessionID
, MAX_SESSION_KEY_LEN
) < MAX_SESSION_KEY_LEN
)
446 Checked::tcscpy_s(m_szSessionID
, _countof(m_szSessionID
), szSessionID
);
448 return E_OUTOFMEMORY
;
453 if(Checked::tcsnlen(szVarName
, MAX_VARIABLE_NAME_LENGTH
) < MAX_VARIABLE_NAME_LENGTH
)
454 Checked::tcscpy_s(m_VariableName
, _countof(m_VariableName
), szVarName
);
456 return E_OUTOFMEMORY
;
461 BEGIN_PARAM_MAP(CSessionDataDeletor
)
462 SET_PARAM_TYPE(DBPARAMIO_INPUT
)
463 COLUMN_ENTRY(1, m_szSessionID
)
464 COLUMN_ENTRY(2, m_VariableName
)
468 class CSessionDataDeleteAll
471 TCHAR m_szSessionID
[MAX_SESSION_KEY_LEN
];
472 HRESULT
Assign(LPCTSTR szSessionID
) throw()
477 if (Checked::tcsnlen(szSessionID
, MAX_SESSION_KEY_LEN
) < MAX_SESSION_KEY_LEN
)
478 Checked::tcscpy_s(m_szSessionID
, _countof(m_szSessionID
), szSessionID
);
480 return E_OUTOFMEMORY
;
485 BEGIN_PARAM_MAP(CSessionDataDeleteAll
)
486 SET_PARAM_TYPE(DBPARAMIO_INPUT
)
487 COLUMN_ENTRY(1, m_szSessionID
)
491 // Used for retrieving the count of session variables for
492 // a given session ID.
497 TCHAR m_szSessionID
[MAX_SESSION_KEY_LEN
];
498 CCountAccessor() throw()
500 m_szSessionID
[0] = '\0';
504 HRESULT
Assign(LPCTSTR szSessionID
) throw()
509 if (Checked::tcsnlen(szSessionID
, MAX_SESSION_KEY_LEN
) < MAX_SESSION_KEY_LEN
)
510 Checked::tcscpy_s(m_szSessionID
, _countof(m_szSessionID
), szSessionID
);
512 return E_OUTOFMEMORY
;
517 BEGIN_COLUMN_MAP(CCountAccessor
)
518 COLUMN_ENTRY(1, m_nCount
)
520 BEGIN_PARAM_MAP(CCountAccessor
)
521 SET_PARAM_TYPE(DBPARAMIO_INPUT
)
522 COLUMN_ENTRY(1, m_szSessionID
)
527 // Used for updating entries in the session
528 // references table, given a session ID
529 class CSessionRefUpdator
532 TCHAR m_SessionID
[MAX_SESSION_KEY_LEN
];
533 HRESULT
Assign(LPCTSTR szSessionID
) throw()
537 if (Checked::tcsnlen(szSessionID
, MAX_SESSION_KEY_LEN
) < MAX_SESSION_KEY_LEN
)
538 Checked::tcscpy_s(m_SessionID
, _countof(m_SessionID
), szSessionID
);
540 return E_OUTOFMEMORY
;
543 BEGIN_PARAM_MAP(CSessionRefUpdator
)
544 SET_PARAM_TYPE(DBPARAMIO_INPUT
)
545 COLUMN_ENTRY(1, m_SessionID
)
549 class CSessionRefIsExpired
552 TCHAR m_SessionID
[MAX_SESSION_KEY_LEN
];
553 TCHAR m_SessionIDOut
[MAX_SESSION_KEY_LEN
];
554 HRESULT
Assign(LPCTSTR szSessionID
) throw()
559 if (Checked::tcsnlen(szSessionID
, MAX_SESSION_KEY_LEN
) < MAX_SESSION_KEY_LEN
)
560 Checked::tcscpy_s(m_SessionID
, _countof(m_SessionID
), szSessionID
);
562 return E_OUTOFMEMORY
;
565 BEGIN_COLUMN_MAP(CSessionRefIsExpired
)
566 COLUMN_ENTRY(1, m_SessionIDOut
)
568 BEGIN_PARAM_MAP(CSessionRefIsExpired
)
569 SET_PARAM_TYPE(DBPARAMIO_INPUT
)
570 COLUMN_ENTRY(1, m_SessionID
)
574 class CSetAllTimeouts
577 unsigned __int64 m_dwNewTimeout
;
578 HRESULT
Assign(unsigned __int64 dwNewValue
)
580 m_dwNewTimeout
= dwNewValue
;
583 BEGIN_PARAM_MAP(CSetAllTimeouts
)
584 SET_PARAM_TYPE(DBPARAMIO_INPUT
)
585 COLUMN_ENTRY(1, m_dwNewTimeout
)
589 class CSessionRefUpdateTimeout
592 TCHAR m_SessionID
[MAX_SESSION_KEY_LEN
];
593 unsigned __int64 m_nNewTimeout
;
594 HRESULT
Assign(LPCTSTR szSessionID
, unsigned __int64 nNewTimeout
) throw()
599 if (Checked::tcsnlen(szSessionID
, MAX_SESSION_KEY_LEN
) < MAX_SESSION_KEY_LEN
)
600 Checked::tcscpy_s(m_SessionID
, _countof(m_SessionID
), szSessionID
);
602 return E_OUTOFMEMORY
;
604 m_nNewTimeout
= nNewTimeout
;
609 BEGIN_PARAM_MAP(CSessionRefUpdateTimeout
)
610 SET_PARAM_TYPE(DBPARAMIO_INPUT
)
611 COLUMN_ENTRY(1, m_nNewTimeout
)
612 COLUMN_ENTRY(2, m_SessionID
)
616 class CSessionRefSelector
619 TCHAR m_SessionID
[MAX_SESSION_KEY_LEN
];
621 HRESULT
Assign(LPCTSTR szSessionID
) throw()
625 if (Checked::tcsnlen(szSessionID
, MAX_SESSION_KEY_LEN
) < MAX_SESSION_KEY_LEN
)
626 Checked::tcscpy_s(m_SessionID
, _countof(m_SessionID
), szSessionID
);
628 return E_OUTOFMEMORY
;
631 BEGIN_COLUMN_MAP(CSessionRefSelector
)
632 COLUMN_ENTRY(1, m_SessionID
)
633 COLUMN_ENTRY(3, m_RefCount
)
635 BEGIN_PARAM_MAP(CSessionRefSelector
)
636 SET_PARAM_TYPE(DBPARAMIO_INPUT
)
637 COLUMN_ENTRY(1, m_SessionID
)
641 class CSessionRefCount
645 BEGIN_COLUMN_MAP(CSessionRefCount
)
646 COLUMN_ENTRY(1, m_nCount
)
650 // Used for creating new entries in the session
652 class CSessionRefCreator
655 TCHAR m_SessionID
[MAX_SESSION_KEY_LEN
];
656 unsigned __int64 m_TimeoutMs
;
657 HRESULT
Assign(LPCTSTR szSessionID
, unsigned __int64 timeout
) throw()
661 if (Checked::tcsnlen(szSessionID
, MAX_SESSION_KEY_LEN
) < MAX_SESSION_KEY_LEN
)
663 Checked::tcscpy_s(m_SessionID
, _countof(m_SessionID
), szSessionID
);
664 m_TimeoutMs
= timeout
;
667 return E_OUTOFMEMORY
;
670 BEGIN_PARAM_MAP(CSessionRefCreator
)
671 SET_PARAM_TYPE(DBPARAMIO_INPUT
)
672 COLUMN_ENTRY(1, m_SessionID
)
673 COLUMN_ENTRY(2, m_TimeoutMs
)
679 // This session persistance class persists session variables to
680 // an OLEDB datasource. The following table gives a general description
681 // of the table schema for the tables this class uses.
683 // TableName: SessionVariables
684 // Column Name Type Description
685 // 1 SessionID char[MAX_SESSION_KEY_LEN] Session Key name
686 // 2 VariableName char[MAX_VARIABLE_NAME_LENGTH] Variable Name
687 // 3 VariableValue varbinary[MAX_VARIABLE_VALUE_LENGTH] Variable Value
690 // TableName: SessionReferences
691 // Column Name Type Description
692 // 1 SessionID char[MAX_SESSION_KEY_LEN] Session Key Name.
693 // 2 LastAccess datetime Date and time of last access to this session.
694 // 3 RefCount int Current references on this session.
695 // 4 TimeoutMS int Timeout value for the session in milli seconds
697 typedef bool (*PFN_GETPROVIDERINFO
)(DWORD_PTR
, wchar_t **);
699 template <class QueryClass
=CDefaultQueryClass
>
702 public CComObjectRootEx
<CComGlobalsThreadModel
>
705 typedef CCommand
<CAccessor
<CAllSessionDataSelector
> > iterator_accessor
;
707 typedef QueryClass DBQUERYCLASS_TYPE
;
708 BEGIN_COM_MAP(CDBSession
)
709 COM_INTERFACE_ENTRY(ISession
)
712 CDBSession() throw():
713 m_dwTimeout(ATL_SESSION_TIMEOUT
)
715 m_szSessionName
[0] = '\0';
718 ~CDBSession() throw()
722 void FinalRelease()throw()
727 STDMETHOD(SetVariable
)(LPCSTR szName
, VARIANT Val
) throw()
733 // Get the data connection for this thread.
734 CDataConnection dataconn
;
735 hr
= GetSessionConnection(&dataconn
, m_spServiceProvider
);
739 // Update the last access time for this session
744 // Allocate an updator command and fill out it's input parameters.
745 CCommand
<CAccessor
<CSessionDataUpdator
> > command
;
749 hr
= command
.Assign(m_szSessionName
, name
, &Val
);
758 // Try an update. Update will fail if the variable is not already there.
759 DBROWCOUNT nRows
= 0;
761 hr
= command
.Open(dataconn
,
762 m_QueryObj
.GetSessionVarUpdate(),
763 NULL
, &nRows
, DBGUID_DEFAULT
, false);
764 if (hr
== S_OK
&& nRows
<= 0)
769 hr
= command
.Open(dataconn
, m_QueryObj
.GetSessionVarInsert(), NULL
, &nRows
, DBGUID_DEFAULT
, false);
770 if (hr
== S_OK
&& nRows
<=0)
777 // Warning: For string data types, depending on the configuration of
778 // your database, strings might be returned with trailing white space.
779 STDMETHOD(GetVariable
)(LPCSTR szName
, VARIANT
*pVal
) throw()
789 // Get the data connection for this thread
790 CDataConnection dataconn
;
791 hr
= GetSessionConnection(&dataconn
, m_spServiceProvider
);
795 // Update the last access time for this session
800 // Allocate a command a fill out it's input parameters.
801 CCommand
<CAccessor
<CSessionDataSelector
> > command
;
805 hr
= command
.Assign(m_szSessionName
, name
, NULL
);
814 hr
= command
.Open(dataconn
, m_QueryObj
.GetSessionVarSelectVar());
817 if ( S_OK
== (hr
= command
.MoveFirst()))
819 CStreamOnByteArray
stream(command
.m_VariableValue
);
821 hr
= vOut
.ReadFromStream(static_cast<IStream
*>(&stream
));
823 hr
= vOut
.Detach(pVal
);
830 STDMETHOD(RemoveVariable
)(LPCSTR szName
) throw()
836 // Get the data connection for this thread.
837 CDataConnection dataconn
;
838 hr
= GetSessionConnection(&dataconn
, m_spServiceProvider
);
842 // update the last access time for this session
847 // allocate a command and set it's input parameters
848 CCommand
<CAccessor
<CSessionDataDeletor
> > command
;
852 hr
= command
.Assign(m_szSessionName
, name
);
856 return E_OUTOFMEMORY
;
859 // execute the command
860 DBROWCOUNT nRows
= 0;
862 hr
= command
.Open(dataconn
, m_QueryObj
.GetSessionVarDeleteVar(),
863 NULL
, &nRows
, DBGUID_DEFAULT
, false);
864 if (hr
== S_OK
&& nRows
<= 0)
869 // Gives the count of rows in the table for this session ID.
870 STDMETHOD(GetCount
)(long *pnCount
) throw()
878 // Get the database connection for this thread.
879 CDataConnection dataconn
;
880 hr
= GetSessionConnection(&dataconn
, m_spServiceProvider
);
886 CCommand
<CAccessor
<CCountAccessor
> > command
;
888 hr
= command
.Assign(m_szSessionName
);
891 hr
= command
.Open(dataconn
, m_QueryObj
.GetSessionVarCount());
894 if (S_OK
== (hr
= command
.MoveFirst()))
896 *pnCount
= command
.m_nCount
;
904 STDMETHOD(RemoveAllVariables
)() throw()
906 HRESULT hr
= E_UNEXPECTED
;
908 // Get the data connection for this thread.
909 CDataConnection dataconn
;
910 hr
= GetSessionConnection(&dataconn
, m_spServiceProvider
);
914 CCommand
<CAccessor
<CSessionDataDeleteAll
> > command
;
915 hr
= command
.Assign(m_szSessionName
);
919 // delete all session variables
920 hr
= command
.Open(dataconn
, m_QueryObj
.GetSessionVarDeleteAllVars(), NULL
, NULL
, DBGUID_DEFAULT
, false);
924 // Iteration of variables works by taking a snapshot
925 // of the sessions at the point in time BeginVariableEnum
926 // is called, and then keeping an index variable that you use to
927 // move through the snapshot rowset. It is important to know
928 // that the handle returned in phEnum is not thread safe. It
929 // should only be used by the calling thread.
930 STDMETHOD(BeginVariableEnum
)(POSITION
*pPOS
, HSESSIONENUM
*phEnum
) throw()
941 // Get the data connection for this thread.
942 CDataConnection dataconn
;
943 hr
= GetSessionConnection(&dataconn
, m_spServiceProvider
);
947 // Update the last access time for this session.
952 // Allocate a new iterator accessor and initialize it's input parameters.
953 iterator_accessor
*pIteratorAccessor
= NULL
;
954 ATLTRYALLOC(pIteratorAccessor
= new iterator_accessor
);
955 if (!pIteratorAccessor
)
956 return E_OUTOFMEMORY
;
958 hr
= pIteratorAccessor
->Assign(m_szSessionName
, NULL
, NULL
);
961 // execute the command and move to the first row of the recordset.
962 hr
= pIteratorAccessor
->Open(dataconn
,
963 m_QueryObj
.GetSessionVarSelectAllVars());
966 hr
= pIteratorAccessor
->MoveFirst();
969 *pPOS
= (POSITION
) INVALID_DB_SESSION_POS
+ 1;
970 *phEnum
= reinterpret_cast<HSESSIONENUM
>(pIteratorAccessor
);
976 *pPOS
= INVALID_DB_SESSION_POS
;
978 delete pIteratorAccessor
;
984 // The values for hEnum and pPos must have been initialized in a previous
985 // call to BeginVariableEnum. On success, the out variant will hold the next
987 STDMETHOD(GetNextVariable
)(POSITION
*pPOS
, VARIANT
*pVal
, HSESSIONENUM hEnum
, LPSTR szName
=NULL
, DWORD dwLen
=0) throw()
1000 if (*pPOS
<= INVALID_DB_SESSION_POS
)
1001 return E_UNEXPECTED
;
1003 iterator_accessor
*pIteratorAccessor
= reinterpret_cast<iterator_accessor
*>(hEnum
);
1005 // update the last access time.
1006 HRESULT hr
= Access();
1008 POSITION posCurrent
= *pPOS
;
1012 // caller wants entry name
1015 CT2CA
szVarName(pIteratorAccessor
->m_VariableName
);
1016 if (szVarName
!= NULL
&& dwLen
> Checked::strnlen(szVarName
, dwLen
))
1018 Checked::strcpy_s(szName
, dwLen
, szVarName
);
1021 hr
= E_OUTOFMEMORY
; // buffer not big enough
1032 CStreamOnByteArray
stream(pIteratorAccessor
->m_VariableValue
);
1034 hr
= vOut
.ReadFromStream(static_cast<IStream
*>(&stream
));
1043 hr
= pIteratorAccessor
->MoveNext();
1044 *pPOS
= ++posCurrent
;
1046 if (hr
== DB_S_ENDOFROWSET
)
1048 // We're done iterating, reset everything
1049 *pPOS
= INVALID_DB_SESSION_POS
;
1060 // CloseEnum frees up any resources allocated by the iterator
1061 STDMETHOD(CloseEnum
)(HSESSIONENUM hEnum
) throw()
1063 iterator_accessor
*pIteratorAccessor
= reinterpret_cast<iterator_accessor
*>(hEnum
);
1064 if (!pIteratorAccessor
)
1065 return E_INVALIDARG
;
1066 pIteratorAccessor
->Close();
1067 delete pIteratorAccessor
;
1072 // Returns S_FALSE if it's not expired
1073 // S_OK if it is expired and an error HRESULT
1074 // if an error occurred.
1075 STDMETHOD(IsExpired
)() throw()
1077 HRESULT hrRet
= S_FALSE
;
1078 HRESULT hr
= E_UNEXPECTED
;
1080 // Get the data connection for this thread.
1081 CDataConnection dataconn
;
1082 hr
= GetSessionConnection(&dataconn
, m_spServiceProvider
);
1086 CCommand
<CAccessor
<CSessionRefIsExpired
> > command
;
1087 hr
= command
.Assign(m_szSessionName
);
1091 hr
= command
.Open(dataconn
, m_QueryObj
.GetSessionRefIsExpired(),
1092 NULL
, NULL
, DBGUID_DEFAULT
, true);
1095 if (S_OK
== command
.MoveFirst())
1097 if (!_tcscmp(command
.m_SessionIDOut
, m_szSessionName
))
1107 STDMETHOD(SetTimeout
)(unsigned __int64 dwNewTimeout
) throw()
1109 HRESULT hr
= E_UNEXPECTED
;
1111 // Get the data connection for this thread.
1112 CDataConnection dataconn
;
1113 hr
= GetSessionConnection(&dataconn
, m_spServiceProvider
);
1117 // allocate a command and set it's input parameters
1118 CCommand
<CAccessor
<CSessionRefUpdateTimeout
> > command
;
1119 hr
= command
.Assign(m_szSessionName
, dwNewTimeout
);
1123 hr
= command
.Open(dataconn
, m_QueryObj
.GetSessionRefUpdateTimeout(),
1124 NULL
, NULL
, DBGUID_DEFAULT
, false);
1129 // SessionLock increments the session reference count for this session.
1130 // If there is not a session by this name in the session references table,
1131 // a new session entry is created in the the table.
1132 HRESULT
SessionLock() throw()
1134 HRESULT hr
= E_UNEXPECTED
;
1135 if (!m_szSessionName
|| m_szSessionName
[0]==0)
1136 return hr
; // no session to lock.
1138 // retrieve the data connection for this thread
1139 CDataConnection dataconn
;
1140 hr
= GetSessionConnection(&dataconn
, m_spServiceProvider
);
1144 // first try to update a session with this name
1145 DBROWCOUNT nRows
= 0;
1146 CCommand
<CAccessor
<CSessionRefUpdator
> > updator
;
1147 if (S_OK
== updator
.Assign(m_szSessionName
))
1149 if (S_OK
!= (hr
= updator
.Open(dataconn
, m_QueryObj
.GetSessionRefAddRef(),
1150 NULL
, &nRows
, DBGUID_DEFAULT
, false)) ||
1153 // No session to update. Use the creator accessor
1154 // to create a new session reference.
1155 CCommand
<CAccessor
<CSessionRefCreator
> > creator
;
1156 hr
= creator
.Assign(m_szSessionName
, m_dwTimeout
);
1158 hr
= creator
.Open(dataconn
, m_QueryObj
.GetSessionRefCreate(),
1159 NULL
, &nRows
, DBGUID_DEFAULT
, false);
1163 // We should have been able to create or update a session.
1164 ATLASSERT(nRows
> 0);
1165 if (hr
== S_OK
&& nRows
<= 0)
1171 // SessionUnlock decrements the session RefCount for this session.
1172 // Sessions cannot be removed from the database unless the session
1174 HRESULT
SessionUnlock() throw()
1176 HRESULT hr
= E_UNEXPECTED
;
1177 if (!m_szSessionName
||
1178 m_szSessionName
[0]==0)
1181 // get the data connection for this thread
1182 CDataConnection dataconn
;
1183 hr
= GetSessionConnection(&dataconn
, m_spServiceProvider
);
1187 // The session must exist at this point in order to unlock it
1188 // so we can just use the session updator here.
1189 DBROWCOUNT nRows
= 0;
1190 CCommand
<CAccessor
<CSessionRefUpdator
> > updator
;
1191 hr
= updator
.Assign(m_szSessionName
);
1194 hr
= updator
.Open( dataconn
,
1195 m_QueryObj
.GetSessionRefRemoveRef(),
1204 // delete the session from the database if
1205 // nobody else is using it and it's expired.
1210 // Access updates the last access time for the session. The access
1211 // time for sessions is updated using the SQL GETDATE function on the
1212 // database server so that all clients will be using the same clock
1213 // to compare access times against.
1214 HRESULT
Access() throw()
1216 HRESULT hr
= E_UNEXPECTED
;
1218 if (!m_szSessionName
||
1219 m_szSessionName
[0]==0)
1220 return hr
; // no session to access
1222 // get the data connection for this thread
1223 CDataConnection dataconn
;
1224 hr
= GetSessionConnection(&dataconn
, m_spServiceProvider
);
1228 // The session reference entry in the references table must
1229 // be created prior to calling this function so we can just
1230 // use an updator to update the current entry.
1231 CCommand
<CAccessor
<CSessionRefUpdator
> > updator
;
1233 DBROWCOUNT nRows
= 0;
1234 hr
= updator
.Assign(m_szSessionName
);
1237 hr
= updator
.Open( dataconn
,
1238 m_QueryObj
.GetSessionRefAccess(),
1245 ATLASSERT(nRows
> 0);
1246 if (hr
== S_OK
&& nRows
<= 0)
1251 // If the session is expired and it's reference is 0,
1252 // it can be deleted. SessionUnlock calls this function to
1253 // unlock the session and delete it after we release a session
1254 // lock. Note that our SQL command will only delete the session
1255 // if it is expired and it's refcount is <= 0
1256 HRESULT
FreeSession() throw()
1258 HRESULT hr
= E_UNEXPECTED
;
1259 if (!m_szSessionName
||
1260 m_szSessionName
[0]==0)
1263 // Get the data connection for this thread.
1264 CDataConnection dataconn
;
1265 hr
= GetSessionConnection(&dataconn
, m_spServiceProvider
);
1269 CCommand
<CAccessor
<CSessionRefUpdator
> > updator
;
1271 // The SQL for this command only deletes the
1272 // session reference from the references table if it's access
1273 // count is 0 and it has expired.
1274 return updator
.Open(dataconn
,
1275 m_QueryObj
.GetSessionRefDelete(),
1282 // Initialize is called each time a new session is created.
1283 HRESULT
Initialize( LPCSTR szSessionName
,
1284 IServiceProvider
*pServiceProvider
,
1286 PFN_GETPROVIDERINFO pfnInfo
) throw()
1289 return E_INVALIDARG
;
1291 if (!pServiceProvider
)
1292 return E_INVALIDARG
;
1295 return E_INVALIDARG
;
1297 m_pfnInfo
= pfnInfo
;
1298 m_dwProvCookie
= dwCookie
;
1299 m_spServiceProvider
= pServiceProvider
;
1303 CA2CT
tcsSessionName(szSessionName
);
1304 if (Checked::tcsnlen(tcsSessionName
, MAX_SESSION_KEY_LEN
) < MAX_SESSION_KEY_LEN
)
1305 Checked::tcscpy_s(m_szSessionName
, _countof(m_szSessionName
), tcsSessionName
);
1307 return E_OUTOFMEMORY
;
1311 return E_OUTOFMEMORY
;
1313 return SessionLock();
1316 HRESULT
GetSessionConnection(CDataConnection
*pConn
,
1317 IServiceProvider
*pProv
) throw()
1320 return E_INVALIDARG
;
1324 return E_UNEXPECTED
;
1326 wchar_t *wszProv
= NULL
;
1327 if (m_pfnInfo(m_dwProvCookie
, &wszProv
) && wszProv
!=NULL
)
1329 return GetDataSource(pProv
,
1339 TCHAR m_szSessionName
[MAX_SESSION_KEY_LEN
];
1340 unsigned __int64 m_dwTimeout
;
1341 CComPtr
<IServiceProvider
> m_spServiceProvider
;
1342 DWORD_PTR m_dwProvCookie
;
1343 PFN_GETPROVIDERINFO m_pfnInfo
;
1344 DBQUERYCLASS_TYPE m_QueryObj
;
1348 template <class TDBSession
=CDBSession
<> >
1349 class CDBSessionServiceImplT
1351 wchar_t m_szConnectionString
[MAX_CONNECTION_STRING_LEN
];
1352 CComPtr
<IServiceProvider
> m_spServiceProvider
;
1353 typename
TDBSession::DBQUERYCLASS_TYPE m_QueryObj
;
1355 typedef const wchar_t* SERVICEIMPL_INITPARAM_TYPE
;
1356 CDBSessionServiceImplT() throw()
1358 m_dwTimeout
= ATL_SESSION_TIMEOUT
;
1359 m_szConnectionString
[0] = '\0';
1362 static bool GetProviderInfo(DWORD_PTR dwProvCookie
, wchar_t **ppszProvInfo
) throw()
1367 CDBSessionServiceImplT
<TDBSession
> *pSvc
=
1368 reinterpret_cast<CDBSessionServiceImplT
<TDBSession
>*>(dwProvCookie
);
1369 *ppszProvInfo
= pSvc
->m_szConnectionString
;
1375 HRESULT
GetSessionConnection(CDataConnection
*pConn
,
1376 IServiceProvider
*pProv
) throw()
1379 return E_INVALIDARG
;
1381 if(!m_szConnectionString
[0])
1382 return E_UNEXPECTED
;
1384 return GetDataSource(pProv
,
1386 m_szConnectionString
,
1390 HRESULT
Initialize(SERVICEIMPL_INITPARAM_TYPE pData
,
1391 IServiceProvider
*pProvider
,
1392 unsigned __int64 dwInitialTimeout
) throw()
1394 if (!pData
|| !pProvider
)
1395 return E_INVALIDARG
;
1397 if (Checked::wcsnlen(pData
, MAX_CONNECTION_STRING_LEN
) < MAX_CONNECTION_STRING_LEN
)
1399 Checked::wcscpy_s(m_szConnectionString
, _countof(m_szConnectionString
), pData
);
1402 return E_OUTOFMEMORY
;
1404 m_dwTimeout
= dwInitialTimeout
;
1405 m_spServiceProvider
= pProvider
;
1409 HRESULT
CreateNewSession(__out_ecount_part_z(*pdwSize
, *pdwSize
) LPSTR szNewID
, __inout DWORD
*pdwSize
, __deref_out ISession
** ppSession
) throw()
1411 HRESULT hr
= E_FAIL
;
1412 CComObject
<TDBSession
> *pNewSession
= NULL
;
1425 return E_INVALIDARG
;
1428 // Create new session
1429 CComObject
<TDBSession
>::CreateInstance(&pNewSession
);
1430 if (pNewSession
== NULL
)
1431 return E_OUTOFMEMORY
;
1433 // Create a session name and initialize the object
1434 hr
= m_SessionNameGenerator
.GetNewSessionName(szNewID
, pdwSize
);
1437 hr
= pNewSession
->Initialize(szNewID
,
1438 m_spServiceProvider
,
1439 reinterpret_cast<DWORD_PTR
>(this),
1443 // we don't hold a reference to the object
1444 hr
= pNewSession
->QueryInterface(ppSession
);
1453 HRESULT
CreateNewSessionByName(__in_z LPSTR szNewID
, __deref_out ISession
** ppSession
) throw()
1455 HRESULT hr
= E_FAIL
;
1456 CComObject
<TDBSession
> *pNewSession
= NULL
;
1458 if (!szNewID
|| *szNewID
== 0)
1459 return E_INVALIDARG
;
1466 // Create new session
1467 CComObject
<TDBSession
>::CreateInstance(&pNewSession
);
1468 if (pNewSession
== NULL
)
1469 return E_OUTOFMEMORY
;
1471 hr
= pNewSession
->Initialize(szNewID
,
1472 m_spServiceProvider
,
1473 reinterpret_cast<DWORD_PTR
>(this),
1477 // we don't hold a reference to the object
1478 hr
= pNewSession
->QueryInterface(ppSession
);
1488 HRESULT
GetSession(LPCSTR szID
, ISession
**ppSession
) throw()
1490 HRESULT hr
= E_FAIL
;
1492 return E_INVALIDARG
;
1499 CComObject
<TDBSession
> *pNewSession
= NULL
;
1501 // Check the DB to see if the session ID is a valid session
1504 CA2CT
session(szID
);
1505 hr
= IsValidSession(session
);
1513 // Create new session object to represent this session
1514 CComObject
<TDBSession
>::CreateInstance(&pNewSession
);
1515 if (pNewSession
== NULL
)
1516 return E_OUTOFMEMORY
;
1518 hr
= pNewSession
->Initialize(szID
,
1519 m_spServiceProvider
,
1520 reinterpret_cast<DWORD_PTR
>(this),
1524 // we don't hold a reference to the object
1525 hr
= pNewSession
->QueryInterface(ppSession
);
1529 if (hr
!= S_OK
&& pNewSession
)
1534 HRESULT
CloseSession(LPCSTR szID
) throw()
1537 return E_INVALIDARG
;
1539 CDataConnection conn
;
1540 HRESULT hr
= GetSessionConnection(&conn
,
1541 m_spServiceProvider
);
1546 CCommand
<CAccessor
<CSessionRefUpdator
> > updator
;
1547 CCommand
<CAccessor
<CSessionDataDeleteAll
> > command
;
1550 CA2CT
session(szID
);
1551 hr
= updator
.Assign(session
);
1553 hr
= command
.Assign(session
);
1562 // delete all session variables (may not be any!)
1563 hr
= command
.Open(conn
,
1564 m_QueryObj
.GetSessionVarDeleteAllVars(),
1571 DBROWCOUNT nRows
= 0;
1573 // delete references in the session references table
1574 hr
= updator
.Open(conn
,
1575 m_QueryObj
.GetSessionRefDeleteFinal(),
1587 HRESULT
SetSessionTimeout(unsigned __int64 nTimeout
) throw()
1589 // Get the data connection for this thread
1590 CDataConnection conn
;
1592 HRESULT hr
= GetSessionConnection(&conn
, m_spServiceProvider
);
1596 // all sessions get the same timeout
1597 CCommand
<CAccessor
<CSetAllTimeouts
> > command
;
1598 hr
= command
.Assign(nTimeout
);
1601 hr
= command
.Open(conn
, m_QueryObj
.GetSessionReferencesSet(),
1608 m_dwTimeout
= nTimeout
;
1615 HRESULT
GetSessionTimeout(unsigned __int64
* pnTimeout
) throw()
1618 *pnTimeout
= m_dwTimeout
;
1620 return E_INVALIDARG
;
1625 HRESULT
GetSessionCount(DWORD
*pnCount
) throw()
1632 CCommand
<CAccessor
<CSessionRefCount
> > command
;
1633 CDataConnection conn
;
1634 HRESULT hr
= GetSessionConnection(&conn
,
1635 m_spServiceProvider
);
1639 hr
= command
.Open(conn
,
1640 m_QueryObj
.GetSessionRefGetCount());
1643 hr
= command
.MoveFirst();
1646 *pnCount
= (DWORD
)command
.m_nCount
;
1653 void ReleaseAllSessions() throw()
1658 void SweepSessions() throw()
1665 HRESULT
IsValidSession(LPCTSTR szID
) throw()
1668 return E_INVALIDARG
;
1669 // Look in the sessionreferences table to see if there is an entry
1670 // for this session.
1671 if (m_szConnectionString
[0] == 0)
1672 return E_UNEXPECTED
;
1674 CDataConnection conn
;
1675 HRESULT hr
= GetSessionConnection(&conn
,
1676 m_spServiceProvider
);
1680 // Check the session references table to see if
1681 // this is a valid session
1682 CCommand
<CAccessor
<CSessionRefSelector
> > selector
;
1683 hr
= selector
.Assign(szID
);
1687 hr
= selector
.Open(conn
,
1688 m_QueryObj
.GetSessionRefSelect(),
1694 return selector
.MoveFirst();
1698 CSessionNameGenerator m_SessionNameGenerator
; // Object for generating session names
1699 unsigned __int64 m_dwTimeout
;
1700 }; // CDBSessionServiceImplT
1702 typedef CDBSessionServiceImplT
<> CDBSessionServiceImpl
;
1708 //////////////////////////////////////////////////////////////////
1710 // In-memory persisted session
1712 //////////////////////////////////////////////////////////////////
1714 // In-memory persisted session service keeps a pointer
1715 // to the session obejct around in memory. The pointer is
1716 // contained in a CComPtr, which is stored in a CAtlMap, so
1717 // we have to have a CElementTraits class for that.
1718 typedef CComPtr
<ISession
> SESSIONPTRTYPE
;
1721 class CElementTraits
<SESSIONPTRTYPE
> :
1722 public CElementTraitsBase
<SESSIONPTRTYPE
>
1725 static ULONG
Hash( INARGTYPE obj
) throw()
1727 return( (ULONG
)(ULONG_PTR
)obj
.p
);
1730 static BOOL
CompareElements( OUTARGTYPE element1
, OUTARGTYPE element2
) throw()
1732 return element1
.IsEqualObject(element2
.p
) ? TRUE
: FALSE
;
1735 static int CompareElementsOrdered( INARGTYPE
, INARGTYPE
) throw()
1737 ATLASSERT(0); // NOT IMPLEMENTED
1744 // This session persistance class persists session variables in memory.
1745 // Note that this type of persistance should only be used on single server
1749 public CComObjectRootEx
<CComGlobalsThreadModel
>
1752 BEGIN_COM_MAP(CMemSession
)
1753 COM_INTERFACE_ENTRY(ISession
)
1756 CMemSession() throw(...)
1759 virtual ~CMemSession()
1763 STDMETHOD(GetVariable
)(LPCSTR szName
, VARIANT
*pVal
) throw()
1766 return E_INVALIDARG
;
1773 HRESULT hr
= Access();
1776 CSLockType
lock(m_cs
, false);
1785 if (m_Variables
.Lookup(szName
, val
))
1787 hr
= VariantCopy(pVal
, &val
);
1798 STDMETHOD(SetVariable
)(LPCSTR szName
, VARIANT vNewVal
) throw()
1801 return E_INVALIDARG
;
1803 HRESULT hr
= Access();
1806 CSLockType
lock(m_cs
, false);
1812 hr
= m_Variables
.SetAt(szName
, vNewVal
) ? S_OK
: E_FAIL
;
1822 STDMETHOD(RemoveVariable
)(LPCSTR szName
) throw()
1825 return E_INVALIDARG
;
1827 HRESULT hr
= Access();
1830 CSLockType
lock(m_cs
, false);
1836 hr
= m_Variables
.RemoveKey(szName
) ? S_OK
: E_FAIL
;
1846 STDMETHOD(GetCount
)(long *pnCount
) throw()
1853 HRESULT hr
= Access();
1856 CSLockType
lock(m_cs
, false);
1860 *pnCount
= (long) m_Variables
.GetCount();
1865 STDMETHOD(RemoveAllVariables
)() throw()
1867 HRESULT hr
= Access();
1870 CSLockType
lock(m_cs
, false);
1874 m_Variables
.RemoveAll();
1880 STDMETHOD(BeginVariableEnum
)(POSITION
*pPOS
, HSESSIONENUM
*phEnumHandle
=NULL
) throw()
1883 *phEnumHandle
= NULL
;
1890 HRESULT hr
= Access();
1893 CSLockType
lock(m_cs
, false);
1897 *pPOS
= m_Variables
.GetStartPosition();
1902 STDMETHOD(GetNextVariable
)(POSITION
*pPOS
, VARIANT
*pVal
,
1903 HSESSIONENUM hEnum
=NULL
,
1905 DWORD dwLen
=0 ) throw()
1917 POSITION pos
= *pPOS
;
1918 HRESULT hr
= Access();
1921 CSLockType
lock(m_cs
, false);
1931 CStringA strName
= m_Variables
.GetKeyAt(pos
);
1932 if (strName
.GetLength())
1934 if (dwLen
> (DWORD
)strName
.GetLength())
1936 Checked::strcpy_s(szName
, dwLen
, strName
);
1948 val
= m_Variables
.GetNextValue(pos
);
1949 hr
= VariantCopy(pVal
, &val
);
1962 STDMETHOD(CloseEnum
)(HSESSIONENUM
/*hEnumHandle*/) throw()
1967 STDMETHOD(IsExpired
)() throw()
1969 CTime tmNow
= CTime::GetCurrentTime();
1970 CTimeSpan span
= tmNow
-m_tLastAccess
;
1971 if ((unsigned __int64
)((span
.GetTotalSeconds()*1000)) > m_dwTimeout
)
1976 HRESULT
Access() throw()
1978 // We lock here to protect against multiple threads
1979 // updating the same member concurrently.
1980 CSLockType
lock(m_cs
, false);
1981 HRESULT hr
= lock
.Lock();
1984 m_tLastAccess
= CTime::GetCurrentTime();
1988 STDMETHOD(SetTimeout
)(unsigned __int64 dwNewTimeout
) throw()
1990 // We lock here to protect against multiple threads
1991 // updating the same member concurrently
1992 CSLockType
lock(m_cs
, false);
1993 HRESULT hr
= lock
.Lock();
1996 m_dwTimeout
= dwNewTimeout
;
2000 HRESULT
SessionLock() throw()
2006 HRESULT
SessionUnlock() throw()
2012 typedef CAtlMap
<CStringA
,
2014 CStringElementTraits
<CStringA
> > VarMapType
;
2015 unsigned __int64 m_dwTimeout
;
2016 CTime m_tLastAccess
;
2017 VarMapType m_Variables
;
2018 CComAutoCriticalSection m_cs
;
2019 typedef CComCritSecLock
<CComAutoCriticalSection
> CSLockType
;
2024 // CMemSessionServiceImpl
2025 // Implements the service part of in-memory persisted session services.
2027 class CMemSessionServiceImpl
2030 typedef void* SERVICEIMPL_INITPARAM_TYPE
;
2031 CMemSessionServiceImpl() throw()
2033 m_dwTimeout
= ATL_SESSION_TIMEOUT
;
2036 ~CMemSessionServiceImpl() throw()
2041 HRESULT
CreateNewSession(__out_ecount_part_z(*pdwSize
, *pdwSize
) LPSTR szNewID
, __inout DWORD
*pdwSize
, __deref_out_opt ISession
** ppSession
) throw()
2043 HRESULT hr
= E_FAIL
;
2044 CComObject
<CMemSession
> *pNewSession
= NULL
;
2047 return E_INVALIDARG
;
2059 // Create new session
2060 CComObject
<CMemSession
>::CreateInstance(&pNewSession
);
2061 if (pNewSession
== NULL
)
2062 return E_OUTOFMEMORY
;
2064 // Initialize and add to list of CSessionData
2065 hr
= m_SessionNameGenerator
.GetNewSessionName(szNewID
, pdwSize
);
2069 CComPtr
<ISession
> spSession
;
2070 hr
= pNewSession
->QueryInterface(&spSession
);
2073 pNewSession
->SetTimeout(m_dwTimeout
);
2074 pNewSession
->Access();
2075 CSLockType
lock(m_CritSec
, false);
2079 hr
= m_Sessions
.SetAt(szNewID
, spSession
) != NULL
? S_OK
: E_FAIL
;
2081 *ppSession
= spSession
.Detach();
2094 HRESULT
CreateNewSessionByName(__in_z LPSTR szNewID
, __deref_out_opt ISession
** ppSession
) throw()
2096 HRESULT hr
= E_FAIL
;
2097 CComObject
<CMemSession
> *pNewSession
= NULL
;
2099 if (!szNewID
|| *szNewID
== 0)
2100 return E_INVALIDARG
;
2107 CComPtr
<ISession
> spSession
;
2108 // If the session already exists, you get a pointer to the
2109 // existing session. You can't have multiple entries with the
2110 // same name in CAtlMap
2111 hr
= GetSession(szNewID
, &spSession
);
2114 *ppSession
= spSession
.Detach();
2120 // Create new session
2121 CComObject
<CMemSession
>::CreateInstance(&pNewSession
);
2122 if (pNewSession
== NULL
)
2123 return E_OUTOFMEMORY
;
2126 hr
= pNewSession
->QueryInterface(&spSession
);
2129 pNewSession
->SetTimeout(m_dwTimeout
);
2130 pNewSession
->Access();
2131 CSLockType
lock(m_CritSec
, false);
2136 hr
= m_Sessions
.SetAt(szNewID
, spSession
) != NULL
? S_OK
: E_FAIL
;
2139 *ppSession
= spSession
.Detach();
2151 HRESULT
GetSession(LPCSTR szID
, ISession
**ppSession
) throw()
2153 HRESULT hr
= E_FAIL
;
2154 SessMapType::CPair
*pPair
= NULL
;
2162 return E_INVALIDARG
;
2164 CSLockType
lock(m_CritSec
, false);
2172 pPair
= m_Sessions
.Lookup(szID
);
2173 if (pPair
) // the session exists and is in our local map of sessions
2175 hr
= pPair
->m_value
.QueryInterface(ppSession
);
2180 return E_UNEXPECTED
;
2186 HRESULT
CloseSession(LPCSTR szID
) throw()
2189 return E_INVALIDARG
;
2191 HRESULT hr
= E_FAIL
;
2192 CSLockType
lock(m_CritSec
, false);
2198 hr
= m_Sessions
.RemoveKey(szID
) ? S_OK
: E_UNEXPECTED
;
2207 void SweepSessions() throw()
2209 POSITION posRemove
= NULL
;
2210 const SessMapType::CPair
*pPair
= NULL
;
2211 POSITION pos
= NULL
;
2213 CSLockType
lock(m_CritSec
, false);
2214 if (FAILED(lock
.Lock()))
2216 pos
= m_Sessions
.GetStartPosition();
2220 pPair
= m_Sessions
.GetNext(pos
);
2223 if (pPair
->m_value
.p
&&
2224 S_OK
== pPair
->m_value
->IsExpired())
2226 // remove our reference on the session
2227 m_Sessions
.RemoveAtPos(posRemove
);
2233 HRESULT
SetSessionTimeout(unsigned __int64 nTimeout
) throw()
2236 CComPtr
<ISession
> spSession
;
2237 m_dwTimeout
= nTimeout
;
2239 CSLockType
lock(m_CritSec
, false);
2244 POSITION pos
= m_Sessions
.GetStartPosition();
2246 return S_OK
; // no sessions to set the timeout on
2251 SessMapType::CPair
*pPair
= const_cast<SessMapType::CPair
*>(m_Sessions
.GetNext(pos
));
2254 spSession
= pPair
->m_value
;
2257 // if we fail on any of the sets we will return the
2258 // error code immediately
2259 hr
= spSession
->SetTimeout(nTimeout
);
2260 spSession
.Release();
2280 HRESULT
GetSessionTimeout(unsigned __int64
* pnTimeout
) throw()
2283 *pnTimeout
= m_dwTimeout
;
2290 HRESULT
GetSessionCount(DWORD
*pnCount
) throw()
2297 CSLockType
lock(m_CritSec
, false);
2298 HRESULT hr
= lock
.Lock();
2301 *pnCount
= (DWORD
)m_Sessions
.GetCount();
2306 void ReleaseAllSessions() throw()
2308 CSLockType
lock(m_CritSec
, false);
2309 if (FAILED(lock
.Lock()))
2311 m_Sessions
.RemoveAll();
2314 HRESULT
Initialize(SERVICEIMPL_INITPARAM_TYPE
,
2316 unsigned __int64 dwNewTimeout
) throw()
2318 m_dwTimeout
= dwNewTimeout
;
2319 return m_CritSec
.Init();
2322 typedef CAtlMap
<CStringA
,
2324 CStringElementTraits
<CStringA
>,
2325 CElementTraitsBase
<SESSIONPTRTYPE
> > SessMapType
;
2327 SessMapType m_Sessions
; // map for holding sessions in memory
2328 CComCriticalSection m_CritSec
; // for synchronizing access to map
2329 typedef CComCritSecLock
<CComCriticalSection
> CSLockType
;
2330 CSessionNameGenerator m_SessionNameGenerator
; // Object for generating session names
2331 unsigned __int64 m_dwTimeout
;
2332 }; // CMemSessionServiceImpl
2337 // CSessionStateService
2338 // This class implements the session state service which can be
2339 // exposed to request handlers.
2341 // Template Parameters:
2342 // MonitorClass: Provides periodic sweeping services for the session service class.
2343 // TServiceImplClass: The class that actually implements the methods of the
2344 // ISessionStateService and ISessionStateControl interfaces.
2345 template <class MonitorClass
, class TServiceImplClass
>
2346 class CSessionStateService
:
2347 public ISessionStateService
,
2348 public ISessionStateControl
,
2349 public IWorkerThreadClient
,
2350 public CComObjectRootEx
<CComGlobalsThreadModel
>
2353 MonitorClass m_Monitor
;
2355 CComPtr
<IServiceProvider
> m_spServiceProvider
;
2356 TServiceImplClass m_SessionServiceImpl
;
2358 // Construction/Initialization
2359 CSessionStateService() throw() :
2364 ~CSessionStateService() throw()
2366 ATLASSUME(m_hTimer
== NULL
);
2368 BEGIN_COM_MAP(CSessionStateService
)
2369 COM_INTERFACE_ENTRY(ISessionStateService
)
2370 COM_INTERFACE_ENTRY(ISessionStateControl
)
2373 // ISessionStateServie methods
2374 STDMETHOD(CreateNewSession
)(LPSTR szNewID
, DWORD
*pdwSize
, ISession
** ppSession
) throw()
2376 return m_SessionServiceImpl
.CreateNewSession(szNewID
, pdwSize
, ppSession
);
2379 STDMETHOD(CreateNewSessionByName
)(LPSTR szNewID
, ISession
** ppSession
) throw()
2381 return m_SessionServiceImpl
.CreateNewSessionByName(szNewID
, ppSession
);
2384 STDMETHOD(GetSession
)(LPCSTR szID
, ISession
**ppSession
) throw()
2386 return m_SessionServiceImpl
.GetSession(szID
, ppSession
);
2389 STDMETHOD(CloseSession
)(LPCSTR szSessionID
) throw()
2391 return m_SessionServiceImpl
.CloseSession(szSessionID
);
2394 STDMETHOD(SetSessionTimeout
)(unsigned __int64 nTimeout
) throw()
2396 return m_SessionServiceImpl
.SetSessionTimeout(nTimeout
);
2399 STDMETHOD(GetSessionTimeout
)(unsigned __int64
*pnTimeout
) throw()
2401 return m_SessionServiceImpl
.GetSessionTimeout(pnTimeout
);
2404 STDMETHOD(GetSessionCount
)(DWORD
*pnSessionCount
) throw()
2406 return m_SessionServiceImpl
.GetSessionCount(pnSessionCount
);
2409 void SweepSessions() throw()
2411 m_SessionServiceImpl
.SweepSessions();
2414 void ReleaseAllSessions() throw()
2416 m_SessionServiceImpl
.ReleaseAllSessions();
2420 IServiceProvider
*pServiceProvider
= NULL
,
2421 typename
TServiceImplClass::SERVICEIMPL_INITPARAM_TYPE pInitData
= NULL
,
2422 unsigned __int64 dwTimeout
= ATL_SESSION_TIMEOUT
) throw()
2425 if (pServiceProvider
)
2426 m_spServiceProvider
= pServiceProvider
;
2428 hr
= m_SessionServiceImpl
.Initialize(pInitData
, pServiceProvider
, dwTimeout
);
2434 template <class ThreadTraits
>
2436 CWorkerThread
<ThreadTraits
> *pWorker
,
2437 IServiceProvider
*pServiceProvider
= NULL
,
2438 typename
TServiceImplClass::SERVICEIMPL_INITPARAM_TYPE pInitData
= NULL
,
2439 unsigned __int64 dwTimeout
= ATL_SESSION_TIMEOUT
) throw()
2442 return E_INVALIDARG
;
2444 HRESULT hr
= Initialize(pServiceProvider
, pInitData
, dwTimeout
);
2447 hr
= m_Monitor
.Initialize(pWorker
);
2451 hr
= m_Monitor
.AddTimer(ATL_SESSION_SWEEPER_TIMEOUT
, this, 0, &m_hTimer
);
2457 void Shutdown() throw()
2461 if(FAILED(m_Monitor
.RemoveHandle(m_hTimer
)))
2463 /* can't report from here */
2468 ReleaseAllSessions();
2471 HRESULT
Execute(DWORD_PTR
/*dwParam*/, HANDLE
/*hObject*/) throw()
2477 HRESULT
CloseHandle(HANDLE hHandle
) throw()
2479 ::CloseHandle(hHandle
);
2484 }; // CSessionStateService
2489 #pragma warning(pop)
2490 #endif // __ATLSESSION_H__