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.

3633 lines
95 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1998 - 1999
  6. //
  7. // File: compbas_.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. // initialize to the thread ID of the thread that loads the snapin
  11. // that is the main thread
  12. extern DWORD _MainThreadId = ::GetCurrentThreadId();
  13. const TCHAR NODE_TYPES_KEY[] = TEXT("Software\\Microsoft\\MMC\\NodeTypes");
  14. const TCHAR SNAPINS_KEY[] = TEXT("Software\\Microsoft\\MMC\\SnapIns");
  15. const TCHAR g_szNodeType[] = TEXT("NodeType");
  16. const TCHAR g_szNameString[] = TEXT("NameString");
  17. const TCHAR g_szNameStringIndirect[] = TEXT("NameStringIndirect");
  18. const TCHAR g_szStandaloneSnap[] = TEXT("Standalone");
  19. const TCHAR g_szExtensionSnap[] = TEXT("Extension");
  20. const TCHAR g_szNodeTypes[] = TEXT("NodeTypes");
  21. const TCHAR g_szExtensions[] = TEXT("Extensions");
  22. const TCHAR g_szDynamicExtensions[] = TEXT("Dynamic Extensions");
  23. const TCHAR g_szVersion[] = TEXT("Version");
  24. const TCHAR g_szProvider[] = _T("Provider");
  25. const TCHAR g_szAbout[] = _T("About");
  26. HRESULT RegisterSnapin(const GUID* pSnapinCLSID,
  27. const GUID* pStaticNodeGUID,
  28. const GUID* pAboutGUID,
  29. LPCTSTR lpszNameString, LPCTSTR lpszVersion, LPCTSTR lpszProvider,
  30. BOOL bExtension, _NODE_TYPE_INFO_ENTRY* pNodeTypeInfoEntryArray,
  31. UINT nSnapinNameID)
  32. {
  33. OLECHAR szSnapinClassID[128] = {0}, szStaticNodeGuid[128] = {0}, szAboutGuid[128] = {0};
  34. ::StringFromGUID2(*pSnapinCLSID,szSnapinClassID,128);
  35. ::StringFromGUID2(*pStaticNodeGUID,szStaticNodeGuid,128);
  36. ::StringFromGUID2(*pAboutGUID,szAboutGuid,128);
  37. CRegKey regkeySnapins;
  38. LONG lRes = regkeySnapins.Open(HKEY_LOCAL_MACHINE, SNAPINS_KEY);
  39. ASSERT(lRes == ERROR_SUCCESS);
  40. if (lRes != ERROR_SUCCESS)
  41. return HRESULT_FROM_WIN32(lRes); // failed to open
  42. CRegKey regkeyThisSnapin;
  43. lRes = regkeyThisSnapin.Create(regkeySnapins, szSnapinClassID);
  44. ASSERT(lRes == ERROR_SUCCESS);
  45. if (lRes != ERROR_SUCCESS)
  46. return HRESULT_FROM_WIN32(lRes); // failed to create
  47. lRes = regkeyThisSnapin.SetValue(lpszNameString, g_szNameString);
  48. if (lRes != ERROR_SUCCESS)
  49. return HRESULT_FROM_WIN32(lRes);
  50. // JeffJon 6/12/00 100624: MUI: MMC: Shared Folders snap-in
  51. // stores its display information in the registry
  52. if (nSnapinNameID != 0)
  53. {
  54. CString str;
  55. WCHAR szModule[_MAX_PATH];
  56. ::GetModuleFileName(AfxGetInstanceHandle(), szModule, _MAX_PATH);
  57. str.Format( _T("@%s,-%d"), szModule, nSnapinNameID );
  58. lRes = regkeyThisSnapin.SetValue(str, g_szNameStringIndirect);
  59. if (lRes != ERROR_SUCCESS)
  60. return HRESULT_FROM_WIN32(lRes);
  61. }
  62. lRes = regkeyThisSnapin.SetValue(szAboutGuid, g_szAbout);
  63. if (lRes != ERROR_SUCCESS)
  64. return HRESULT_FROM_WIN32(lRes);
  65. lRes = regkeyThisSnapin.SetValue(szStaticNodeGuid, g_szNodeType);
  66. if (lRes != ERROR_SUCCESS)
  67. return HRESULT_FROM_WIN32(lRes);
  68. lRes = regkeyThisSnapin.SetValue(lpszProvider, g_szProvider);
  69. if (lRes != ERROR_SUCCESS)
  70. return HRESULT_FROM_WIN32(lRes);
  71. lRes = regkeyThisSnapin.SetValue(lpszVersion, g_szVersion);
  72. if (lRes != ERROR_SUCCESS)
  73. return HRESULT_FROM_WIN32(lRes);
  74. CRegKey regKeyStandaloneorExtension;
  75. lRes = regKeyStandaloneorExtension.Create(regkeyThisSnapin,
  76. bExtension ? g_szExtensionSnap : g_szStandaloneSnap);
  77. if (lRes != ERROR_SUCCESS)
  78. return HRESULT_FROM_WIN32(lRes);
  79. CRegKey regKeyNodeTypes;
  80. lRes = regKeyNodeTypes.Create(regkeyThisSnapin, g_szNodeTypes);
  81. if (lRes != ERROR_SUCCESS)
  82. {
  83. return HRESULT_FROM_WIN32(lRes);
  84. }
  85. OLECHAR szNodeGUID[128];
  86. for (_NODE_TYPE_INFO_ENTRY* pCurrEntry = pNodeTypeInfoEntryArray;
  87. pCurrEntry->m_pNodeGUID != NULL; pCurrEntry++)
  88. {
  89. ::StringFromGUID2(*(pCurrEntry->m_pNodeGUID),szNodeGUID,128);
  90. CRegKey regKeyNode;
  91. lRes = regKeyNode.Create(regKeyNodeTypes, szNodeGUID);
  92. if (lRes != ERROR_SUCCESS)
  93. {
  94. return HRESULT_FROM_WIN32(lRes);
  95. }
  96. }
  97. return HRESULT_FROM_WIN32(lRes);
  98. }
  99. HRESULT UnregisterSnapin(const GUID* pSnapinCLSID)
  100. {
  101. OLECHAR szSnapinClassID[128];
  102. ::StringFromGUID2(*pSnapinCLSID,szSnapinClassID,128);
  103. CRegKey regkeySnapins;
  104. LONG lRes = regkeySnapins.Open(HKEY_LOCAL_MACHINE, SNAPINS_KEY);
  105. ASSERT(lRes == ERROR_SUCCESS);
  106. if (lRes != ERROR_SUCCESS)
  107. {
  108. return HRESULT_FROM_WIN32(lRes); // failed to open
  109. }
  110. lRes = regkeySnapins.RecurseDeleteKey(szSnapinClassID);
  111. ASSERT(lRes == ERROR_SUCCESS);
  112. return HRESULT_FROM_WIN32(lRes);
  113. }
  114. HRESULT RegisterNodeType(const GUID* pGuid, LPCTSTR lpszNodeDescription)
  115. {
  116. OLECHAR szNodeGuid[128];
  117. ::StringFromGUID2(*pGuid,szNodeGuid,128);
  118. CRegKey regkeyNodeTypes;
  119. LONG lRes = regkeyNodeTypes.Open(HKEY_LOCAL_MACHINE, NODE_TYPES_KEY);
  120. ASSERT(lRes == ERROR_SUCCESS);
  121. if (lRes != ERROR_SUCCESS)
  122. {
  123. return HRESULT_FROM_WIN32(lRes); // failed to open
  124. }
  125. CRegKey regkeyThisNodeType;
  126. lRes = regkeyThisNodeType.Create(regkeyNodeTypes, szNodeGuid);
  127. ASSERT(lRes == ERROR_SUCCESS);
  128. if (lRes != ERROR_SUCCESS)
  129. {
  130. return HRESULT_FROM_WIN32(lRes); // failed to create
  131. }
  132. lRes = regkeyThisNodeType.SetValue(lpszNodeDescription);
  133. ASSERT(lRes == ERROR_SUCCESS);
  134. return HRESULT_FROM_WIN32(lRes);
  135. }
  136. HRESULT UnregisterNodeType(const GUID* pGuid)
  137. {
  138. OLECHAR szNodeGuid[128];
  139. ::StringFromGUID2(*pGuid,szNodeGuid,128);
  140. CRegKey regkeyNodeTypes;
  141. LONG lRes = regkeyNodeTypes.Open(HKEY_LOCAL_MACHINE, NODE_TYPES_KEY);
  142. ASSERT(lRes == ERROR_SUCCESS);
  143. if (lRes != ERROR_SUCCESS)
  144. {
  145. return HRESULT_FROM_WIN32(lRes); // failed to open
  146. }
  147. lRes = regkeyNodeTypes.RecurseDeleteKey(szNodeGuid);
  148. ASSERT(lRes == ERROR_SUCCESS);
  149. return HRESULT_FROM_WIN32(lRes);
  150. }
  151. HRESULT RegisterNodeExtension(const GUID* pNodeGuid, LPCTSTR lpszExtensionType,
  152. const GUID* pExtensionSnapinCLSID, LPCTSTR lpszDescription,
  153. BOOL bDynamic)
  154. {
  155. OLECHAR szNodeGuid[128], szExtensionSnapinCLSID[128];
  156. ::StringFromGUID2(*pNodeGuid, szNodeGuid,128);
  157. ::StringFromGUID2(*pExtensionSnapinCLSID, szExtensionSnapinCLSID,128);
  158. // compose full path of key up to the node GUID
  159. WCHAR szKeyPath[2048];
  160. wsprintf(szKeyPath, L"%s\\%s", NODE_TYPES_KEY, szNodeGuid);
  161. CRegKey regkeyNodeTypesNode;
  162. LONG lRes = regkeyNodeTypesNode.Open(HKEY_LOCAL_MACHINE, szKeyPath);
  163. ASSERT(lRes == ERROR_SUCCESS);
  164. if (lRes != ERROR_SUCCESS)
  165. {
  166. return HRESULT_FROM_WIN32(lRes); // failed to open
  167. }
  168. CRegKey regkeyExtensions;
  169. lRes = regkeyExtensions.Create(regkeyNodeTypesNode, g_szExtensions);
  170. ASSERT(lRes == ERROR_SUCCESS);
  171. if (lRes != ERROR_SUCCESS)
  172. {
  173. return HRESULT_FROM_WIN32(lRes); // failed to create
  174. }
  175. CRegKey regkeyExtensionType;
  176. lRes = regkeyExtensionType.Create(regkeyExtensions, lpszExtensionType);
  177. ASSERT(lRes == ERROR_SUCCESS);
  178. if (lRes != ERROR_SUCCESS)
  179. {
  180. return HRESULT_FROM_WIN32(lRes); // failed to create
  181. }
  182. lRes = regkeyExtensionType.SetValue(lpszDescription, szExtensionSnapinCLSID);
  183. ASSERT(lRes == ERROR_SUCCESS);
  184. if (lRes != ERROR_SUCCESS)
  185. {
  186. return HRESULT_FROM_WIN32(lRes); // failed to set value
  187. }
  188. if (bDynamic)
  189. {
  190. // create a subkey under the node GUID
  191. CRegKey regkeyDynamicExtensions;
  192. lRes = regkeyDynamicExtensions.Create(regkeyNodeTypesNode, g_szDynamicExtensions);
  193. ASSERT(lRes == ERROR_SUCCESS);
  194. if (lRes != ERROR_SUCCESS)
  195. return HRESULT_FROM_WIN32(lRes); // failed to create
  196. // set value (same value as the extension type above)
  197. lRes = regkeyDynamicExtensions.SetValue(lpszDescription, szExtensionSnapinCLSID);
  198. ASSERT(lRes == ERROR_SUCCESS);
  199. if (lRes != ERROR_SUCCESS)
  200. {
  201. return HRESULT_FROM_WIN32(lRes); // failed to set value
  202. }
  203. }
  204. return HRESULT_FROM_WIN32(lRes);
  205. }
  206. HRESULT UnregisterNodeExtension(const GUID* pNodeGuid, LPCTSTR lpszExtensionType,
  207. const GUID* pExtensionSnapinCLSID, BOOL bDynamic)
  208. {
  209. OLECHAR szNodeGuid[128], szExtensionSnapinCLSID[128];
  210. ::StringFromGUID2(*pNodeGuid, szNodeGuid,128);
  211. ::StringFromGUID2(*pExtensionSnapinCLSID, szExtensionSnapinCLSID,128);
  212. // compose full path of key up to the node GUID
  213. WCHAR szKeyPath[2048];
  214. wsprintf(szKeyPath, L"%s\\%s", NODE_TYPES_KEY, szNodeGuid);
  215. CRegKey regkeyNodeTypesNode;
  216. LONG lRes = regkeyNodeTypesNode.Open(HKEY_LOCAL_MACHINE, szKeyPath);
  217. ASSERT(lRes == ERROR_SUCCESS);
  218. if (lRes != ERROR_SUCCESS)
  219. return HRESULT_FROM_WIN32(lRes); // failed to open
  220. lRes = ERROR_SUCCESS;
  221. // open the key for the Dynamic extensions
  222. if (bDynamic)
  223. {
  224. CRegKey regkeyDynamicExtensions;
  225. lRes = regkeyDynamicExtensions.Open(regkeyNodeTypesNode, g_szDynamicExtensions);
  226. if (lRes == ERROR_SUCCESS)
  227. {
  228. lRes = regkeyDynamicExtensions.DeleteValue(szExtensionSnapinCLSID);
  229. }
  230. }
  231. else
  232. {
  233. //
  234. // Open the extensions key
  235. //
  236. CRegKey regkeyExtensions;
  237. lRes = regkeyExtensions.Open(regkeyNodeTypesNode, g_szExtensions);
  238. if (lRes == ERROR_SUCCESS)
  239. {
  240. CRegKey regkeyExtensionType;
  241. lRes = regkeyExtensionType.Open(regkeyExtensions, lpszExtensionType);
  242. if (lRes == ERROR_SUCCESS)
  243. {
  244. lRes = regkeyExtensionType.DeleteValue(szExtensionSnapinCLSID);
  245. }
  246. }
  247. }
  248. lRes = ERROR_SUCCESS;
  249. return HRESULT_FROM_WIN32(lRes);
  250. }
  251. /////////////////////////////////////////////////////////////////////////////
  252. // CTimerThread
  253. BOOL CTimerThread::Start(HWND hWnd)
  254. {
  255. ASSERT(m_hWnd == NULL);
  256. ASSERT(::IsWindow(hWnd));
  257. m_hWnd = hWnd;
  258. return CreateThread();
  259. }
  260. BOOL CTimerThread::PostMessageToWnd(WPARAM wParam, LPARAM lParam)
  261. {
  262. ASSERT(::IsWindow(m_hWnd));
  263. return ::PostMessage(m_hWnd, CHiddenWnd::s_TimerThreadMessage, wParam, lParam);
  264. }
  265. /////////////////////////////////////////////////////////////////////////////
  266. // CWorkerThread
  267. CWorkerThread::CWorkerThread()
  268. {
  269. m_bAutoDelete = FALSE;
  270. m_bAbandoned = FALSE;
  271. m_hEventHandle = NULL;
  272. ExceptionPropagatingInitializeCriticalSection(&m_cs);
  273. m_hWnd = NULL;
  274. }
  275. CWorkerThread::~CWorkerThread()
  276. {
  277. ::DeleteCriticalSection(&m_cs);
  278. if (m_hEventHandle != NULL)
  279. {
  280. VERIFY(::CloseHandle(m_hEventHandle));
  281. m_hEventHandle = NULL;
  282. }
  283. }
  284. BOOL CWorkerThread::Start(HWND hWnd)
  285. {
  286. ASSERT(m_hWnd == NULL);
  287. ASSERT(::IsWindow(hWnd));
  288. m_hWnd = hWnd;
  289. ASSERT(m_hEventHandle == NULL); // cannot call start twice or reuse the same C++ object
  290. m_hEventHandle = ::CreateEvent(NULL,TRUE /*bManualReset*/,FALSE /*signalled*/, NULL);
  291. if (m_hEventHandle == NULL)
  292. {
  293. return FALSE;
  294. }
  295. return CreateThread();
  296. }
  297. void CWorkerThread::Abandon()
  298. {
  299. Lock();
  300. OnAbandon();
  301. m_bAutoDelete = TRUE;
  302. m_bAbandoned = TRUE;
  303. Unlock();
  304. }
  305. BOOL CWorkerThread::IsAbandoned()
  306. {
  307. Lock();
  308. BOOL b = m_bAbandoned;
  309. Unlock();
  310. return b;
  311. }
  312. BOOL CWorkerThread::PostMessageToWnd(UINT Msg, WPARAM wParam, LPARAM lParam)
  313. {
  314. BOOL b = IsAbandoned();
  315. if (b)
  316. {
  317. return TRUE; // no need to post
  318. }
  319. ASSERT(::IsWindow(m_hWnd));
  320. return ::PostMessage(m_hWnd, Msg, wParam, lParam);
  321. }
  322. void CWorkerThread::WaitForExitAcknowledge()
  323. {
  324. BOOL b = IsAbandoned();
  325. if (b)
  326. {
  327. return;
  328. }
  329. VERIFY(WAIT_OBJECT_0 == ::WaitForSingleObject(m_hEventHandle,INFINITE));
  330. }
  331. /////////////////////////////////////////////////////////////////////////////
  332. // CHiddenWnd
  333. const UINT CHiddenWnd::s_NodeThreadHaveDataNotificationMessage = WM_USER + 1;
  334. const UINT CHiddenWnd::s_NodeThreadErrorNotificationMessage = WM_USER + 2;
  335. const UINT CHiddenWnd::s_NodeThreadExitingNotificationMessage = WM_USER + 3;
  336. const UINT CHiddenWnd::s_NodePropertySheetCreateMessage = WM_USER + 4;
  337. const UINT CHiddenWnd::s_NodePropertySheetDeleteMessage = WM_USER + 5;
  338. const UINT CHiddenWnd::s_ExecCommandMessage = WM_USER + 6;
  339. const UINT CHiddenWnd::s_ForceEnumerationMessage = WM_USER + 7;
  340. const UINT CHiddenWnd::s_TimerThreadMessage = WM_USER + 8;
  341. CHiddenWnd::CHiddenWnd(CComponentDataObject* pComponentDataObject)
  342. {
  343. m_pComponentDataObject = pComponentDataObject;
  344. m_nTimerID = 0;
  345. }
  346. LRESULT CHiddenWnd::OnNodeThreadHaveDataNotification(UINT, WPARAM wParam, LPARAM, BOOL&)
  347. {
  348. //TRACE(_T("CHiddenWnd::OnNodeThreadHaveDataNotification()\n"));
  349. ASSERT(m_pComponentDataObject != NULL);
  350. // call into the CTreeNode code
  351. CMTContainerNode* pNode = reinterpret_cast<CMTContainerNode*>(wParam);
  352. ASSERT(pNode);
  353. ASSERT(pNode->IsContainer());
  354. pNode->OnThreadHaveDataNotification(m_pComponentDataObject);
  355. return 1;
  356. }
  357. LRESULT CHiddenWnd::OnNodeThreadExitingNotification(UINT, WPARAM wParam, LPARAM lParam, BOOL&)
  358. {
  359. //TRACE(_T("CHiddenWnd::OnNodeThreadExitingNotification()\n"));
  360. ASSERT(m_pComponentDataObject != NULL);
  361. // call into the CTreeNode code
  362. CMTContainerNode* pNode = reinterpret_cast<CMTContainerNode*>(wParam);
  363. ASSERT(pNode);
  364. ASSERT(pNode->IsContainer());
  365. pNode->OnThreadExitingNotification(m_pComponentDataObject);
  366. // notify anybody interested in this event
  367. m_pComponentDataObject->GetNotificationSinkTable()->Notify(
  368. CHiddenWnd::s_NodeThreadExitingNotificationMessage ,wParam,lParam);
  369. return 1;
  370. }
  371. LRESULT CHiddenWnd::OnNodeThreadErrorNotification(UINT, WPARAM wParam, LPARAM lParam, BOOL&)
  372. {
  373. ASSERT(m_pComponentDataObject != NULL);
  374. // call into the CTreeNode code
  375. CMTContainerNode* pNode = reinterpret_cast<CMTContainerNode*>(wParam);
  376. DWORD dwErr = static_cast<DWORD>(lParam);
  377. ASSERT(pNode);
  378. ASSERT(pNode->IsContainer());
  379. pNode->OnThreadErrorNotification(dwErr, m_pComponentDataObject);
  380. return 1;
  381. }
  382. LRESULT CHiddenWnd::OnNodePropertySheetCreate(UINT, WPARAM wParam, LPARAM lParam, BOOL&)
  383. {
  384. //TRACE(_T("CHiddenWnd::OnNodePropertySheetCreate()\n"));
  385. ASSERT(m_pComponentDataObject != NULL);
  386. CPropertyPageHolderBase* pPPHolder = reinterpret_cast<CPropertyPageHolderBase*>(wParam);
  387. ASSERT(pPPHolder != NULL);
  388. HWND hWnd = reinterpret_cast<HWND>(lParam);
  389. ASSERT(::IsWindow(hWnd));
  390. m_pComponentDataObject->GetPropertyPageHolderTable()->AddWindow(pPPHolder, hWnd);
  391. return 1;
  392. }
  393. LRESULT CHiddenWnd::OnNodePropertySheetDelete(UINT, WPARAM wParam, LPARAM lParam, BOOL&)
  394. {
  395. //TRACE(_T("CHiddenWnd::OnNodePropertySheetDestroy()\n"));
  396. ASSERT(m_pComponentDataObject != NULL);
  397. CPropertyPageHolderBase* pPPHolder = reinterpret_cast<CPropertyPageHolderBase*>(wParam);
  398. ASSERT(pPPHolder != NULL);
  399. CTreeNode* pNode = reinterpret_cast<CTreeNode*>(lParam);
  400. ASSERT(pNode != NULL);
  401. m_pComponentDataObject->GetPropertyPageHolderTable()->Remove(pPPHolder);
  402. pNode->OnDeleteSheet();
  403. return 1;
  404. }
  405. LRESULT CHiddenWnd::OnExecCommand(UINT, WPARAM wParam, LPARAM lParam, BOOL&)
  406. {
  407. //TRACE(_T("CHiddenWnd::OnExecCommand()\n"));
  408. ASSERT(m_pComponentDataObject != NULL);
  409. CExecContext* pExec = reinterpret_cast<CExecContext*>(wParam);
  410. ASSERT(pExec != NULL);
  411. pExec->Execute((long)lParam); // execute code
  412. TRACE(_T("CHiddenWnd::BeforeDone()\n"));
  413. pExec->Done(); // let the secondary thread proceed
  414. return 1;
  415. }
  416. LRESULT CHiddenWnd::OnForceEnumeration(UINT, WPARAM wParam, LPARAM, BOOL&)
  417. {
  418. TRACE(_T("CHiddenWnd::OnForceEnumeration()\n"));
  419. ASSERT(m_pComponentDataObject != NULL);
  420. // call into the CTreeNode code
  421. CMTContainerNode* pNode = reinterpret_cast<CMTContainerNode*>(wParam);
  422. ASSERT(pNode);
  423. ASSERT(pNode->GetContainer() != NULL); // not the root!!!
  424. ASSERT(pNode->IsContainer());
  425. pNode->ForceEnumeration(m_pComponentDataObject);
  426. return 1;
  427. }
  428. LRESULT CHiddenWnd::OnTimerThread(UINT, WPARAM wParam, LPARAM lParam, BOOL&)
  429. {
  430. //TRACE(_T("CHiddenWnd::OnTimerThread()\n"));
  431. ASSERT(m_pComponentDataObject != NULL);
  432. // NULL arguments means that the thread acknowledge it is running properly
  433. // only to be called once
  434. if ((wParam == 0) && (lParam == 0))
  435. {
  436. ASSERT(!m_pComponentDataObject->m_bTimerThreadStarted);
  437. m_pComponentDataObject->m_bTimerThreadStarted = TRUE;
  438. }
  439. else
  440. {
  441. // got some object specific message
  442. m_pComponentDataObject->OnTimerThread(wParam, lParam);
  443. }
  444. return 1;
  445. }
  446. LRESULT CHiddenWnd::OnTimer(UINT, WPARAM, LPARAM, BOOL&)
  447. {
  448. ASSERT(m_pComponentDataObject != NULL);
  449. m_pComponentDataObject->OnTimer();
  450. return 1;
  451. }
  452. ////////////////////////////////////////////////////////////////////////////////////
  453. // CRunningThreadTable
  454. #define RUNNING_THREAD_ARRAY_DEF_SIZE (4)
  455. CRunningThreadTable::CRunningThreadTable(CComponentDataObject* pComponentData)
  456. {
  457. m_pComponentData = pComponentData;
  458. m_pEntries = (CMTContainerNode**)malloc(sizeof(CMTContainerNode*) * RUNNING_THREAD_ARRAY_DEF_SIZE);
  459. if (m_pEntries != NULL)
  460. {
  461. memset(m_pEntries,NULL, sizeof(CMTContainerNode*) * RUNNING_THREAD_ARRAY_DEF_SIZE);
  462. }
  463. m_nSize = RUNNING_THREAD_ARRAY_DEF_SIZE;
  464. }
  465. CRunningThreadTable::~CRunningThreadTable()
  466. {
  467. #ifdef _DEBUG
  468. for (int k=0; k < m_nSize; k++)
  469. {
  470. ASSERT(m_pEntries[k] == NULL);
  471. }
  472. #endif
  473. free(m_pEntries);
  474. }
  475. void CRunningThreadTable::Add(CMTContainerNode* pNode)
  476. {
  477. ASSERT(pNode != NULL);
  478. for (int k=0; k < m_nSize; k++)
  479. {
  480. if (m_pEntries[k] == NULL) // get the first empty spot
  481. {
  482. pNode->IncrementThreadLockCount();
  483. m_pEntries[k] = pNode;
  484. return;
  485. }
  486. }
  487. // all full, need to grow the array
  488. int nAlloc = m_nSize*2;
  489. m_pEntries = (CMTContainerNode**)realloc(m_pEntries, sizeof(CMTContainerNode*)*nAlloc);
  490. memset(&m_pEntries[m_nSize], NULL, sizeof(CMTContainerNode*)*m_nSize);
  491. pNode->IncrementThreadLockCount();
  492. m_pEntries[m_nSize] = pNode;
  493. m_nSize = nAlloc;
  494. }
  495. BOOL CRunningThreadTable::IsPresent(CMTContainerNode* pNode)
  496. {
  497. ASSERT(pNode != NULL);
  498. for (int k=0; k < m_nSize; k++)
  499. {
  500. if (m_pEntries[k] == pNode)
  501. {
  502. return TRUE;
  503. }
  504. }
  505. return FALSE;
  506. }
  507. void CRunningThreadTable::Remove(CMTContainerNode* pNode)
  508. {
  509. ASSERT(pNode != NULL);
  510. for (int k=0; k < m_nSize; k++)
  511. {
  512. if (m_pEntries[k] == pNode)
  513. {
  514. m_pEntries[k] = NULL;
  515. pNode->DecrementThreadLockCount();
  516. return; // assume no more that one holder entry
  517. }
  518. }
  519. }
  520. void CRunningThreadTable::RemoveAll()
  521. {
  522. for (int k=0; k < m_nSize; k++)
  523. {
  524. if (m_pEntries[k] != NULL)
  525. {
  526. m_pEntries[k]->AbandonThread(m_pComponentData);
  527. m_pEntries[k] = NULL;
  528. }
  529. }
  530. }
  531. ////////////////////////////////////////////////////////////////////////////////////
  532. // CExecContext
  533. CExecContext::CExecContext()
  534. {
  535. m_hEventHandle = ::CreateEvent(NULL,TRUE /*bManualReset*/,FALSE /*signalled*/, NULL);
  536. ASSERT(m_hEventHandle != NULL);
  537. }
  538. CExecContext::~CExecContext()
  539. {
  540. ASSERT(m_hEventHandle != NULL);
  541. VERIFY(::CloseHandle(m_hEventHandle));
  542. }
  543. void CExecContext::Done()
  544. {
  545. VERIFY(0 != ::SetEvent(m_hEventHandle));
  546. }
  547. void CExecContext::Wait()
  548. {
  549. ASSERT(m_hEventHandle != NULL);
  550. VERIFY(WAIT_OBJECT_0 == ::WaitForSingleObject(m_hEventHandle,INFINITE));
  551. }
  552. ////////////////////////////////////////////////////////////////////////////////////
  553. // CNotificationSinkEvent
  554. CNotificationSinkEvent::CNotificationSinkEvent()
  555. {
  556. m_hEventHandle = ::CreateEvent(NULL,TRUE /*bManualReset*/,FALSE /*signalled*/, NULL);
  557. ASSERT(m_hEventHandle != NULL);
  558. }
  559. CNotificationSinkEvent::~CNotificationSinkEvent()
  560. {
  561. ASSERT(m_hEventHandle != NULL);
  562. VERIFY(::CloseHandle(m_hEventHandle));
  563. }
  564. void CNotificationSinkEvent::OnNotify(DWORD, WPARAM, LPARAM)
  565. {
  566. TRACE(_T("CNotificationSinkEvent::OnNotify()\n"));
  567. VERIFY(0 != ::SetEvent(m_hEventHandle));
  568. }
  569. void CNotificationSinkEvent::Wait()
  570. {
  571. TRACE(_T("CNotificationSinkEvent::Wait()\n"));
  572. ASSERT(m_hEventHandle != NULL);
  573. VERIFY(WAIT_OBJECT_0 == ::WaitForSingleObject(m_hEventHandle,INFINITE));
  574. }
  575. ////////////////////////////////////////////////////////////////////////////////////
  576. // CNotificationSinkTable
  577. #define NOTIFICATION_SINK_ARRAY_DEF_SIZE (4)
  578. CNotificationSinkTable::CNotificationSinkTable()
  579. {
  580. ExceptionPropagatingInitializeCriticalSection(&m_cs);
  581. m_pEntries = (CNotificationSinkBase**)malloc(sizeof(CNotificationSinkBase*) * NOTIFICATION_SINK_ARRAY_DEF_SIZE);
  582. if (m_pEntries != NULL)
  583. {
  584. memset(m_pEntries,NULL, sizeof(CNotificationSinkBase*) * NOTIFICATION_SINK_ARRAY_DEF_SIZE);
  585. }
  586. m_nSize = NOTIFICATION_SINK_ARRAY_DEF_SIZE;
  587. }
  588. CNotificationSinkTable::~CNotificationSinkTable()
  589. {
  590. free(m_pEntries);
  591. ::DeleteCriticalSection(&m_cs);
  592. }
  593. void CNotificationSinkTable::Advise(CNotificationSinkBase* p)
  594. {
  595. Lock();
  596. ASSERT(p != NULL);
  597. for (int k=0; k < m_nSize; k++)
  598. {
  599. if (m_pEntries[k] == NULL) // get the first empty spot
  600. {
  601. m_pEntries[k] = p;
  602. Unlock();
  603. return;
  604. }
  605. }
  606. // all full, need to grow the array
  607. int nAlloc = m_nSize*2;
  608. m_pEntries = (CNotificationSinkBase**)realloc(m_pEntries, sizeof(CNotificationSinkBase*)*nAlloc);
  609. memset(&m_pEntries[m_nSize], NULL, sizeof(CNotificationSinkBase*)*m_nSize);
  610. m_pEntries[m_nSize] = p;
  611. m_nSize = nAlloc;
  612. Unlock();
  613. }
  614. void CNotificationSinkTable::Unadvise(CNotificationSinkBase* p)
  615. {
  616. Lock();
  617. ASSERT(p != NULL);
  618. for (int k=0; k < m_nSize; k++)
  619. {
  620. if (m_pEntries[k] == p)
  621. {
  622. m_pEntries[k] = NULL;
  623. Unlock();
  624. return; // assume no more that one holder entry
  625. }
  626. }
  627. Unlock();
  628. }
  629. void CNotificationSinkTable::Notify(DWORD dwEvent, WPARAM dwArg1, LPARAM dwArg2)
  630. {
  631. Lock();
  632. for (int k=0; k < m_nSize; k++)
  633. {
  634. if (m_pEntries[k] != NULL)
  635. {
  636. m_pEntries[k]->OnNotify(dwEvent, dwArg1, dwArg2);
  637. }
  638. }
  639. Unlock();
  640. }
  641. ///////////////////////////////////////////////////////////////////////////////
  642. // CWatermarkInfoState (private class)
  643. class CWatermarkInfoState
  644. {
  645. public:
  646. CWatermarkInfoState()
  647. {
  648. m_pWatermarkInfo = NULL;
  649. m_hBanner = m_hWatermark = NULL;
  650. }
  651. ~CWatermarkInfoState()
  652. {
  653. DeleteBitmaps();
  654. if (m_pWatermarkInfo != NULL)
  655. {
  656. delete m_pWatermarkInfo;
  657. }
  658. }
  659. void DeleteBitmaps()
  660. {
  661. if (m_hBanner != NULL)
  662. {
  663. ::DeleteObject(m_hBanner);
  664. m_hBanner = NULL;
  665. }
  666. if (m_hWatermark != NULL)
  667. {
  668. ::DeleteObject(m_hWatermark);
  669. m_hWatermark = NULL;
  670. }
  671. }
  672. void LoadBitmaps()
  673. {
  674. ASSERT(m_pWatermarkInfo != NULL);
  675. if (m_hBanner == NULL)
  676. {
  677. m_hBanner = ::LoadBitmap(AfxGetInstanceHandle(), MAKEINTRESOURCE(m_pWatermarkInfo->m_nIDBanner));
  678. }
  679. if (m_hWatermark == NULL)
  680. {
  681. m_hWatermark = ::LoadBitmap(AfxGetInstanceHandle(), MAKEINTRESOURCE(m_pWatermarkInfo->m_nIDWatermark));
  682. }
  683. }
  684. CWatermarkInfo* m_pWatermarkInfo;
  685. HBITMAP m_hBanner;
  686. HBITMAP m_hWatermark;
  687. };
  688. ///////////////////////////////////////////////////////////////////////////////
  689. // CComponentDataObject implementation: helpers
  690. #ifdef _DEBUG_REFCOUNT
  691. unsigned int CComponentDataObject::m_nOustandingObjects = 0;
  692. #endif // _DEBUG_REFCOUNT
  693. CComponentDataObject::CComponentDataObject() :
  694. m_hiddenWnd((CComponentDataObject*)this), // initialize backpointer
  695. m_pTimerThreadObj(NULL),
  696. m_PPHTable(this), m_RTTable(this),
  697. m_pConsole(NULL), m_pConsoleNameSpace(NULL), m_pRootData(NULL), m_hWnd(NULL),
  698. m_nTimerThreadID(0x0), m_bTimerThreadStarted(FALSE), m_dwTimerInterval(1),
  699. m_dwTimerTime(0), m_pWatermarkInfoState(NULL), m_bExtensionSnapin(FALSE)
  700. {
  701. ExceptionPropagatingInitializeCriticalSection(&m_cs);
  702. #ifdef _DEBUG_REFCOUNT
  703. dbg_cRef = 0;
  704. ++m_nOustandingObjects;
  705. TRACE(_T("CComponentDataObject(), count = %d\n"),m_nOustandingObjects);
  706. #endif // _DEBUG_REFCOUNT
  707. }
  708. CComponentDataObject::~CComponentDataObject()
  709. {
  710. ::DeleteCriticalSection(&m_cs);
  711. #ifdef _DEBUG_REFCOUNT
  712. --m_nOustandingObjects;
  713. TRACE(_T("~CComponentDataObject(), count = %d\n"),m_nOustandingObjects);
  714. #endif // _DEBUG_REFCOUNT
  715. ASSERT(m_pConsole == NULL);
  716. ASSERT(m_pConsoleNameSpace == NULL);
  717. ASSERT(m_pRootData == NULL);
  718. }
  719. HRESULT CComponentDataObject::FinalConstruct()
  720. {
  721. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  722. if (!m_hiddenWnd.Create())
  723. {
  724. TRACE(_T("Failed to create hidden window\n"));
  725. return E_FAIL;
  726. }
  727. m_hWnd = m_hiddenWnd.m_hWnd;
  728. m_pRootData = OnCreateRootData();
  729. ASSERT(m_pRootData != NULL);
  730. return S_OK;
  731. }
  732. void CComponentDataObject::FinalRelease()
  733. {
  734. if (m_hiddenWnd.m_hWnd != NULL)
  735. {
  736. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  737. VERIFY(m_hiddenWnd.DestroyWindow());
  738. }
  739. // delete data
  740. if(m_pRootData != NULL)
  741. {
  742. delete m_pRootData;
  743. m_pRootData = NULL;
  744. }
  745. if (m_pWatermarkInfoState != NULL)
  746. {
  747. delete m_pWatermarkInfoState;
  748. }
  749. m_ColList.RemoveAndDeleteAllColumnSets();
  750. if (log_instance != NULL)
  751. {
  752. log_instance->KillInstance();
  753. }
  754. }
  755. ///////////////////////////////////////////////////////////////////////////////
  756. // CComponentDataObject::IComponentData members
  757. STDMETHODIMP CComponentDataObject::Initialize(LPUNKNOWN pUnknown)
  758. {
  759. ASSERT(m_pRootData != NULL);
  760. ASSERT(pUnknown != NULL);
  761. HRESULT hr = E_FAIL;
  762. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  763. // MMC should only call ::Initialize once!
  764. ASSERT(m_pConsole == NULL);
  765. ASSERT(m_pConsoleNameSpace == NULL);
  766. // get the pointers we need to hold on to
  767. hr = pUnknown->QueryInterface(IID_IConsoleNameSpace2, reinterpret_cast<void**>(&m_pConsoleNameSpace));
  768. ASSERT(hr == S_OK);
  769. ASSERT(m_pConsoleNameSpace != NULL);
  770. hr = pUnknown->QueryInterface(IID_IConsole2, reinterpret_cast<void**>(&m_pConsole));
  771. ASSERT(hr == S_OK);
  772. ASSERT(m_pConsole != NULL);
  773. // add the images for the scope tree
  774. LPIMAGELIST lpScopeImage;
  775. hr = m_pConsole->QueryScopeImageList(&lpScopeImage);
  776. ASSERT(hr == S_OK);
  777. // Set the images
  778. hr = OnSetImages(lpScopeImage); // Load the bitmaps from the dll
  779. ASSERT(hr == S_OK);
  780. lpScopeImage->Release();
  781. OnInitialize();
  782. return S_OK;
  783. }
  784. STDMETHODIMP CComponentDataObject::Notify(LPDATAOBJECT lpDataObject, MMC_NOTIFY_TYPE event, LPARAM arg, LPARAM param)
  785. {
  786. ASSERT(m_pConsoleNameSpace != NULL);
  787. HRESULT hr = S_OK;
  788. // Since it's my folder it has an internal format.
  789. // Design Note: for extension. I can use the fact, that the data object doesn't have
  790. // my internal format and I should look at the node type and see how to extend it.
  791. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  792. if (event == MMCN_PROPERTY_CHANGE)
  793. {
  794. ASSERT(lpDataObject == NULL);
  795. hr = OnPropertyChange(param, static_cast<long>(arg));
  796. }
  797. else
  798. {
  799. CInternalFormatCracker ifc;
  800. ifc.Extract(lpDataObject);
  801. if (ifc.GetCookieCount() == 0)
  802. {
  803. if ((event == MMCN_EXPAND) && (arg == TRUE) && IsExtensionSnapin())
  804. {
  805. return OnExtensionExpand(lpDataObject, param);
  806. // this is a namespace extension, need to add
  807. // the root of the snapin
  808. CContainerNode* pContNode = GetRootData();
  809. HSCOPEITEM pParent = param;
  810. pContNode->SetScopeID(pParent);
  811. pContNode->MarkExpanded();
  812. return AddContainerNode(pContNode, pParent);
  813. }
  814. else if ((event == MMCN_REMOVE_CHILDREN) && IsExtensionSnapin())
  815. {
  816. hr = OnRemoveChildren(lpDataObject, arg);
  817. }
  818. return S_OK; // Extensions not supported
  819. }
  820. switch(event)
  821. {
  822. case MMCN_PASTE:
  823. break;
  824. case MMCN_DELETE:
  825. hr = OnDeleteVerbHandler(ifc, NULL);
  826. break;
  827. case MMCN_REFRESH:
  828. hr = OnRefreshVerbHandler(ifc);
  829. break;
  830. case MMCN_RENAME:
  831. hr = OnRename(ifc, arg, param);
  832. break;
  833. case MMCN_EXPAND:
  834. hr = OnExpand(ifc, arg, param);
  835. break;
  836. case MMCN_EXPANDSYNC:
  837. hr = OnExpand(ifc, arg, param, FALSE);
  838. break;
  839. case MMCN_BTN_CLICK:
  840. break;
  841. case MMCN_SELECT:
  842. hr = OnSelect(ifc, arg, param);
  843. break;
  844. default:
  845. break;
  846. } // switch
  847. } // if
  848. return hr;
  849. }
  850. STDMETHODIMP CComponentDataObject::Destroy()
  851. {
  852. InternalAddRef();
  853. TRACE(_T("CComponentDataObject::Destroy()\n"));
  854. OnDestroy();
  855. SAFE_RELEASE(m_pConsoleNameSpace);
  856. SAFE_RELEASE(m_pConsole);
  857. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  858. VERIFY(m_hiddenWnd.DestroyWindow());
  859. InternalRelease();
  860. return S_OK;
  861. }
  862. BOOL CComponentDataObject::PostExecMessage(CExecContext* pExec, LPARAM arg)
  863. {
  864. ASSERT(pExec != NULL);
  865. ASSERT(::IsWindow(m_hWnd));
  866. return ::PostMessage(m_hWnd, CHiddenWnd::s_ExecCommandMessage,
  867. (WPARAM)pExec, (LPARAM)arg);
  868. }
  869. BOOL CComponentDataObject::PostForceEnumeration(CMTContainerNode* pContainerNode)
  870. {
  871. ASSERT(::IsWindow(m_hWnd));
  872. return ::PostMessage(m_hWnd, CHiddenWnd::s_ForceEnumerationMessage,
  873. (WPARAM)pContainerNode, (LPARAM)0);
  874. }
  875. BOOL CComponentDataObject::OnCreateSheet(CPropertyPageHolderBase* pPPHolder, HWND hWnd)
  876. {
  877. ASSERT(pPPHolder != NULL);
  878. ASSERT(::IsWindow(hWnd));
  879. ASSERT(::IsWindow(m_hWnd));
  880. TRACE(_T("\nCComponentDataObject::OnCreateSheet()\n"));
  881. return ::PostMessage(m_hWnd, CHiddenWnd::s_NodePropertySheetCreateMessage,
  882. (WPARAM)pPPHolder, (LPARAM)hWnd);
  883. }
  884. BOOL CComponentDataObject::OnDeleteSheet(CPropertyPageHolderBase* pPPHolder, CTreeNode* pNode)
  885. {
  886. ASSERT(pPPHolder != NULL);
  887. ASSERT(pNode != NULL);
  888. ASSERT(::IsWindow(m_hWnd));
  889. TRACE(_T("\nCComponentDataObject::OnDeleteSheet()\n"));
  890. return ::PostMessage(m_hWnd, CHiddenWnd::s_NodePropertySheetDeleteMessage,
  891. (WPARAM)pPPHolder, (LPARAM)pNode);
  892. }
  893. void CComponentDataObject::OnInitialize()
  894. {
  895. VERIFY(StartTimerThread());
  896. }
  897. void CComponentDataObject::OnDestroy()
  898. {
  899. // stop timer and worker thread
  900. ShutDownTimerThread();
  901. // detach all the threads that might be still running
  902. GetRunningThreadTable()->RemoveAll();
  903. // tell all the open property sheets to shut down
  904. // shut down property sheets, if any
  905. GetPropertyPageHolderTable()->WaitForAllToShutDown();
  906. }
  907. STDMETHODIMP CComponentDataObject::QueryDataObject(MMC_COOKIE cookie, DATA_OBJECT_TYPES type, LPDATAOBJECT* ppDataObject)
  908. {
  909. ASSERT(ppDataObject != NULL);
  910. CComObject<CDataObject>* pObject;
  911. CComObject<CDataObject>::CreateInstance(&pObject);
  912. ASSERT(pObject != NULL);
  913. // Save cookie and type for delayed rendering
  914. pObject->SetType(type);
  915. CTreeNode* pNode;
  916. //
  917. // -1 is an uninitialized data object, just ignore
  918. //
  919. if (cookie != -1)
  920. {
  921. if (cookie == NULL)
  922. {
  923. pNode = GetRootData();
  924. }
  925. else
  926. {
  927. pNode = reinterpret_cast<CTreeNode*>(cookie);
  928. }
  929. ASSERT(pNode != NULL);
  930. pObject->AddCookie(pNode);
  931. }
  932. // save a pointer to "this"
  933. IUnknown* pUnkComponentData = GetUnknown(); // no addref
  934. ASSERT(pUnkComponentData != NULL);
  935. pObject->SetComponentData(pUnkComponentData); // will addref it
  936. return pObject->QueryInterface(IID_IDataObject,
  937. reinterpret_cast<void**>(ppDataObject));
  938. }
  939. STDMETHODIMP CComponentDataObject::GetDisplayInfo(SCOPEDATAITEM* pScopeDataItem)
  940. {
  941. ASSERT(pScopeDataItem != NULL);
  942. CTreeNode* pNode = reinterpret_cast<CTreeNode*>(pScopeDataItem->lParam);
  943. ASSERT(pNode != NULL);
  944. ASSERT(pNode->IsContainer());
  945. ASSERT(pScopeDataItem->mask & SDI_STR);
  946. pScopeDataItem->displayname = const_cast<LPWSTR>(pNode->GetDisplayName());
  947. ASSERT(pScopeDataItem->displayname != NULL);
  948. return S_OK;
  949. }
  950. STDMETHODIMP CComponentDataObject::CompareObjects(LPDATAOBJECT lpDataObjectA, LPDATAOBJECT lpDataObjectB)
  951. {
  952. ASSERT(lpDataObjectA != NULL);
  953. ASSERT(lpDataObjectB != NULL);
  954. CInternalFormatCracker ifcA, ifcB;
  955. VERIFY(SUCCEEDED(ifcA.Extract(lpDataObjectA)));
  956. VERIFY(SUCCEEDED(ifcB.Extract(lpDataObjectB)));
  957. CTreeNode* pNodeA = ifcA.GetCookieAt(0);
  958. CTreeNode* pNodeB = ifcB.GetCookieAt(0);
  959. ASSERT(pNodeA != NULL);
  960. ASSERT(pNodeB != NULL);
  961. if ( (pNodeA == NULL) || (pNodeB == NULL) )
  962. {
  963. return E_FAIL;
  964. }
  965. return (pNodeA == pNodeB) ? S_OK : S_FALSE;
  966. }
  967. ///////////////////////////////////////////////////////////////////////////////
  968. // Message handlers for CComponentDataObject::IComponentData::Notify()
  969. HRESULT CComponentDataObject::OnAdd(CTreeNode*, LPARAM, LPARAM)
  970. {
  971. return E_UNEXPECTED;
  972. }
  973. HRESULT CComponentDataObject::OnRemoveChildren(LPDATAOBJECT lpDataObject, LPARAM)
  974. {
  975. CInternalFormatCracker ifc;
  976. HRESULT hr = S_OK;
  977. hr = ifc.Extract(lpDataObject);
  978. if (SUCCEEDED(hr))
  979. {
  980. if (ifc.GetCookieCount() == 1)
  981. {
  982. CTreeNode* pNode = ifc.GetCookieAt(0);
  983. if (pNode != NULL)
  984. {
  985. if (pNode->IsContainer())
  986. {
  987. CContainerNode* pContainerNode = dynamic_cast<CContainerNode*>(pNode);
  988. if (pContainerNode != NULL)
  989. {
  990. pContainerNode->RemoveAllChildrenFromList();
  991. }
  992. }
  993. }
  994. }
  995. else
  996. {
  997. ASSERT(FALSE);
  998. }
  999. }
  1000. return hr;
  1001. }
  1002. HRESULT CComponentDataObject::OnRename(CInternalFormatCracker& ifc, LPARAM, LPARAM param)
  1003. {
  1004. HRESULT hr = S_FALSE;
  1005. CTreeNode* pNode = ifc.GetCookieAt(0);
  1006. ASSERT(pNode != NULL);
  1007. hr = pNode->OnRename(this, (LPOLESTR)param);
  1008. if (hr == S_OK)
  1009. {
  1010. UpdateAllViewsHelper(reinterpret_cast<LONG_PTR>(pNode), CHANGE_RESULT_ITEM);
  1011. }
  1012. return hr;
  1013. }
  1014. HRESULT CComponentDataObject::OnExpand(CInternalFormatCracker& ifc,
  1015. LPARAM arg,
  1016. LPARAM param,
  1017. BOOL bAsync)
  1018. {
  1019. if (arg == TRUE)
  1020. {
  1021. // Did Initialize get called?
  1022. ASSERT(m_pConsoleNameSpace != NULL);
  1023. //
  1024. // I shouldn't have to deal with multiple select here...
  1025. //
  1026. ASSERT(ifc.GetCookieCount() == 1);
  1027. CTreeNode* pNode = ifc.GetCookieAt(0);
  1028. if (pNode == NULL)
  1029. {
  1030. ASSERT(pNode != NULL);
  1031. return S_FALSE;
  1032. }
  1033. EnumerateScopePane(pNode, param, bAsync);
  1034. }
  1035. else if (!bAsync)
  1036. {
  1037. ASSERT(m_pConsoleNameSpace != NULL);
  1038. //
  1039. // I shouldn't have to deal with multiple select here...
  1040. //
  1041. ASSERT(ifc.GetCookieCount() == 1);
  1042. CTreeNode* pNode = ifc.GetCookieAt(0);
  1043. ASSERT(pNode != NULL);
  1044. if (pNode && pNode->CanExpandSync())
  1045. {
  1046. MMC_EXPANDSYNC_STRUCT* pExpandStruct = reinterpret_cast<MMC_EXPANDSYNC_STRUCT*>(param);
  1047. if (pExpandStruct && pExpandStruct->bExpanding)
  1048. {
  1049. EnumerateScopePane(pNode, pExpandStruct->hItem, bAsync);
  1050. pExpandStruct->bHandled = TRUE;
  1051. }
  1052. }
  1053. else
  1054. {
  1055. return S_FALSE;
  1056. }
  1057. }
  1058. return S_OK;
  1059. }
  1060. HRESULT CComponentDataObject::OnSelect(CInternalFormatCracker&, LPARAM, LPARAM)
  1061. {
  1062. return E_UNEXPECTED;
  1063. }
  1064. HRESULT CComponentDataObject::OnContextMenu(CTreeNode*, LPARAM, LPARAM)
  1065. {
  1066. return S_OK;
  1067. }
  1068. HRESULT CComponentDataObject::OnPropertyChange(LPARAM param, long fScopePane)
  1069. {
  1070. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  1071. TRACE(_T("CComponentDataObject::OnPropertyChange()\n"));
  1072. ASSERT(param != NULL);
  1073. CPropertyPageHolderBase* pPPHolder = reinterpret_cast<CPropertyPageHolderBase*>(param);
  1074. ASSERT(pPPHolder != NULL);
  1075. CTreeNode* pNode = pPPHolder->GetTreeNode();
  1076. ASSERT(pNode != NULL);
  1077. // allow both types in the result pane, but only scope items in the scope pane
  1078. ASSERT(!fScopePane || (fScopePane && pNode->IsContainer()) );
  1079. long changeMask = CHANGE_RESULT_ITEM; // default, the holder can change it
  1080. BOOL bUpdate = pPPHolder->OnPropertyChange(fScopePane, &changeMask);
  1081. // fire event to let the property page thread proceed
  1082. pPPHolder->AcknowledgeNotify();
  1083. if (bUpdate)
  1084. {
  1085. pNode->OnPropertyChange(this, fScopePane, changeMask);
  1086. }
  1087. return S_OK;
  1088. }
  1089. /////////////////////////////////////////////////////////////////////////////
  1090. // CComponentDataObject::IExtendPropertySheet2 memebers
  1091. STDMETHODIMP CComponentDataObject::CreatePropertyPages(LPPROPERTYSHEETCALLBACK lpProvider,
  1092. LONG_PTR handle,
  1093. LPDATAOBJECT lpIDataObject)
  1094. {
  1095. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  1096. CInternalFormatCracker ifc;
  1097. HRESULT hr = ifc.Extract(lpIDataObject);
  1098. if (FAILED(hr))
  1099. {
  1100. return hr;
  1101. }
  1102. //
  1103. // this was an object created by the modal wizard, do nothing
  1104. //
  1105. if (ifc.GetCookieType() == CCT_UNINITIALIZED)
  1106. {
  1107. return hr;
  1108. }
  1109. if (ifc.GetCookieType() == CCT_SNAPIN_MANAGER)
  1110. {
  1111. return SnapinManagerCreatePropertyPages(lpProvider,handle);
  1112. }
  1113. CTreeNode* pNode = ifc.GetCookieAt(0);
  1114. ASSERT(ifc.GetCookieType() == CCT_SCOPE || ifc.GetCookieType() == CCT_RESULT);
  1115. CNodeList nodeList;
  1116. ifc.GetCookieList(nodeList);
  1117. if (nodeList.GetCount() > 1) // multiple selection
  1118. {
  1119. //
  1120. // Delegate to the container
  1121. //
  1122. ASSERT(pNode->GetContainer() != NULL);
  1123. hr = pNode->GetContainer()->CreatePropertyPages(lpProvider, handle, &nodeList);
  1124. }
  1125. else if (nodeList.GetCount() == 1) // single selection
  1126. {
  1127. //
  1128. // Delegate to the node
  1129. //
  1130. ASSERT(pNode != NULL);
  1131. hr = pNode->CreatePropertyPages(lpProvider, handle, &nodeList);
  1132. }
  1133. else
  1134. {
  1135. hr = E_FAIL;
  1136. }
  1137. return hr;
  1138. }
  1139. STDMETHODIMP CComponentDataObject::QueryPagesFor(LPDATAOBJECT lpDataObject)
  1140. {
  1141. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  1142. CTreeNode* pNode;
  1143. DATA_OBJECT_TYPES type;
  1144. CInternalFormatCracker ifc;
  1145. HRESULT hr = ifc.Extract(lpDataObject);
  1146. if (FAILED(hr))
  1147. {
  1148. return hr;
  1149. }
  1150. type = ifc.GetCookieType();
  1151. pNode = ifc.GetCookieAt(0);
  1152. //
  1153. // Retrieve node list and count
  1154. //
  1155. CNodeList nodeList;
  1156. ifc.GetCookieList(nodeList);
  1157. //
  1158. // this was an object created by the modal wizard, do nothing
  1159. //
  1160. if (type == CCT_UNINITIALIZED)
  1161. {
  1162. return hr;
  1163. }
  1164. if (type == CCT_SNAPIN_MANAGER)
  1165. {
  1166. return HasPropertyPages(type) ? S_OK : S_FALSE;
  1167. }
  1168. //
  1169. // we have a node, so delegate to it
  1170. //
  1171. ASSERT(pNode != NULL);
  1172. BOOL bDummy;
  1173. if (nodeList.GetCount() == 1) // single selection
  1174. {
  1175. ASSERT((type == CCT_SCOPE) || (type == CCT_RESULT));
  1176. if (pNode->GetSheetCount() > 0)
  1177. {
  1178. pNode->ShowPageForNode(this);
  1179. return S_FALSE;
  1180. }
  1181. else if (pNode->DelegatesPPToContainer() && pNode->GetContainer()->GetSheetCount() > 0)
  1182. {
  1183. //
  1184. // Find the page and bring it to foreground
  1185. //
  1186. pNode->ShowPageForNode(this);
  1187. return S_FALSE;
  1188. }
  1189. if (pNode->HasPropertyPages(type, &bDummy, &nodeList))
  1190. {
  1191. hr = S_OK;
  1192. }
  1193. else
  1194. {
  1195. hr = S_FALSE;
  1196. }
  1197. }
  1198. else if (nodeList.GetCount() > 1) // multiple selection
  1199. {
  1200. ASSERT(pNode->GetContainer() != NULL);
  1201. if (pNode->GetContainer()->HasPropertyPages(type, &bDummy, &nodeList))
  1202. {
  1203. hr = S_OK;
  1204. }
  1205. else
  1206. {
  1207. hr = S_FALSE;
  1208. }
  1209. }
  1210. return hr;
  1211. }
  1212. HRESULT CComponentDataObject::CreatePropertySheet(CTreeNode* pNode,
  1213. HWND hWndParent,
  1214. LPCWSTR lpszTitle)
  1215. {
  1216. HRESULT hr = S_OK;
  1217. HWND hWnd = hWndParent;
  1218. if (hWnd == NULL)
  1219. {
  1220. hr = m_pConsole->GetMainWindow(&hWnd);
  1221. if (FAILED(hr))
  1222. {
  1223. ASSERT(FALSE);
  1224. return hr;
  1225. }
  1226. }
  1227. //
  1228. // get an interface to a sheet provider
  1229. //
  1230. CComPtr<IPropertySheetProvider> spSheetProvider;
  1231. hr = m_pConsole->QueryInterface(IID_IPropertySheetProvider,(void**)&spSheetProvider);
  1232. ASSERT(SUCCEEDED(hr));
  1233. ASSERT(spSheetProvider != NULL);
  1234. //
  1235. // get an interface to a sheet callback
  1236. //
  1237. CComPtr<IPropertySheetCallback> spSheetCallback;
  1238. hr = m_pConsole->QueryInterface(IID_IPropertySheetCallback,(void**)&spSheetCallback);
  1239. ASSERT(SUCCEEDED(hr));
  1240. ASSERT(spSheetCallback != NULL);
  1241. //
  1242. // get a sheet
  1243. //
  1244. MMC_COOKIE cookie = reinterpret_cast<MMC_COOKIE>(pNode);
  1245. DATA_OBJECT_TYPES type = (pNode->IsContainer()) ? CCT_SCOPE : CCT_RESULT;
  1246. CComPtr<IDataObject> spDataObject;
  1247. hr = QueryDataObject(cookie, type, &spDataObject);
  1248. ASSERT(SUCCEEDED(hr));
  1249. ASSERT(spDataObject != NULL);
  1250. hr = spSheetProvider->CreatePropertySheet(lpszTitle, TRUE, cookie,
  1251. spDataObject, 0x0 /*dwOptions*/);
  1252. ASSERT(SUCCEEDED(hr));
  1253. hr = spSheetProvider->AddPrimaryPages(GetUnknown(),
  1254. TRUE /*bCreateHandle*/,
  1255. hWnd,
  1256. pNode->IsContainer() /* bScopePane*/);
  1257. hr = spSheetProvider->AddExtensionPages();
  1258. ASSERT(SUCCEEDED(hr));
  1259. hr = spSheetProvider->Show(reinterpret_cast<LONG_PTR>(hWnd), 0);
  1260. ASSERT(SUCCEEDED(hr));
  1261. return hr;
  1262. }
  1263. CWatermarkInfo* CComponentDataObject::SetWatermarkInfo(CWatermarkInfo* pWatermarkInfo)
  1264. {
  1265. if (m_pWatermarkInfoState == NULL)
  1266. {
  1267. m_pWatermarkInfoState = new CWatermarkInfoState;
  1268. }
  1269. CWatermarkInfo* pOldWatermarkInfo = m_pWatermarkInfoState->m_pWatermarkInfo;
  1270. m_pWatermarkInfoState->m_pWatermarkInfo = pWatermarkInfo;
  1271. // we changed info, so dump the old bitmap handles
  1272. m_pWatermarkInfoState->DeleteBitmaps();
  1273. return pOldWatermarkInfo;
  1274. }
  1275. STDMETHODIMP CComponentDataObject::GetWatermarks(LPDATAOBJECT,
  1276. HBITMAP* lphWatermark,
  1277. HBITMAP* lphHeader,
  1278. HPALETTE* lphPalette,
  1279. BOOL* pbStretch)
  1280. {
  1281. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  1282. *lphHeader = NULL;
  1283. *lphWatermark = NULL;
  1284. *lphPalette = NULL;
  1285. *pbStretch = TRUE;
  1286. if ((m_pWatermarkInfoState == NULL) || (m_pWatermarkInfoState->m_pWatermarkInfo == NULL))
  1287. {
  1288. return E_FAIL;
  1289. }
  1290. *pbStretch = m_pWatermarkInfoState->m_pWatermarkInfo->m_bStretch;
  1291. *lphPalette = m_pWatermarkInfoState->m_pWatermarkInfo->m_hPalette;
  1292. // load bitmaps if not loaded yet
  1293. m_pWatermarkInfoState->LoadBitmaps();
  1294. *lphHeader = m_pWatermarkInfoState->m_hBanner;
  1295. if (*lphHeader == NULL)
  1296. {
  1297. return E_FAIL;
  1298. }
  1299. *lphWatermark = m_pWatermarkInfoState->m_hWatermark;
  1300. if (*lphWatermark == NULL)
  1301. {
  1302. return E_FAIL;
  1303. }
  1304. return S_OK;
  1305. }
  1306. /////////////////////////////////////////////////////////////////////////////
  1307. // CComponentDataObject::IExtendContextMenu memebers
  1308. STDMETHODIMP CComponentDataObject::AddMenuItems(LPDATAOBJECT pDataObject,
  1309. LPCONTEXTMENUCALLBACK pContextMenuCallback,
  1310. long *pInsertionAllowed)
  1311. {
  1312. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  1313. HRESULT hr = S_OK;
  1314. CTreeNode* pNode;
  1315. DATA_OBJECT_TYPES type;
  1316. CInternalFormatCracker ifc;
  1317. hr = ifc.Extract(pDataObject);
  1318. if (FAILED(hr))
  1319. {
  1320. return hr;
  1321. }
  1322. type = ifc.GetCookieType();
  1323. pNode = ifc.GetCookieAt(0);
  1324. ASSERT(pNode != NULL);
  1325. if (pNode == NULL)
  1326. {
  1327. return hr;
  1328. }
  1329. CComPtr<IContextMenuCallback2> spContextMenuCallback2;
  1330. hr = pContextMenuCallback->QueryInterface(IID_IContextMenuCallback2, (PVOID*)&spContextMenuCallback2);
  1331. if (FAILED(hr))
  1332. {
  1333. return hr;
  1334. }
  1335. CNodeList nodeList;
  1336. ifc.GetCookieList(nodeList);
  1337. if (nodeList.GetCount() > 1) // multiple selection
  1338. {
  1339. ASSERT(pNode->GetContainer() != NULL);
  1340. hr = pNode->GetContainer()->OnAddMenuItems(spContextMenuCallback2,
  1341. type,
  1342. pInsertionAllowed,
  1343. &nodeList);
  1344. }
  1345. else if (nodeList.GetCount() == 1) // single selection
  1346. {
  1347. hr = pNode->OnAddMenuItems(spContextMenuCallback2,
  1348. type,
  1349. pInsertionAllowed,
  1350. &nodeList);
  1351. }
  1352. else
  1353. {
  1354. hr = E_FAIL;
  1355. }
  1356. return hr;
  1357. }
  1358. STDMETHODIMP CComponentDataObject::Command(long nCommandID, LPDATAOBJECT pDataObject)
  1359. {
  1360. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  1361. CInternalFormatCracker ifc;
  1362. HRESULT hr = ifc.Extract(pDataObject);
  1363. if (FAILED(hr))
  1364. {
  1365. return hr;
  1366. }
  1367. CTreeNode* pNode = ifc.GetCookieAt(0);
  1368. ASSERT(pNode != NULL);
  1369. //
  1370. // Retrieve node list and count
  1371. //
  1372. CNodeList nodeList;
  1373. ifc.GetCookieList(nodeList);
  1374. if (nodeList.GetCount() > 1) // multiple selection
  1375. {
  1376. //
  1377. // Delegate the command to the container
  1378. //
  1379. ASSERT(pNode->GetContainer() != NULL);
  1380. hr = pNode->GetContainer()->OnCommand(nCommandID,
  1381. ifc.GetCookieType(),
  1382. this,
  1383. &nodeList);
  1384. }
  1385. else if (nodeList.GetCount() == 1) // single selection
  1386. {
  1387. //
  1388. // Let the node take care of it
  1389. //
  1390. hr = pNode->OnCommand(nCommandID,
  1391. ifc.GetCookieType(),
  1392. this,
  1393. &nodeList);
  1394. }
  1395. else
  1396. {
  1397. hr = E_FAIL;
  1398. }
  1399. return hr;
  1400. }
  1401. /////////////////////////////////////////////////////////////////////////////
  1402. // CComponentDataObject::IPersistStream members
  1403. STDMETHODIMP CComponentDataObject::IsDirty()
  1404. {
  1405. // forward to the root of the tree
  1406. CRootData* pRootData = GetRootData();
  1407. ASSERT(pRootData != NULL);
  1408. return pRootData->IsDirty();
  1409. }
  1410. STDMETHODIMP CComponentDataObject::Load(IStream __RPC_FAR *pStm)
  1411. {
  1412. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  1413. // forward to the root of the tree
  1414. CRootData* pRootData = GetRootData();
  1415. ASSERT(pRootData != NULL);
  1416. return pRootData->Load(pStm);
  1417. }
  1418. STDMETHODIMP CComponentDataObject::Save(IStream __RPC_FAR *pStm, BOOL fClearDirty)
  1419. {
  1420. // forward to the root of the tree
  1421. CRootData* pRootData = GetRootData();
  1422. ASSERT(pRootData != NULL);
  1423. return pRootData->Save(pStm,fClearDirty);
  1424. }
  1425. /////////////////////////////////////////////////////////////////////////////
  1426. // CComponentDataObject::ISnapinHelp2 memebers
  1427. STDMETHODIMP CComponentDataObject::GetHelpTopic(LPOLESTR* lpCompiledHelpFile)
  1428. {
  1429. if (lpCompiledHelpFile == NULL)
  1430. {
  1431. return E_INVALIDARG;
  1432. }
  1433. LPCWSTR lpszHelpFileName = GetHTMLHelpFileName();
  1434. if (lpszHelpFileName == NULL)
  1435. {
  1436. *lpCompiledHelpFile = NULL;
  1437. return E_NOTIMPL;
  1438. }
  1439. CString szHelpFilePath;
  1440. LPTSTR lpszBuffer = szHelpFilePath.GetBuffer(2*MAX_PATH);
  1441. UINT nLen = ::GetSystemWindowsDirectory(lpszBuffer, 2*MAX_PATH);
  1442. if (nLen == 0)
  1443. {
  1444. return E_FAIL;
  1445. }
  1446. wcscpy(&lpszBuffer[nLen], lpszHelpFileName);
  1447. szHelpFilePath.ReleaseBuffer();
  1448. UINT nBytes = (szHelpFilePath.GetLength()+1) * sizeof(WCHAR);
  1449. *lpCompiledHelpFile = (LPOLESTR)::CoTaskMemAlloc(nBytes);
  1450. if (*lpCompiledHelpFile != NULL)
  1451. {
  1452. memcpy(*lpCompiledHelpFile, (LPCWSTR)szHelpFilePath, nBytes);
  1453. }
  1454. else
  1455. {
  1456. return E_OUTOFMEMORY;
  1457. }
  1458. return S_OK;
  1459. }
  1460. HRESULT CComponentDataObject::GetLinkedTopics(LPOLESTR*)
  1461. {
  1462. return S_FALSE;
  1463. }
  1464. ///////////////////////////////////////////////////////////////////////////////
  1465. // CComponentDataObject Helpers
  1466. HRESULT CComponentDataObject::UpdateAllViewsHelper(LPARAM data, LONG_PTR hint)
  1467. {
  1468. ASSERT(m_pConsole != NULL);
  1469. CComObject<CDummyDataObject>* pObject;
  1470. CComObject<CDummyDataObject>::CreateInstance(&pObject);
  1471. ASSERT(pObject != NULL);
  1472. IDataObject* pDataObject;
  1473. HRESULT hr = pObject->QueryInterface(IID_IDataObject, reinterpret_cast<void**>(&pDataObject));
  1474. ASSERT(SUCCEEDED(hr));
  1475. ASSERT(pDataObject != NULL);
  1476. hr = m_pConsole->UpdateAllViews(pDataObject,data, hint);
  1477. pDataObject->Release();
  1478. return hr;
  1479. }
  1480. void CComponentDataObject::HandleStandardVerbsHelper(CComponentObject* pComponentObj,
  1481. LPCONSOLEVERB pConsoleVerb,
  1482. BOOL bScope, BOOL bSelect,
  1483. LPDATAOBJECT lpDataObject)
  1484. {
  1485. // You should crack the data object and enable/disable/hide standard
  1486. // commands appropriately. The standard commands are reset everytime you get
  1487. // called. So you must reset them back.
  1488. ASSERT(pConsoleVerb != NULL);
  1489. ASSERT(pComponentObj != NULL);
  1490. ASSERT(lpDataObject != NULL);
  1491. // reset the selection
  1492. pComponentObj->SetSelectedNode(NULL, CCT_UNINITIALIZED);
  1493. CInternalFormatCracker ifc;
  1494. VERIFY(SUCCEEDED(ifc.Extract(lpDataObject)));
  1495. CTreeNode* pNode = ifc.GetCookieAt(0);
  1496. if (pNode == NULL)
  1497. {
  1498. return;
  1499. }
  1500. //
  1501. // Retrieve node list and count
  1502. //
  1503. CNodeList nodeList;
  1504. ifc.GetCookieList(nodeList);
  1505. if (nodeList.GetCount() > 1) // multiple selection
  1506. {
  1507. //
  1508. // Delegate to the container
  1509. //
  1510. ASSERT(pNode->GetContainer() != NULL);
  1511. pNode->GetContainer()->OnSetVerbState(pConsoleVerb, ifc.GetCookieType(), &nodeList);
  1512. }
  1513. else if (nodeList.GetCount() == 1) // single selection
  1514. {
  1515. //
  1516. // set selection, if any
  1517. //
  1518. if (bSelect)
  1519. {
  1520. pComponentObj->SetSelectedNode(pNode, ifc.GetCookieType());
  1521. }
  1522. ASSERT((ifc.GetCookieType() == CCT_SCOPE) || (ifc.GetCookieType() == CCT_RESULT));
  1523. TRACE(_T("HandleStandardVerbsHelper: Node <%s> bScope = %d bSelect = %d, type = %s\n"),
  1524. pNode->GetDisplayName(), bScope, bSelect,
  1525. (ifc.GetCookieType() == CCT_SCOPE) ? _T("CCT_SCOPE") : _T("CCT_RESULT"));
  1526. pConsoleVerb->SetDefaultVerb(pNode->GetDefaultVerb(ifc.GetCookieType(), &nodeList));
  1527. pNode->OnSetVerbState(pConsoleVerb, ifc.GetCookieType(), &nodeList);
  1528. }
  1529. }
  1530. void CComponentDataObject::EnumerateScopePane(CTreeNode* cookie,
  1531. HSCOPEITEM pParent,
  1532. BOOL bAsync)
  1533. {
  1534. ASSERT(m_pConsoleNameSpace != NULL); // make sure we QI'ed for the interface
  1535. // find the node corresponding to the cookie
  1536. ASSERT(cookie != NULL);
  1537. ASSERT(cookie->IsContainer());
  1538. CContainerNode* pContNode = (CContainerNode*)cookie;
  1539. pContNode->MarkExpanded();
  1540. if (pContNode == GetRootData())
  1541. {
  1542. pContNode->SetScopeID(pParent);
  1543. }
  1544. // allow the node to enumerate its children, if not enumerated yet
  1545. if (!pContNode->IsEnumerated())
  1546. {
  1547. BOOL bAddChildrenNow = pContNode->OnEnumerate(this, bAsync);
  1548. pContNode->MarkEnumerated();
  1549. if (!bAddChildrenNow)
  1550. {
  1551. return;
  1552. }
  1553. }
  1554. // scan the list of children, looking for containers and add them
  1555. ASSERT(pParent != NULL);
  1556. CNodeList* pChildList = pContNode->GetContainerChildList();
  1557. ASSERT(pChildList != NULL);
  1558. POSITION pos;
  1559. for( pos = pChildList->GetHeadPosition(); pos != NULL; )
  1560. {
  1561. CContainerNode* pCurrChildNode = (CContainerNode*)pChildList->GetNext(pos);
  1562. ASSERT(pCurrChildNode != NULL);
  1563. if (pCurrChildNode->IsVisible())
  1564. {
  1565. AddContainerNode(pCurrChildNode, pParent);
  1566. }
  1567. }
  1568. }
  1569. HRESULT CComponentDataObject::OnDeleteVerbHandler(CInternalFormatCracker& ifc, CComponentObject*)
  1570. {
  1571. HRESULT hr = S_OK;
  1572. CTreeNode* pNode = ifc.GetCookieAt(0);
  1573. ASSERT(pNode != NULL);
  1574. //
  1575. // Retrieve the cookie list and count
  1576. //
  1577. CNodeList nodeList;
  1578. ifc.GetCookieList(nodeList);
  1579. if (nodeList.GetCount() > 1) // multiple selection
  1580. {
  1581. ASSERT(pNode->GetContainer() != NULL);
  1582. pNode->GetContainer()->OnDelete(this, &nodeList);
  1583. }
  1584. else if (nodeList.GetCount() == 1) // single selection
  1585. {
  1586. pNode->OnDelete(this, &nodeList);
  1587. }
  1588. else
  1589. {
  1590. hr = E_FAIL;
  1591. }
  1592. return hr;
  1593. }
  1594. HRESULT CComponentDataObject::OnRefreshVerbHandler(CInternalFormatCracker& ifc)
  1595. {
  1596. HRESULT hr = S_OK;
  1597. CTreeNode* pNode = ifc.GetCookieAt(0);
  1598. ASSERT(pNode != NULL);
  1599. //
  1600. // Retrieve the node list and the count
  1601. //
  1602. CNodeList nodeList;
  1603. ifc.GetCookieList(nodeList);
  1604. if (nodeList.GetCount() > 1) // multiple selection
  1605. {
  1606. ASSERT(pNode->GetContainer() != NULL);
  1607. pNode->GetContainer()->OnRefresh(this, &nodeList);
  1608. }
  1609. else if (nodeList.GetCount() == 1) // single selection
  1610. {
  1611. pNode->OnRefresh(this, &nodeList);
  1612. }
  1613. else
  1614. {
  1615. hr = E_FAIL;
  1616. }
  1617. return hr;
  1618. }
  1619. HRESULT CComponentDataObject::OnHelpHandler(CInternalFormatCracker& ifc, CComponentObject* pComponentObject)
  1620. {
  1621. //
  1622. // responding to MMCN_CONTEXTHELP
  1623. //
  1624. ASSERT(pComponentObject != NULL);
  1625. HRESULT hr = S_OK;
  1626. CTreeNode* pNode = ifc.GetCookieAt(0);
  1627. ASSERT(pNode != NULL);
  1628. //
  1629. // Retrieve the node list and count
  1630. //
  1631. CNodeList nodeList;
  1632. ifc.GetCookieList(nodeList);
  1633. if (nodeList.GetCount() > 1) // Multiple selection
  1634. {
  1635. ASSERT(pNode->GetContainer() != NULL);
  1636. OnNodeContextHelp(&nodeList);
  1637. }
  1638. else if (nodeList.GetCount() == 1) // Single selection
  1639. {
  1640. OnNodeContextHelp(&nodeList);
  1641. }
  1642. else
  1643. {
  1644. hr = E_FAIL;
  1645. }
  1646. return hr;
  1647. }
  1648. BOOL CComponentDataObject::WinHelp(LPCTSTR lpszHelpFileName, // file, no path
  1649. UINT uCommand, // type of Help
  1650. DWORD dwData // additional data
  1651. )
  1652. {
  1653. HWND hWnd;
  1654. GetConsole()->GetMainWindow(&hWnd);
  1655. CString szHelpFilePath;
  1656. LPTSTR lpszBuffer = szHelpFilePath.GetBuffer(2*MAX_PATH);
  1657. UINT nLen = ::GetSystemWindowsDirectory(lpszBuffer, 2*MAX_PATH);
  1658. if (nLen == 0)
  1659. {
  1660. return FALSE;
  1661. }
  1662. wcscpy(&lpszBuffer[nLen], lpszHelpFileName);
  1663. szHelpFilePath.ReleaseBuffer();
  1664. return ::WinHelp(hWnd, szHelpFilePath, uCommand, dwData);
  1665. }
  1666. HRESULT CComponentDataObject::AddNode(CTreeNode* pNodeToAdd)
  1667. {
  1668. ASSERT(pNodeToAdd != NULL);
  1669. // if the node is hidden, just ignore
  1670. if (!pNodeToAdd->IsVisible())
  1671. return S_OK;
  1672. if (pNodeToAdd->IsContainer())
  1673. {
  1674. ASSERT(pNodeToAdd->GetContainer() != NULL);
  1675. HSCOPEITEM pParentScopeItem = pNodeToAdd->GetContainer()->GetScopeID();
  1676. ASSERT(pParentScopeItem != NULL);
  1677. return AddContainerNode((CContainerNode*)pNodeToAdd, pParentScopeItem);
  1678. }
  1679. return AddLeafNode((CLeafNode*)pNodeToAdd);
  1680. }
  1681. HRESULT CComponentDataObject::AddNodeSorted(CTreeNode* pNodeToAdd)
  1682. {
  1683. ASSERT(pNodeToAdd != NULL);
  1684. // if the node is hidden, just ignore
  1685. if (!pNodeToAdd->IsVisible())
  1686. {
  1687. return S_OK;
  1688. }
  1689. if (pNodeToAdd->IsContainer())
  1690. {
  1691. ASSERT(pNodeToAdd->GetContainer() != NULL);
  1692. HSCOPEITEM pParentScopeItem = pNodeToAdd->GetContainer()->GetScopeID();
  1693. ASSERT(pParentScopeItem != NULL);
  1694. return AddContainerNodeSorted((CContainerNode*)pNodeToAdd, pParentScopeItem);
  1695. }
  1696. return AddLeafNode((CLeafNode*)pNodeToAdd);
  1697. }
  1698. HRESULT CComponentDataObject::DeleteNode(CTreeNode* pNodeToDelete)
  1699. {
  1700. if (pNodeToDelete->IsContainer())
  1701. {
  1702. return DeleteContainerNode((CContainerNode*)pNodeToDelete);
  1703. }
  1704. return DeleteLeafNode((CLeafNode*)pNodeToDelete);
  1705. }
  1706. HRESULT CComponentDataObject::DeleteMultipleNodes(CNodeList* pNodeList)
  1707. {
  1708. HRESULT hr = S_OK;
  1709. POSITION pos = pNodeList->GetHeadPosition();
  1710. while (pos != NULL)
  1711. {
  1712. CTreeNode* pNode = pNodeList->GetNext(pos);
  1713. if (pNode->IsContainer())
  1714. {
  1715. DeleteContainerNode((CContainerNode*)pNode);
  1716. }
  1717. }
  1718. hr = UpdateAllViewsHelper(reinterpret_cast<LONG_PTR>(pNodeList), DELETE_MULTIPLE_RESULT_ITEMS);
  1719. return hr;
  1720. }
  1721. HRESULT CComponentDataObject::ChangeNode(CTreeNode* pNodeToChange, long changeMask)
  1722. {
  1723. if (!pNodeToChange->IsVisible())
  1724. {
  1725. return S_OK;
  1726. }
  1727. if (pNodeToChange->IsContainer())
  1728. {
  1729. CContainerNode* pContNode = (CContainerNode*)pNodeToChange;
  1730. //if (!pContNode->IsExpanded())
  1731. // return S_OK;
  1732. return ChangeContainerNode(pContNode, changeMask);
  1733. }
  1734. return ChangeLeafNode((CLeafNode*)pNodeToChange, changeMask);
  1735. }
  1736. HRESULT CComponentDataObject::RemoveAllChildren(CContainerNode* pNode)
  1737. {
  1738. // if the node is hidden or not expanded yet, just ignore
  1739. if (!pNode->IsVisible() || !pNode->IsExpanded())
  1740. {
  1741. return S_OK;
  1742. }
  1743. ASSERT(pNode != NULL);
  1744. HSCOPEITEM nID = pNode->GetScopeID();
  1745. ASSERT(nID != 0);
  1746. // remove the container itself
  1747. HRESULT hr = m_pConsoleNameSpace->DeleteItem(nID, /*fDeleteThis*/ FALSE);
  1748. ASSERT(SUCCEEDED(hr));
  1749. DeleteAllResultPaneItems(pNode);
  1750. // remove the result items from all the views (will do only if container selected)
  1751. ASSERT(SUCCEEDED(hr));
  1752. return hr;
  1753. }
  1754. HRESULT CComponentDataObject::RepaintSelectedFolderInResultPane()
  1755. {
  1756. return UpdateAllViewsHelper((long)NULL, REPAINT_RESULT_PANE);
  1757. }
  1758. HRESULT CComponentDataObject::RepaintResultPane(CContainerNode* pNode)
  1759. {
  1760. ASSERT(pNode != NULL);
  1761. return UpdateAllViewsHelper(reinterpret_cast<LONG_PTR>(pNode), REPAINT_RESULT_PANE);
  1762. }
  1763. HRESULT CComponentDataObject::DeleteAllResultPaneItems(CContainerNode* pNode)
  1764. {
  1765. ASSERT(pNode != NULL);
  1766. return UpdateAllViewsHelper(reinterpret_cast<LONG_PTR>(pNode), DELETE_ALL_RESULT_ITEMS);
  1767. }
  1768. HRESULT CComponentDataObject::AddContainerNode(CContainerNode* pNodeToInsert, HSCOPEITEM pParentScopeItem)
  1769. {
  1770. ASSERT(pNodeToInsert != NULL);
  1771. if ((pNodeToInsert != GetRootData()) && (!pNodeToInsert->GetContainer()->IsExpanded()))
  1772. {
  1773. return S_OK;
  1774. }
  1775. //ASSERT(pNodeToInsert->GetScopeID() == 0);
  1776. SCOPEDATAITEM scopeDataItem;
  1777. InitializeScopeDataItem(&scopeDataItem,
  1778. pParentScopeItem,
  1779. reinterpret_cast<LPARAM>(pNodeToInsert), // lParam, use the node pointer as cookie
  1780. pNodeToInsert->GetImageIndex(FALSE), // close image
  1781. pNodeToInsert->GetImageIndex(TRUE), // open image
  1782. pNodeToInsert->HasChildren());
  1783. HRESULT hr = m_pConsoleNameSpace->InsertItem(&scopeDataItem);
  1784. ASSERT(SUCCEEDED(hr));
  1785. if (FAILED(hr))
  1786. {
  1787. return hr;
  1788. }
  1789. // Note - On return, the ID member of 'scopeDataItem'
  1790. // contains the handle to the newly inserted item, so we have to save
  1791. ASSERT(scopeDataItem.ID != NULL);
  1792. pNodeToInsert->SetScopeID(scopeDataItem.ID);
  1793. return hr;
  1794. }
  1795. //
  1796. // Note : This should combined with the function above adding a third parameter that is a compare function,
  1797. // which is NULL by default. If it is NULL then we just skip the GetChildItem() and the while loop.
  1798. //
  1799. HRESULT CComponentDataObject::AddContainerNodeSorted(CContainerNode* pNodeToInsert, HSCOPEITEM pParentScopeItem)
  1800. {
  1801. ASSERT(pNodeToInsert != NULL);
  1802. if ((pNodeToInsert != GetRootData()) && (!pNodeToInsert->GetContainer()->IsExpanded()))
  1803. {
  1804. return S_OK;
  1805. }
  1806. SCOPEDATAITEM scopeDataItem;
  1807. InitializeScopeDataItem(&scopeDataItem,
  1808. pParentScopeItem,
  1809. reinterpret_cast<LPARAM>(pNodeToInsert), // lParam, use the node pointer as cookie
  1810. pNodeToInsert->GetImageIndex(FALSE), // close image
  1811. pNodeToInsert->GetImageIndex(TRUE), // open image
  1812. pNodeToInsert->HasChildren());
  1813. HSCOPEITEM pChildScopeItem;
  1814. CTreeNode* pChildNode = NULL;
  1815. // Enumerate through the scope node items and insert the new node in sorted order
  1816. HRESULT hr = m_pConsoleNameSpace->GetChildItem(pParentScopeItem, &pChildScopeItem, (MMC_COOKIE*)&pChildNode);
  1817. ASSERT(SUCCEEDED(hr));
  1818. if (FAILED(hr))
  1819. {
  1820. return hr;
  1821. }
  1822. while (pChildNode != NULL)
  1823. {
  1824. // REVIEW_JEFFJON : we should probably have a compare function as a parameter and use that here.
  1825. if (_wcsicoll(pNodeToInsert->GetDisplayName(), pChildNode->GetDisplayName()) < 0)
  1826. {
  1827. // Insert the node before the node pointed to by pChildScopeItem
  1828. scopeDataItem.relativeID = pChildScopeItem;
  1829. scopeDataItem.mask |= SDI_NEXT;
  1830. break;
  1831. }
  1832. pChildNode = NULL;
  1833. hr = m_pConsoleNameSpace->GetNextItem(pChildScopeItem, &pChildScopeItem, (MMC_COOKIE*)&pChildNode);
  1834. ASSERT(SUCCEEDED(hr));
  1835. if (FAILED(hr))
  1836. {
  1837. return hr;
  1838. }
  1839. }
  1840. hr = m_pConsoleNameSpace->InsertItem(&scopeDataItem);
  1841. ASSERT(SUCCEEDED(hr));
  1842. if (FAILED(hr))
  1843. {
  1844. return hr;
  1845. }
  1846. // Note - On return, the ID member of 'scopeDataItem'
  1847. // contains the handle to the newly inserted item, so we have to save
  1848. ASSERT(scopeDataItem.ID != NULL);
  1849. pNodeToInsert->SetScopeID(scopeDataItem.ID);
  1850. return hr;
  1851. }
  1852. HRESULT CComponentDataObject::DeleteContainerNode(CContainerNode* pNodeToDelete)
  1853. {
  1854. ASSERT(pNodeToDelete != NULL);
  1855. ASSERT(pNodeToDelete->GetContainer() != NULL);
  1856. HSCOPEITEM nID = pNodeToDelete->GetScopeID();
  1857. ASSERT(nID != 0);
  1858. HRESULT hr = m_pConsoleNameSpace->DeleteItem(nID, /*fDeleteThis*/ TRUE);
  1859. pNodeToDelete->SetScopeID(0);
  1860. return hr;
  1861. }
  1862. HRESULT CComponentDataObject::ChangeContainerNode(CContainerNode* pNodeToChange, long changeMask)
  1863. {
  1864. ASSERT(pNodeToChange != NULL);
  1865. ASSERT(changeMask & CHANGE_RESULT_ITEM);
  1866. ASSERT(m_pConsoleNameSpace != NULL);
  1867. if (!pNodeToChange->AddedToScopePane())
  1868. {
  1869. return S_OK;
  1870. }
  1871. SCOPEDATAITEM scopeDataItem;
  1872. memset(&scopeDataItem, 0, sizeof(SCOPEDATAITEM));
  1873. scopeDataItem.ID = pNodeToChange->GetScopeID();
  1874. ASSERT(scopeDataItem.ID != 0);
  1875. if (changeMask & CHANGE_RESULT_ITEM_DATA)
  1876. {
  1877. scopeDataItem.mask |= SDI_STR;
  1878. scopeDataItem.displayname = MMC_CALLBACK;
  1879. }
  1880. if (changeMask & CHANGE_RESULT_ITEM_ICON)
  1881. {
  1882. scopeDataItem.mask |= SDI_IMAGE;
  1883. scopeDataItem.nImage = pNodeToChange->GetImageIndex(FALSE);
  1884. scopeDataItem.mask |= SDI_OPENIMAGE;
  1885. scopeDataItem.nOpenImage = pNodeToChange->GetImageIndex(TRUE);
  1886. }
  1887. return m_pConsoleNameSpace->SetItem(&scopeDataItem);
  1888. }
  1889. HRESULT CComponentDataObject::AddLeafNode(CLeafNode* pNodeToAdd)
  1890. {
  1891. // will have to broadcast to all views
  1892. ASSERT(pNodeToAdd != NULL);
  1893. return UpdateAllViewsHelper(reinterpret_cast<LONG_PTR>(pNodeToAdd), ADD_RESULT_ITEM);
  1894. }
  1895. HRESULT CComponentDataObject::DeleteLeafNode(CLeafNode* pNodeToDelete)
  1896. {
  1897. // will have to broadcast to all views
  1898. ASSERT(pNodeToDelete != NULL);
  1899. return UpdateAllViewsHelper(reinterpret_cast<LONG_PTR>(pNodeToDelete), DELETE_RESULT_ITEM);
  1900. }
  1901. HRESULT CComponentDataObject::ChangeLeafNode(CLeafNode* pNodeToChange, long changeMask)
  1902. {
  1903. // will have to broadcast to all views
  1904. ASSERT(pNodeToChange != NULL);
  1905. return UpdateAllViewsHelper(reinterpret_cast<LONG_PTR>(pNodeToChange), changeMask);
  1906. }
  1907. HRESULT CComponentDataObject::UpdateVerbState(CTreeNode* pNodeToChange)
  1908. {
  1909. // will have to broadcast to all views
  1910. ASSERT(pNodeToChange != NULL);
  1911. return UpdateAllViewsHelper(reinterpret_cast<LONG_PTR>(pNodeToChange), UPDATE_VERB_STATE);
  1912. }
  1913. HRESULT CComponentDataObject::SetDescriptionBarText(CTreeNode* pTreeNode)
  1914. {
  1915. ASSERT(pTreeNode != NULL);
  1916. return UpdateAllViewsHelper(reinterpret_cast<LONG_PTR>(pTreeNode), UPDATE_DESCRIPTION_BAR);
  1917. }
  1918. HRESULT CComponentDataObject::SortResultPane(CContainerNode* pContainerNode)
  1919. {
  1920. ASSERT(pContainerNode != NULL);
  1921. return UpdateAllViewsHelper(reinterpret_cast<LONG_PTR>(pContainerNode), SORT_RESULT_PANE);
  1922. }
  1923. HRESULT CComponentDataObject::UpdateResultPaneView(CContainerNode* pContainerNode)
  1924. {
  1925. ASSERT(pContainerNode != NULL);
  1926. return UpdateAllViewsHelper(reinterpret_cast<LONG_PTR>(pContainerNode), UPDATE_RESULT_PANE_VIEW);
  1927. }
  1928. void CComponentDataObject::InitializeScopeDataItem(LPSCOPEDATAITEM pScopeDataItem,
  1929. HSCOPEITEM pParentScopeItem, LPARAM lParam,
  1930. int nImage, int nOpenImage, BOOL bHasChildren)
  1931. {
  1932. ASSERT(pScopeDataItem != NULL);
  1933. memset(pScopeDataItem, 0, sizeof(SCOPEDATAITEM));
  1934. // set parent scope item
  1935. pScopeDataItem->mask |= SDI_PARENT;
  1936. pScopeDataItem->relativeID = pParentScopeItem;
  1937. // Add node name, we implement callback
  1938. pScopeDataItem->mask |= SDI_STR;
  1939. pScopeDataItem->displayname = MMC_CALLBACK;
  1940. // Add the lParam
  1941. pScopeDataItem->mask |= SDI_PARAM;
  1942. pScopeDataItem->lParam = lParam;
  1943. // Add close image
  1944. if (nImage != -1)
  1945. {
  1946. pScopeDataItem->mask |= SDI_IMAGE;
  1947. pScopeDataItem->nImage = nImage;
  1948. }
  1949. // Add open image
  1950. if (nOpenImage != -1)
  1951. {
  1952. pScopeDataItem->mask |= SDI_OPENIMAGE;
  1953. pScopeDataItem->nOpenImage = nOpenImage;
  1954. }
  1955. // Add button to node if the folder has children
  1956. if (bHasChildren == TRUE)
  1957. {
  1958. pScopeDataItem->mask |= SDI_CHILDREN;
  1959. pScopeDataItem->cChildren = 1;
  1960. }
  1961. }
  1962. ///////////////////////////////////////////////////////////////////////////////
  1963. // Timer and Background Thread
  1964. BOOL CComponentDataObject::StartTimerThread()
  1965. {
  1966. ASSERT(::IsWindow(m_hWnd));
  1967. m_pTimerThreadObj = OnCreateTimerThread();
  1968. if (m_pTimerThreadObj == NULL)
  1969. {
  1970. return TRUE;
  1971. }
  1972. // start the the thread
  1973. if (!m_pTimerThreadObj->Start(m_hWnd))
  1974. {
  1975. return FALSE;
  1976. }
  1977. ASSERT(m_pTimerThreadObj->m_nThreadID != 0);
  1978. m_nTimerThreadID = m_pTimerThreadObj->m_nThreadID;
  1979. WaitForTimerThreadStartAck();
  1980. return SetTimer();
  1981. }
  1982. void CComponentDataObject::ShutDownTimerThread()
  1983. {
  1984. KillTimer();
  1985. PostMessageToTimerThread(WM_QUIT, 0,0);
  1986. //
  1987. // Wait for the thread to die or else we could AV since there may be more
  1988. // messages in the queue than just the WM_QUIT
  1989. //
  1990. if (m_pTimerThreadObj != NULL)
  1991. {
  1992. DWORD dwRetState = ::WaitForSingleObject(m_pTimerThreadObj->m_hThread,INFINITE);
  1993. ASSERT(dwRetState != WAIT_FAILED);
  1994. }
  1995. //
  1996. // Threads now gone, delete the thread object
  1997. //
  1998. delete m_pTimerThreadObj;
  1999. m_pTimerThreadObj = NULL;
  2000. }
  2001. BOOL CComponentDataObject::PostMessageToTimerThread(UINT Msg, WPARAM wParam, LPARAM lParam)
  2002. {
  2003. if (m_nTimerThreadID != 0)
  2004. {
  2005. return ::PostThreadMessage(m_nTimerThreadID, Msg, wParam, lParam);
  2006. }
  2007. return TRUE;
  2008. }
  2009. BOOL CComponentDataObject::SetTimer()
  2010. {
  2011. ASSERT(::IsWindow(m_hWnd));
  2012. ASSERT(m_hiddenWnd.m_nTimerID == 0);
  2013. m_dwTimerTime = 0;
  2014. DWORD dwTimerIntervalMillisec = m_dwTimerInterval*1000;
  2015. m_hiddenWnd.m_nTimerID = m_hiddenWnd.SetTimer(1, dwTimerIntervalMillisec);
  2016. return (m_hiddenWnd.m_nTimerID != 0);
  2017. }
  2018. void CComponentDataObject::KillTimer()
  2019. {
  2020. ASSERT(::IsWindow(m_hWnd));
  2021. if (m_hiddenWnd.m_nTimerID != 0)
  2022. {
  2023. VERIFY(m_hiddenWnd.KillTimer(static_cast<UINT>(m_hiddenWnd.m_nTimerID)));
  2024. m_hiddenWnd.m_nTimerID = 0;
  2025. }
  2026. }
  2027. void CComponentDataObject::WaitForTimerThreadStartAck()
  2028. {
  2029. MSG tempMSG;
  2030. ASSERT(!m_bTimerThreadStarted);
  2031. while(!m_bTimerThreadStarted)
  2032. {
  2033. if (::PeekMessage(&tempMSG,m_hWnd,CHiddenWnd::s_TimerThreadMessage,
  2034. CHiddenWnd::s_TimerThreadMessage,
  2035. PM_REMOVE))
  2036. {
  2037. DispatchMessage(&tempMSG);
  2038. }
  2039. }
  2040. }
  2041. void CComponentDataObject::WaitForThreadExitMessage(CMTContainerNode* pNode)
  2042. {
  2043. MSG tempMSG;
  2044. while(GetRunningThreadTable()->IsPresent(pNode))
  2045. {
  2046. if (::PeekMessage(&tempMSG,
  2047. m_hiddenWnd.m_hWnd,
  2048. CHiddenWnd::s_NodeThreadHaveDataNotificationMessage,
  2049. CHiddenWnd::s_NodeThreadExitingNotificationMessage,
  2050. PM_REMOVE))
  2051. {
  2052. DispatchMessage(&tempMSG);
  2053. }
  2054. } // while
  2055. }
  2056. ///////////////////////////////////////////////////////////////////////////////
  2057. // CComponentObject implementation
  2058. ///////////////////////////////////////////////////////////////////////////////
  2059. #ifdef _DEBUG_REFCOUNT
  2060. unsigned int CComponentObject::m_nOustandingObjects = 0;
  2061. #endif // _DEBUG_REFCOUNT
  2062. CComponentObject::CComponentObject()
  2063. {
  2064. #ifdef _DEBUG_REFCOUNT
  2065. dbg_cRef = 0;
  2066. ++m_nOustandingObjects;
  2067. TRACE(_T("CComponentObject(), count = %d\n"),m_nOustandingObjects);
  2068. #endif // _DEBUG_REFCOUNT
  2069. Construct();
  2070. }
  2071. CComponentObject::~CComponentObject()
  2072. {
  2073. #ifdef _DEBUG_REFCOUNT
  2074. --m_nOustandingObjects;
  2075. TRACE(_T("~CComponentObject(), count = %d\n"),m_nOustandingObjects);
  2076. #endif // _DEBUG_REFCOUNT
  2077. // Make sure the interfaces have been released
  2078. ASSERT(m_pConsole == NULL);
  2079. ASSERT(m_pHeader == NULL);
  2080. //SAFE_RELEASE(m_pComponentData); // QI'ed in IComponentDataImpl::CreateComponent
  2081. if (m_pComponentData != NULL)
  2082. {
  2083. m_pComponentData->Release();
  2084. m_pComponentData = NULL;
  2085. TRACE(_T("~CComponentObject() released m_pCompomentData\n"));
  2086. }
  2087. Construct();
  2088. }
  2089. void CComponentObject::Construct()
  2090. {
  2091. m_pConsole = NULL;
  2092. m_pHeader = NULL;
  2093. m_pResult = NULL;
  2094. m_pImageResult = NULL;
  2095. m_pComponentData = NULL;
  2096. m_pToolbar = NULL;
  2097. m_pControlbar = NULL;
  2098. m_pConsoleVerb = NULL;
  2099. m_pSelectedContainerNode = NULL;
  2100. m_pSelectedNode = NULL;
  2101. m_selectedType = CCT_UNINITIALIZED;
  2102. }
  2103. ///////////////////////////////////////////////////////////////////////////////
  2104. // CComponentObject::IComponent members
  2105. STDMETHODIMP CComponentObject::Initialize(LPCONSOLE lpConsole)
  2106. {
  2107. ASSERT(lpConsole != NULL);
  2108. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  2109. // Save the IConsole pointer
  2110. m_pConsole = lpConsole;
  2111. m_pConsole->AddRef();
  2112. // QI for a IHeaderCtrl
  2113. HRESULT hr = m_pConsole->QueryInterface(IID_IHeaderCtrl,
  2114. reinterpret_cast<void**>(&m_pHeader));
  2115. // Give the console the header control interface pointer
  2116. if (SUCCEEDED(hr))
  2117. {
  2118. m_pConsole->SetHeader(m_pHeader);
  2119. }
  2120. m_pConsole->QueryInterface(IID_IResultData,
  2121. reinterpret_cast<void**>(&m_pResult));
  2122. hr = m_pConsole->QueryResultImageList(&m_pImageResult);
  2123. ASSERT(hr == S_OK);
  2124. hr = m_pConsole->QueryConsoleVerb(&m_pConsoleVerb);
  2125. ASSERT(hr == S_OK);
  2126. return S_OK;
  2127. }
  2128. STDMETHODIMP CComponentObject::Notify(LPDATAOBJECT lpDataObject, MMC_NOTIFY_TYPE event, LPARAM arg, LPARAM param)
  2129. {
  2130. HRESULT hr = S_OK;
  2131. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  2132. if (event == MMCN_PROPERTY_CHANGE)
  2133. {
  2134. ASSERT(lpDataObject == NULL);
  2135. hr = OnPropertyChange(param, static_cast<ULONG>(arg));
  2136. }
  2137. else if (event == MMCN_VIEW_CHANGE)
  2138. {
  2139. hr = OnUpdateView(lpDataObject,arg,param);
  2140. }
  2141. else if (event == MMCN_DESELECT_ALL)
  2142. {
  2143. TRACE(_T("CComponentObject::Notify -> MMCN_DESELECT_ALL \n"));
  2144. }
  2145. else if (event == MMCN_COLUMN_CLICK)
  2146. {
  2147. OnColumnSortChanged(arg, param);
  2148. }
  2149. else if (event == MMCN_CUTORMOVE)
  2150. {
  2151. hr = S_FALSE;
  2152. }
  2153. else if (lpDataObject != NULL)
  2154. {
  2155. CInternalFormatCracker ifc;
  2156. ifc.Extract(lpDataObject);
  2157. if (ifc.GetCookieCount() < 1)
  2158. {
  2159. CComponentDataObject* pComponentDataObject = (CComponentDataObject*)m_pComponentData;
  2160. if ( (event == MMCN_ADD_IMAGES) && pComponentDataObject->IsExtensionSnapin() )
  2161. {
  2162. CTreeNode* pTreeNode = pComponentDataObject->GetRootData();
  2163. return InitializeBitmaps(pTreeNode); // cookie for the root
  2164. }
  2165. return S_OK;
  2166. }
  2167. switch(event)
  2168. {
  2169. case MMCN_ACTIVATE:
  2170. break;
  2171. case MMCN_CLICK:
  2172. OnResultItemClk(ifc, FALSE);
  2173. break;
  2174. case MMCN_DBLCLICK:
  2175. hr = S_FALSE;
  2176. break;
  2177. case MMCN_ADD_IMAGES:
  2178. OnAddImages(ifc, arg, param);
  2179. break;
  2180. case MMCN_SHOW:
  2181. hr = OnShow(ifc, arg, param);
  2182. break;
  2183. case MMCN_COLUMNS_CHANGED:
  2184. hr = OnColumnsChanged(ifc, arg, param);
  2185. break;
  2186. case MMCN_MINIMIZED:
  2187. hr = OnMinimize(ifc, arg, param);
  2188. break;
  2189. case MMCN_SELECT:
  2190. HandleStandardVerbs( (BOOL) LOWORD(arg)/*bScope*/,
  2191. (BOOL) HIWORD(arg)/*bSelect*/,lpDataObject);
  2192. break;
  2193. case MMCN_QUERY_PASTE:
  2194. hr = S_FALSE;
  2195. break;
  2196. case MMCN_PASTE:
  2197. AfxMessageBox(_T("CComponentObject::MMCN_PASTE"));
  2198. break;
  2199. case MMCN_DELETE:
  2200. // just delegate to the component data object
  2201. hr = ((CComponentDataObject*)m_pComponentData)->OnDeleteVerbHandler(
  2202. ifc, this);
  2203. break;
  2204. case MMCN_REFRESH:
  2205. // just delegate to the component data object
  2206. hr = ((CComponentDataObject*)m_pComponentData)->OnRefreshVerbHandler(
  2207. ifc);
  2208. //
  2209. // Once the refresh has begun, update the verbs associated with the
  2210. // object being refreshed.
  2211. //
  2212. HandleStandardVerbs( (BOOL) LOWORD(arg)/*bScope*/,
  2213. (BOOL) HIWORD(arg)/*bSelect*/,lpDataObject);
  2214. break;
  2215. case MMCN_RENAME:
  2216. // just delegate to the component data object
  2217. hr = ((CComponentDataObject*)m_pComponentData)->OnRename(ifc, arg, param);
  2218. break;
  2219. case MMCN_CONTEXTHELP:
  2220. // just delegate to the component data object
  2221. hr = ((CComponentDataObject*)m_pComponentData)->OnHelpHandler(ifc, this);
  2222. break;
  2223. default:
  2224. hr = E_UNEXPECTED;
  2225. break;
  2226. }
  2227. }
  2228. return hr;
  2229. }
  2230. STDMETHODIMP CComponentObject::Destroy(MMC_COOKIE)
  2231. {
  2232. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  2233. //
  2234. // Release the interfaces that we QI'ed
  2235. //
  2236. if (m_pConsole != NULL)
  2237. {
  2238. //
  2239. // Tell the console to release the header control interface
  2240. //
  2241. m_pConsole->SetHeader(NULL);
  2242. SAFE_RELEASE(m_pHeader);
  2243. SAFE_RELEASE(m_pToolbar);
  2244. SAFE_RELEASE(m_pControlbar);
  2245. SAFE_RELEASE(m_pResult);
  2246. SAFE_RELEASE(m_pImageResult);
  2247. SAFE_RELEASE(m_pConsoleVerb);
  2248. // Release the IConsole interface last
  2249. SAFE_RELEASE(m_pConsole);
  2250. }
  2251. return S_OK;
  2252. }
  2253. STDMETHODIMP CComponentObject::GetResultViewType(MMC_COOKIE cookie, LPOLESTR* ppViewType,
  2254. long* pViewOptions)
  2255. {
  2256. CTreeNode* pNode;
  2257. if (cookie == NULL)
  2258. {
  2259. pNode = ((CComponentDataObject*)m_pComponentData)->GetRootData();
  2260. }
  2261. else
  2262. {
  2263. pNode = reinterpret_cast<CTreeNode*>(cookie);
  2264. }
  2265. ASSERT(pNode != NULL);
  2266. if (pNode != NULL)
  2267. {
  2268. return pNode->GetResultViewType((CComponentDataObject*)m_pComponentData,
  2269. ppViewType,
  2270. pViewOptions);
  2271. }
  2272. // Use default view
  2273. if (((CComponentDataObject*)m_pComponentData)->IsMultiSelect())
  2274. {
  2275. *pViewOptions = MMC_VIEW_OPTIONS_MULTISELECT;
  2276. }
  2277. else
  2278. {
  2279. *pViewOptions = MMC_VIEW_OPTIONS_NONE;
  2280. }
  2281. *ppViewType = NULL;
  2282. return S_FALSE;
  2283. }
  2284. STDMETHODIMP CComponentObject::QueryDataObject(MMC_COOKIE cookie, DATA_OBJECT_TYPES type,
  2285. LPDATAOBJECT* ppDataObject)
  2286. {
  2287. HRESULT hr = S_OK;
  2288. ASSERT(ppDataObject != NULL);
  2289. CComObject<CDataObject>* pObject;
  2290. CComObject<CDataObject>::CreateInstance(&pObject);
  2291. ASSERT(pObject != NULL);
  2292. if (pObject != NULL)
  2293. {
  2294. CTreeNode* pNode = NULL;
  2295. if (cookie == MMC_MULTI_SELECT_COOKIE)
  2296. {
  2297. TRACE(_T("CDSEvent::GetDataObject() - multi-select.\n"));
  2298. RESULTDATAITEM rdi;
  2299. ZeroMemory(&rdi, sizeof(rdi));
  2300. rdi.mask = RDI_STATE;
  2301. rdi.nIndex = -1;
  2302. rdi.nState = LVIS_SELECTED;
  2303. do
  2304. {
  2305. rdi.lParam = 0;
  2306. ASSERT(rdi.mask == RDI_STATE);
  2307. ASSERT(rdi.nState == LVIS_SELECTED);
  2308. hr = m_pResult->GetNextItem(&rdi);
  2309. if (hr != S_OK)
  2310. break;
  2311. pNode = reinterpret_cast<CTreeNode*>(rdi.lParam);
  2312. pObject->AddCookie(pNode);
  2313. } while (1);
  2314. // addref() the new pointer and return it.
  2315. pObject->AddRef();
  2316. *ppDataObject = pObject;
  2317. }
  2318. else
  2319. {
  2320. // Delegate it to the IComponentData implementation
  2321. ASSERT(m_pComponentData != NULL);
  2322. hr = m_pComponentData->QueryDataObject(cookie, type, ppDataObject);
  2323. }
  2324. }
  2325. return hr;
  2326. }
  2327. STDMETHODIMP CComponentObject::GetDisplayInfo(LPRESULTDATAITEM pResultDataItem)
  2328. {
  2329. ASSERT(pResultDataItem != NULL);
  2330. CTreeNode* pNode = reinterpret_cast<CTreeNode*>(pResultDataItem->lParam);
  2331. ASSERT(pNode != NULL);
  2332. ASSERT(pResultDataItem->bScopeItem == pNode->IsContainer());
  2333. if (pResultDataItem->mask & RDI_STR)
  2334. {
  2335. LPCWSTR lpszString = pNode->GetString(pResultDataItem->nCol);
  2336. if (lpszString != NULL)
  2337. {
  2338. pResultDataItem->str = (LPWSTR)lpszString;
  2339. }
  2340. }
  2341. if ((pResultDataItem->mask & RDI_IMAGE) && (pResultDataItem->nCol == 0))
  2342. {
  2343. pResultDataItem->nImage = pNode->GetImageIndex(FALSE);
  2344. }
  2345. return S_OK;
  2346. }
  2347. STDMETHODIMP CComponentObject::CompareObjects(LPDATAOBJECT lpDataObjectA, LPDATAOBJECT lpDataObjectB)
  2348. {
  2349. // Delegate it to the IComponentData implementation
  2350. ASSERT(m_pComponentData != NULL);
  2351. return m_pComponentData->CompareObjects(lpDataObjectA, lpDataObjectB);
  2352. }
  2353. ///////////////////////////////////////////////////////////////////////////////
  2354. // Message handlers for CComponentObject::IComponent::Notify()
  2355. HRESULT CComponentObject::OnFolder(CTreeNode*, LPARAM, LPARAM)
  2356. {
  2357. ASSERT(FALSE);
  2358. return S_OK;
  2359. }
  2360. HRESULT CComponentObject::OnShow(CInternalFormatCracker& ifc, LPARAM arg, LPARAM)
  2361. {
  2362. HRESULT hr = S_OK;
  2363. ASSERT(ifc.GetCookieCount() == 1);
  2364. //
  2365. // I shouldn't have to deal with multiple select here
  2366. //
  2367. CTreeNode* pNode = ifc.GetCookieAt(0);
  2368. ASSERT(pNode != NULL);
  2369. ASSERT(pNode->IsContainer());
  2370. CContainerNode* pContainerNode = (CContainerNode*)pNode;
  2371. // Note - arg is TRUE when it is time to enumerate
  2372. if (arg == TRUE)
  2373. {
  2374. long lResultView;
  2375. LPOLESTR lpoleResultView = NULL;
  2376. pNode->GetResultViewType((CComponentDataObject*)m_pComponentData,
  2377. &lpoleResultView,
  2378. &lResultView);
  2379. if (lResultView == MMC_VIEW_OPTIONS_NONE || lResultView == MMC_VIEW_OPTIONS_MULTISELECT)
  2380. {
  2381. // Show the headers for this nodetype
  2382. InitializeHeaders(pContainerNode);
  2383. EnumerateResultPane(pContainerNode);
  2384. m_pSelectedContainerNode = pContainerNode;
  2385. SetDescriptionBarText(pContainerNode);
  2386. }
  2387. else
  2388. {
  2389. m_pSelectedContainerNode = pContainerNode;
  2390. hr = pNode->OnShow(m_pConsole);
  2391. }
  2392. }
  2393. else
  2394. {
  2395. // Removed by JEFFJON : new column header implementation
  2396. // if we want we can notify ourselves that the focus is being lost
  2397. // SaveHeadersInfo(pContainerNode);
  2398. m_pSelectedContainerNode = NULL;
  2399. // Free data associated with the result pane items, because
  2400. // your node is no longer being displayed.
  2401. // Note: The console will remove the items from the result pane
  2402. }
  2403. #ifdef _DEBUG
  2404. if (m_pSelectedContainerNode == NULL)
  2405. TRACE(_T("NULL selection\n"));
  2406. else
  2407. TRACE(_T("Node <%s> selected\n"), m_pSelectedContainerNode->GetDisplayName());
  2408. #endif
  2409. return hr;
  2410. }
  2411. HRESULT CComponentObject::OnColumnsChanged(CInternalFormatCracker& ifc, LPARAM, LPARAM param)
  2412. {
  2413. CTreeNode* pNode = ifc.GetCookieAt(0);
  2414. ASSERT(pNode != NULL);
  2415. ASSERT(pNode->IsContainer());
  2416. CContainerNode* pContainerNode = (CContainerNode*)pNode;
  2417. MMC_VISIBLE_COLUMNS* pVisibleCols = reinterpret_cast<MMC_VISIBLE_COLUMNS*>(param);
  2418. pContainerNode->OnColumnsChanged(pVisibleCols->rgVisibleCols, pVisibleCols->nVisibleColumns);
  2419. return S_OK;
  2420. }
  2421. HRESULT CComponentObject::OnColumnSortChanged(LPARAM, LPARAM)
  2422. {
  2423. return S_OK;
  2424. }
  2425. HRESULT CComponentObject::ForceSort(UINT iCol, DWORD dwDirection)
  2426. {
  2427. HRESULT hr = m_pResult->Sort(iCol, dwDirection, NULL);
  2428. return hr;
  2429. }
  2430. HRESULT CComponentObject::OnActivate(CTreeNode*, LPARAM, LPARAM)
  2431. {
  2432. ASSERT(FALSE);
  2433. return S_OK;
  2434. }
  2435. HRESULT CComponentObject::OnResultItemClk(CInternalFormatCracker&, BOOL)
  2436. {
  2437. return S_OK;
  2438. }
  2439. HRESULT CComponentObject::OnMinimize(CInternalFormatCracker&, LPARAM, LPARAM)
  2440. {
  2441. return S_OK;
  2442. }
  2443. HRESULT CComponentObject::OnPropertyChange(LPARAM param, long fScopePane)
  2444. {
  2445. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  2446. ASSERT(param != NULL);
  2447. #ifdef _DEBUG
  2448. TRACE(_T("CComponentObject::OnPropertyChange()\n"));
  2449. CPropertyPageHolderBase* pPPHolder = reinterpret_cast<CPropertyPageHolderBase*>(param);
  2450. ASSERT(pPPHolder != NULL);
  2451. CTreeNode* pNode = pPPHolder->GetTreeNode();
  2452. ASSERT(pNode != NULL);
  2453. // the item must be a result item and in the result pane
  2454. ASSERT(!fScopePane);
  2455. #endif
  2456. // we delegate the call to the IComponentData implementation
  2457. CComponentDataObject* pComponentDataObject = (CComponentDataObject*)m_pComponentData;
  2458. ASSERT(pComponentDataObject != NULL);
  2459. return pComponentDataObject->OnPropertyChange(param, fScopePane);
  2460. }
  2461. HRESULT CComponentObject::OnUpdateView(LPDATAOBJECT, LPARAM data, LONG_PTR hint)
  2462. {
  2463. if (m_pSelectedContainerNode == NULL)
  2464. {
  2465. return S_OK; // no selection for our IComponentData
  2466. }
  2467. if (hint == DELETE_ALL_RESULT_ITEMS)
  2468. {
  2469. // data contains the container whose result pane has to be refreshed
  2470. CContainerNode* pNode = reinterpret_cast<CContainerNode*>(data);
  2471. ASSERT(pNode != NULL);
  2472. // do it only if selected and we are using the standard list view,
  2473. // if not, reselecting will do a delete/enumeration
  2474. long lResultView;
  2475. LPOLESTR lpoleResultView = NULL;
  2476. pNode->GetResultViewType((CComponentDataObject*)m_pComponentData,
  2477. &lpoleResultView,
  2478. &lResultView);
  2479. if (m_pSelectedContainerNode == pNode &&
  2480. (lResultView == MMC_VIEW_OPTIONS_NONE || lResultView == MMC_VIEW_OPTIONS_MULTISELECT))
  2481. {
  2482. ASSERT(m_pResult != NULL);
  2483. VERIFY(SUCCEEDED(m_pResult->DeleteAllRsltItems()));
  2484. SetDescriptionBarText(pNode);
  2485. }
  2486. }
  2487. else if (hint == SORT_RESULT_PANE)
  2488. {
  2489. // data contains the container whose result pane has to be refreshed
  2490. CContainerNode* pNode = reinterpret_cast<CContainerNode*>(data);
  2491. ASSERT(pNode != NULL);
  2492. // do it only if selected, if not, reselecting will do a delete/enumeration
  2493. if (m_pSelectedContainerNode == pNode)
  2494. {
  2495. MMC_SORT_SET_DATA* pColumnSortData = NULL;
  2496. // build the column id
  2497. LPCWSTR lpszColumnID = pNode->GetColumnID();
  2498. size_t iLen = wcslen(lpszColumnID);
  2499. // allocate memory for the struct and add on enough to make the byte[1] into a string
  2500. // for the column id
  2501. SColumnSetID* pColumnID = (SColumnSetID*)malloc(sizeof(SColumnSetID) + (iLen * sizeof(WCHAR)));
  2502. memset(pColumnID, 0, sizeof(SColumnSetID) + (iLen * sizeof(WCHAR)));
  2503. pColumnID->cBytes = static_cast<DWORD>(iLen * sizeof(WCHAR));
  2504. wcscpy((LPWSTR)pColumnID->id, lpszColumnID);
  2505. // Get the sort column and direction
  2506. IColumnData* pColumnData = NULL;
  2507. HRESULT hr = m_pConsole->QueryInterface(IID_IColumnData, reinterpret_cast<void**>(&pColumnData));
  2508. if (pColumnData != NULL)
  2509. hr = pColumnData->GetColumnSortData(pColumnID, &pColumnSortData);
  2510. if (SUCCEEDED(hr))
  2511. {
  2512. if (pColumnSortData != NULL)
  2513. {
  2514. UINT iCurrentSortColumn = pColumnSortData->pSortData->nColIndex;
  2515. DWORD dwCurrentSortDirection = pColumnSortData->pSortData->dwSortOptions;
  2516. VERIFY(SUCCEEDED(ForceSort(iCurrentSortColumn, dwCurrentSortDirection)));
  2517. CoTaskMemFree(pColumnSortData);
  2518. }
  2519. }
  2520. if (pColumnData != NULL)
  2521. pColumnData->Release();
  2522. free(pColumnID);
  2523. }
  2524. }
  2525. else if (hint == REPAINT_RESULT_PANE)
  2526. {
  2527. // data contains the container whose result pane has to be refreshed
  2528. CContainerNode* pNode = reinterpret_cast<CContainerNode*>(data);
  2529. if (pNode == NULL)
  2530. pNode = m_pSelectedContainerNode; // passing NULL means apply to the current selection
  2531. // update all the leaf nodes in the result pane
  2532. CNodeList* pChildList = ((CContainerNode*)pNode)->GetLeafChildList();
  2533. for( POSITION pos = pChildList->GetHeadPosition(); pos != NULL; )
  2534. {
  2535. CLeafNode* pCurrentChild = (CLeafNode*)pChildList->GetNext(pos);
  2536. ChangeResultPaneItem(pCurrentChild,CHANGE_RESULT_ITEM);
  2537. }
  2538. }
  2539. else if ( hint == DELETE_MULTIPLE_RESULT_ITEMS)
  2540. {
  2541. CNodeList* pNodeList = reinterpret_cast<CNodeList*>(data);
  2542. ASSERT(pNodeList != NULL);
  2543. POSITION pos = pNodeList->GetHeadPosition();
  2544. while (pos != NULL)
  2545. {
  2546. CTreeNode* pNode = pNodeList->GetNext(pos);
  2547. ASSERT(pNode != NULL);
  2548. if (!pNode->IsContainer())
  2549. {
  2550. DeleteResultPaneItem(static_cast<CLeafNode*>(pNode));
  2551. }
  2552. }
  2553. SetDescriptionBarText(pNodeList->GetHead()->GetContainer());
  2554. }
  2555. else if ( (hint == ADD_RESULT_ITEM) || (hint == DELETE_RESULT_ITEM) || (hint & CHANGE_RESULT_ITEM))
  2556. {
  2557. // we deal with a leaf node
  2558. CLeafNode* pNode = reinterpret_cast<CLeafNode*>(data);
  2559. ASSERT(pNode != NULL);
  2560. // consider only if the parent is selected, otherwise will enumerate later when selected
  2561. if (m_pSelectedContainerNode == pNode->GetContainer())
  2562. {
  2563. if (hint & CHANGE_RESULT_ITEM)
  2564. {
  2565. ChangeResultPaneItem(pNode,hint);
  2566. }
  2567. else if ( hint == ADD_RESULT_ITEM)
  2568. {
  2569. AddResultPaneItem(pNode);
  2570. SetDescriptionBarText(pNode);
  2571. }
  2572. else if ( hint == DELETE_RESULT_ITEM)
  2573. {
  2574. DeleteResultPaneItem(pNode);
  2575. SetDescriptionBarText(pNode);
  2576. }
  2577. }
  2578. }
  2579. else if (hint == UPDATE_VERB_STATE)
  2580. {
  2581. CTreeNode* pTreeNode = reinterpret_cast<CTreeNode*>(data);
  2582. ASSERT(pTreeNode != NULL);
  2583. if (m_pSelectedNode == pTreeNode)
  2584. {
  2585. ASSERT(m_selectedType != CCT_UNINITIALIZED);
  2586. CNodeList nodeList;
  2587. nodeList.AddTail(pTreeNode);
  2588. m_pConsoleVerb->SetDefaultVerb(pTreeNode->GetDefaultVerb(m_selectedType, &nodeList));
  2589. pTreeNode->OnSetVerbState(m_pConsoleVerb, m_selectedType, &nodeList);
  2590. }
  2591. }
  2592. else if (hint == UPDATE_DESCRIPTION_BAR)
  2593. {
  2594. CTreeNode* pTreeNode = reinterpret_cast<CTreeNode*>(data);
  2595. ASSERT(pTreeNode != NULL);
  2596. SetDescriptionBarText(pTreeNode);
  2597. }
  2598. else if (hint == UPDATE_RESULT_PANE_VIEW)
  2599. {
  2600. CContainerNode* pNode = reinterpret_cast<CContainerNode*>(data);
  2601. ASSERT(pNode != NULL);
  2602. HSCOPEITEM hScopeID = pNode->GetScopeID();
  2603. if (hScopeID != 0)
  2604. {
  2605. m_pConsole->SelectScopeItem(hScopeID);
  2606. }
  2607. }
  2608. return S_OK;
  2609. }
  2610. HRESULT CComponentObject::SetDescriptionBarText(CTreeNode* pTreeNode)
  2611. {
  2612. ASSERT(pTreeNode != NULL);
  2613. HRESULT hr = S_OK;
  2614. if (m_pSelectedContainerNode == pTreeNode)
  2615. {
  2616. LPWSTR lpszText = pTreeNode->GetDescriptionBarText();
  2617. hr = m_pResult->SetDescBarText(lpszText);
  2618. }
  2619. else if (m_pSelectedContainerNode == pTreeNode->GetContainer())
  2620. {
  2621. LPWSTR lpszText = pTreeNode->GetContainer()->GetDescriptionBarText();
  2622. hr = m_pResult->SetDescBarText(lpszText);
  2623. }
  2624. return hr;
  2625. }
  2626. HRESULT CComponentObject::OnAddImages(CInternalFormatCracker& ifc, LPARAM, LPARAM)
  2627. {
  2628. CTreeNode* pNode = ifc.GetCookieAt(0);
  2629. ASSERT(pNode != NULL);
  2630. return InitializeBitmaps(pNode);
  2631. }
  2632. void CComponentObject::HandleStandardVerbs(BOOL bScope, BOOL bSelect, LPDATAOBJECT lpDataObject)
  2633. {
  2634. if (lpDataObject == NULL)
  2635. {
  2636. return;
  2637. }
  2638. ((CComponentDataObject*)m_pComponentData)->HandleStandardVerbsHelper(
  2639. this, m_pConsoleVerb, bScope, bSelect, lpDataObject);
  2640. }
  2641. void CComponentObject::EnumerateResultPane(CContainerNode* pContainerNode)
  2642. {
  2643. ASSERT(m_pResult != NULL); // make sure we QI'ed for the interfaces
  2644. ASSERT(m_pComponentData != NULL);
  2645. ASSERT(pContainerNode != NULL);
  2646. //
  2647. // get the list of children
  2648. // subfolders already added by console, add only the leaf nodes
  2649. //
  2650. CNodeList* pChildList = pContainerNode->GetLeafChildList();
  2651. ASSERT(pChildList != NULL);
  2652. POSITION pos;
  2653. for( pos = pChildList->GetHeadPosition(); pos != NULL; )
  2654. {
  2655. CTreeNode* pCurrChildNode = pChildList->GetNext(pos);
  2656. ASSERT(pCurrChildNode != NULL);
  2657. if(pCurrChildNode->IsVisible())
  2658. {
  2659. VERIFY(SUCCEEDED(AddResultPaneItem((CLeafNode*)pCurrChildNode)));
  2660. }
  2661. }
  2662. }
  2663. HRESULT CComponentObject::AddResultPaneItem(CLeafNode* pNodeToInsert)
  2664. {
  2665. ASSERT(m_pResult != NULL);
  2666. ASSERT(pNodeToInsert != NULL);
  2667. RESULTDATAITEM resultItem;
  2668. memset(&resultItem, 0, sizeof(RESULTDATAITEM));
  2669. resultItem.mask = RDI_STR | RDI_IMAGE | RDI_PARAM;
  2670. resultItem.str = MMC_CALLBACK;
  2671. //use close image index on result pane
  2672. resultItem.nImage = pNodeToInsert->GetImageIndex(FALSE);
  2673. resultItem.lParam = reinterpret_cast<LPARAM>(pNodeToInsert);
  2674. return m_pResult->InsertItem(&resultItem);
  2675. }
  2676. HRESULT CComponentObject::DeleteResultPaneItem(CLeafNode* pNodeToDelete)
  2677. {
  2678. ASSERT(m_pResult != NULL);
  2679. ASSERT(pNodeToDelete != NULL);
  2680. RESULTDATAITEM resultItem;
  2681. memset(&resultItem, 0, sizeof(RESULTDATAITEM));
  2682. HRESULTITEM itemID;
  2683. HRESULT hr = m_pResult->FindItemByLParam(reinterpret_cast<LPARAM>(pNodeToDelete), &itemID);
  2684. ASSERT(SUCCEEDED(hr));
  2685. if (FAILED(hr))
  2686. {
  2687. return hr;
  2688. }
  2689. return m_pResult->DeleteItem(itemID,0 /* all cols */);
  2690. }
  2691. HRESULT CComponentObject::ChangeResultPaneItem(CLeafNode* pNodeToChange, LONG_PTR changeMask)
  2692. {
  2693. ASSERT(changeMask & CHANGE_RESULT_ITEM);
  2694. ASSERT(m_pResult != NULL);
  2695. ASSERT(pNodeToChange != NULL);
  2696. HRESULTITEM itemID;
  2697. HRESULT hr = m_pResult->FindItemByLParam(reinterpret_cast<LPARAM>(pNodeToChange), &itemID);
  2698. ASSERT(SUCCEEDED(hr));
  2699. if (FAILED(hr))
  2700. {
  2701. return hr;
  2702. }
  2703. RESULTDATAITEM resultItem;
  2704. memset(&resultItem, 0, sizeof(RESULTDATAITEM));
  2705. resultItem.itemID = itemID;
  2706. if (changeMask & CHANGE_RESULT_ITEM_DATA)
  2707. {
  2708. //
  2709. // UpdateItem() alone does not allow the
  2710. // item string buffer to grow and you get "foo..." when
  2711. // "foo" changes to "foobar" the first time (buffer grows)
  2712. //
  2713. resultItem.mask |= RDI_STR;
  2714. resultItem.str = MMC_CALLBACK;
  2715. //
  2716. // this line asserts, use the one above ask Tony
  2717. //
  2718. //resultItem.str = (LPWSTR)pNodeToChange->GetDisplayName();
  2719. }
  2720. if (changeMask & CHANGE_RESULT_ITEM_ICON)
  2721. {
  2722. resultItem.mask |= RDI_IMAGE;
  2723. resultItem.nImage = pNodeToChange->GetImageIndex(FALSE);
  2724. }
  2725. hr = m_pResult->SetItem(&resultItem);
  2726. ASSERT(SUCCEEDED(hr));
  2727. hr = m_pResult->UpdateItem(itemID);
  2728. ASSERT(SUCCEEDED(hr));
  2729. return hr;
  2730. }
  2731. HRESULT CComponentObject::FindResultPaneItemID(CLeafNode* pNode, HRESULTITEM*)
  2732. {
  2733. ASSERT(FALSE);
  2734. ASSERT(m_pResult != NULL);
  2735. RESULTDATAITEM resultItem;
  2736. memset(&resultItem, 0, sizeof(RESULTDATAITEM));
  2737. resultItem.mask = SDI_PARAM;
  2738. resultItem.lParam = reinterpret_cast<LPARAM>(pNode);
  2739. HRESULT hr = m_pResult->GetItem(&resultItem);
  2740. ASSERT(SUCCEEDED(hr));
  2741. return E_FAIL;
  2742. }
  2743. ///////////////////////////////////////////////////////////////////////////////
  2744. // CComponentObject::IExtendPropertySheet2 members
  2745. STDMETHODIMP CComponentObject::CreatePropertyPages(LPPROPERTYSHEETCALLBACK lpProvider,
  2746. LONG_PTR handle,
  2747. LPDATAOBJECT lpIDataObject)
  2748. {
  2749. // Delegate it to the IComponentData implementation
  2750. ASSERT(m_pComponentData != NULL);
  2751. IExtendPropertySheet2* pIExtendPropertySheet2;
  2752. VERIFY(SUCCEEDED(m_pComponentData->QueryInterface(IID_IExtendPropertySheet2,
  2753. reinterpret_cast<void**>(&pIExtendPropertySheet2))));
  2754. ASSERT(pIExtendPropertySheet2 != NULL);
  2755. HRESULT hr = pIExtendPropertySheet2->CreatePropertyPages(lpProvider, handle, lpIDataObject);
  2756. pIExtendPropertySheet2->Release();
  2757. return hr;
  2758. }
  2759. STDMETHODIMP CComponentObject::QueryPagesFor(LPDATAOBJECT lpDataObject)
  2760. {
  2761. // Delegate it to the IComponentData implementation
  2762. ASSERT(m_pComponentData != NULL);
  2763. IExtendPropertySheet2* pIExtendPropertySheet2;
  2764. VERIFY(SUCCEEDED(m_pComponentData->QueryInterface(IID_IExtendPropertySheet2,
  2765. reinterpret_cast<void**>(&pIExtendPropertySheet2))));
  2766. ASSERT(pIExtendPropertySheet2 != NULL);
  2767. HRESULT hr = pIExtendPropertySheet2->QueryPagesFor(lpDataObject);
  2768. pIExtendPropertySheet2->Release();
  2769. return hr;
  2770. }
  2771. STDMETHODIMP CComponentObject::GetWatermarks(LPDATAOBJECT lpDataObject,
  2772. HBITMAP* lphWatermark,
  2773. HBITMAP* lphHeader,
  2774. HPALETTE* lphPalette,
  2775. BOOL* pbStretch)
  2776. {
  2777. // Delegate it to the IComponentData implementation
  2778. ASSERT(m_pComponentData != NULL);
  2779. IExtendPropertySheet2* pIExtendPropertySheet2;
  2780. VERIFY(SUCCEEDED(m_pComponentData->QueryInterface(IID_IExtendPropertySheet2,
  2781. reinterpret_cast<void**>(&pIExtendPropertySheet2))));
  2782. ASSERT(pIExtendPropertySheet2 != NULL);
  2783. HRESULT hr = pIExtendPropertySheet2->GetWatermarks(lpDataObject,
  2784. lphWatermark,
  2785. lphHeader,
  2786. lphPalette,
  2787. pbStretch);
  2788. pIExtendPropertySheet2->Release();
  2789. return hr;
  2790. }
  2791. ///////////////////////////////////////////////////////////////////////////////
  2792. // CComponentObject::IExtendContextMenu members
  2793. STDMETHODIMP CComponentObject::AddMenuItems(LPDATAOBJECT pDataObject,
  2794. LPCONTEXTMENUCALLBACK pContextMenuCallback,
  2795. long *pInsertionAllowed)
  2796. {
  2797. HRESULT hr = S_OK;
  2798. CComPtr<IContextMenuCallback2> spContextMenuCallback2;
  2799. hr = pContextMenuCallback->QueryInterface(IID_IContextMenuCallback2, (PVOID*)&spContextMenuCallback2);
  2800. if (FAILED(hr))
  2801. {
  2802. return hr;
  2803. }
  2804. if (pDataObject == DOBJ_CUSTOMOCX)
  2805. {
  2806. //
  2807. // A custom result pane is being used and we don't know what node it cooresponds to so we assume that it
  2808. // is the previously selected container.
  2809. //
  2810. ASSERT(m_pSelectedContainerNode != NULL);
  2811. CTreeNode* pNode = (CTreeNode*)m_pSelectedContainerNode;
  2812. CNodeList nodeList;
  2813. nodeList.AddTail(pNode);
  2814. hr = m_pSelectedContainerNode->OnAddMenuItems(spContextMenuCallback2,
  2815. CCT_UNINITIALIZED,
  2816. pInsertionAllowed,
  2817. &nodeList);
  2818. }
  2819. else
  2820. {
  2821. //
  2822. // Delegate it to the IComponentData implementation
  2823. //
  2824. ASSERT(m_pComponentData != NULL);
  2825. IExtendContextMenu* pIExtendContextMenu;
  2826. VERIFY(SUCCEEDED(m_pComponentData->QueryInterface(IID_IExtendContextMenu,
  2827. reinterpret_cast<void**>(&pIExtendContextMenu))));
  2828. ASSERT(pIExtendContextMenu != NULL);
  2829. hr = pIExtendContextMenu->AddMenuItems(pDataObject,
  2830. pContextMenuCallback,
  2831. pInsertionAllowed);
  2832. pIExtendContextMenu->Release();
  2833. }
  2834. return hr;
  2835. }
  2836. STDMETHODIMP CComponentObject::Command(long nCommandID, LPDATAOBJECT pDataObject)
  2837. {
  2838. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  2839. HRESULT hr = S_OK;
  2840. if (pDataObject == DOBJ_CUSTOMOCX)
  2841. {
  2842. //
  2843. // A custom result pane is being used and we don't know what node it cooresponds to so we assume that it
  2844. // is the previously selected container.
  2845. //
  2846. ASSERT(m_pSelectedContainerNode != NULL);
  2847. CTreeNode* pNode = (CTreeNode*)m_pSelectedContainerNode;
  2848. CNodeList nodeList;
  2849. nodeList.AddTail(pNode);
  2850. hr = m_pSelectedContainerNode->OnCommand(nCommandID,
  2851. CCT_UNINITIALIZED,
  2852. (CComponentDataObject*)m_pComponentData,
  2853. &nodeList);
  2854. }
  2855. else
  2856. {
  2857. // Delegate it to the IComponentData implementation
  2858. ASSERT(m_pComponentData != NULL);
  2859. IExtendContextMenu* pIExtendContextMenu;
  2860. VERIFY(SUCCEEDED(m_pComponentData->QueryInterface(IID_IExtendContextMenu,
  2861. reinterpret_cast<void**>(&pIExtendContextMenu))));
  2862. ASSERT(pIExtendContextMenu != NULL);
  2863. hr = pIExtendContextMenu->Command(nCommandID, pDataObject);
  2864. pIExtendContextMenu->Release();
  2865. }
  2866. return hr;
  2867. }
  2868. ///////////////////////////////////////////////////////////////////////////////
  2869. // CComponentObject::IExtendControlbar members
  2870. STDMETHODIMP CComponentObject::SetControlbar(LPCONTROLBAR pControlbar)
  2871. {
  2872. HRESULT hr = S_OK;
  2873. if (pControlbar == NULL)
  2874. {
  2875. //
  2876. // Detach the controls here
  2877. //
  2878. if (m_pControlbar != NULL && m_pToolbar != NULL)
  2879. {
  2880. hr = m_pControlbar->Detach((IUnknown *) m_pToolbar);
  2881. SAFE_RELEASE(m_pControlbar);
  2882. }
  2883. }
  2884. else
  2885. {
  2886. //
  2887. // Save the controlbar interface pointer
  2888. //
  2889. if (m_pControlbar == NULL)
  2890. {
  2891. m_pControlbar = pControlbar;
  2892. m_pControlbar->AddRef();
  2893. }
  2894. //
  2895. // Do something here that checks to see if we have toolbars
  2896. // already created and use those. If not then create one
  2897. // and load everything necessary for it.
  2898. //
  2899. //
  2900. // Create the toolbar
  2901. //
  2902. hr = m_pControlbar->Create (TOOLBAR,
  2903. this,
  2904. (IUnknown **) &m_pToolbar);
  2905. if (SUCCEEDED(hr))
  2906. {
  2907. //
  2908. // Load the toolbar
  2909. //
  2910. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  2911. hr = InitializeToolbar(m_pToolbar);
  2912. if (FAILED(hr))
  2913. {
  2914. hr = m_pControlbar->Detach((IUnknown*) m_pToolbar);
  2915. SAFE_RELEASE(m_pControlbar);
  2916. }
  2917. }
  2918. }
  2919. return hr;
  2920. }
  2921. STDMETHODIMP CComponentObject::ControlbarNotify(MMC_NOTIFY_TYPE event, LPARAM arg, LPARAM param)
  2922. {
  2923. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  2924. HRESULT hr = S_OK;
  2925. if (m_pControlbar == NULL)
  2926. {
  2927. return hr;
  2928. }
  2929. //
  2930. // MMC provides two events here MMCN_SELECT at the time a node is selected
  2931. // and MMCN_BTN_CLICK when a toolbar button is pressed
  2932. //
  2933. switch (event)
  2934. {
  2935. case MMCN_SELECT:
  2936. {
  2937. //
  2938. // Attach the toolbar to the controlbar
  2939. //
  2940. hr = m_pControlbar->Attach(TOOLBAR, (IUnknown *) m_pToolbar);
  2941. if (SUCCEEDED(hr))
  2942. {
  2943. ASSERT(m_pToolbar != NULL);
  2944. //
  2945. // bSelect is TRUE if the node was selected, FALSE if the node was deselected
  2946. // bScope is TRUE if the a scope node is selected, FALSE if a result node was selected
  2947. //
  2948. BOOL bSelect = HIWORD(arg);
  2949. if (bSelect)
  2950. {
  2951. CInternalFormatCracker ifc;
  2952. hr = ifc.Extract((LPDATAOBJECT)param);
  2953. if (SUCCEEDED(hr))
  2954. {
  2955. CTreeNode* pNode = ifc.GetCookieAt(0);
  2956. ASSERT(pNode != NULL);
  2957. CNodeList nodeList;
  2958. ifc.GetCookieList(nodeList);
  2959. if (ifc.GetCookieCount() > 1) // multiple selection
  2960. {
  2961. ASSERT(pNode->GetContainer() != NULL);
  2962. hr = pNode->GetContainer()->OnSetToolbarVerbState(m_pToolbar,
  2963. &nodeList);
  2964. }
  2965. else if (ifc.GetCookieCount() == 1) // single selection
  2966. {
  2967. hr = pNode->OnSetToolbarVerbState(m_pToolbar,
  2968. &nodeList);
  2969. }
  2970. }
  2971. }
  2972. }
  2973. break;
  2974. }
  2975. case MMCN_BTN_CLICK:
  2976. {
  2977. //
  2978. // The arg is -1 for custom views like MessageView
  2979. //
  2980. if (DOBJ_CUSTOMOCX == (LPDATAOBJECT)arg)
  2981. {
  2982. if (m_pSelectedContainerNode != NULL)
  2983. {
  2984. CNodeList nodeList;
  2985. nodeList.AddTail(m_pSelectedContainerNode);
  2986. hr = m_pSelectedContainerNode->ToolbarNotify(static_cast<int>(param),
  2987. (CComponentDataObject*)m_pComponentData,
  2988. &nodeList);
  2989. }
  2990. else
  2991. {
  2992. hr = S_FALSE;
  2993. }
  2994. }
  2995. else
  2996. {
  2997. CInternalFormatCracker ifc;
  2998. hr = ifc.Extract((LPDATAOBJECT)arg);
  2999. CTreeNode* pNode = ifc.GetCookieAt(0);
  3000. ASSERT(pNode != NULL);
  3001. CNodeList nodeList;
  3002. ifc.GetCookieList(nodeList);
  3003. if (ifc.GetCookieCount() > 1) // multiple selection
  3004. {
  3005. ASSERT(pNode->GetContainer() != NULL);
  3006. hr = pNode->GetContainer()->ToolbarNotify(static_cast<int>(param),
  3007. (CComponentDataObject*)m_pComponentData,
  3008. &nodeList);
  3009. }
  3010. else if (ifc.GetCookieCount() == 1) // single selection
  3011. {
  3012. hr = pNode->ToolbarNotify(static_cast<int>(param),
  3013. (CComponentDataObject*)m_pComponentData,
  3014. &nodeList);
  3015. }
  3016. else
  3017. {
  3018. hr = S_FALSE;
  3019. }
  3020. }
  3021. break;
  3022. }
  3023. default:
  3024. {
  3025. break;
  3026. }
  3027. }
  3028. return hr;
  3029. }
  3030. ///////////////////////////////////////////////////////////////////////////////
  3031. // CComponentObject::IResultDataCompareEx members
  3032. // This compare is used to sort the item's in the listview
  3033. //
  3034. // Note: Assum sort is ascending when comparing.
  3035. STDMETHODIMP CComponentObject::Compare(RDCOMPARE* prdc, int* pnResult)
  3036. {
  3037. if (pnResult == NULL)
  3038. {
  3039. ASSERT(FALSE);
  3040. return E_POINTER;
  3041. }
  3042. if (prdc == NULL)
  3043. {
  3044. ASSERT(FALSE);
  3045. return E_POINTER;
  3046. }
  3047. CTreeNode* pNodeA = reinterpret_cast<CTreeNode*>(prdc->prdch1->cookie);
  3048. CTreeNode* pNodeB = reinterpret_cast<CTreeNode*>(prdc->prdch2->cookie);
  3049. ASSERT(pNodeA != NULL);
  3050. ASSERT(pNodeB != NULL);
  3051. CContainerNode* pContNode = pNodeA->GetContainer();
  3052. ASSERT(pContNode != NULL);
  3053. // delegate the sorting to the container
  3054. int nCol = prdc->nColumn;
  3055. *pnResult = pContNode->Compare(pNodeA, pNodeB, nCol, prdc->lUserParam);
  3056. return S_OK;
  3057. }
  3058. ///////////////////////////////////////////////////////////////////////////////
  3059. // CComponentObject Helpers
  3060. // This wrapper function required to make prefast shut up when we are
  3061. // initializing a critical section in a constructor.
  3062. void
  3063. ExceptionPropagatingInitializeCriticalSection(LPCRITICAL_SECTION critsec)
  3064. {
  3065. __try
  3066. {
  3067. ::InitializeCriticalSection(critsec);
  3068. }
  3069. //
  3070. // propagate the exception to our caller.
  3071. //
  3072. __except (EXCEPTION_CONTINUE_SEARCH)
  3073. {
  3074. }
  3075. }