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.

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