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.

739 lines
19 KiB

  1. /******************************************************************************
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. AsyncDatabase.cpp
  5. Abstract:
  6. This file contains the implementation of the asynchronous database access.
  7. Revision History:
  8. Davide Massarenti (Dmassare) 08/13/2000
  9. created
  10. ******************************************************************************/
  11. #include "stdafx.h"
  12. ////////////////////////////////////////////////////////////////////////////////
  13. AsynchronousTaxonomyDatabase::NotifyHandle::NotifyHandle()
  14. {
  15. m_iType = OfflineCache::ET_INVALID; // int m_iType;
  16. // CComBSTR m_bstrID;
  17. //
  18. m_hEvent = NULL; // HANDLE m_hEvent;
  19. //
  20. m_hr = HRESULT_FROM_WIN32(ERROR_BUSY); // HRESULT m_hr;
  21. m_pColl = NULL; // CPCHQueryResultCollection* m_pColl;
  22. }
  23. AsynchronousTaxonomyDatabase::NotifyHandle::~NotifyHandle()
  24. {
  25. Detach();
  26. MPC::Release( m_pColl );
  27. if(m_hEvent)
  28. {
  29. ::CloseHandle( m_hEvent );
  30. }
  31. }
  32. STDMETHODIMP_(ULONG) AsynchronousTaxonomyDatabase::NotifyHandle::AddRef()
  33. {
  34. return InternalAddRef();
  35. }
  36. STDMETHODIMP_(ULONG) AsynchronousTaxonomyDatabase::NotifyHandle::Release()
  37. {
  38. ULONG c = InternalRelease();
  39. if(c == 0) delete this;
  40. return c;
  41. }
  42. ////////////////////////////////////////
  43. HRESULT AsynchronousTaxonomyDatabase::NotifyHandle::Init()
  44. {
  45. __HCP_FUNC_ENTRY( "AsynchronousTaxonomyDatabase::NotifyHandle::Init" );
  46. HRESULT hr;
  47. MPC::SmartLock<_ThreadModel> lock( this );
  48. __MPC_EXIT_IF_CALL_RETURNS_NULL(hr, (m_hEvent = ::CreateEvent( NULL, FALSE, FALSE, NULL )));
  49. m_fAttached = true;
  50. hr = S_OK;
  51. __HCP_FUNC_CLEANUP;
  52. __HCP_FUNC_EXIT(hr);
  53. }
  54. void AsynchronousTaxonomyDatabase::NotifyHandle::Bind( /*[in]*/ int iType, /*[in]*/ LPCWSTR szID )
  55. {
  56. MPC::SmartLock<_ThreadModel> lock( this );
  57. m_iType = iType;
  58. m_bstrID = szID;
  59. m_hr = HRESULT_FROM_WIN32(ERROR_BUSY);
  60. MPC::Release( m_pColl );
  61. }
  62. void AsynchronousTaxonomyDatabase::NotifyHandle::Call( /*[in]*/ QueryStore* qs )
  63. {
  64. MPC::SmartLock<_ThreadModel> lock( this );
  65. MPC::Release( m_pColl );
  66. m_hr = qs ? qs->GetData( &m_pColl ) : E_ABORT;
  67. //
  68. // Look ahead all the URLs, to Get all the Copy the items in the remote collection.
  69. //
  70. if(m_pColl)
  71. {
  72. long lCount;
  73. long lPos;
  74. if(SUCCEEDED(m_pColl->get_Count( &lCount )))
  75. {
  76. for(lPos=0; lPos<lCount; lPos++)
  77. {
  78. CComPtr<CPCHQueryResult> item;
  79. if(SUCCEEDED(m_pColl->GetItem( lPos, &item )))
  80. {
  81. CComBSTR bstrURL;
  82. if(SUCCEEDED(item->get_TopicURL( &bstrURL )))
  83. {
  84. if(STRINGISPRESENT(bstrURL)) (void)HyperLinks::Lookup::s_GLOBAL->Queue( bstrURL );
  85. }
  86. }
  87. }
  88. }
  89. }
  90. if(m_hEvent)
  91. {
  92. ::SetEvent( m_hEvent );
  93. }
  94. }
  95. void AsynchronousTaxonomyDatabase::NotifyHandle::Detach()
  96. {
  97. MPC::SmartLock<_ThreadModel> lock( this );
  98. m_fAttached = false;
  99. }
  100. bool AsynchronousTaxonomyDatabase::NotifyHandle::IsAttached()
  101. {
  102. MPC::SmartLock<_ThreadModel> lock( this );
  103. return m_fAttached;
  104. }
  105. ////////////////////////////////////////
  106. HRESULT AsynchronousTaxonomyDatabase::NotifyHandle::GetData( /*[out]*/ CPCHQueryResultCollection* *pColl )
  107. {
  108. MPC::SmartLock<_ThreadModel> lock( this );
  109. if(pColl)
  110. {
  111. *pColl = NULL;
  112. if(SUCCEEDED(m_hr))
  113. {
  114. if(m_pColl) (*pColl = m_pColl)->AddRef();
  115. }
  116. }
  117. return m_hr;
  118. }
  119. HRESULT AsynchronousTaxonomyDatabase::NotifyHandle::Wait( /*[in]*/ DWORD dwTimeout )
  120. {
  121. if(IsAttached())
  122. {
  123. for(int pass=0; pass<2; pass++)
  124. {
  125. DWORD dwRes;
  126. DWORD dwWait;
  127. //
  128. // On first pass, do a synchronous wait.
  129. //
  130. if(pass == 0)
  131. {
  132. dwRes = ::WaitForSingleObject( m_hEvent, min( dwTimeout, 200 ) );
  133. }
  134. else
  135. {
  136. dwRes = MPC::WaitForSingleObject( m_hEvent, dwTimeout );
  137. }
  138. if(dwRes == WAIT_OBJECT_0 ||
  139. dwRes == WAIT_ABANDONED_0 )
  140. {
  141. break;
  142. }
  143. if(pass == 1)
  144. {
  145. return HRESULT_FROM_WIN32(ERROR_BUSY);
  146. }
  147. }
  148. }
  149. return S_OK;
  150. }
  151. ////////////////////////////////////////////////////////////////////////////////
  152. AsynchronousTaxonomyDatabase::Notifier::Notifier()
  153. {
  154. // List m_lstCallback;
  155. }
  156. AsynchronousTaxonomyDatabase::Notifier::~Notifier()
  157. {
  158. MPC::ReleaseAll( m_lstCallback );
  159. }
  160. ////////////////////
  161. void AsynchronousTaxonomyDatabase::Notifier::Notify( /*[in]*/ QueryStore* qs )
  162. {
  163. List lst;
  164. Iter it;
  165. //
  166. // Phase 1: copy list, under lock.
  167. //
  168. {
  169. MPC::SmartLock<_ThreadModel> lock( this );
  170. for(it = m_lstCallback.begin(); it != m_lstCallback.end(); it++)
  171. {
  172. NotifyHandle* nb = *it;
  173. if(qs)
  174. {
  175. if(qs->m_iType != nb->m_iType || MPC::StrCmp( qs->m_bstrID, nb->m_bstrID )) continue;
  176. }
  177. lst.push_back( nb ); nb->AddRef();
  178. }
  179. }
  180. //
  181. // Phase 2: send the notification.
  182. //
  183. for(it = lst.begin(); it != lst.end(); it++)
  184. {
  185. NotifyHandle* nb = *it;
  186. nb->Call ( qs );
  187. nb->Detach( );
  188. }
  189. MPC::ReleaseAll( lst );
  190. //
  191. // Phase 3: clean list, under lock.
  192. //
  193. {
  194. MPC::SmartLock<_ThreadModel> lock( this );
  195. for(it = m_lstCallback.begin(); it != m_lstCallback.end();)
  196. {
  197. NotifyHandle* nb = *it;
  198. if(nb->IsAttached() == false)
  199. {
  200. m_lstCallback.erase( it ); nb->Release();
  201. it = m_lstCallback.begin();
  202. }
  203. else
  204. {
  205. it++;
  206. }
  207. }
  208. }
  209. }
  210. ////////////////////
  211. HRESULT AsynchronousTaxonomyDatabase::Notifier::AddNotification( /*[in]*/ QueryStore* qs, /*[in]*/ NotifyHandle* nb )
  212. {
  213. __HCP_FUNC_ENTRY( "AsynchronousTaxonomyDatabase::Notifier::AddNotification" );
  214. HRESULT hr;
  215. MPC::SmartLock<_ThreadModel> lock( this );
  216. if(nb == NULL)
  217. {
  218. __MPC_SET_ERROR_AND_EXIT(hr, E_OUTOFMEMORY);
  219. }
  220. __MPC_EXIT_IF_METHOD_FAILS(hr, nb->Init());
  221. nb->Bind( qs->m_iType, qs->m_bstrID );
  222. m_lstCallback.push_back( nb ); nb->AddRef();
  223. hr = S_OK;
  224. __HCP_FUNC_CLEANUP;
  225. __HCP_FUNC_EXIT(hr);
  226. }
  227. ////////////////////////////////////////////////////////////////////////////////
  228. ////////////////////////////////////////////////////////////////////////////////
  229. AsynchronousTaxonomyDatabase::QueryStore::QueryStore( /*[in]*/ int iType, /*[in]*/ LPCWSTR szID, /*[in]*/ VARIANT* option )
  230. {
  231. m_iType = iType; // int m_iType;
  232. m_bstrID = szID; // CComBSTR m_bstrID;
  233. // CComVariant m_vOption;
  234. //
  235. m_fDone = false; // bool m_fDone;
  236. m_hr = E_INVALIDARG; // HRESULT m_hr;
  237. // MPC::CComHGLOBAL m_hgData;
  238. // FILETIME m_dLastUsed;
  239. if(option) m_vOption = *option;
  240. }
  241. AsynchronousTaxonomyDatabase::QueryStore::~QueryStore()
  242. {
  243. Invalidate();
  244. }
  245. ////////////////////
  246. bool AsynchronousTaxonomyDatabase::QueryStore::LessThen( /*[in]*/ QueryStore const &qs ) const
  247. {
  248. int iCmp = (m_iType - qs.m_iType);
  249. if(iCmp == 0)
  250. {
  251. iCmp = MPC::StrCmp( m_bstrID, qs.m_bstrID );
  252. if(iCmp == 0)
  253. {
  254. switch(m_iType)
  255. {
  256. case OfflineCache::ET_LOCATECONTEXT:
  257. case OfflineCache::ET_SEARCH :
  258. {
  259. bool fHasLeft = ( m_vOption.vt == VT_BSTR);
  260. bool fHasRight = (qs.m_vOption.vt == VT_BSTR);
  261. if(fHasLeft)
  262. {
  263. iCmp = fHasRight ? MPC::StrCmp( m_vOption.bstrVal, qs.m_vOption.bstrVal ) : 1;
  264. }
  265. else
  266. {
  267. iCmp = fHasRight ? -1 : 0;
  268. }
  269. }
  270. break;
  271. }
  272. }
  273. }
  274. return (iCmp < 0);
  275. }
  276. bool AsynchronousTaxonomyDatabase::QueryStore::NewerThen( /*[in]*/ QueryStore const &qs ) const
  277. {
  278. return ::CompareFileTime( &m_dLastUsed, &qs.m_dLastUsed ) > 0;
  279. }
  280. ////////////////////
  281. HRESULT AsynchronousTaxonomyDatabase::QueryStore::Execute( /*[in]*/ OfflineCache::Handle* handle ,
  282. /*[in]*/ CPCHProxy_IPCHTaxonomyDatabase* parent ,
  283. /*[in]*/ bool fForce )
  284. {
  285. __HCP_FUNC_ENTRY( "AsynchronousTaxonomyDatabase::QueryStore::Execute" );
  286. HRESULT hr;
  287. CComPtr<IPCHCollection> pColl;
  288. __MPC_TRY_BEGIN();
  289. if(fForce) m_fDone = false;
  290. if(m_fDone == false)
  291. {
  292. DebugLog( L"AsynchronousTaxonomyDatabase::QueryStore::Execute - Start : %s\n", SAFEBSTR( m_bstrID ) );
  293. DEBUG_AppendPerf( DEBUG_PERF_QUERIES, L"AsynchronousTaxonomyDatabase::QueryStore::Execute - Start : %s", SAFEBSTR( m_bstrID ) );
  294. if(handle)
  295. {
  296. CComPtr<CPCHQueryResultCollection> coll;
  297. if(SUCCEEDED((*handle)->Retrieve( m_bstrID, m_iType, &coll )))
  298. {
  299. DEBUG_AppendPerf( DEBUG_PERF_QUERIES, L"AsynchronousTaxonomyDatabase::QueryStore::Execute - Cache Hit" );
  300. pColl = coll;
  301. }
  302. }
  303. if(!pColl && parent)
  304. {
  305. CComPtr<IPCHTaxonomyDatabase> db;
  306. DEBUG_AppendPerf( DEBUG_PERF_QUERIES, L"AsynchronousTaxonomyDatabase::QueryStore::Execute - Get DB" );
  307. __MPC_EXIT_IF_METHOD_FAILS(hr, parent->EnsureDirectConnection( db ));
  308. DEBUG_AppendPerf( DEBUG_PERF_QUERIES, L"AsynchronousTaxonomyDatabase::QueryStore::Execute - Got DB" );
  309. switch(m_iType)
  310. {
  311. case OfflineCache::ET_NODE : hr = db->LookupNode ( m_bstrID, &pColl ); break;
  312. case OfflineCache::ET_SUBNODES : hr = db->LookupSubNodes ( m_bstrID, VARIANT_FALSE, &pColl ); break;
  313. case OfflineCache::ET_SUBNODES_VISIBLE : hr = db->LookupSubNodes ( m_bstrID, VARIANT_TRUE , &pColl ); break;
  314. case OfflineCache::ET_NODESANDTOPICS : hr = db->LookupNodesAndTopics( m_bstrID, VARIANT_FALSE, &pColl ); break;
  315. case OfflineCache::ET_NODESANDTOPICS_VISIBLE: hr = db->LookupNodesAndTopics( m_bstrID, VARIANT_TRUE , &pColl ); break;
  316. case OfflineCache::ET_TOPICS : hr = db->LookupTopics ( m_bstrID, VARIANT_FALSE, &pColl ); break;
  317. case OfflineCache::ET_TOPICS_VISIBLE : hr = db->LookupTopics ( m_bstrID, VARIANT_TRUE , &pColl ); break;
  318. case OfflineCache::ET_LOCATECONTEXT : hr = db->LocateContext ( m_bstrID, m_vOption , &pColl ); break;
  319. case OfflineCache::ET_SEARCH : hr = db->KeywordSearch ( m_bstrID, m_vOption , &pColl ); break;
  320. case OfflineCache::ET_NODES_RECURSIVE : hr = db->GatherNodes ( m_bstrID, VARIANT_TRUE , &pColl ); break;
  321. case OfflineCache::ET_TOPICS_RECURSIVE : hr = db->GatherTopics ( m_bstrID, VARIANT_TRUE , &pColl ); break;
  322. default : hr = E_INVALIDARG;
  323. }
  324. DEBUG_AppendPerf( DEBUG_PERF_QUERIES, L"AsynchronousTaxonomyDatabase::QueryStore::Execute - Query Done" );
  325. }
  326. }
  327. if(pColl)
  328. {
  329. CComPtr<IPersistStream> persist;
  330. CComPtr<IStream> stream;
  331. DEBUG_AppendPerf( DEBUG_PERF_QUERIES, L"AsynchronousTaxonomyDatabase::QueryStore::Execute - Local Copy Start" );
  332. __MPC_EXIT_IF_METHOD_FAILS(hr, pColl->QueryInterface( IID_IPersistStream, (void**)&persist ));
  333. __MPC_EXIT_IF_METHOD_FAILS(hr, m_hgData.NewStream( &stream ));
  334. __MPC_EXIT_IF_METHOD_FAILS(hr, persist->Save ( stream, FALSE ));
  335. DEBUG_AppendPerf( DEBUG_PERF_QUERIES, L"AsynchronousTaxonomyDatabase::QueryStore::Execute - Local Copy Done" );
  336. }
  337. ::GetSystemTimeAsFileTime( &m_dLastUsed );
  338. hr = S_OK;
  339. __HCP_FUNC_CLEANUP;
  340. __MPC_TRY_CATCHALL(hr);
  341. if(m_fDone == false)
  342. {
  343. m_hr = hr;
  344. m_fDone = true;
  345. }
  346. __HCP_FUNC_EXIT(hr);
  347. }
  348. HRESULT AsynchronousTaxonomyDatabase::QueryStore::GetData( /*[out]*/ CPCHQueryResultCollection* *ppC )
  349. {
  350. __HCP_FUNC_ENTRY( "AsynchronousTaxonomyDatabase::QueryStore::GetData" );
  351. HRESULT hr;
  352. CComPtr<CPCHQueryResultCollection> pColl;
  353. CComPtr<IPersistStream> persist;
  354. CComPtr<IStream> stream;
  355. __MPC_PARAMCHECK_BEGIN(hr)
  356. __MPC_PARAMCHECK_POINTER_AND_SET(ppC,NULL);
  357. __MPC_PARAMCHECK_END();
  358. __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::CreateInstance( &pColl ));
  359. __MPC_EXIT_IF_METHOD_FAILS(hr, pColl->QueryInterface( IID_IPersistStream, (void**)&persist ));
  360. __MPC_EXIT_IF_METHOD_FAILS(hr, m_hgData.GetAsStream( &stream, /*fClone*/false ));
  361. __MPC_EXIT_IF_METHOD_FAILS(hr, persist->Load ( stream ));
  362. *ppC = pColl.Detach();
  363. hr = S_OK;
  364. __HCP_FUNC_CLEANUP;
  365. __HCP_FUNC_EXIT(hr);
  366. }
  367. void AsynchronousTaxonomyDatabase::QueryStore::Invalidate()
  368. {
  369. m_hgData.Release();
  370. m_fDone = false;
  371. }
  372. ////////////////////////////////////////////////////////////////////////////////
  373. ////////////////////////////////////////////////////////////////////////////////
  374. bool AsynchronousTaxonomyDatabase::Engine::CompareQueryStores::operator()( /*[in]*/ const QueryStore *left, /*[in]*/ const QueryStore *right ) const
  375. {
  376. if(left)
  377. {
  378. return right ? left->LessThen( *right ) : true;
  379. }
  380. return false;
  381. }
  382. AsynchronousTaxonomyDatabase::Engine::Engine( /*[in]*/ CPCHProxy_IPCHTaxonomyDatabase* parent )
  383. {
  384. m_parent = parent; // CPCHProxy_IPCHTaxonomyDatabase* m_parent;
  385. // Set m_setQueries;
  386. // Notifier m_notifier;
  387. }
  388. AsynchronousTaxonomyDatabase::Engine::~Engine()
  389. {
  390. Passivate();
  391. }
  392. ////////////////////
  393. void AsynchronousTaxonomyDatabase::Engine::Passivate()
  394. {
  395. Thread_Wait();
  396. MPC::CallDestructorForAll( m_setQueries );
  397. }
  398. void AsynchronousTaxonomyDatabase::Engine::RefreshConnection()
  399. {
  400. //
  401. // The connection to the database has changed, so we need to flush all the cached queries...
  402. //
  403. InvalidateQueries();
  404. Thread_Signal();
  405. }
  406. ////////////////////////////////////////
  407. bool AsynchronousTaxonomyDatabase::Engine::LookupCache( /*[out]*/ OfflineCache::Handle& handle )
  408. {
  409. if(m_parent && m_parent->Parent())
  410. {
  411. CComPtr<CPCHProxy_IPCHUserSettings2> us;
  412. if(SUCCEEDED(m_parent->Parent()->GetUserSettings2( &us )))
  413. {
  414. if(SUCCEEDED(OfflineCache::Root::s_GLOBAL->Locate( us->THS(), handle )))
  415. {
  416. return true;
  417. }
  418. }
  419. }
  420. return false;
  421. }
  422. void AsynchronousTaxonomyDatabase::Engine::InvalidateQueries()
  423. {
  424. MPC::SmartLock<_ThreadModel> lock( this );
  425. Iter it;
  426. for(it = m_setQueries.begin(); it != m_setQueries.end(); it++)
  427. {
  428. QueryStore* qs = *it;
  429. qs->Invalidate();
  430. }
  431. }
  432. HRESULT AsynchronousTaxonomyDatabase::Engine::Run()
  433. {
  434. __HCP_FUNC_ENTRY( "AsynchronousTaxonomyDatabase::Engine::Run" );
  435. HRESULT hr;
  436. MPC::SmartLock<_ThreadModel> lock( this );
  437. while(Thread_IsAborted() == false)
  438. {
  439. OfflineCache::Handle handle;
  440. bool fValidCache = false;
  441. bool fInit = false;
  442. bool fSleep = true;
  443. Iter it;
  444. //
  445. // Look for the first query store not ready and execute it.
  446. //
  447. for(it = m_setQueries.begin(); it != m_setQueries.end(); it++)
  448. {
  449. QueryStore* qs = *it;
  450. if(qs->m_fDone == false)
  451. {
  452. if(fInit == false)
  453. {
  454. __MPC_PROTECT( fValidCache = LookupCache( handle ) );
  455. fInit = true;
  456. }
  457. lock = NULL;
  458. qs->Execute( fValidCache ? &handle : NULL, m_parent );
  459. lock = this;
  460. fSleep = false;
  461. break;
  462. }
  463. }
  464. //
  465. // Notify all the query stores that are ready.
  466. //
  467. if(it == m_setQueries.end())
  468. {
  469. for(it = m_setQueries.begin(); it != m_setQueries.end(); it++)
  470. {
  471. QueryStore* qs = *it;
  472. if(qs->m_fDone)
  473. {
  474. m_notifier.Notify( qs );
  475. }
  476. }
  477. }
  478. if(fSleep)
  479. {
  480. lock = NULL;
  481. Thread_WaitForEvents( NULL, INFINITE );
  482. lock = this;
  483. }
  484. }
  485. hr = S_OK;
  486. m_notifier.Notify( NULL );
  487. Thread_Abort();
  488. __HCP_FUNC_EXIT(hr);
  489. }
  490. ////////////////////////////////////////
  491. HRESULT AsynchronousTaxonomyDatabase::Engine::ExecuteQuery( /*[in]*/ int iType ,
  492. /*[in]*/ LPCWSTR szID ,
  493. /*[in]*/ VARIANT* option ,
  494. /*[in]*/ NotifyHandle* nb )
  495. {
  496. __HCP_FUNC_ENTRY( "AsynchronousTaxonomyDatabase::Engine::ExecuteQuery" );
  497. HRESULT hr;
  498. MPC::SmartLock<_ThreadModel> lock( this );
  499. QueryStore* qsNew = NULL;
  500. QueryStore* qs;
  501. Iter it;
  502. __MPC_PARAMCHECK_BEGIN(hr)
  503. __MPC_PARAMCHECK_NOTNULL(m_parent);
  504. __MPC_PARAMCHECK_NOTNULL(nb);
  505. __MPC_PARAMCHECK_END();
  506. __MPC_EXIT_IF_ALLOC_FAILS(hr, qsNew, new QueryStore( iType, szID, option ));
  507. it = m_setQueries.find( qsNew );
  508. if(it == m_setQueries.end())
  509. {
  510. qs = qsNew;
  511. m_setQueries.insert( qsNew ); qsNew = NULL;
  512. }
  513. else
  514. {
  515. qs = *it;
  516. }
  517. __MPC_EXIT_IF_METHOD_FAILS(hr, m_notifier.AddNotification( qs, nb ));
  518. if(Thread_IsRunning() == false)
  519. {
  520. __MPC_EXIT_IF_METHOD_FAILS(hr, Thread_Start( this, Run, NULL ));
  521. }
  522. else
  523. {
  524. Thread_Signal();
  525. }
  526. hr = S_OK;
  527. __HCP_FUNC_CLEANUP;
  528. delete qsNew;
  529. __HCP_FUNC_EXIT(hr);
  530. }
  531. HRESULT AsynchronousTaxonomyDatabase::Engine::ExecuteQuery( /*[in]*/ int iType ,
  532. /*[in]*/ LPCWSTR szID ,
  533. /*[in]*/ VARIANT* option ,
  534. /*[out, retval]*/ CPCHQueryResultCollection* *ppC )
  535. {
  536. __HCP_FUNC_ENTRY( "AsynchronousTaxonomyDatabase::Engine::ExecuteQuery" );
  537. HRESULT hr;
  538. NotifyHandle* nb = new NotifyHandle(); if(nb) nb->AddRef();
  539. __MPC_EXIT_IF_METHOD_FAILS(hr, ExecuteQuery( iType, szID, option, nb ));
  540. __MPC_EXIT_IF_METHOD_FAILS(hr, nb->Wait());
  541. __MPC_EXIT_IF_METHOD_FAILS(hr, nb->GetData( ppC ));
  542. hr = S_OK;
  543. __HCP_FUNC_CLEANUP;
  544. if(nb) nb->Release();
  545. __HCP_FUNC_EXIT(hr);
  546. }