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.

808 lines
21 KiB

  1. //=============================================================================
  2. //
  3. // Copyright (c) 1996-1999, Microsoft Corporation, All rights reserved
  4. //
  5. // ESSSINK.CPP
  6. //
  7. // This files implements the class that implements IWbemObjectSink for the ESS.
  8. //
  9. // See esssink.h for documentation.
  10. //
  11. // History:
  12. //
  13. // 11/27/96 a-levn Compiles
  14. //
  15. //=============================================================================
  16. #include "precomp.h"
  17. #include <stdio.h>
  18. #include "ess.h"
  19. #include "esssink.h"
  20. #define IN_ESS_OPERATION \
  21. CInEssSharedLock isl( &m_pObject->m_Lock, FALSE ); \
  22. if ( m_pObject->m_pEss == NULL ) \
  23. return WBEM_E_INVALID_OPERATION; \
  24. if ( m_pObject->m_bShutdown ) \
  25. return WBEM_E_SHUTTING_DOWN;
  26. //*****************************************************************************
  27. // public
  28. //
  29. // See esssink.h for documentation
  30. //
  31. //*****************************************************************************
  32. CEssObjectSink::CEssObjectSink(CLifeControl* pControl, IUnknown* pOuter)
  33. : CUnk(pControl, pOuter), m_XESS(this), m_XNewESS(this), m_XShutdown(this),
  34. m_XHook(this), m_bShutdown(FALSE), m_pEss(NULL), m_pCoreServices(NULL)
  35. {
  36. }
  37. //*****************************************************************************
  38. // public
  39. //
  40. // See esssink.h for documentation
  41. //
  42. //*****************************************************************************
  43. CEssObjectSink::~CEssObjectSink()
  44. {
  45. if( m_pCoreServices )
  46. {
  47. m_pCoreServices->Release();
  48. }
  49. }
  50. //*****************************************************************************
  51. // public
  52. //
  53. // See esssink.h for documentation
  54. //
  55. //*****************************************************************************
  56. void* CEssObjectSink::GetInterface(REFIID riid)
  57. {
  58. if(riid == IID_IWbemEventSubsystem_m4)
  59. return &m_XESS;
  60. else if(riid == IID_IWbemShutdown)
  61. return &m_XShutdown;
  62. else if(riid == IID__IWmiESS)
  63. return &m_XNewESS;
  64. else if(riid == IID__IWmiCoreWriteHook)
  65. return &m_XHook;
  66. return NULL;
  67. }
  68. //*****************************************************************************
  69. // public
  70. //
  71. // See esssink.h for documentation
  72. //
  73. //*****************************************************************************
  74. STDMETHODIMP CEssObjectSink::XESS::ProcessInternalEvent(long lSendType,
  75. LPCWSTR str1, LPCWSTR str2,
  76. LPCWSTR str3, DWORD dw1, DWORD dw2, DWORD dwObjectCount,
  77. _IWmiObject** apObjects, IWbemContext* pContext)
  78. {
  79. IN_ESS_OPERATION
  80. CEventRepresentation Event;
  81. Event.type = lSendType;
  82. Event.dw1 = dw1;
  83. Event.dw2 = dw2;
  84. Event.wsz1 = (LPWSTR)str1;
  85. Event.wsz2 = (LPWSTR)str2;
  86. Event.wsz3 = (LPWSTR)str3;
  87. Event.nObjects = (int)dwObjectCount;
  88. Event.apObjects = (IWbemClassObject**)apObjects;
  89. // Store the old context value for the future
  90. // ==========================================
  91. CEssThreadObject* pOldThreadObject = GetCurrentEssThreadObject();
  92. // Set it to the current one
  93. // =========================
  94. SetCurrentEssThreadObject(pContext);
  95. //
  96. // we must remove the client's security context from the thread because
  97. // it is really winmgmt raising these events, not the client.
  98. //
  99. IUnknown *pGarb, *pCtx = NULL;
  100. CoSwitchCallContext( NULL, &pCtx );
  101. // Do the actual processing
  102. // ========================
  103. HRESULT hres = m_pObject->m_pEss->ProcessEvent(Event, (long)dw2);
  104. // Restore the context
  105. // ===================
  106. CoSwitchCallContext( pCtx, &pGarb );
  107. CEssThreadObject* pNewThreadObject = GetCurrentEssThreadObject();
  108. delete pNewThreadObject;
  109. if(pOldThreadObject)
  110. {
  111. SetConstructedEssThreadObject(pOldThreadObject);
  112. }
  113. else
  114. {
  115. ClearCurrentEssThreadObject();
  116. }
  117. return hres;
  118. }
  119. STDMETHODIMP CEssObjectSink::XESS::VerifyInternalEvent(long lSendType,
  120. LPCWSTR str1, LPCWSTR str2,
  121. LPCWSTR str3, DWORD dw1, DWORD dw2, DWORD dwObjectCount,
  122. _IWmiObject** apObjects, IWbemContext* pContext)
  123. {
  124. IN_ESS_OPERATION
  125. CEventRepresentation Event;
  126. Event.type = lSendType;
  127. Event.dw1 = dw1;
  128. Event.dw2 = dw2;
  129. Event.wsz1 = (LPWSTR)str1;
  130. Event.wsz2 = (LPWSTR)str2;
  131. Event.wsz3 = (LPWSTR)str3;
  132. Event.nObjects = (int)dwObjectCount;
  133. Event.apObjects = (IWbemClassObject**)apObjects;
  134. // Store the old context value for the future
  135. // ==========================================
  136. CEssThreadObject* pOldThreadObject = GetCurrentEssThreadObject();
  137. // Set it to the current one
  138. // =========================
  139. SetCurrentEssThreadObject(pContext);
  140. // Do the actual processing
  141. // ========================
  142. HRESULT hres = m_pObject->m_pEss->VerifyInternalEvent(Event);
  143. // Restore the context
  144. // ===================
  145. CEssThreadObject* pNewThreadObject = GetCurrentEssThreadObject();
  146. delete pNewThreadObject;
  147. if(pOldThreadObject)
  148. {
  149. SetConstructedEssThreadObject(pOldThreadObject);
  150. }
  151. else
  152. {
  153. ClearCurrentEssThreadObject();
  154. }
  155. return hres;
  156. }
  157. STDMETHODIMP CEssObjectSink::XESS::RegisterNotificationSink(
  158. LPCWSTR wszNamespace,
  159. LPCWSTR wszQueryLanguage, LPCWSTR wszQuery, long lFlags,
  160. IWbemContext* pContext, IWbemObjectSink* pSink)
  161. {
  162. IN_ESS_OPERATION
  163. // Store the old context value for the future
  164. // ==========================================
  165. CEssThreadObject* pOldThreadObject = GetCurrentEssThreadObject();
  166. // Set it to the current one
  167. // =========================
  168. SetCurrentEssThreadObject(pContext);
  169. // Do the actual processing
  170. // ========================
  171. HRESULT hres = m_pObject->m_pEss->RegisterNotificationSink(wszNamespace,
  172. wszQueryLanguage, wszQuery, lFlags, pContext, pSink);
  173. // Restore the context
  174. // ===================
  175. CEssThreadObject* pNewThreadObject = GetCurrentEssThreadObject();
  176. delete pNewThreadObject;
  177. if(pOldThreadObject)
  178. {
  179. SetConstructedEssThreadObject(pOldThreadObject);
  180. }
  181. else
  182. {
  183. ClearCurrentEssThreadObject();
  184. }
  185. // Return
  186. // ======
  187. if(FAILED(hres))
  188. {
  189. pSink->SetStatus(0, hres, NULL, NULL);
  190. }
  191. return hres;
  192. }
  193. STDMETHODIMP CEssObjectSink::XESS::RemoveNotificationSink(
  194. IWbemObjectSink* pSink)
  195. {
  196. IN_ESS_OPERATION
  197. // Store the old context value for the future
  198. // ==========================================
  199. CEssThreadObject* pOldThreadObject = GetCurrentEssThreadObject();
  200. // Set it to the current one
  201. // =========================
  202. SetCurrentEssThreadObject(NULL);
  203. // Do the actual processing
  204. // ========================
  205. HRESULT hres = m_pObject->m_pEss->RemoveNotificationSink(pSink);
  206. // Restore the context
  207. // ===================
  208. CEssThreadObject* pNewThreadObject = GetCurrentEssThreadObject();
  209. delete pNewThreadObject;
  210. if(pOldThreadObject)
  211. {
  212. SetConstructedEssThreadObject(pOldThreadObject);
  213. }
  214. else
  215. {
  216. ClearCurrentEssThreadObject();
  217. }
  218. return hres;
  219. }
  220. STDMETHODIMP CEssObjectSink::XESS::GetNamespaceSink(LPCWSTR wszNamespace,
  221. IWbemObjectSink** ppSink)
  222. {
  223. IN_ESS_OPERATION
  224. CEssNamespaceSink* pSink = _new CEssNamespaceSink(m_pObject->m_pEss,
  225. m_pObject->m_pControl);
  226. if(pSink == NULL)
  227. return WBEM_E_OUT_OF_MEMORY;
  228. HRESULT hres = pSink->Initialize(wszNamespace);
  229. if(FAILED(hres))
  230. {
  231. delete pSink;
  232. return hres;
  233. }
  234. return pSink->QueryInterface(IID_IWbemObjectSink, (void**)ppSink);
  235. }
  236. STDMETHODIMP CEssObjectSink::XNewESS::Initialize( long lFlags,
  237. IWbemContext* pCtx,
  238. _IWmiCoreServices* pServices)
  239. {
  240. //
  241. // This function is not multi-thread safe by design. We do not support
  242. // concurrent operations while in this function. The expectation is that
  243. // the user will call this method and THEN introduce the object into
  244. // an environment where it can be called concurrently.
  245. //
  246. //
  247. // This object will not support being called after a failed initialization.
  248. // The user must deallocate the object and then allocate a new one.
  249. //
  250. HRESULT hres;
  251. if ( m_pObject->m_pEss != NULL )
  252. {
  253. return WBEM_S_FALSE;
  254. }
  255. if ( m_pObject->m_bShutdown )
  256. {
  257. return WBEM_E_INVALID_OPERATION;
  258. }
  259. if ( !m_pObject->m_Lock.Initialize() )
  260. {
  261. return WBEM_E_OUT_OF_MEMORY;
  262. }
  263. //
  264. // set shutdown to true in case we exit prematurely. This will prevent
  265. // any future calls to this function after a failed init.
  266. //
  267. m_pObject->m_bShutdown = TRUE;
  268. //
  269. // Get current machine name --- core is not giving it to us anymore
  270. //
  271. WCHAR wszComputerName[MAX_COMPUTERNAME_LENGTH+1];
  272. DWORD dwSize = MAX_COMPUTERNAME_LENGTH+1;
  273. if(!GetComputerNameW(wszComputerName, &dwSize))
  274. {
  275. ERRORTRACE((LOG_ESS, "Cannot retrieve computer name: %d\n",
  276. GetLastError()));
  277. return WBEM_E_CRITICAL_ERROR;
  278. }
  279. //
  280. // Get the decorator from core services
  281. //
  282. CWbemPtr<IWbemDecorator> pDecor;
  283. hres = pServices->GetDecorator(0, &pDecor);
  284. if(FAILED(hres))
  285. {
  286. ERRORTRACE((LOG_ESS, "Cannot retrieve decorator: 0x%X\n", hres));
  287. return WBEM_E_CRITICAL_ERROR;
  288. }
  289. //
  290. // Hook all core write operations
  291. //
  292. m_pObject->m_pCoreServices = pServices;
  293. m_pObject->m_pCoreServices->AddRef();
  294. hres = m_pObject->m_pCoreServices->RegisterWriteHook(WBEM_FLAG_INST_PUT|WBEM_FLAG_INST_DELETE,
  295. &m_pObject->m_XHook);
  296. if(FAILED(hres))
  297. {
  298. ERRORTRACE((LOG_ESS, "Unable to hook core write operations: 0x%X\n",
  299. hres));
  300. return WBEM_E_CRITICAL_ERROR;
  301. }
  302. //
  303. // Initialize for real
  304. //
  305. CEss* pEss = NULL;
  306. try
  307. {
  308. pEss = new CEss();
  309. }
  310. catch(CX_MemoryException)
  311. {
  312. return WBEM_E_OUT_OF_MEMORY;
  313. }
  314. if ( pEss == NULL )
  315. {
  316. return WBEM_E_OUT_OF_MEMORY;
  317. }
  318. //
  319. // create a context object that will be passed around with all work that
  320. // is done on behalf of ess init.
  321. //
  322. CWbemPtr<IWbemContext> pContext;
  323. hres = CoCreateInstance( CLSID_WbemContext,
  324. NULL,
  325. CLSCTX_INPROC_SERVER,
  326. IID_IWbemContext,
  327. (void**)&pContext );
  328. if ( SUCCEEDED(hres) )
  329. {
  330. //
  331. // set the context to be an init context object.
  332. //
  333. VARIANT vInit;
  334. V_VT(&vInit) = VT_BOOL;
  335. V_BOOL(&vInit) = VARIANT_TRUE;
  336. hres = pContext->SetValue( L"__EssInInitialize", 0, &vInit );
  337. }
  338. if ( SUCCEEDED(hres) )
  339. {
  340. //
  341. // attach the init context to the thread
  342. //
  343. SetCurrentEssThreadObject( pContext );
  344. if ( GetCurrentEssThreadObject() == NULL )
  345. {
  346. hres = WBEM_E_OUT_OF_MEMORY;
  347. }
  348. }
  349. if ( FAILED(hres) )
  350. {
  351. ERRORTRACE(( LOG_ESS, "Error creating ess context object during init"
  352. "HR=0x%x\n", hres ));
  353. return hres;
  354. }
  355. hres = pEss->Initialize( wszComputerName, lFlags, pServices, pDecor );
  356. //
  357. // Restore the context
  358. //
  359. CEssThreadObject* pNewThreadObject = GetCurrentEssThreadObject();
  360. delete pNewThreadObject;
  361. ClearCurrentEssThreadObject();
  362. if ( FAILED(hres) )
  363. {
  364. delete pEss;
  365. return hres;
  366. }
  367. m_pObject->m_pEss = pEss;
  368. m_pObject->m_bShutdown = FALSE;
  369. return hres;
  370. }
  371. STDMETHODIMP CEssObjectSink::XNewESS::ExecNotificationQuery(
  372. LPCWSTR wszNamespace, LPCWSTR wszQueryText, long lFlags,
  373. IWbemContext* pContext, IWbemObjectSink* pSink)
  374. {
  375. return m_pObject->m_XESS.RegisterNotificationSink(wszNamespace,
  376. L"WQL", wszQueryText, lFlags, pContext, pSink);
  377. }
  378. STDMETHODIMP CEssObjectSink::XNewESS::CancelAsyncCall(IWbemObjectSink* pSink)
  379. {
  380. return m_pObject->m_XESS.RemoveNotificationSink(pSink);
  381. }
  382. STDMETHODIMP CEssObjectSink::XNewESS::QueryObjectSink(LPCWSTR wszNamespace,
  383. IWbemObjectSink** ppSink)
  384. {
  385. return m_pObject->m_XESS.GetNamespaceSink(wszNamespace, ppSink);
  386. }
  387. STDMETHODIMP CEssObjectSink::XESS::Initialize(LPCWSTR wszServer,
  388. IWbemLocator* pAdminLocator,
  389. IUnknown* pServices)
  390. {
  391. //
  392. // Use the _IWmiESS version.
  393. //
  394. return WBEM_E_NOT_SUPPORTED;
  395. }
  396. STDMETHODIMP CEssObjectSink::XShutdown::Shutdown( LONG uReason,
  397. ULONG uMaxMilliseconds,
  398. IWbemContext* pCtx )
  399. {
  400. // uMaxMilliseconds == 0 means system shutdown
  401. if (0 == uMaxMilliseconds)
  402. return WBEM_S_NO_ERROR;
  403. {
  404. //
  405. // wait for all current operations to complete. Lock will prevent
  406. // any new operations from getting through.
  407. //
  408. CInEssSharedLock isl( &m_pObject->m_Lock, TRUE );
  409. if ( m_pObject->m_bShutdown )
  410. {
  411. return WBEM_S_FALSE;
  412. }
  413. m_pObject->m_bShutdown = TRUE;
  414. }
  415. HRESULT hres;
  416. //
  417. // Unhook all core write operations
  418. //
  419. hres = m_pObject->m_pCoreServices->UnregisterWriteHook(
  420. &m_pObject->m_XHook);
  421. if(FAILED(hres))
  422. {
  423. ERRORTRACE((LOG_ESS, "Unable to unhook core write operations: 0x%X\n",
  424. hres));
  425. }
  426. SetCurrentEssThreadObject(NULL);
  427. hres = m_pObject->m_pEss->Shutdown((0 == uMaxMilliseconds)?TRUE:FALSE);
  428. CEssThreadObject* pNewThreadObject = GetCurrentEssThreadObject();
  429. delete pNewThreadObject;
  430. ClearCurrentEssThreadObject();
  431. if ( m_pObject->m_pEss != NULL )
  432. {
  433. delete m_pObject->m_pEss;
  434. m_pObject->m_pEss = NULL;
  435. }
  436. return hres;
  437. }
  438. STDMETHODIMP CEssObjectSink::XESS::Shutdown()
  439. {
  440. HRESULT hres;
  441. {
  442. //
  443. // wait for all current operations to complete. Lock will prevent
  444. // any new operations from getting through.
  445. //
  446. CInEssSharedLock isl( &m_pObject->m_Lock, TRUE );
  447. if ( m_pObject->m_bShutdown )
  448. {
  449. return WBEM_S_FALSE;
  450. }
  451. m_pObject->m_bShutdown = TRUE;
  452. }
  453. SetCurrentEssThreadObject(NULL);
  454. hres = m_pObject->m_pEss->Shutdown(FALSE); // no system shutdown
  455. CEssThreadObject* pNewThreadObject = GetCurrentEssThreadObject();
  456. delete pNewThreadObject;
  457. ClearCurrentEssThreadObject();
  458. return hres;
  459. }
  460. STDMETHODIMP CEssObjectSink::XESS::LastCallForCore(LONG bIsSystemShutdown)
  461. {
  462. IN_ESS_OPERATION
  463. return m_pObject->m_pEss->LastCallForCore(bIsSystemShutdown);
  464. }
  465. //*********************** NAMESPACE SINK **************************************
  466. //******************************************************************************
  467. // public
  468. //
  469. // See esssink.h for documentation
  470. //
  471. //******************************************************************************
  472. CEssNamespaceSink::CEssNamespaceSink(CEss* pEss,
  473. CLifeControl* pControl, IUnknown* pOuter) :
  474. CUnk(pControl, pOuter), m_XSink(this),
  475. m_pEss(pEss)
  476. {
  477. }
  478. HRESULT CEssNamespaceSink::Initialize(LPCWSTR wszNamespace)
  479. {
  480. m_strNamespace = SysAllocString(wszNamespace);
  481. if(m_strNamespace == NULL)
  482. return WBEM_E_OUT_OF_MEMORY;
  483. return WBEM_S_NO_ERROR;
  484. }
  485. //******************************************************************************
  486. // public
  487. //
  488. // See esssink.h for documentation
  489. //
  490. //******************************************************************************
  491. CEssNamespaceSink::~CEssNamespaceSink()
  492. {
  493. SysFreeString(m_strNamespace);
  494. }
  495. //******************************************************************************
  496. // public
  497. //
  498. // See esssink.h for documentation
  499. //
  500. //******************************************************************************
  501. void* CEssNamespaceSink::GetInterface(REFIID riid)
  502. {
  503. if(riid == IID_IWbemObjectSink || riid == IID_IUnknown)
  504. {
  505. return &m_XSink;
  506. }
  507. return NULL;
  508. }
  509. //******************************************************************************
  510. // public
  511. //
  512. // See esssink.h for documentation
  513. //
  514. //******************************************************************************
  515. STDMETHODIMP CEssNamespaceSink::XSink::Indicate(long lObjectCount,
  516. IWbemClassObject** apObjArray)
  517. {
  518. HRESULT hres = WBEM_S_NO_ERROR;
  519. for(int i = 0; i < lObjectCount; i++)
  520. {
  521. IWbemClassObject* pEvent = apObjArray[0];
  522. CEventRepresentation Event;
  523. Event.CreateFromObject(pEvent, m_pObject->m_strNamespace);
  524. hres = m_pObject->m_pEss->ProcessQueryObjectSinkEvent( Event );
  525. }
  526. return hres;
  527. }
  528. STDMETHODIMP CEssObjectSink::XHook::PrePut(long lFlags, long lUserFlags,
  529. IWbemContext* pContext,
  530. IWbemPath* pPath, LPCWSTR wszNamespace,
  531. LPCWSTR wszClass, _IWmiObject* pCopy)
  532. {
  533. HRESULT hres;
  534. IN_ESS_OPERATION
  535. //
  536. // Construct the old CEventRepresentation --- simplest route
  537. //
  538. CEventRepresentation Event;
  539. //
  540. // Determine whether a class or an instance is being put
  541. //
  542. if(pCopy->IsObjectInstance() == S_OK)
  543. Event.type = e_EventTypeInstanceCreation;
  544. else
  545. Event.type = e_EventTypeClassCreation;
  546. Event.dw1 = 0;
  547. Event.dw2 = 0;
  548. Event.wsz1 = (LPWSTR)wszNamespace;
  549. Event.wsz2 = (LPWSTR)wszClass;
  550. Event.wsz3 = NULL;
  551. Event.nObjects = 1;
  552. Event.apObjects = (IWbemClassObject**)&pCopy;
  553. // Store the old context value for the future
  554. // ==========================================
  555. CEssThreadObject* pOldThreadObject = GetCurrentEssThreadObject();
  556. // Set it to the current one
  557. // =========================
  558. SetCurrentEssThreadObject(pContext);
  559. // Do the actual processing
  560. // ========================
  561. hres = m_pObject->m_pEss->VerifyInternalEvent(Event);
  562. // Restore the context
  563. // ===================
  564. CEssThreadObject* pNewThreadObject = GetCurrentEssThreadObject();
  565. delete pNewThreadObject;
  566. if(pOldThreadObject)
  567. {
  568. SetConstructedEssThreadObject(pOldThreadObject);
  569. }
  570. else
  571. {
  572. ClearCurrentEssThreadObject();
  573. }
  574. return hres;
  575. }
  576. STDMETHODIMP CEssObjectSink::XHook::PostPut(long lFlags, HRESULT hApiResult,
  577. IWbemContext* pContext,
  578. IWbemPath* pPath, LPCWSTR wszNamespace,
  579. LPCWSTR wszClass, _IWmiObject* pNew,
  580. _IWmiObject* pOld)
  581. {
  582. return WBEM_S_NO_ERROR;
  583. }
  584. STDMETHODIMP CEssObjectSink::XHook::PreDelete(long lFlags, long lUserFlags,
  585. IWbemContext* pContext,
  586. IWbemPath* pPath, LPCWSTR wszNamespace,
  587. LPCWSTR wszClass)
  588. {
  589. return WBEM_S_NO_ERROR;
  590. }
  591. STDMETHODIMP CEssObjectSink::XHook::PostDelete(long lFlags,
  592. HRESULT hApiResult,
  593. IWbemContext* pContext,
  594. IWbemPath* pPath, LPCWSTR wszNamespace,
  595. LPCWSTR wszClass, _IWmiObject* pOld)
  596. {
  597. return WBEM_S_NO_ERROR;
  598. }
  599. /****************************************************************************
  600. CEssInternalOperationSink
  601. *****************************************************************************/
  602. STDMETHODIMP CEssInternalOperationSink::Indicate( long cObjs,
  603. IWbemClassObject** ppObjs )
  604. {
  605. HRESULT hr;
  606. //
  607. // if the calling thread already has a thread object, leave it.
  608. //
  609. CEssThreadObject* pOldThreadObject = GetCurrentEssThreadObject();
  610. if ( pOldThreadObject == NULL )
  611. {
  612. //
  613. // set up a new thread object.
  614. //
  615. SetCurrentEssThreadObject(NULL);
  616. if ( GetCurrentEssThreadObject() == NULL )
  617. {
  618. return WBEM_E_OUT_OF_MEMORY;
  619. }
  620. }
  621. hr = m_pSink->Indicate( cObjs, ppObjs );
  622. //
  623. // delete the thread object if necessary
  624. //
  625. if ( pOldThreadObject == NULL )
  626. {
  627. delete GetCurrentEssThreadObject();
  628. ClearCurrentEssThreadObject();
  629. }
  630. return hr;
  631. }
  632. STDMETHODIMP CEssInternalOperationSink::SetStatus( long lFlags,
  633. HRESULT hres,
  634. BSTR bstr,
  635. IWbemClassObject* pObj )
  636. {
  637. //
  638. // simply delegate ( for now )
  639. //
  640. return m_pSink->SetStatus( lFlags, hres, bstr, pObj );
  641. }