Fix(ed) crash issues with NV12/NV21+"Piture Size=>Vertical padding not setting to...
[xy_vsfilter.git] / include / atl / atlsession.h
blob808748b21f375023899dfd4b426358d45de223b8
1 // This is a part of the Active Template Library.
2 // Copyright (C) Microsoft Corporation
3 // All rights reserved.
4 //
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__
14 #pragma once
15 #pragma warning(push)
16 #pragma warning(disable: 4702) // unreachable code
18 #include <atldbcli.h>
19 #include <atlcom.h>
20 #include <atlstr.h>
21 #include <stdio.h>
22 #include <atlcoll.h>
23 #include <atltime.h>
24 #include <atlcrypt.h>
25 #include <atlenc.h>
26 #include <atlutil.h>
27 #include <atlcache.h>
28 #include <atlspriv.h>
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
36 #endif
38 #ifndef MAX_VARIABLE_NAME_LENGTH
39 #define MAX_VARIABLE_NAME_LENGTH 50
40 #endif
42 #ifndef MAX_VARIABLE_VALUE_LENGTH
43 #define MAX_VARIABLE_VALUE_LENGTH 1024
44 #endif
46 #ifndef MAX_CONNECTION_STRING_LEN
47 #define MAX_CONNECTION_STRING_LEN 2048
48 #endif
50 #ifndef SESSION_COOKIE_NAME
51 #define SESSION_COOKIE_NAME "SESSIONID"
52 #endif
54 #ifndef ATL_SESSION_TIMEOUT
55 #define ATL_SESSION_TIMEOUT 600000 //10 min
56 #endif
58 #ifndef ATL_SESSION_SWEEPER_TIMEOUT
59 #define ATL_SESSION_SWEEPER_TIMEOUT 1000 // 1sec
60 #endif
62 #define INVALID_DB_SESSION_POS 0x0
63 #define ATL_DBSESSION_ID _T("__ATL_SESSION_DB_CONNECTION")
65 #pragma pack(push,_ATL_PACKING)
66 namespace ATL {
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 :
76 public CCryptProv
78 public:
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
87 // information
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()
99 HRESULT hr = E_FAIL;
101 if (!pdwSize)
102 return E_POINTER;
104 if (*pdwSize < MIN_SESSION_KEY_LEN ||
105 *pdwSize > MAX_SESSION_KEY_LEN)
106 return E_INVALIDARG;
108 if (!szNewID)
109 return E_POINTER;
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);
123 if (SUCCEEDED(hr))
125 if( Base64Encode(key,
126 dwDataSize,
127 szNewID,
128 &dwKeySize,
129 ATL_BASE64_FLAG_NOCRLF) )
131 //null terminate
132 szNewID[dwKeySize]=0;
133 *pdwSize = dwKeySize+1;
135 else
136 hr = E_FAIL;
138 else
140 *pdwSize = (DWORD)(Base64EncodeGetRequiredLength(dwDataSize,
141 ATL_BASE64_FLAG_NOCRLF));
142 return E_OUTOFMEMORY;
145 return hr;
148 DWORD CalcMaxInputSize(DWORD nOutputSize) throw()
150 if (nOutputSize < (DWORD)MIN_SESSION_KEY_LEN)
151 return 0;
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;
159 if (factor)
160 nInputSize -= factor;
161 return nInputSize;
165 HRESULT GenerateRandomName(BYTE *pBuff, DWORD dwBuffSize) throw()
167 if (!pBuff)
168 return E_POINTER;
170 if (!dwBuffSize)
171 return E_UNEXPECTED;
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.
185 FILETIME ft;
186 GetSystemTimeAsFileTime(&ft);
187 static DWORD dwVal = 0x21;
188 DWORD dwSeed = (dwVal++ << 0x18) | (ft.dwLowDateTime & 0x00ffff00) | dwVal++ & 0x000000ff;
189 srand(dwSeed);
190 BYTE *pCurr = pBuff;
191 // fill buffer with random bytes
192 for (int i=0; i < (int)dwBuffSize; i++)
194 *pCurr = (BYTE) (rand() & 0x000000ff);
195 pCurr++;
197 return S_OK;
203 // CDefaultQueryClass
204 // returns Query strings for use in SQL queries used
205 // by the database persisted session service.
206 class CDefaultQueryClass
208 public:
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
330 public:
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';
340 m_VariableLen = 0;
342 HRESULT Assign(LPCTSTR szSessionID, LPCTSTR szVarName, VARIANT *pVal) throw()
344 HRESULT hr = S_OK;
345 CVariantStream stream;
346 if ( szSessionID )
348 if (Checked::tcsnlen(szSessionID, MAX_SESSION_KEY_LEN)< MAX_SESSION_KEY_LEN)
349 Checked::tcscpy_s(m_szSessionID, _countof(m_szSessionID), szSessionID);
350 else
351 hr = E_OUTOFMEMORY;
353 else
354 return E_INVALIDARG;
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);
359 else
360 hr = E_OUTOFMEMORY;
362 if (hr == S_OK && pVal)
364 hr = stream.InsertVariant(pVal);
365 if (hr == S_OK)
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);
374 else
375 hr = E_INVALIDARG;
379 return hr;
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
387 public:
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)
392 END_COLUMN_MAP()
393 BEGIN_PARAM_MAP(CSessionDataSelector)
394 SET_PARAM_TYPE(DBPARAMIO_INPUT)
395 COLUMN_ENTRY(1, m_szSessionID)
396 COLUMN_ENTRY(2, m_VariableName)
397 END_PARAM_MAP()
400 // Use to select all session variables given the name of
401 // of a session.
402 class CAllSessionDataSelector : public CSessionDataBase
404 public:
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)
409 END_COLUMN_MAP()
410 BEGIN_PARAM_MAP(CAllSessionDataSelector)
411 SET_PARAM_TYPE(DBPARAMIO_INPUT)
412 COLUMN_ENTRY(1, m_szSessionID)
413 END_PARAM_MAP()
416 // Use to update the value of a session variable
417 class CSessionDataUpdator : public CSessionDataBase
419 public:
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)
425 END_PARAM_MAP()
428 // Use to delete a session variable given the
429 // session name and the name of the variable
430 class CSessionDataDeletor
432 public:
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()
443 if (szSessionID)
445 if (Checked::tcsnlen(szSessionID, MAX_SESSION_KEY_LEN) < MAX_SESSION_KEY_LEN)
446 Checked::tcscpy_s(m_szSessionID, _countof(m_szSessionID), szSessionID);
447 else
448 return E_OUTOFMEMORY;
451 if (szVarName)
453 if(Checked::tcsnlen(szVarName, MAX_VARIABLE_NAME_LENGTH) < MAX_VARIABLE_NAME_LENGTH)
454 Checked::tcscpy_s(m_VariableName, _countof(m_VariableName), szVarName);
455 else
456 return E_OUTOFMEMORY;
458 return S_OK;
461 BEGIN_PARAM_MAP(CSessionDataDeletor)
462 SET_PARAM_TYPE(DBPARAMIO_INPUT)
463 COLUMN_ENTRY(1, m_szSessionID)
464 COLUMN_ENTRY(2, m_VariableName)
465 END_PARAM_MAP()
468 class CSessionDataDeleteAll
470 public:
471 TCHAR m_szSessionID[MAX_SESSION_KEY_LEN];
472 HRESULT Assign(LPCTSTR szSessionID) throw()
474 if (!szSessionID)
475 return E_INVALIDARG;
477 if (Checked::tcsnlen(szSessionID, MAX_SESSION_KEY_LEN) < MAX_SESSION_KEY_LEN)
478 Checked::tcscpy_s(m_szSessionID, _countof(m_szSessionID), szSessionID);
479 else
480 return E_OUTOFMEMORY;
482 return S_OK;
485 BEGIN_PARAM_MAP(CSessionDataDeleteAll)
486 SET_PARAM_TYPE(DBPARAMIO_INPUT)
487 COLUMN_ENTRY(1, m_szSessionID)
488 END_PARAM_MAP()
491 // Used for retrieving the count of session variables for
492 // a given session ID.
493 class CCountAccessor
495 public:
496 LONG m_nCount;
497 TCHAR m_szSessionID[MAX_SESSION_KEY_LEN];
498 CCountAccessor() throw()
500 m_szSessionID[0] = '\0';
501 m_nCount = 0;
504 HRESULT Assign(LPCTSTR szSessionID) throw()
506 if (!szSessionID)
507 return E_INVALIDARG;
509 if (Checked::tcsnlen(szSessionID, MAX_SESSION_KEY_LEN) < MAX_SESSION_KEY_LEN)
510 Checked::tcscpy_s(m_szSessionID, _countof(m_szSessionID), szSessionID);
511 else
512 return E_OUTOFMEMORY;
514 return S_OK;
517 BEGIN_COLUMN_MAP(CCountAccessor)
518 COLUMN_ENTRY(1, m_nCount)
519 END_COLUMN_MAP()
520 BEGIN_PARAM_MAP(CCountAccessor)
521 SET_PARAM_TYPE(DBPARAMIO_INPUT)
522 COLUMN_ENTRY(1, m_szSessionID)
523 END_PARAM_MAP()
527 // Used for updating entries in the session
528 // references table, given a session ID
529 class CSessionRefUpdator
531 public:
532 TCHAR m_SessionID[MAX_SESSION_KEY_LEN];
533 HRESULT Assign(LPCTSTR szSessionID) throw()
535 if (!szSessionID)
536 return E_INVALIDARG;
537 if (Checked::tcsnlen(szSessionID, MAX_SESSION_KEY_LEN) < MAX_SESSION_KEY_LEN)
538 Checked::tcscpy_s(m_SessionID, _countof(m_SessionID), szSessionID);
539 else
540 return E_OUTOFMEMORY;
541 return S_OK;
543 BEGIN_PARAM_MAP(CSessionRefUpdator)
544 SET_PARAM_TYPE(DBPARAMIO_INPUT)
545 COLUMN_ENTRY(1, m_SessionID)
546 END_PARAM_MAP()
549 class CSessionRefIsExpired
551 public:
552 TCHAR m_SessionID[MAX_SESSION_KEY_LEN];
553 TCHAR m_SessionIDOut[MAX_SESSION_KEY_LEN];
554 HRESULT Assign(LPCTSTR szSessionID) throw()
556 m_SessionIDOut[0]=0;
557 if (!szSessionID)
558 return E_INVALIDARG;
559 if (Checked::tcsnlen(szSessionID, MAX_SESSION_KEY_LEN) < MAX_SESSION_KEY_LEN)
560 Checked::tcscpy_s(m_SessionID, _countof(m_SessionID), szSessionID);
561 else
562 return E_OUTOFMEMORY;
563 return S_OK;
565 BEGIN_COLUMN_MAP(CSessionRefIsExpired)
566 COLUMN_ENTRY(1, m_SessionIDOut)
567 END_COLUMN_MAP()
568 BEGIN_PARAM_MAP(CSessionRefIsExpired)
569 SET_PARAM_TYPE(DBPARAMIO_INPUT)
570 COLUMN_ENTRY(1, m_SessionID)
571 END_PARAM_MAP()
574 class CSetAllTimeouts
576 public:
577 unsigned __int64 m_dwNewTimeout;
578 HRESULT Assign(unsigned __int64 dwNewValue)
580 m_dwNewTimeout = dwNewValue;
581 return S_OK;
583 BEGIN_PARAM_MAP(CSetAllTimeouts)
584 SET_PARAM_TYPE(DBPARAMIO_INPUT)
585 COLUMN_ENTRY(1, m_dwNewTimeout)
586 END_PARAM_MAP()
589 class CSessionRefUpdateTimeout
591 public:
592 TCHAR m_SessionID[MAX_SESSION_KEY_LEN];
593 unsigned __int64 m_nNewTimeout;
594 HRESULT Assign(LPCTSTR szSessionID, unsigned __int64 nNewTimeout) throw()
596 if (!szSessionID)
597 return E_INVALIDARG;
599 if (Checked::tcsnlen(szSessionID, MAX_SESSION_KEY_LEN) < MAX_SESSION_KEY_LEN)
600 Checked::tcscpy_s(m_SessionID, _countof(m_SessionID), szSessionID);
601 else
602 return E_OUTOFMEMORY;
604 m_nNewTimeout = nNewTimeout;
606 return S_OK;
609 BEGIN_PARAM_MAP(CSessionRefUpdateTimeout)
610 SET_PARAM_TYPE(DBPARAMIO_INPUT)
611 COLUMN_ENTRY(1, m_nNewTimeout)
612 COLUMN_ENTRY(2, m_SessionID)
613 END_PARAM_MAP()
616 class CSessionRefSelector
618 public:
619 TCHAR m_SessionID[MAX_SESSION_KEY_LEN];
620 int m_RefCount;
621 HRESULT Assign(LPCTSTR szSessionID) throw()
623 if (!szSessionID)
624 return E_INVALIDARG;
625 if (Checked::tcsnlen(szSessionID, MAX_SESSION_KEY_LEN) < MAX_SESSION_KEY_LEN)
626 Checked::tcscpy_s(m_SessionID, _countof(m_SessionID), szSessionID);
627 else
628 return E_OUTOFMEMORY;
629 return S_OK;
631 BEGIN_COLUMN_MAP(CSessionRefSelector)
632 COLUMN_ENTRY(1, m_SessionID)
633 COLUMN_ENTRY(3, m_RefCount)
634 END_COLUMN_MAP()
635 BEGIN_PARAM_MAP(CSessionRefSelector)
636 SET_PARAM_TYPE(DBPARAMIO_INPUT)
637 COLUMN_ENTRY(1, m_SessionID)
638 END_PARAM_MAP()
641 class CSessionRefCount
643 public:
644 LONG m_nCount;
645 BEGIN_COLUMN_MAP(CSessionRefCount)
646 COLUMN_ENTRY(1, m_nCount)
647 END_COLUMN_MAP()
650 // Used for creating new entries in the session
651 // references table.
652 class CSessionRefCreator
654 public:
655 TCHAR m_SessionID[MAX_SESSION_KEY_LEN];
656 unsigned __int64 m_TimeoutMs;
657 HRESULT Assign(LPCTSTR szSessionID, unsigned __int64 timeout) throw()
659 if (!szSessionID)
660 return E_INVALIDARG;
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;
666 else
667 return E_OUTOFMEMORY;
668 return S_OK;
670 BEGIN_PARAM_MAP(CSessionRefCreator)
671 SET_PARAM_TYPE(DBPARAMIO_INPUT)
672 COLUMN_ENTRY(1, m_SessionID)
673 COLUMN_ENTRY(2, m_TimeoutMs)
674 END_PARAM_MAP()
678 // CDBSession
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>
700 class CDBSession:
701 public ISession,
702 public CComObjectRootEx<CComGlobalsThreadModel>
705 typedef CCommand<CAccessor<CAllSessionDataSelector> > iterator_accessor;
706 public:
707 typedef QueryClass DBQUERYCLASS_TYPE;
708 BEGIN_COM_MAP(CDBSession)
709 COM_INTERFACE_ENTRY(ISession)
710 END_COM_MAP()
712 CDBSession() throw():
713 m_dwTimeout(ATL_SESSION_TIMEOUT)
715 m_szSessionName[0] = '\0';
718 ~CDBSession() throw()
722 void FinalRelease()throw()
724 SessionUnlock();
727 STDMETHOD(SetVariable)(LPCSTR szName, VARIANT Val) throw()
729 HRESULT hr = E_FAIL;
730 if (!szName)
731 return E_INVALIDARG;
733 // Get the data connection for this thread.
734 CDataConnection dataconn;
735 hr = GetSessionConnection(&dataconn, m_spServiceProvider);
736 if (hr != S_OK)
737 return hr;
739 // Update the last access time for this session
740 hr = Access();
741 if (hr != S_OK)
742 return hr;
744 // Allocate an updator command and fill out it's input parameters.
745 CCommand<CAccessor<CSessionDataUpdator> > command;
746 _ATLTRY
748 CA2CT name(szName);
749 hr = command.Assign(m_szSessionName, name, &Val);
751 _ATLCATCHALL()
753 hr = E_OUTOFMEMORY;
755 if (hr != S_OK)
756 return hr;
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)
765 hr = E_UNEXPECTED;
766 if (hr != S_OK)
768 // Try an insert
769 hr = command.Open(dataconn, m_QueryObj.GetSessionVarInsert(), NULL, &nRows, DBGUID_DEFAULT, false);
770 if (hr == S_OK && nRows <=0)
771 hr = E_UNEXPECTED;
774 return hr;
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()
781 HRESULT hr = E_FAIL;
782 if (!szName)
783 return E_INVALIDARG;
784 if (pVal)
785 VariantInit(pVal);
786 else
787 return E_POINTER;
789 // Get the data connection for this thread
790 CDataConnection dataconn;
791 hr = GetSessionConnection(&dataconn, m_spServiceProvider);
792 if (hr != S_OK)
793 return hr;
795 // Update the last access time for this session
796 hr = Access();
797 if (hr != S_OK)
798 return hr;
800 // Allocate a command a fill out it's input parameters.
801 CCommand<CAccessor<CSessionDataSelector> > command;
802 _ATLTRY
804 CA2CT name(szName);
805 hr = command.Assign(m_szSessionName, name, NULL);
807 _ATLCATCHALL()
809 hr = E_OUTOFMEMORY;
812 if (hr == S_OK)
814 hr = command.Open(dataconn, m_QueryObj.GetSessionVarSelectVar());
815 if (SUCCEEDED(hr))
817 if ( S_OK == (hr = command.MoveFirst()))
819 CStreamOnByteArray stream(command.m_VariableValue);
820 CComVariant vOut;
821 hr = vOut.ReadFromStream(static_cast<IStream*>(&stream));
822 if (hr == S_OK)
823 hr = vOut.Detach(pVal);
827 return hr;
830 STDMETHOD(RemoveVariable)(LPCSTR szName) throw()
832 HRESULT hr = E_FAIL;
833 if (!szName)
834 return E_INVALIDARG;
836 // Get the data connection for this thread.
837 CDataConnection dataconn;
838 hr = GetSessionConnection(&dataconn, m_spServiceProvider);
839 if (hr != S_OK)
840 return hr;
842 // update the last access time for this session
843 hr = Access();
844 if (hr != S_OK)
845 return hr;
847 // allocate a command and set it's input parameters
848 CCommand<CAccessor<CSessionDataDeletor> > command;
849 _ATLTRY
851 CA2CT name(szName);
852 hr = command.Assign(m_szSessionName, name);
854 _ATLCATCHALL()
856 return E_OUTOFMEMORY;
859 // execute the command
860 DBROWCOUNT nRows = 0;
861 if (hr == S_OK)
862 hr = command.Open(dataconn, m_QueryObj.GetSessionVarDeleteVar(),
863 NULL, &nRows, DBGUID_DEFAULT, false);
864 if (hr == S_OK && nRows <= 0)
865 hr = E_FAIL;
866 return hr;
869 // Gives the count of rows in the table for this session ID.
870 STDMETHOD(GetCount)(long *pnCount) throw()
872 HRESULT hr = S_OK;
873 if (pnCount)
874 *pnCount = 0;
875 else
876 return E_POINTER;
878 // Get the database connection for this thread.
879 CDataConnection dataconn;
880 hr = GetSessionConnection(&dataconn, m_spServiceProvider);
881 if (hr != S_OK)
882 return hr;
883 hr = Access();
884 if (hr != S_OK)
885 return hr;
886 CCommand<CAccessor<CCountAccessor> > command;
888 hr = command.Assign(m_szSessionName);
889 if (hr == S_OK)
891 hr = command.Open(dataconn, m_QueryObj.GetSessionVarCount());
892 if (hr == S_OK)
894 if (S_OK == (hr = command.MoveFirst()))
896 *pnCount = command.m_nCount;
897 hr = S_OK;
901 return hr;
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);
911 if (hr != S_OK)
912 return hr;
914 CCommand<CAccessor<CSessionDataDeleteAll> > command;
915 hr = command.Assign(m_szSessionName);
916 if (hr != S_OK)
917 return hr;
919 // delete all session variables
920 hr = command.Open(dataconn, m_QueryObj.GetSessionVarDeleteAllVars(), NULL, NULL, DBGUID_DEFAULT, false);
921 return hr;
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()
932 HRESULT hr = E_FAIL;
933 if (!pPOS)
934 return E_POINTER;
936 if (phEnum)
937 *phEnum = NULL;
938 else
939 return E_POINTER;
941 // Get the data connection for this thread.
942 CDataConnection dataconn;
943 hr = GetSessionConnection(&dataconn, m_spServiceProvider);
944 if (hr != S_OK)
945 return hr;
947 // Update the last access time for this session.
948 hr = Access();
949 if (hr != S_OK)
950 return hr;
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);
959 if (hr == S_OK)
961 // execute the command and move to the first row of the recordset.
962 hr = pIteratorAccessor->Open(dataconn,
963 m_QueryObj.GetSessionVarSelectAllVars());
964 if (hr == S_OK)
966 hr = pIteratorAccessor->MoveFirst();
967 if (hr == S_OK)
969 *pPOS = (POSITION) INVALID_DB_SESSION_POS + 1;
970 *phEnum = reinterpret_cast<HSESSIONENUM>(pIteratorAccessor);
974 if (hr != S_OK)
976 *pPOS = INVALID_DB_SESSION_POS;
977 *phEnum = NULL;
978 delete pIteratorAccessor;
981 return hr;
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
986 // variable
987 STDMETHOD(GetNextVariable)(POSITION *pPOS, VARIANT *pVal, HSESSIONENUM hEnum, LPSTR szName=NULL, DWORD dwLen=0) throw()
989 if (!pPOS)
990 return E_INVALIDARG;
992 if (pVal)
993 VariantInit(pVal);
994 else
995 return E_POINTER;
997 if (!hEnum)
998 return E_UNEXPECTED;
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;
1010 if (szName)
1012 // caller wants entry name
1013 _ATLTRY
1015 CT2CA szVarName(pIteratorAccessor->m_VariableName);
1016 if (szVarName != NULL && dwLen > Checked::strnlen(szVarName, dwLen))
1018 Checked::strcpy_s(szName, dwLen, szVarName);
1020 else
1021 hr = E_OUTOFMEMORY; // buffer not big enough
1023 _ATLCATCHALL()
1025 hr = E_OUTOFMEMORY;
1030 if (hr == S_OK)
1032 CStreamOnByteArray stream(pIteratorAccessor->m_VariableValue);
1033 CComVariant vOut;
1034 hr = vOut.ReadFromStream(static_cast<IStream*>(&stream));
1035 if (hr == S_OK)
1036 vOut.Detach(pVal);
1037 else
1038 return hr;
1040 else
1041 return hr;
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;
1050 hr = S_OK;
1053 if (hr != S_OK)
1055 VariantClear(pVal);
1057 return hr;
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;
1068 return S_OK;
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);
1083 if (hr != S_OK)
1084 return hr;
1086 CCommand<CAccessor<CSessionRefIsExpired> > command;
1087 hr = command.Assign(m_szSessionName);
1088 if (hr != S_OK)
1089 return hr;
1091 hr = command.Open(dataconn, m_QueryObj.GetSessionRefIsExpired(),
1092 NULL, NULL, DBGUID_DEFAULT, true);
1093 if (hr == S_OK)
1095 if (S_OK == command.MoveFirst())
1097 if (!_tcscmp(command.m_SessionIDOut, m_szSessionName))
1098 hrRet = S_OK;
1102 if (hr == S_OK)
1103 return hrRet;
1104 return hr;
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);
1114 if (hr != S_OK)
1115 return hr;
1117 // allocate a command and set it's input parameters
1118 CCommand<CAccessor<CSessionRefUpdateTimeout> > command;
1119 hr = command.Assign(m_szSessionName, dwNewTimeout);
1120 if (hr != S_OK)
1121 return hr;
1123 hr = command.Open(dataconn, m_QueryObj.GetSessionRefUpdateTimeout(),
1124 NULL, NULL, DBGUID_DEFAULT, false);
1126 return hr;
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);
1141 if (hr != S_OK)
1142 return hr;
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)) ||
1151 nRows == 0)
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);
1157 if (hr == S_OK)
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)
1166 hr = E_UNEXPECTED;
1168 return hr;
1171 // SessionUnlock decrements the session RefCount for this session.
1172 // Sessions cannot be removed from the database unless the session
1173 // refcount is 0
1174 HRESULT SessionUnlock() throw()
1176 HRESULT hr = E_UNEXPECTED;
1177 if (!m_szSessionName ||
1178 m_szSessionName[0]==0)
1179 return hr;
1181 // get the data connection for this thread
1182 CDataConnection dataconn;
1183 hr = GetSessionConnection(&dataconn, m_spServiceProvider);
1184 if (hr != S_OK)
1185 return hr;
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);
1192 if (hr == S_OK)
1194 hr = updator.Open( dataconn,
1195 m_QueryObj.GetSessionRefRemoveRef(),
1196 NULL,
1197 &nRows,
1198 DBGUID_DEFAULT,
1199 false);
1201 if (hr != S_OK)
1202 return hr;
1204 // delete the session from the database if
1205 // nobody else is using it and it's expired.
1206 hr = FreeSession();
1207 return hr;
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);
1225 if (hr != S_OK)
1226 return hr;
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);
1235 if (hr == S_OK)
1237 hr = updator.Open( dataconn,
1238 m_QueryObj.GetSessionRefAccess(),
1239 NULL,
1240 &nRows,
1241 DBGUID_DEFAULT,
1242 false);
1245 ATLASSERT(nRows > 0);
1246 if (hr == S_OK && nRows <= 0)
1247 hr = E_UNEXPECTED;
1248 return hr;
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)
1261 return hr;
1263 // Get the data connection for this thread.
1264 CDataConnection dataconn;
1265 hr = GetSessionConnection(&dataconn, m_spServiceProvider);
1266 if (hr != S_OK)
1267 return hr;
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(),
1276 NULL,
1277 NULL,
1278 DBGUID_DEFAULT,
1279 false);
1282 // Initialize is called each time a new session is created.
1283 HRESULT Initialize( LPCSTR szSessionName,
1284 IServiceProvider *pServiceProvider,
1285 DWORD_PTR dwCookie,
1286 PFN_GETPROVIDERINFO pfnInfo) throw()
1288 if (!szSessionName)
1289 return E_INVALIDARG;
1291 if (!pServiceProvider)
1292 return E_INVALIDARG;
1294 if (!pfnInfo)
1295 return E_INVALIDARG;
1297 m_pfnInfo = pfnInfo;
1298 m_dwProvCookie = dwCookie;
1299 m_spServiceProvider = pServiceProvider;
1301 _ATLTRY
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);
1306 else
1307 return E_OUTOFMEMORY;
1309 _ATLCATCHALL()
1311 return E_OUTOFMEMORY;
1313 return SessionLock();
1316 HRESULT GetSessionConnection(CDataConnection *pConn,
1317 IServiceProvider *pProv) throw()
1319 if (!pProv)
1320 return E_INVALIDARG;
1322 if (!m_pfnInfo ||
1323 !m_dwProvCookie)
1324 return E_UNEXPECTED;
1326 wchar_t *wszProv = NULL;
1327 if (m_pfnInfo(m_dwProvCookie, &wszProv) && wszProv!=NULL)
1329 return GetDataSource(pProv,
1330 ATL_DBSESSION_ID,
1331 wszProv,
1332 pConn);
1334 return E_FAIL;
1338 protected:
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;
1345 }; // CDBSession
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;
1354 public:
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()
1364 if (dwProvCookie &&
1365 ppszProvInfo)
1367 CDBSessionServiceImplT<TDBSession> *pSvc =
1368 reinterpret_cast<CDBSessionServiceImplT<TDBSession>*>(dwProvCookie);
1369 *ppszProvInfo = pSvc->m_szConnectionString;
1370 return true;
1372 return false;
1375 HRESULT GetSessionConnection(CDataConnection *pConn,
1376 IServiceProvider *pProv) throw()
1378 if (!pProv)
1379 return E_INVALIDARG;
1381 if(!m_szConnectionString[0])
1382 return E_UNEXPECTED;
1384 return GetDataSource(pProv,
1385 ATL_DBSESSION_ID,
1386 m_szConnectionString,
1387 pConn);
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);
1401 else
1402 return E_OUTOFMEMORY;
1404 m_dwTimeout = dwInitialTimeout;
1405 m_spServiceProvider = pProvider;
1406 return S_OK;
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;
1414 if (!pdwSize)
1415 return E_POINTER;
1417 if (ppSession)
1418 *ppSession = NULL;
1419 else
1420 return E_POINTER;
1422 if (szNewID)
1423 *szNewID = NULL;
1424 else
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);
1435 if (hr == S_OK)
1437 hr = pNewSession->Initialize(szNewID,
1438 m_spServiceProvider,
1439 reinterpret_cast<DWORD_PTR>(this),
1440 GetProviderInfo);
1441 if (hr == S_OK)
1443 // we don't hold a reference to the object
1444 hr = pNewSession->QueryInterface(ppSession);
1448 if (hr != S_OK)
1449 delete pNewSession;
1450 return hr;
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;
1461 if (ppSession)
1462 *ppSession = NULL;
1463 else
1464 return E_POINTER;
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),
1474 GetProviderInfo);
1475 if (hr == S_OK)
1477 // we don't hold a reference to the object
1478 hr = pNewSession->QueryInterface(ppSession);
1482 if (hr != S_OK)
1483 delete pNewSession;
1484 return hr;
1488 HRESULT GetSession(LPCSTR szID, ISession **ppSession) throw()
1490 HRESULT hr = E_FAIL;
1491 if (!szID)
1492 return E_INVALIDARG;
1494 if (ppSession)
1495 *ppSession = NULL;
1496 else
1497 return E_POINTER;
1499 CComObject<TDBSession> *pNewSession = NULL;
1501 // Check the DB to see if the session ID is a valid session
1502 _ATLTRY
1504 CA2CT session(szID);
1505 hr = IsValidSession(session);
1507 _ATLCATCHALL()
1509 hr = E_OUTOFMEMORY;
1511 if (hr == S_OK)
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),
1521 GetProviderInfo);
1522 if (hr == S_OK)
1524 // we don't hold a reference to the object
1525 hr = pNewSession->QueryInterface(ppSession);
1529 if (hr != S_OK && pNewSession)
1530 delete pNewSession;
1531 return hr;
1534 HRESULT CloseSession(LPCSTR szID) throw()
1536 if (!szID)
1537 return E_INVALIDARG;
1539 CDataConnection conn;
1540 HRESULT hr = GetSessionConnection(&conn,
1541 m_spServiceProvider);
1542 if (hr != S_OK)
1543 return hr;
1545 // set up accessors
1546 CCommand<CAccessor<CSessionRefUpdator> > updator;
1547 CCommand<CAccessor<CSessionDataDeleteAll> > command;
1548 _ATLTRY
1550 CA2CT session(szID);
1551 hr = updator.Assign(session);
1552 if (hr == S_OK)
1553 hr = command.Assign(session);
1555 _ATLCATCHALL()
1557 hr = E_OUTOFMEMORY;
1560 if (hr == S_OK)
1562 // delete all session variables (may not be any!)
1563 hr = command.Open(conn,
1564 m_QueryObj.GetSessionVarDeleteAllVars(),
1565 NULL,
1566 NULL,
1567 DBGUID_DEFAULT,
1568 false);
1569 if (hr == S_OK)
1571 DBROWCOUNT nRows = 0;
1572 nRows = 0;
1573 // delete references in the session references table
1574 hr = updator.Open(conn,
1575 m_QueryObj.GetSessionRefDeleteFinal(),
1576 NULL,
1577 &nRows,
1578 DBGUID_DEFAULT,
1579 false);
1580 if (nRows == 0)
1581 hr = E_UNEXPECTED;
1584 return hr;
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);
1593 if (hr != S_OK)
1594 return hr;
1596 // all sessions get the same timeout
1597 CCommand<CAccessor<CSetAllTimeouts> > command;
1598 hr = command.Assign(nTimeout);
1599 if (hr == S_OK)
1601 hr = command.Open(conn, m_QueryObj.GetSessionReferencesSet(),
1602 NULL,
1603 NULL,
1604 DBGUID_DEFAULT,
1605 false);
1606 if (hr == S_OK)
1608 m_dwTimeout = nTimeout;
1611 return hr;
1615 HRESULT GetSessionTimeout(unsigned __int64* pnTimeout) throw()
1617 if (pnTimeout)
1618 *pnTimeout = m_dwTimeout;
1619 else
1620 return E_INVALIDARG;
1622 return S_OK;
1625 HRESULT GetSessionCount(DWORD *pnCount) throw()
1627 if (pnCount)
1628 *pnCount = 0;
1629 else
1630 return E_POINTER;
1632 CCommand<CAccessor<CSessionRefCount> > command;
1633 CDataConnection conn;
1634 HRESULT hr = GetSessionConnection(&conn,
1635 m_spServiceProvider);
1636 if (hr != S_OK)
1637 return hr;
1639 hr = command.Open(conn,
1640 m_QueryObj.GetSessionRefGetCount());
1641 if (hr == S_OK)
1643 hr = command.MoveFirst();
1644 if (hr == S_OK)
1646 *pnCount = (DWORD)command.m_nCount;
1650 return hr;
1653 void ReleaseAllSessions() throw()
1655 // nothing to do
1658 void SweepSessions() throw()
1660 // nothing to do
1664 // Helpers
1665 HRESULT IsValidSession(LPCTSTR szID) throw()
1667 if (!szID)
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);
1677 if (hr != S_OK)
1678 return hr;
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);
1684 if (hr != S_OK)
1685 return hr;
1687 hr = selector.Open(conn,
1688 m_QueryObj.GetSessionRefSelect(),
1689 NULL,
1690 NULL,
1691 DBGUID_DEFAULT,
1692 true);
1693 if (hr == S_OK)
1694 return selector.MoveFirst();
1695 return hr;
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;
1720 template<>
1721 class CElementTraits<SESSIONPTRTYPE> :
1722 public CElementTraitsBase<SESSIONPTRTYPE>
1724 public:
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
1738 return 0;
1743 // CMemSession
1744 // This session persistance class persists session variables in memory.
1745 // Note that this type of persistance should only be used on single server
1746 // web sites.
1747 class CMemSession :
1748 public ISession,
1749 public CComObjectRootEx<CComGlobalsThreadModel>
1751 public:
1752 BEGIN_COM_MAP(CMemSession)
1753 COM_INTERFACE_ENTRY(ISession)
1754 END_COM_MAP()
1756 CMemSession() throw(...)
1759 virtual ~CMemSession()
1763 STDMETHOD(GetVariable)(LPCSTR szName, VARIANT *pVal) throw()
1765 if (!szName)
1766 return E_INVALIDARG;
1768 if (pVal)
1769 VariantInit(pVal);
1770 else
1771 return E_POINTER;
1773 HRESULT hr = Access();
1774 if (hr == S_OK)
1776 CSLockType lock(m_cs, false);
1777 hr = lock.Lock();
1778 if (FAILED(hr))
1779 return hr;
1781 hr = E_FAIL;
1782 _ATLTRY
1784 CComVariant val;
1785 if (m_Variables.Lookup(szName, val))
1787 hr = VariantCopy(pVal, &val);
1790 _ATLCATCHALL()
1792 hr = E_UNEXPECTED;
1795 return hr;
1798 STDMETHOD(SetVariable)(LPCSTR szName, VARIANT vNewVal) throw()
1800 if (!szName)
1801 return E_INVALIDARG;
1803 HRESULT hr = Access();
1804 if (hr == S_OK)
1806 CSLockType lock(m_cs, false);
1807 hr = lock.Lock();
1808 if (FAILED(hr))
1809 return hr;
1810 _ATLTRY
1812 hr = m_Variables.SetAt(szName, vNewVal) ? S_OK : E_FAIL;
1814 _ATLCATCHALL()
1816 hr = E_UNEXPECTED;
1819 return hr;
1822 STDMETHOD(RemoveVariable)(LPCSTR szName) throw()
1824 if (!szName)
1825 return E_INVALIDARG;
1827 HRESULT hr = Access();
1828 if (hr == S_OK)
1830 CSLockType lock(m_cs, false);
1831 hr = lock.Lock();
1832 if (FAILED(hr))
1833 return hr;
1834 _ATLTRY
1836 hr = m_Variables.RemoveKey(szName) ? S_OK : E_FAIL;
1838 _ATLCATCHALL()
1840 hr = E_UNEXPECTED;
1843 return hr;
1846 STDMETHOD(GetCount)(long *pnCount) throw()
1848 if (pnCount)
1849 *pnCount = 0;
1850 else
1851 return E_POINTER;
1853 HRESULT hr = Access();
1854 if (hr == S_OK)
1856 CSLockType lock(m_cs, false);
1857 hr = lock.Lock();
1858 if (FAILED(hr))
1859 return hr;
1860 *pnCount = (long) m_Variables.GetCount();
1862 return hr;
1865 STDMETHOD(RemoveAllVariables)() throw()
1867 HRESULT hr = Access();
1868 if (hr == S_OK)
1870 CSLockType lock(m_cs, false);
1871 hr = lock.Lock();
1872 if (FAILED(hr))
1873 return hr;
1874 m_Variables.RemoveAll();
1877 return hr;
1880 STDMETHOD(BeginVariableEnum)(POSITION *pPOS, HSESSIONENUM *phEnumHandle=NULL) throw()
1882 if (phEnumHandle)
1883 *phEnumHandle = NULL;
1885 if (pPOS)
1886 *pPOS = NULL;
1887 else
1888 return E_POINTER;
1890 HRESULT hr = Access();
1891 if (hr == S_OK)
1893 CSLockType lock(m_cs, false);
1894 hr = lock.Lock();
1895 if (FAILED(hr))
1896 return hr;
1897 *pPOS = m_Variables.GetStartPosition();
1899 return hr;
1902 STDMETHOD(GetNextVariable)(POSITION *pPOS, VARIANT *pVal,
1903 HSESSIONENUM hEnum=NULL,
1904 LPSTR szName=NULL,
1905 DWORD dwLen=0 ) throw()
1907 (hEnum); // Unused!
1908 if (pVal)
1909 VariantInit(pVal);
1910 else
1911 return E_POINTER;
1913 if (!pPOS)
1914 return E_POINTER;
1916 CComVariant val;
1917 POSITION pos = *pPOS;
1918 HRESULT hr = Access();
1919 if (hr == S_OK)
1921 CSLockType lock(m_cs, false);
1922 hr = lock.Lock();
1923 if (FAILED(hr))
1924 return hr;
1926 hr = E_FAIL;
1927 _ATLTRY
1929 if (szName)
1931 CStringA strName = m_Variables.GetKeyAt(pos);
1932 if (strName.GetLength())
1934 if (dwLen > (DWORD)strName.GetLength())
1936 Checked::strcpy_s(szName, dwLen, strName);
1937 hr = S_OK;
1939 else
1940 hr = E_OUTOFMEMORY;
1943 else
1944 hr = S_OK;
1946 if (hr == S_OK)
1948 val = m_Variables.GetNextValue(pos);
1949 hr = VariantCopy(pVal, &val);
1950 if (hr == S_OK)
1951 *pPOS = pos;
1954 _ATLCATCHALL()
1956 hr = E_UNEXPECTED;
1959 return hr;
1962 STDMETHOD(CloseEnum)(HSESSIONENUM /*hEnumHandle*/) throw()
1964 return S_OK;
1967 STDMETHOD(IsExpired)() throw()
1969 CTime tmNow = CTime::GetCurrentTime();
1970 CTimeSpan span = tmNow-m_tLastAccess;
1971 if ((unsigned __int64)((span.GetTotalSeconds()*1000)) > m_dwTimeout)
1972 return S_OK;
1973 return S_FALSE;
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();
1982 if (FAILED(hr))
1983 return hr;
1984 m_tLastAccess = CTime::GetCurrentTime();
1985 return S_OK;
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();
1994 if (FAILED(hr))
1995 return hr;
1996 m_dwTimeout = dwNewTimeout;
1997 return S_OK;
2000 HRESULT SessionLock() throw()
2002 Access();
2003 return S_OK;
2006 HRESULT SessionUnlock() throw()
2008 return S_OK;
2011 protected:
2012 typedef CAtlMap<CStringA,
2013 CComVariant,
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;
2020 }; // CMemSession
2024 // CMemSessionServiceImpl
2025 // Implements the service part of in-memory persisted session services.
2027 class CMemSessionServiceImpl
2029 public:
2030 typedef void* SERVICEIMPL_INITPARAM_TYPE;
2031 CMemSessionServiceImpl() throw()
2033 m_dwTimeout = ATL_SESSION_TIMEOUT;
2036 ~CMemSessionServiceImpl() throw()
2038 m_CritSec.Term();
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;
2046 if (!szNewID)
2047 return E_INVALIDARG;
2049 if (!pdwSize)
2050 return E_POINTER;
2052 if (ppSession)
2053 *ppSession = NULL;
2054 else
2055 return E_POINTER;
2057 _ATLTRY
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);
2067 if (SUCCEEDED(hr))
2069 CComPtr<ISession> spSession;
2070 hr = pNewSession->QueryInterface(&spSession);
2071 if (SUCCEEDED(hr))
2073 pNewSession->SetTimeout(m_dwTimeout);
2074 pNewSession->Access();
2075 CSLockType lock(m_CritSec, false);
2076 hr = lock.Lock();
2077 if (FAILED(hr))
2078 return hr;
2079 hr = m_Sessions.SetAt(szNewID, spSession) != NULL ? S_OK : E_FAIL;
2080 if (hr == S_OK)
2081 *ppSession = spSession.Detach();
2085 _ATLCATCHALL()
2087 hr = E_UNEXPECTED;
2090 return hr;
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;
2102 if (ppSession)
2103 *ppSession = NULL;
2104 else
2105 return E_POINTER;
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);
2112 if (hr == S_OK)
2114 *ppSession = spSession.Detach();
2115 return hr;
2118 _ATLTRY
2120 // Create new session
2121 CComObject<CMemSession>::CreateInstance(&pNewSession);
2122 if (pNewSession == NULL)
2123 return E_OUTOFMEMORY;
2126 hr = pNewSession->QueryInterface(&spSession);
2127 if (SUCCEEDED(hr))
2129 pNewSession->SetTimeout(m_dwTimeout);
2130 pNewSession->Access();
2131 CSLockType lock(m_CritSec, false);
2132 hr = lock.Lock();
2133 if (FAILED(hr))
2134 return hr;
2136 hr = m_Sessions.SetAt(szNewID, spSession) != NULL ? S_OK : E_FAIL;
2138 if (hr == S_OK)
2139 *ppSession = spSession.Detach();
2142 _ATLCATCHALL()
2144 hr = E_UNEXPECTED;
2147 return hr;
2151 HRESULT GetSession(LPCSTR szID, ISession **ppSession) throw()
2153 HRESULT hr = E_FAIL;
2154 SessMapType::CPair *pPair = NULL;
2156 if (ppSession)
2157 *ppSession = NULL;
2158 else
2159 return E_POINTER;
2161 if (!szID)
2162 return E_INVALIDARG;
2164 CSLockType lock(m_CritSec, false);
2165 hr = lock.Lock();
2166 if (FAILED(hr))
2167 return hr;
2169 hr = E_FAIL;
2170 _ATLTRY
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);
2178 _ATLCATCHALL()
2180 return E_UNEXPECTED;
2183 return hr;
2186 HRESULT CloseSession(LPCSTR szID) throw()
2188 if (!szID)
2189 return E_INVALIDARG;
2191 HRESULT hr = E_FAIL;
2192 CSLockType lock(m_CritSec, false);
2193 hr = lock.Lock();
2194 if (FAILED(hr))
2195 return hr;
2196 _ATLTRY
2198 hr = m_Sessions.RemoveKey(szID) ? S_OK : E_UNEXPECTED;
2200 _ATLCATCHALL()
2202 hr = E_UNEXPECTED;
2204 return hr;
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()))
2215 return;
2216 pos = m_Sessions.GetStartPosition();
2217 while (pos)
2219 posRemove = pos;
2220 pPair = m_Sessions.GetNext(pos);
2221 if (pPair)
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()
2235 HRESULT hr = S_OK;
2236 CComPtr<ISession> spSession;
2237 m_dwTimeout = nTimeout;
2239 CSLockType lock(m_CritSec, false);
2240 hr = lock.Lock();
2241 if (FAILED(hr))
2242 return hr;
2244 POSITION pos = m_Sessions.GetStartPosition();
2245 if (!pos)
2246 return S_OK; // no sessions to set the timeout on
2249 while (pos)
2251 SessMapType::CPair *pPair = const_cast<SessMapType::CPair*>(m_Sessions.GetNext(pos));
2252 if (pPair)
2254 spSession = pPair->m_value;
2255 if (spSession)
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();
2261 if (hr != S_OK)
2262 break;
2264 else
2266 hr = E_UNEXPECTED;
2267 break;
2270 else
2272 hr = E_UNEXPECTED;
2273 break;
2277 return hr;
2280 HRESULT GetSessionTimeout(unsigned __int64* pnTimeout) throw()
2282 if (pnTimeout)
2283 *pnTimeout = m_dwTimeout;
2284 else
2285 return E_POINTER;
2287 return S_OK;
2290 HRESULT GetSessionCount(DWORD *pnCount) throw()
2292 if (pnCount)
2293 *pnCount = 0;
2294 else
2295 return E_POINTER;
2297 CSLockType lock(m_CritSec, false);
2298 HRESULT hr = lock.Lock();
2299 if (FAILED(hr))
2300 return hr;
2301 *pnCount = (DWORD)m_Sessions.GetCount();
2303 return S_OK;
2306 void ReleaseAllSessions() throw()
2308 CSLockType lock(m_CritSec, false);
2309 if (FAILED(lock.Lock()))
2310 return;
2311 m_Sessions.RemoveAll();
2314 HRESULT Initialize(SERVICEIMPL_INITPARAM_TYPE,
2315 IServiceProvider*,
2316 unsigned __int64 dwNewTimeout) throw()
2318 m_dwTimeout = dwNewTimeout;
2319 return m_CritSec.Init();
2322 typedef CAtlMap<CStringA,
2323 SESSIONPTRTYPE,
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>
2352 protected:
2353 MonitorClass m_Monitor;
2354 HANDLE m_hTimer;
2355 CComPtr<IServiceProvider> m_spServiceProvider;
2356 TServiceImplClass m_SessionServiceImpl;
2357 public:
2358 // Construction/Initialization
2359 CSessionStateService() throw() :
2360 m_hTimer(NULL)
2364 ~CSessionStateService() throw()
2366 ATLASSUME(m_hTimer == NULL);
2368 BEGIN_COM_MAP(CSessionStateService)
2369 COM_INTERFACE_ENTRY(ISessionStateService)
2370 COM_INTERFACE_ENTRY(ISessionStateControl)
2371 END_COM_MAP()
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();
2419 HRESULT Initialize(
2420 IServiceProvider *pServiceProvider = NULL,
2421 typename TServiceImplClass::SERVICEIMPL_INITPARAM_TYPE pInitData = NULL,
2422 unsigned __int64 dwTimeout = ATL_SESSION_TIMEOUT) throw()
2424 HRESULT hr = S_OK;
2425 if (pServiceProvider)
2426 m_spServiceProvider = pServiceProvider;
2428 hr = m_SessionServiceImpl.Initialize(pInitData, pServiceProvider, dwTimeout);
2430 return hr;
2434 template <class ThreadTraits>
2435 HRESULT Initialize(
2436 CWorkerThread<ThreadTraits> *pWorker,
2437 IServiceProvider *pServiceProvider = NULL,
2438 typename TServiceImplClass::SERVICEIMPL_INITPARAM_TYPE pInitData = NULL,
2439 unsigned __int64 dwTimeout = ATL_SESSION_TIMEOUT) throw()
2441 if (!pWorker)
2442 return E_INVALIDARG;
2444 HRESULT hr = Initialize(pServiceProvider, pInitData, dwTimeout);
2445 if (hr == S_OK)
2447 hr = m_Monitor.Initialize(pWorker);
2448 if (hr == S_OK)
2450 //sweep every 500ms
2451 hr = m_Monitor.AddTimer(ATL_SESSION_SWEEPER_TIMEOUT, this, 0, &m_hTimer);
2454 return hr;
2457 void Shutdown() throw()
2459 if (m_hTimer)
2461 if(FAILED(m_Monitor.RemoveHandle(m_hTimer)))
2463 /* can't report from here */
2464 ATLASSERT(FALSE);
2466 m_hTimer = NULL;
2468 ReleaseAllSessions();
2470 // Implementation
2471 HRESULT Execute(DWORD_PTR /*dwParam*/, HANDLE /*hObject*/) throw()
2473 SweepSessions();
2474 return S_OK;
2477 HRESULT CloseHandle(HANDLE hHandle) throw()
2479 ::CloseHandle(hHandle);
2480 m_hTimer = NULL;
2481 return S_OK;
2484 }; // CSessionStateService
2486 } // namespace ATL
2487 #pragma pack(pop)
2489 #pragma warning(pop)
2490 #endif // __ATLSESSION_H__