Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

507 lines
14 KiB

  1. //***************************************************************************
  2. //
  3. // Copyright (c) 1998-1999 Microsoft Corporation
  4. //
  5. // objsink.h
  6. //
  7. // rogerbo 22-May-98 Created.
  8. //
  9. // Implementation of IWbemObjectSink for async stuff
  10. //
  11. //***************************************************************************
  12. #ifndef _OBJSINK_H_
  13. #define _OBJSINK_H_
  14. // CIWbemObjectSinkCachedMethodItem is the base class of link list items
  15. // representing cached method calls to IWbemObjectSink. Whenever we are inside
  16. // an IWbemObjectSink method, and we receive a nested call to IWbemObjectSink,
  17. // we store the parameters to the nested call and redo the call just before the
  18. // original method returns. It is important to cache all methods on the sink to
  19. // preserve the order that they are seen by the client. This means that
  20. // if calls to SetStatus come in during a call to Indicate, it must be cached.
  21. // In addition, we cache calls across all instances of IWbemObjectSink. In
  22. // other words, suppose we have two async requests (request1 and request2). If
  23. // we are processing an Indicate for request1 and get an Indicate for request2,
  24. // we have to cache the nested Indicate (including the this pointer for the
  25. // IWbemObjectSink), and call the recall the nested Indicate at the end of the
  26. // Indicate for request1.
  27. class CIWbemObjectSinkCachedMethodItem
  28. {
  29. public:
  30. CIWbemObjectSinkCachedMethodItem(IWbemObjectSink *pSink) :
  31. m_pSink (pSink),
  32. m_pNext (NULL)
  33. {
  34. if (m_pSink)
  35. m_pSink->AddRef();
  36. }
  37. virtual ~CIWbemObjectSinkCachedMethodItem()
  38. {
  39. if (m_pSink)
  40. m_pSink->Release();
  41. }
  42. // DoCallAgain is to be overridden in derived classes to recall cached
  43. // methods.
  44. virtual void DoCallAgain() = 0;
  45. // This is a pointer to the next cached interface call
  46. CIWbemObjectSinkCachedMethodItem *m_pNext;
  47. protected:
  48. // Pointer to the original IWbemObjectSink for the cached call
  49. IWbemObjectSink *m_pSink;
  50. };
  51. // CIWbemObjectSinkCachedIndicate represents a cached call to Indicate
  52. class CIWbemObjectSinkCachedIndicate : public CIWbemObjectSinkCachedMethodItem
  53. {
  54. public:
  55. CIWbemObjectSinkCachedIndicate(IWbemObjectSink *pSink, long lObjectCount, IWbemClassObject **apObjArray)
  56. : CIWbemObjectSinkCachedMethodItem (pSink)
  57. {
  58. _RD(static char *me = "CIWbemObjectSinkCachedIndicate::CIWbemObjectSinkCachedIndicate";)
  59. _RPrint(me, "", 0, "");
  60. // Store the original parameters to the Indicate call
  61. // TODO: What if lObjectCount = 0 ?
  62. m_lObjectCount = lObjectCount;
  63. m_apObjArray = new IWbemClassObject*[lObjectCount];
  64. if (m_apObjArray)
  65. {
  66. for(int i=0;i<lObjectCount;i++)
  67. {
  68. apObjArray[i]->AddRef();
  69. m_apObjArray[i] = apObjArray[i];
  70. }
  71. }
  72. }
  73. ~CIWbemObjectSinkCachedIndicate()
  74. {
  75. _RD(static char *me = "CIWbemObjectSinkCachedIndicate::~CIWbemObjectSinkCachedIndicate";)
  76. _RPrint(me, "", 0, "");
  77. // Free memory used to store original parameters to Indicate
  78. if (m_apObjArray)
  79. {
  80. for(int i=0;i<m_lObjectCount;i++)
  81. {
  82. RELEASEANDNULL(m_apObjArray[i])
  83. }
  84. delete [] m_apObjArray;
  85. }
  86. }
  87. void DoCallAgain()
  88. {
  89. // Recall the Indicate method with the cached parameters
  90. if (m_pSink && m_apObjArray)
  91. m_pSink->Indicate(m_lObjectCount, m_apObjArray);
  92. }
  93. private:
  94. // Parameters to Indicate that we must store
  95. long m_lObjectCount;
  96. IWbemClassObject **m_apObjArray;
  97. };
  98. // CIWbemObjectSinkCachedSetStatus represents a cached call to SetStatus
  99. class CIWbemObjectSinkCachedSetStatus : public CIWbemObjectSinkCachedMethodItem
  100. {
  101. public:
  102. CIWbemObjectSinkCachedSetStatus(
  103. IWbemObjectSink *pSink,
  104. long lFlags,
  105. HRESULT hResult,
  106. BSTR strParam,
  107. IWbemClassObject *pObjParam) :
  108. CIWbemObjectSinkCachedMethodItem (pSink),
  109. m_lFlags (lFlags),
  110. m_hResult (hResult),
  111. m_strParam (NULL),
  112. m_pObjParam (pObjParam)
  113. {
  114. _RD(static char *me = "CIWbemObjectSinkCachedSetStatus::CIWbemObjectSinkCachedSetStatus";)
  115. _RPrint(me, "", 0, "");
  116. if(strParam)
  117. m_strParam = SysAllocString(strParam);
  118. if(m_pObjParam)
  119. m_pObjParam->AddRef();
  120. }
  121. ~CIWbemObjectSinkCachedSetStatus()
  122. {
  123. _RD(static char *me = "CIWbemObjectSinkCachedSetStatus::~CIWbemObjectSinkCachedSetStatus";)
  124. _RPrint(me, "", 0, "");
  125. // Free memory used to store original parameters to SetStatus
  126. FREEANDNULL(m_strParam)
  127. RELEASEANDNULL(m_pObjParam)
  128. }
  129. void DoCallAgain()
  130. {
  131. // Recall the SetStatus method with the cached parameters
  132. if (m_pSink)
  133. m_pSink->SetStatus(m_lFlags, m_hResult, m_strParam, m_pObjParam);
  134. }
  135. private:
  136. // Parameters to SetStatus that we must store
  137. long m_lFlags;
  138. HRESULT m_hResult;
  139. BSTR m_strParam;
  140. IWbemClassObject *m_pObjParam;
  141. };
  142. // This is the class that manages all cached calls to IWbemObjectSink. To
  143. // cache the interface method calls, each interface method should call
  144. // TestOkToRunXXX where XXX is the method name. If this function returns
  145. // FALSE, it means that we are already inside another method call. The
  146. // parameters will have been cached, the the method should return immediately.
  147. // At the end of the method, Cleanup should be called so that all cached method
  148. // calls can be recalled.
  149. class CIWbemObjectSinkMethodCache
  150. {
  151. protected:
  152. // Constructor/destructor are protected since this object should only be
  153. // created/destroyed by the static methods AddRefForThread/ReleaseForThread
  154. CIWbemObjectSinkMethodCache() :
  155. m_fInInterface (FALSE),
  156. m_pFirst (NULL),
  157. m_pLast (NULL),
  158. m_fOverrideTest (FALSE),
  159. m_fOverrideCleanup (FALSE),
  160. m_dwRef (1)
  161. {
  162. _RD(static char *me = "CIWbemObjectSinkMethodCache::CIWbemObjectSinkMethodCache";)
  163. _RPrint(me, "", 0, "");
  164. }
  165. ~CIWbemObjectSinkMethodCache()
  166. {
  167. _RD(static char *me = "CIWbemObjectSinkMethodCache::~CIWbemObjectSinkMethodCache";)
  168. _RPrint(me, "", 0, "");
  169. _RPrint(me, "m_pFirst: ", long(m_pFirst), "");
  170. _RPrint(me, "m_pLast: ", long(m_pLast), "");
  171. // TODO: ASSERT that m_pFirst and m_pLast are NULL. In other words,
  172. // as long as Cleanup is called at the end of each interface method,
  173. // the internal link list should be completely empty.
  174. }
  175. public:
  176. // Public Methods
  177. static void Initialize () {
  178. sm_dwTlsForInterfaceCache = TlsAlloc();
  179. }
  180. static void TidyUp () {
  181. if (-1 != sm_dwTlsForInterfaceCache)
  182. {
  183. TlsFree (sm_dwTlsForInterfaceCache);
  184. sm_dwTlsForInterfaceCache = -1;
  185. }
  186. }
  187. static void AddRefForThread()
  188. {
  189. if(-1 == sm_dwTlsForInterfaceCache)
  190. return; // We failed the original alloc
  191. // The Tls value for sm_dwTlsForInterfaceCache is guaranteed to
  192. // initialize to NULL
  193. CIWbemObjectSinkMethodCache *pSinkMethodCache = (CIWbemObjectSinkMethodCache *)TlsGetValue(sm_dwTlsForInterfaceCache);
  194. if(NULL == pSinkMethodCache)
  195. TlsSetValue(sm_dwTlsForInterfaceCache, new CIWbemObjectSinkMethodCache);
  196. else
  197. pSinkMethodCache->AddRef();
  198. }
  199. static void ReleaseForThread()
  200. {
  201. if(-1 == sm_dwTlsForInterfaceCache)
  202. return; // We failed the original alloc
  203. CIWbemObjectSinkMethodCache *pSinkMethodCache = (CIWbemObjectSinkMethodCache *)TlsGetValue(sm_dwTlsForInterfaceCache);
  204. if(NULL != pSinkMethodCache)
  205. {
  206. DWORD dwCount = pSinkMethodCache->Release();
  207. if(dwCount == 0)
  208. {
  209. delete pSinkMethodCache;
  210. TlsSetValue(sm_dwTlsForInterfaceCache, NULL);
  211. }
  212. }
  213. }
  214. static CIWbemObjectSinkMethodCache *GetThreadsCache()
  215. {
  216. if(-1 == sm_dwTlsForInterfaceCache)
  217. return NULL; // We failed the original alloc
  218. return (CIWbemObjectSinkMethodCache *)TlsGetValue(sm_dwTlsForInterfaceCache);
  219. }
  220. protected:
  221. // TLS slot for Interface Cache pointer
  222. static DWORD sm_dwTlsForInterfaceCache;
  223. public:
  224. // Public Instance Methods
  225. // Call this method at the start of the Indicate method. If this method
  226. // returns TRUE, Indicate should return immediately.
  227. BOOL TestOkToRunIndicate(IWbemObjectSink *pSink, long lObjectCount, IWbemClassObject **apObjArray)
  228. {
  229. // If there was a problem allocating the TLS instance of the cache,
  230. // 'this' might be NULL. In that case, act as if there was no cache
  231. if(NULL == this)
  232. return TRUE;
  233. // If m_fOverrideTest is TRUE, it means that we are recalling a cached
  234. // call to Indicate. We therefore must complete the body of Indicate.
  235. if(m_fOverrideTest)
  236. {
  237. m_fOverrideTest = FALSE;
  238. return TRUE;
  239. }
  240. // If we are already in an interface method, cache this call
  241. if(m_fInInterface)
  242. {
  243. CIWbemObjectSinkCachedIndicate *pItem = new CIWbemObjectSinkCachedIndicate(pSink, lObjectCount, apObjArray);
  244. // TODO: What if allocation fails?
  245. if(pItem)
  246. AddItem(pItem);
  247. return FALSE;
  248. }
  249. // We are not already in another interface method, but we set
  250. // m_fInInterface to TRUE to prevent nested calls
  251. m_fInInterface = TRUE;
  252. return TRUE;
  253. }
  254. // Call this method at the start of the SetStatus method. If this method
  255. // returns TRUE, SetStatus should return immediately.
  256. BOOL TestOkToRunSetStatus(IWbemObjectSink *pSink, long lFlags, HRESULT hResult, BSTR strParam, IWbemClassObject *pObjParam)
  257. {
  258. // If there was a problem allocating the TLS instance of the cache,
  259. // 'this' might be NULL. In that case, act as if there was no cache
  260. if(NULL == this)
  261. return TRUE;
  262. // If m_fOverrideTest is TRUE, it means that we are recalling a cached
  263. // call to SetStatus. We therefore must complete the body of SetStatus.
  264. if(m_fOverrideTest)
  265. {
  266. m_fOverrideTest = FALSE;
  267. return TRUE;
  268. }
  269. // If we are already in an interface method, cache this call
  270. if(m_fInInterface)
  271. {
  272. CIWbemObjectSinkCachedSetStatus *pItem = new CIWbemObjectSinkCachedSetStatus(pSink, lFlags, hResult, strParam, pObjParam);
  273. // TODO: What if allocation fails?
  274. if(pItem)
  275. AddItem(pItem);
  276. return FALSE;
  277. }
  278. // We are not already in another interface method, but we set
  279. // m_fInInterface to TRUE to prevent nested calls
  280. m_fInInterface = TRUE;
  281. return TRUE;
  282. }
  283. // At the end of every IWbemObjectSink method, Cleanup should be called.
  284. // This will recall any cached method parameters
  285. void Cleanup()
  286. {
  287. // If there was a problem allocating the TLS instance of the cache,
  288. // 'this' might be NULL. In that case, act as if there was no cache
  289. if(NULL == this)
  290. return;
  291. // If m_fOverridCleanup is TRUE, we are in an interface method because
  292. // we are recalling it. There is nothing more that Cleanup should do
  293. if(m_fOverrideCleanup)
  294. {
  295. m_fOverrideCleanup = FALSE;
  296. return;
  297. }
  298. // While there are any items in the link list, recall the methods.
  299. // NOTE: It is possible that new items will be added to the end of the
  300. // link list during DoCallAgain, but when this 'while' loop finishes
  301. // we will be in a state where all cached methods have been called
  302. while(m_pFirst)
  303. {
  304. // Set override flags so that the interface methods know that they
  305. // are not receiving a nested call
  306. m_fOverrideTest = TRUE;
  307. m_fOverrideCleanup = TRUE;
  308. // Recall the cached method
  309. m_pFirst->DoCallAgain();
  310. // Remove this item from the start of the link list
  311. CIWbemObjectSinkCachedMethodItem *pItem = m_pFirst;
  312. m_pFirst = pItem->m_pNext;
  313. delete pItem;
  314. }
  315. // The link list is empty
  316. m_pLast = NULL;
  317. // We are about to leave the interface method
  318. m_fInInterface = FALSE;
  319. }
  320. protected:
  321. // Add cached method information to the link list
  322. void AddItem(CIWbemObjectSinkCachedMethodItem *pItem)
  323. {
  324. if(NULL == m_pLast)
  325. {
  326. m_pFirst = pItem;
  327. m_pLast = pItem;
  328. }
  329. else
  330. {
  331. m_pLast->m_pNext = pItem;
  332. m_pLast = pItem;
  333. }
  334. }
  335. protected:
  336. // Reference counting of thread local object
  337. void AddRef()
  338. {
  339. m_dwRef++;
  340. }
  341. int Release()
  342. {
  343. m_dwRef--;
  344. return m_dwRef;
  345. }
  346. DWORD m_dwRef;
  347. protected:
  348. // Member Variables
  349. // Flag that specifies if we are currently processing an interface method
  350. BOOL m_fInInterface;
  351. // Pointer to the first and last items of the link list of cached methods
  352. CIWbemObjectSinkCachedMethodItem *m_pFirst;
  353. CIWbemObjectSinkCachedMethodItem *m_pLast;
  354. // Flags to tell interface method implementations that they are being called
  355. // to recall a cached method as opposed to receiving a nested call.
  356. BOOL m_fOverrideTest;
  357. BOOL m_fOverrideCleanup;
  358. };
  359. //***************************************************************************
  360. //
  361. // CLASS NAME:
  362. //
  363. // CWbemObjectSink
  364. //
  365. // DESCRIPTION:
  366. //
  367. // Implements the IWbemObjectSink interface.
  368. //
  369. //***************************************************************************
  370. class CWbemObjectSink : public IWbemObjectSink
  371. {
  372. private:
  373. CSWbemServices *m_pServices;
  374. IUnsecuredApartment *m_pUnsecuredApartment;
  375. ISWbemPrivateSink *m_pSWbemSink;
  376. IDispatch *m_pContext;
  377. IWbemObjectSink *m_pObjectStub;
  378. BSTR m_bsClassName;
  379. bool m_putOperation;
  380. bool m_operationInProgress;
  381. bool m_setStatusCompletedCalled;
  382. // Members required for just-in-time initialization of m_pServices
  383. BSTR m_bsNamespace;
  384. BSTR m_bsUser;
  385. BSTR m_bsPassword;
  386. BSTR m_bsLocale;
  387. void RemoveObjectSink();
  388. HRESULT AddObjectSink(IWbemObjectSink *pSink);
  389. protected:
  390. long m_cRef; //Object reference count
  391. public:
  392. CWbemObjectSink(CSWbemServices *pServices, IDispatch *pSWbemSink, IDispatch *pContext,
  393. bool putOperation = false, BSTR bsClassName = NULL);
  394. ~CWbemObjectSink(void);
  395. static IWbemObjectSink *CreateObjectSink(CWbemObjectSink **pWbemObjectSink,
  396. CSWbemServices *pServices,
  397. IDispatch *pSWbemSink,
  398. IDispatch *pContext,
  399. bool putOperation = false,
  400. BSTR bsClassName = NULL);
  401. //Non-delegating object IUnknown
  402. STDMETHODIMP QueryInterface(REFIID, LPVOID*);
  403. STDMETHODIMP_(ULONG) AddRef(void);
  404. STDMETHODIMP_(ULONG) Release(void);
  405. // IDispatch
  406. STDMETHODIMP GetTypeInfoCount(UINT* pctinfo)
  407. {return E_NOTIMPL;}
  408. STDMETHODIMP GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo** pptinfo)
  409. {return E_NOTIMPL;}
  410. STDMETHODIMP GetIDsOfNames(REFIID riid, OLECHAR** rgszNames,
  411. UINT cNames, LCID lcid, DISPID* rgdispid)
  412. {return E_NOTIMPL;}
  413. STDMETHODIMP Invoke(DISPID dispidMember, REFIID riid, LCID lcid,
  414. WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult,
  415. EXCEPINFO* pexcepinfo, UINT* puArgErr)
  416. {return E_NOTIMPL;}
  417. // IWbemObjectSink methods
  418. HRESULT STDMETHODCALLTYPE Indicate(
  419. /* [in] */ long lObjectCount,
  420. /* [size_is][in] */ IWbemClassObject __RPC_FAR *__RPC_FAR *apObjArray);
  421. HRESULT STDMETHODCALLTYPE SetStatus(
  422. /* [in] */ long lFlags,
  423. /* [in] */ HRESULT hResult,
  424. /* [in] */ BSTR strParam,
  425. /* [in] */ IWbemClassObject __RPC_FAR *pObjParam);
  426. IWbemObjectSink *GetObjectStub();
  427. void ReleaseTheStubIfNecessary(HRESULT hResult);
  428. };
  429. #endif