Leaked source code of windows server 2003
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.

468 lines
12 KiB

  1. //***************************************************************************
  2. //
  3. // Copyright (c) 1998-2000 Microsoft Corporation
  4. //
  5. // objsink.cpp
  6. //
  7. // rogerbo 22-May-98 Created.
  8. //
  9. // Defines the implementation of IWbemObjectSink
  10. //
  11. //***************************************************************************
  12. #include "precomp.h"
  13. #include "objsink.h"
  14. DWORD CIWbemObjectSinkMethodCache::sm_dwTlsForInterfaceCache = -1;
  15. CWbemObjectSink::CWbemObjectSink(CSWbemServices *pServices, IDispatch *pSWbemSink, IDispatch *pContext,
  16. bool putOperation, BSTR bsClassName) :
  17. m_pServices (NULL),
  18. m_pUnsecuredApartment (NULL),
  19. m_bsNamespace (NULL),
  20. m_bsUser (NULL),
  21. m_bsPassword (NULL),
  22. m_bsLocale (NULL)
  23. {
  24. _RD(static char *me = "CWbemObjectSink::CWbemObjectSink";)
  25. _RPrint(me, "Called", 0, "");
  26. CIWbemObjectSinkMethodCache::AddRefForThread();
  27. m_cRef = 0;
  28. m_pObjectStub = NULL;
  29. m_pSWbemSink = NULL;
  30. m_putOperation = putOperation;
  31. m_pContext = pContext;
  32. m_bsClassName = NULL;
  33. m_operationInProgress = TRUE;
  34. m_setStatusCompletedCalled = FALSE;
  35. if (pSWbemSink)
  36. {
  37. ISWbemPrivateSinkLocator *pSinkLocator = NULL;
  38. HRESULT hr = pSWbemSink->QueryInterface(IID_ISWbemPrivateSinkLocator, (PPVOID)&pSinkLocator);
  39. if(SUCCEEDED(hr) && pSinkLocator)
  40. {
  41. IUnknown *pUnk = NULL;
  42. hr = pSinkLocator->GetPrivateSink(&pUnk);
  43. if(SUCCEEDED(hr) && pUnk)
  44. {
  45. pUnk->QueryInterface(IID_ISWbemPrivateSink, (PPVOID)&m_pSWbemSink);
  46. pUnk->Release();
  47. }
  48. pSinkLocator->Release();
  49. }
  50. }
  51. if (bsClassName)
  52. m_bsClassName = SysAllocString(bsClassName);
  53. /*
  54. * Copy the services proxy to ensure independence of security attributes
  55. * from the parent CSWbemServices.
  56. */
  57. if (pServices)
  58. {
  59. m_pServices = new CSWbemServices (pServices, NULL);
  60. if (m_pServices)
  61. m_pServices->AddRef ();
  62. m_pUnsecuredApartment = pServices->GetCachedUnsecuredApartment ();
  63. }
  64. if (m_pContext)
  65. m_pContext->AddRef();
  66. InterlockedIncrement(&g_cObj);
  67. }
  68. CWbemObjectSink::~CWbemObjectSink(void)
  69. {
  70. _RD(static char *me = "CWbemObjectSink::~CWbemObjectSink";)
  71. _RPrint(me, "Called", 0, "");
  72. CIWbemObjectSinkMethodCache::ReleaseForThread();
  73. InterlockedDecrement(&g_cObj);
  74. RELEASEANDNULL(m_pServices)
  75. RELEASEANDNULL(m_pUnsecuredApartment)
  76. RELEASEANDNULL(m_pSWbemSink)
  77. RELEASEANDNULL(m_pContext)
  78. FREEANDNULL(m_bsClassName)
  79. FREEANDNULL(m_bsNamespace)
  80. FREEANDNULL(m_bsUser)
  81. FREEANDNULL(m_bsPassword)
  82. FREEANDNULL(m_bsLocale)
  83. }
  84. IWbemObjectSink *CWbemObjectSink::CreateObjectSink (CWbemObjectSink **pWbemObjectSink,
  85. CSWbemServices *pServices,
  86. IDispatch *pSWbemSink,
  87. IDispatch *pContext,
  88. bool putOperation,
  89. BSTR bsClassName)
  90. {
  91. IWbemObjectSink *pIWbemObjectSink = NULL;
  92. CWbemObjectSink *pTmpSink = NULL;
  93. if (pSWbemSink)
  94. {
  95. pTmpSink = new CWbemObjectSink(pServices, pSWbemSink, pContext, putOperation, bsClassName);
  96. if (pTmpSink)
  97. {
  98. pIWbemObjectSink = pTmpSink->GetObjectStub();
  99. if (pIWbemObjectSink && FAILED(pTmpSink->AddObjectSink(pIWbemObjectSink)))
  100. pIWbemObjectSink = NULL;
  101. if (!pIWbemObjectSink)
  102. {
  103. delete pTmpSink;
  104. pTmpSink = NULL;
  105. }
  106. }
  107. }
  108. *pWbemObjectSink = pTmpSink;
  109. return pIWbemObjectSink;
  110. }
  111. void CWbemObjectSink::ReleaseTheStubIfNecessary(HRESULT hResult) {
  112. /*
  113. * If we failed locally and SetStatus has not been called
  114. * then we need to remove object from list of outstanding sinks
  115. */
  116. if (FAILED(hResult) && !m_setStatusCompletedCalled)
  117. RemoveObjectSink();
  118. /*
  119. * SetStatus can be called whilst we were in the async op.
  120. * if this happens then SetStatus will not release the sink
  121. * but will set a flag (m_setStatusCompletedCalled). In this
  122. * case we will need to release the stub here (the call has completed)
  123. * Of course we could have also failed locally (regardless of whether
  124. * SetStatus has been called or not) - in this case we must also
  125. * release the stub.
  126. */
  127. if (m_pObjectStub && (FAILED(hResult) || m_setStatusCompletedCalled)) {
  128. // Call to release is same as (delete this !)
  129. IWbemObjectSink *tmpSink = m_pObjectStub;
  130. m_pObjectStub = NULL;
  131. tmpSink->Release();
  132. } else {
  133. m_operationInProgress = FALSE;
  134. }
  135. }
  136. //***************************************************************************
  137. // HRESULT CWbemObjectSink::QueryInterface
  138. // long CWbemObjectSink::AddRef
  139. // long CWbemObjectSink::Release
  140. //
  141. // DESCRIPTION:
  142. //
  143. // Standard Com IUNKNOWN functions.
  144. //
  145. //***************************************************************************
  146. STDMETHODIMP CWbemObjectSink::QueryInterface (
  147. IN REFIID riid,
  148. OUT LPVOID *ppv
  149. )
  150. {
  151. *ppv=NULL;
  152. if (IID_IUnknown==riid)
  153. *ppv = reinterpret_cast<IUnknown*>(this);
  154. else if (IID_IWbemObjectSink==riid)
  155. *ppv = (IWbemObjectSink *)this;
  156. else if (IID_IDispatch==riid)
  157. *ppv = (IDispatch *)this;
  158. if (NULL!=*ppv)
  159. {
  160. ((LPUNKNOWN)*ppv)->AddRef();
  161. return NOERROR;
  162. }
  163. return ResultFromScode(E_NOINTERFACE);
  164. }
  165. STDMETHODIMP_(ULONG) CWbemObjectSink::AddRef(void)
  166. {
  167. InterlockedIncrement(&m_cRef);
  168. return m_cRef;
  169. }
  170. STDMETHODIMP_(ULONG) CWbemObjectSink::Release(void)
  171. {
  172. _RD(static char *me = "CWbemObjectSink::Release";)
  173. LONG cRef = InterlockedDecrement(&m_cRef);
  174. _RPrint(me, "After decrement", m_cRef, "RefCount: ");
  175. if (0 != cRef)
  176. {
  177. _ASSERT(cRef > 0);
  178. return cRef;
  179. }
  180. delete this;
  181. return 0;
  182. }
  183. #ifdef __RTEST_RPC_FAILURE
  184. int __Rx = 0;
  185. bool __Rdone = true;
  186. #endif
  187. HRESULT STDMETHODCALLTYPE CWbemObjectSink::Indicate(
  188. /* [in] */ long lObjectCount,
  189. /* [size_is][in] */ IWbemClassObject __RPC_FAR *__RPC_FAR *apObjArray)
  190. {
  191. _RD(static char *me = "CWbemObjectSink::Indicate";)
  192. _RPrint(me, "Called", 0, "");
  193. // See if we need to cache this method call if we are already in another
  194. // IWbemObjectSink interface method
  195. CIWbemObjectSinkMethodCache *pSinkMethodCache = CIWbemObjectSinkMethodCache::GetThreadsCache();
  196. if(pSinkMethodCache && !pSinkMethodCache->TestOkToRunIndicate(this, lObjectCount, apObjArray))
  197. {
  198. _RPrint(me, ">>>Re-entrant Indicate call", 0, "");
  199. return S_OK;
  200. }
  201. //------------------------------
  202. // walk though the classObjects...
  203. for (int i = 0; i < lObjectCount; i++)
  204. {
  205. #ifdef __RTEST_RPC_FAILURE
  206. __Rx++;
  207. #endif
  208. /*
  209. * NB: Although the CSWbemObject constructor has AddRef'd the
  210. * apObjArray[i] above, we do not balance this with a Release call
  211. * before leaving this function. According to CIMOM documentation
  212. * this is correct behavior if it cannot be gauranteed that the
  213. * objects will not be used after this call has returned.
  214. *
  215. * Also it appears the case that when calling into the OnObjectReady
  216. * function, the ISWbemObject should have a RefCount of 0 to be
  217. * garbage collected properly.
  218. */
  219. CSWbemObject *pObject = new CSWbemObject(m_pServices, apObjArray[i]);
  220. if (pObject)
  221. {
  222. CComPtr<IDispatch> pObjDisp;
  223. if (SUCCEEDED(pObject->QueryInterface(IID_IDispatch, (PPVOID)&pObjDisp)))
  224. {
  225. if (m_pSWbemSink)
  226. m_pSWbemSink->OnObjectReady(pObjDisp, m_pContext);
  227. } else {
  228. delete pObject;
  229. }
  230. }
  231. } // endfor
  232. #ifdef __RTEST_RPC_FAILURE
  233. if ((__Rx >= 15) && !__Rdone)
  234. {
  235. __Rdone = true;
  236. return RPC_E_SERVERFAULT;
  237. }
  238. #endif
  239. // Recall any cached interface methods if nested calls were received
  240. if (pSinkMethodCache)
  241. pSinkMethodCache->Cleanup();
  242. return S_OK;
  243. }
  244. HRESULT STDMETHODCALLTYPE CWbemObjectSink::SetStatus(
  245. /* [in] */ long lFlags,
  246. /* [in] */ HRESULT hResult,
  247. /* [in] */ BSTR strParam,
  248. /* [in] */ IWbemClassObject __RPC_FAR *pObjParam)
  249. {
  250. // See if we need to cache this method call if we are already in another
  251. // IWbemObjectSink interface method
  252. CIWbemObjectSinkMethodCache *pSinkMethodCache = CIWbemObjectSinkMethodCache::GetThreadsCache();
  253. if(pSinkMethodCache && !pSinkMethodCache->TestOkToRunSetStatus(this, lFlags, hResult, strParam, pObjParam))
  254. return S_OK;
  255. if (lFlags == WBEM_STATUS_COMPLETE)
  256. {
  257. IDispatch *pCSWbemObjectDisp = NULL;
  258. IDispatch *pObjectPathDisp = NULL;
  259. if (pObjParam)
  260. {
  261. /*
  262. * NB: Although the CSWbemObject constructor has AddRef'd the
  263. * pObjParam above, we do not balance this with a Release call
  264. * before leaving this function. According to CIMOM documentation
  265. * this is correct behavior if it cannot be gauranteed that the
  266. * objects will not be used after this call has returned.
  267. * Also it appears the case that when calling into the OnObjectReady
  268. * function, the ISWbemObject should have a RefCount of 0 to be
  269. * garbage collected properly.
  270. */
  271. CSWbemObject *pCSWbemObject = new CSWbemObject(m_pServices, pObjParam);
  272. if (pCSWbemObject)
  273. {
  274. if (FAILED(pCSWbemObject->QueryInterface(IID_IDispatch, (PPVOID)&pCSWbemObjectDisp)))
  275. {
  276. delete pCSWbemObject;
  277. pCSWbemObjectDisp = NULL;
  278. }
  279. }
  280. }
  281. if (m_putOperation && m_pServices)
  282. {
  283. CSWbemSecurity *pSecurity = m_pServices->GetSecurityInfo ();
  284. ISWbemObjectPath *pObjectPath = new CSWbemObjectPath (pSecurity);
  285. if (pSecurity)
  286. pSecurity->Release ();
  287. if (pObjectPath)
  288. {
  289. if (SUCCEEDED(pObjectPath->QueryInterface(IID_IDispatch, (PPVOID)&pObjectPathDisp)))
  290. {
  291. pObjectPath->put_Path (m_pServices->GetPath ());
  292. if (m_bsClassName)
  293. pObjectPath->put_RelPath (m_bsClassName);
  294. else if (strParam)
  295. pObjectPath->put_RelPath (strParam);
  296. }
  297. else
  298. {
  299. delete pObjectPath;
  300. pObjectPathDisp = NULL;
  301. }
  302. }
  303. }
  304. RemoveObjectSink();
  305. // Transform the error code if need be
  306. if (WBEM_S_ACCESS_DENIED == hResult)
  307. hResult = wbemErrAccessDenied;
  308. else if (WBEM_S_OPERATION_CANCELLED == hResult)
  309. hResult = wbemErrCallCancelled;
  310. else if (SUCCEEDED(hResult))
  311. hResult = wbemNoErr; // Ignore the other success codes for now.
  312. if (m_pSWbemSink)
  313. m_pSWbemSink->OnCompleted((WbemErrorEnum)hResult, pCSWbemObjectDisp, pObjectPathDisp, m_pContext);
  314. // Release the stub but only if an op is not in progress
  315. // If an op is in progress, stub will be removed on exit from op
  316. // If op is in Progress - stash hResult for later
  317. if (m_pObjectStub && !m_operationInProgress) {
  318. IWbemObjectSink *tmpStub = m_pObjectStub;
  319. m_pObjectStub = NULL;
  320. tmpStub->Release();
  321. }
  322. else {
  323. m_setStatusCompletedCalled = TRUE;
  324. }
  325. if (pCSWbemObjectDisp)
  326. pCSWbemObjectDisp->Release();
  327. if (pObjectPathDisp)
  328. pObjectPathDisp->Release();
  329. } else if (lFlags & WBEM_STATUS_PROGRESS)
  330. {
  331. if (m_pSWbemSink)
  332. m_pSWbemSink->OnProgress(HIWORD(hResult), LOWORD(hResult), strParam, m_pContext);
  333. }
  334. // Recall any cached interface methods if nested calls were received
  335. if (pSinkMethodCache)
  336. pSinkMethodCache->Cleanup();
  337. return S_OK;
  338. }
  339. IWbemObjectSink *CWbemObjectSink::GetObjectStub()
  340. {
  341. HRESULT hr = S_OK;
  342. if (!m_pObjectStub && m_pUnsecuredApartment)
  343. {
  344. // Create the object stub using unsecapp
  345. IUnknown *pSubstitute = NULL;
  346. // If we are called before this object has been handed out
  347. // we'd better protect our ref count
  348. bool bBumpUpRefCount = false;
  349. if (0 == m_cRef)
  350. {
  351. m_cRef++;
  352. bBumpUpRefCount = true;
  353. }
  354. if (SUCCEEDED (hr = m_pUnsecuredApartment->CreateObjectStub(this, &pSubstitute)))
  355. {
  356. // Ensure we QI for IWbemObjectSink
  357. hr = pSubstitute->QueryInterface (IID_IWbemObjectSink, (PPVOID) &m_pObjectStub);
  358. if (FAILED(hr))
  359. m_pObjectStub = NULL;
  360. // Now we're done with the returned stub
  361. pSubstitute->Release ();
  362. }
  363. if (bBumpUpRefCount)
  364. m_cRef--;
  365. }
  366. return m_pObjectStub;
  367. }
  368. HRESULT CWbemObjectSink::AddObjectSink(IWbemObjectSink *pSink)
  369. {
  370. HRESULT hr = S_OK;
  371. if (m_pSWbemSink)
  372. {
  373. if(m_pServices)
  374. {
  375. CComPtr<IWbemServices> pIWbemServices;
  376. pIWbemServices.Attach( m_pServices->GetIWbemServices ());
  377. // Is AddObjectSink assuming these 2 args have been AddRef'd already??
  378. m_pSWbemSink->AddObjectSink(pSink, pIWbemServices);
  379. }
  380. }
  381. return hr;
  382. }
  383. void CWbemObjectSink::RemoveObjectSink()
  384. {
  385. if (m_pSWbemSink)
  386. m_pSWbemSink->RemoveObjectSink(GetObjectStub());
  387. }