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.

3332 lines
101 KiB

  1. // This is a part of the Microsoft Management Console.
  2. // Copyright (C) Microsoft Corporation, 1995 - 1999
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Microsoft Management Console and related
  7. // electronic documentation provided with the interfaces.
  8. #include "stdafx.h"
  9. #include "resource.h"
  10. #include "genpage.h"
  11. #include "chooser.h"
  12. #include "cryptui.h"
  13. #include "misc.h"
  14. #include <htmlhelp.h>
  15. #ifdef _DEBUG
  16. #undef THIS_FILE
  17. static char THIS_FILE[] = __FILE__;
  18. #endif
  19. // approx convert chars->pixels
  20. #define CHARS_TO_MMCCOLUMNWIDTH(__strlen__) ((int)(__strlen__ * 7))
  21. enum ENUM_MMCBUTTONS
  22. {
  23. ENUM_BUTTON_STARTSVC=0,
  24. ENUM_BUTTON_STOPSVC,
  25. };
  26. MY_MMCBUTTON SvrMgrToolbar1Buttons[] =
  27. {
  28. {
  29. { 0, IDC_STARTSERVER, TBSTATE_ENABLED, TBSTYLE_BUTTON, L"", L"" },
  30. IDS_TASKMENU_STARTSERVICE,
  31. IDS_TASKMENU_STATUSBAR_STARTSERVICE,
  32. },
  33. {
  34. { 1, IDC_STOPSERVER, TBSTATE_ENABLED, TBSTYLE_BUTTON, L"", L"" },
  35. IDS_TASKMENU_STOPSERVICE,
  36. IDS_TASKMENU_STATUSBAR_STOPSERVICE,
  37. },
  38. {
  39. { 0, 0, 0, 0, NULL, NULL },
  40. IDS_EMPTY,
  41. IDS_EMPTY,
  42. }
  43. };
  44. // Array of view items to be inserted into the context menu.
  45. // keep this enum in synch with viewItems[]
  46. enum ENUM_VIEW_ITEMS
  47. {
  48. ENUM_VIEW_ALL=0,
  49. ENUM_VIEW_FILTER,
  50. ENUM_VIEW_SEPERATOR,
  51. };
  52. MY_CONTEXTMENUITEM viewResultItems[] =
  53. {
  54. {
  55. {
  56. L"", L"",
  57. IDC_VIEW_ALLRECORDS, CCM_INSERTIONPOINTID_PRIMARY_VIEW, 0, 0
  58. },
  59. IDS_VIEWMENU_ALL_RECORDS,
  60. IDS_VIEWMENU_STATUSBAR_ALL_RECORDS,
  61. },
  62. {
  63. {
  64. L"", L"",
  65. IDC_VIEW_FILTER, CCM_INSERTIONPOINTID_PRIMARY_VIEW, 0, 0
  66. },
  67. IDS_VIEWMENU_FILTER,
  68. IDS_VIEWMENU_STATUSBAR_FILTER,
  69. },
  70. // seperator
  71. {
  72. {
  73. L"", L"",
  74. 0, CCM_INSERTIONPOINTID_PRIMARY_VIEW, MF_ENABLED, CCM_SPECIAL_SEPARATOR
  75. },
  76. IDS_EMPTY,
  77. IDS_EMPTY,
  78. },
  79. {
  80. { NULL, NULL, 0, 0, 0 },
  81. IDS_EMPTY,
  82. IDS_EMPTY,
  83. }
  84. };
  85. enum ENUM_TASK_SINGLESELITEMS
  86. {
  87. ENUM_TASK_SEPERATOR1=0,
  88. ENUM_TASK_UNREVOKE,
  89. };
  90. TASKITEM taskResultItemsSingleSel[] =
  91. {
  92. // seperator
  93. { SERVERFUNC_CRL_PUBLICATION,
  94. TRUE,
  95. {
  96. {
  97. L"", L"",
  98. 0, CCM_INSERTIONPOINTID_PRIMARY_TASK, MF_ENABLED, CCM_SPECIAL_SEPARATOR
  99. },
  100. IDS_EMPTY,
  101. IDS_EMPTY,
  102. }
  103. },
  104. { SERVERFUNC_CRL_PUBLICATION,
  105. TRUE,
  106. {
  107. {
  108. L"", L"",
  109. IDC_UNREVOKE_CERT, CCM_INSERTIONPOINTID_PRIMARY_TASK, MF_ENABLED, 0
  110. },
  111. IDS_TASKMENU_UNREVOKECERT,
  112. IDS_TASKMENU_STATUSBAR_UNREVOKECERT,
  113. }
  114. },
  115. { NONE,
  116. FALSE,
  117. {
  118. { NULL, NULL, 0, 0, 0 },
  119. IDS_EMPTY,
  120. IDS_EMPTY,
  121. }
  122. }
  123. };
  124. //
  125. // Extracts the coclass guid format from the data object
  126. //
  127. template <class TYPE>
  128. TYPE* Extract(LPDATAOBJECT lpDataObject, unsigned int cf)
  129. {
  130. ASSERT(lpDataObject != NULL);
  131. TYPE* p = NULL;
  132. STGMEDIUM stgmedium = { TYMED_HGLOBAL, NULL };
  133. FORMATETC formatetc = { (CLIPFORMAT)cf, NULL,
  134. DVASPECT_CONTENT, -1, TYMED_HGLOBAL
  135. };
  136. // Allocate memory for the stream
  137. int len;
  138. if (cf == CDataObject::m_cfSelectedCA_CommonName)
  139. len = (MAX_PATH+1) * sizeof(TYPE);
  140. else if (cf == CDataObject::m_cfSelectedCA_MachineName)
  141. len = (MAX_COMPUTERNAME_LENGTH+1) * sizeof(TYPE);
  142. else
  143. len = sizeof(TYPE);
  144. stgmedium.hGlobal = GlobalAlloc(GMEM_SHARE, len);
  145. // Get the workstation name from the data object
  146. do
  147. {
  148. if (stgmedium.hGlobal == NULL)
  149. break;
  150. if (FAILED(lpDataObject->GetDataHere(&formatetc, &stgmedium)))
  151. break;
  152. p = reinterpret_cast<TYPE*>(stgmedium.hGlobal);
  153. if (p == NULL)
  154. break;
  155. } while (FALSE);
  156. return p;
  157. }
  158. BOOL IsMMCMultiSelectDataObject(LPDATAOBJECT pDataObject)
  159. {
  160. if (pDataObject == NULL)
  161. return FALSE;
  162. FORMATETC fmt = {(CLIPFORMAT)CDataObject::m_cfIsMultiSel, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  163. return (pDataObject->QueryGetData(&fmt) == S_OK);
  164. }
  165. // rip real pDataObject out of SMMCDataObjects struct
  166. HGLOBAL GetMMCMultiSelDataObject(LPDATAOBJECT pDataObject)
  167. {
  168. if (pDataObject == NULL)
  169. return FALSE;
  170. static unsigned int s_cf = 0;
  171. if (s_cf == 0)
  172. s_cf = RegisterClipboardFormatW(CCF_MULTI_SELECT_SNAPINS);
  173. STGMEDIUM stgmedium = { TYMED_HGLOBAL, NULL };
  174. FORMATETC fmt = {(CLIPFORMAT)s_cf, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  175. if (FAILED(pDataObject->GetData(&fmt, &stgmedium)))
  176. return NULL;
  177. return stgmedium.hGlobal;
  178. }
  179. // Data object extraction helpers
  180. CLSID* ExtractClassID(LPDATAOBJECT lpDataObject)
  181. {
  182. return Extract<CLSID>(lpDataObject, CDataObject::m_cfCoClass);
  183. }
  184. HGLOBAL ExtractNodeID(LPDATAOBJECT lpDataObject)
  185. {
  186. if (lpDataObject == NULL)
  187. return FALSE;
  188. static unsigned int s_cf = 0;
  189. if (s_cf == 0)
  190. s_cf = RegisterClipboardFormatW(CCF_COLUMN_SET_ID);
  191. STGMEDIUM stgmedium = { TYMED_HGLOBAL, NULL };
  192. FORMATETC fmt = {(CLIPFORMAT)s_cf, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  193. if (FAILED(lpDataObject->GetData(&fmt, &stgmedium)))
  194. return NULL;
  195. return stgmedium.hGlobal;
  196. }
  197. GUID* ExtractNodeType(LPDATAOBJECT lpDataObject)
  198. {
  199. return Extract<GUID>(lpDataObject, CDataObject::m_cfNodeType);
  200. }
  201. INTERNAL* ExtractInternalFormat(LPDATAOBJECT lpDataObject)
  202. {
  203. HRESULT hr;
  204. if (lpDataObject == NULL)
  205. return NULL;
  206. // see if this is a multisel object
  207. HGLOBAL hMem = NULL;
  208. SMMCDataObjects* pRealObjectStruct = NULL;
  209. INTERNAL* pRet = NULL;
  210. if (IsMMCMultiSelectDataObject(lpDataObject))
  211. {
  212. // multisel object: extract real SMMCDataObjects
  213. hMem = GetMMCMultiSelDataObject(lpDataObject);
  214. _JumpIfOutOfMemory(hr, Ret, hMem);
  215. pRealObjectStruct = (SMMCDataObjects*)::GlobalLock(hMem);
  216. _JumpIfOutOfMemory(hr, Ret, pRealObjectStruct);
  217. // may be a number of data objs in here; find OURS
  218. BOOL fFound = FALSE;
  219. for (DWORD i=0; i<pRealObjectStruct->count; i++)
  220. {
  221. CLSID* pExtractedID = ExtractClassID(pRealObjectStruct->lpDataObject[i]);
  222. if (NULL != pExtractedID)
  223. {
  224. if (IsEqualCLSID(CLSID_Snapin, *pExtractedID))
  225. {
  226. fFound = TRUE;
  227. break;
  228. }
  229. // Free resources
  230. GlobalFree(reinterpret_cast<HANDLE>(pExtractedID));
  231. }
  232. }
  233. if (!fFound)
  234. goto Ret;
  235. // data obj that matches our CLSID
  236. lpDataObject = pRealObjectStruct->lpDataObject[i];
  237. }
  238. pRet = Extract<INTERNAL>(lpDataObject, CDataObject::m_cfInternal);
  239. if (pRet == NULL)
  240. {
  241. hr = myHLastError();
  242. _PrintIfError(hr, "Extract CDO::m_cfInternal returned NULL");
  243. }
  244. Ret:
  245. // free hMem
  246. if (NULL != hMem)
  247. {
  248. GlobalUnlock(hMem);
  249. GlobalFree(hMem);
  250. }
  251. return pRet;
  252. }
  253. /*
  254. // only for use by OnRefresh -- this is a worker fxn
  255. void CSnapin::RefreshFolder(CFolder* pFolder)
  256. {
  257. MMC_COOKIE cookie = (MMC_COOKIE)pFolder;
  258. if (pFolder != NULL) // not base folder
  259. {
  260. // HIDE, remove all items, remove header, SHOW
  261. OnShow(cookie, FALSE, 0); // emulate HIDE
  262. m_pResult->DeleteAllRsltItems(); // delete items from m_pResult
  263. while(S_OK == m_pHeader->DeleteColumn(0)) {}; // remove all cols from header
  264. OnShow(cookie, TRUE, 0); // emulate SHOW
  265. }
  266. return;
  267. }
  268. */
  269. CFolder* CSnapin::GetParentFolder(INTERNAL* pInternal)
  270. {
  271. CFolder* p;
  272. if(m_bVirtualView)
  273. p = GetVirtualFolder();
  274. else
  275. p = ::GetParentFolder(pInternal);
  276. #if DBG
  277. if (p != m_pCurrentlySelectedScopeFolder)
  278. {
  279. if (NULL == p)
  280. DBGPRINT((DBG_SS_CERTMMC, "Parent derived NULL, current saved folder is <%ws>\n", m_pCurrentlySelectedScopeFolder->m_pszName));
  281. else if (NULL == m_pCurrentlySelectedScopeFolder)
  282. DBGPRINT((DBG_SS_CERTMMC, "Parent derived as <%ws>, current saved folder is NULL\n", p->m_pszName));
  283. else
  284. DBGPRINT((DBG_SS_CERTMMC, "Parent derived as <%ws>, current saved folder is <%ws>\n", p->m_pszName, m_pCurrentlySelectedScopeFolder->m_pszName));
  285. }
  286. #endif
  287. return p;
  288. }
  289. // independent of scope/result type, will return parent folder
  290. CFolder* GetParentFolder(INTERNAL* pInternal)
  291. {
  292. if (NULL == pInternal)
  293. return NULL;
  294. if (CCT_SCOPE == pInternal->m_type)
  295. {
  296. return reinterpret_cast<CFolder*>(pInternal->m_cookie);
  297. }
  298. else if (CCT_RESULT == pInternal->m_type)
  299. {
  300. RESULT_DATA* pData = reinterpret_cast<RESULT_DATA*>(pInternal->m_cookie);
  301. ASSERT(pData != NULL);
  302. if (pData != NULL)
  303. return pData->pParentFolder;
  304. }
  305. return NULL;
  306. }
  307. HRESULT _QueryDataObject(MMC_COOKIE cookie, DATA_OBJECT_TYPES type, DWORD dwViewID,
  308. CComponentDataImpl* pImpl, LPDATAOBJECT* ppDataObject)
  309. {
  310. ASSERT(ppDataObject != NULL);
  311. ASSERT(pImpl != NULL);
  312. CComObject<CDataObject>* pObject;
  313. CComObject<CDataObject>::CreateInstance(&pObject);
  314. ASSERT(pObject != NULL);
  315. if (pObject == NULL)
  316. return E_OUTOFMEMORY;
  317. // Save cookie and type for delayed rendering
  318. pObject->SetType(type);
  319. pObject->SetCookie(cookie);
  320. pObject->SetViewID(dwViewID);
  321. // tell dataobj who we are
  322. pObject->SetComponentData(pImpl);
  323. // Store the coclass with the data object
  324. pObject->SetClsid(pImpl->GetCoClassID());
  325. return pObject->QueryInterface(IID_IDataObject,
  326. reinterpret_cast<void**>(ppDataObject));
  327. }
  328. /////////////////////////////////////////////////////////////////////////////
  329. // Return TRUE if we are enumerating our main folder
  330. BOOL CSnapin::IsEnumerating(LPDATAOBJECT lpDataObject)
  331. {
  332. BOOL bResult = FALSE;
  333. ASSERT(lpDataObject);
  334. GUID* nodeType = ExtractNodeType(lpDataObject);
  335. if (NULL != nodeType)
  336. {
  337. // Is this my main node (static folder node type)
  338. if (::IsEqualGUID(*nodeType, cNodeTypeMachineInstance) == TRUE)
  339. bResult = TRUE;
  340. // Free resources
  341. ::GlobalFree(reinterpret_cast<HANDLE>(nodeType));
  342. }
  343. return bResult;
  344. }
  345. /////////////////////////////////////////////////////////////////////////////
  346. // CSnapin's IComponent implementation
  347. STDMETHODIMP CSnapin::GetResultViewType(MMC_COOKIE cookie, LPOLESTR* ppViewType, LONG* pViewOptions)
  348. {
  349. m_bVirtualView = FALSE;
  350. // custom view: check guid
  351. if (NULL == cookie)
  352. {
  353. *pViewOptions = MMC_VIEW_OPTIONS_NONE;
  354. return S_FALSE;
  355. }
  356. *pViewOptions = MMC_VIEW_OPTIONS_MULTISELECT | MMC_VIEW_OPTIONS_NOLISTVIEWS;
  357. // if ISSUED_CERT then make virtual list
  358. CFolder* pFolder = (CFolder*)cookie;
  359. if ((SERVERFUNC_CRL_PUBLICATION == pFolder->GetType()) ||
  360. (SERVERFUNC_ISSUED_CERTIFICATES == pFolder->GetType()) ||
  361. (SERVERFUNC_PENDING_CERTIFICATES == pFolder->GetType()) ||
  362. (SERVERFUNC_FAILED_CERTIFICATES == pFolder->GetType()) ||
  363. (SERVERFUNC_ALIEN_CERTIFICATES == pFolder->GetType()) )
  364. {
  365. *pViewOptions |= MMC_VIEW_OPTIONS_OWNERDATALIST;
  366. m_bVirtualView = TRUE;
  367. }
  368. // if list view
  369. return S_FALSE;
  370. }
  371. STDMETHODIMP CSnapin::Initialize(LPCONSOLE lpConsole)
  372. {
  373. HRESULT hr;
  374. ASSERT(lpConsole != NULL);
  375. m_bInitializedC = true;
  376. // Save the IConsole pointer
  377. if (lpConsole == NULL)
  378. return E_POINTER;
  379. hr = lpConsole->QueryInterface(IID_IConsole2,
  380. reinterpret_cast<void**>(&m_pConsole));
  381. _JumpIfError(hr, Ret, "QI IID_IConsole2");
  382. // QI for a IHeaderCtrl
  383. hr = m_pConsole->QueryInterface(IID_IHeaderCtrl,
  384. reinterpret_cast<void**>(&m_pHeader));
  385. _JumpIfError(hr, Ret, "QI IID_IHeaderCtrl");
  386. // Give the console the header control interface pointer
  387. m_pConsole->SetHeader(m_pHeader);
  388. m_pConsole->QueryInterface(IID_IResultData,
  389. reinterpret_cast<void**>(&m_pResult));
  390. _JumpIfError(hr, Ret, "QI IID_IResultData");
  391. hr = m_pConsole->QueryResultImageList(&m_pImageResult);
  392. _JumpIfError(hr, Ret, "QueryResultImageList");
  393. hr = m_pConsole->QueryConsoleVerb(&m_pConsoleVerb);
  394. _JumpIfError(hr, Ret, "QueryConsoleVerb");
  395. hr = m_pConsole->QueryInterface(IID_IColumnData,
  396. reinterpret_cast<void**>(&m_pViewData));
  397. _JumpIfError(hr, Ret, "QI IID_IViewData");
  398. Ret:
  399. return hr;
  400. }
  401. // called by CompDataImpl on creation
  402. void CSnapin::SetIComponentData(CComponentDataImpl* pData)
  403. {
  404. ASSERT(pData);
  405. ASSERT(m_pComponentData == NULL);
  406. LPUNKNOWN pUnk = pData->GetUnknown();
  407. HRESULT hr;
  408. hr = pUnk->QueryInterface(IID_IComponentData, reinterpret_cast<void**>(&m_pComponentData));
  409. ASSERT(hr == S_OK);
  410. }
  411. STDMETHODIMP CSnapin::Destroy(MMC_COOKIE cookie)
  412. {
  413. ASSERT(m_bInitializedC);
  414. m_bDestroyedC = true;
  415. // Release the interfaces that we QI'ed
  416. if (m_pConsole != NULL)
  417. {
  418. // Tell the console to release the header control interface
  419. m_pConsole->SetHeader(NULL);
  420. SAFE_RELEASE(m_pHeader);
  421. SAFE_RELEASE(m_pResult);
  422. SAFE_RELEASE(m_pImageResult);
  423. // Release the IConsole interface last
  424. SAFE_RELEASE(m_pConsole);
  425. SAFE_RELEASE(m_pComponentData); // QI'ed in CSnapin::SetIComponent
  426. SAFE_RELEASE(m_pConsoleVerb);
  427. SAFE_RELEASE(m_pViewData);
  428. }
  429. return S_OK;
  430. }
  431. STDMETHODIMP CSnapin::Notify(LPDATAOBJECT lpDataObject, MMC_NOTIFY_TYPE event, LPARAM arg, LPARAM param)
  432. {
  433. HRESULT hr = S_OK;
  434. MMC_COOKIE cookie=0;
  435. if (IS_SPECIAL_DATAOBJECT(lpDataObject))
  436. {
  437. if (event == MMCN_BTN_CLICK)
  438. {
  439. if (m_CustomViewID != VIEW_DEFAULT_LV)
  440. {
  441. switch (param)
  442. {
  443. case MMC_VERB_REFRESH:
  444. OnRefresh(lpDataObject);
  445. break;
  446. case MMC_VERB_PROPERTIES:
  447. break;
  448. default:
  449. DBGPRINT((DBG_SS_CERTMMC, "MMCN_BTN_CLICK::param unknown"));
  450. break;
  451. }
  452. }
  453. }
  454. else
  455. {
  456. switch (event)
  457. {
  458. case MMCN_VIEW_CHANGE:
  459. case MMCN_REFRESH:
  460. OnRefresh(lpDataObject);
  461. break;
  462. case MMCN_COLUMN_CLICK:
  463. // On click, we need to fix sorting.
  464. // Sorting info is usually retrieved from the view, but if a user column-clicks,
  465. // IComponent::Sort is called before GetColumnSortData() is updated.
  466. // In this case, we capture notification here and override GetColumnSortData() wrapper,
  467. // and force a folder refresh.
  468. // ask "IComponent::SortItems" if this is a valid column to sort on
  469. hr = SortItems((int)arg, (DWORD)param, NULL);
  470. // is sort allowed?
  471. if (S_OK == hr)
  472. {
  473. m_ColSortOverride.colIdx = (int)arg;
  474. m_ColSortOverride.dwOptions = (DWORD)param;
  475. }
  476. else
  477. {
  478. // don't allow sort
  479. m_ColSortOverride.colIdx = -1;
  480. }
  481. m_ColSortOverride.fClickOverride = TRUE;
  482. // notify view: sort was chosen
  483. OnRefresh(lpDataObject);
  484. m_ColSortOverride.fClickOverride = FALSE;
  485. // bug 322746: since we're add/removing columns we should send Sort request
  486. // m_pResult->Sort((int)arg, (DWORD)param, NULL);
  487. break;
  488. }
  489. }
  490. return S_OK;
  491. }
  492. switch(event)
  493. {
  494. case MMCN_VIEW_CHANGE:
  495. hr = OnUpdateView(lpDataObject, arg);
  496. break;
  497. case MMCN_DESELECT_ALL:
  498. break;
  499. case MMCN_COLUMN_CLICK:
  500. break;
  501. case MMCN_SNAPINHELP:
  502. break;
  503. case MMCN_HELP:
  504. default:
  505. {
  506. INTERNAL* pInternal = NULL;
  507. if (IsMMCMultiSelectDataObject(lpDataObject) == FALSE)
  508. {
  509. pInternal = ExtractInternalFormat(lpDataObject);
  510. if (pInternal == NULL)
  511. {
  512. ASSERT(FALSE);
  513. return S_OK;
  514. }
  515. if (pInternal)
  516. cookie = pInternal->m_cookie;
  517. }
  518. switch(event)
  519. {
  520. case MMCN_ACTIVATE:
  521. break;
  522. case MMCN_CLICK:
  523. hr = S_OK;
  524. break;
  525. case MMCN_DBLCLICK:
  526. // handle dblclick on Issued, CRL result items
  527. if (pInternal && (CCT_RESULT == pInternal->m_type))
  528. {
  529. CFolder* pFolder = GetParentFolder(pInternal);
  530. // if not base scope
  531. ASSERT(pFolder != NULL);
  532. if (pFolder == NULL)
  533. {
  534. hr = S_FALSE;
  535. break;
  536. }
  537. // switch on folder type
  538. switch(pFolder->m_type)
  539. {
  540. case SERVERFUNC_ISSUED_CERTIFICATES:
  541. case SERVERFUNC_CRL_PUBLICATION:
  542. case SERVERFUNC_ALIEN_CERTIFICATES:
  543. ASSERT(!IsMMCMultiSelectDataObject(lpDataObject));
  544. if (!IsMMCMultiSelectDataObject(lpDataObject))
  545. Command(IDC_VIEW_CERT_PROPERTIES, lpDataObject);
  546. break;
  547. default:
  548. break;
  549. }
  550. }
  551. hr = S_FALSE; // returning S_FALSE here means "Do the default verb"
  552. break;
  553. case MMCN_ADD_IMAGES:
  554. OnAddImages(cookie, arg, param);
  555. break;
  556. case MMCN_SHOW:
  557. hr = OnShow(cookie, arg, param);
  558. break;
  559. case MMCN_MINIMIZED:
  560. hr = S_OK;
  561. break;
  562. case MMCN_INITOCX:
  563. break;
  564. case MMCN_DESELECT_ALL:
  565. case MMCN_SELECT:
  566. HandleStandardVerbs((event == MMCN_DESELECT_ALL),
  567. arg, lpDataObject);
  568. break;
  569. case MMCN_PASTE:
  570. break;
  571. case MMCN_DELETE:
  572. break;
  573. case MMCN_CONTEXTHELP:
  574. hr = OnContextHelp(lpDataObject);
  575. break;
  576. case MMCN_REFRESH:
  577. OnRefresh(lpDataObject);
  578. break;
  579. case MMCN_RENAME:
  580. break;
  581. case MMCN_COLUMNS_CHANGED:
  582. {
  583. MMC_VISIBLE_COLUMNS* psMMCCols = (MMC_VISIBLE_COLUMNS*)param;
  584. if (psMMCCols == NULL)
  585. break;
  586. MMC_COLUMN_SET_DATA* pColSetData;
  587. #if DEBUG_COLUMNS_CHANGED
  588. hr = GetColumnSetData(cookie, &pColSetData);
  589. if (hr == S_OK)
  590. {
  591. DBGPRINT((DBG_SS_CERTMMC, "GetColumnSetData:\n"));
  592. for (int i=0; i<pColSetData->nNumCols; i++)
  593. {
  594. DBGPRINT((DBG_SS_CERTMMC,
  595. L"pColData[%i]->nColIndex=%i (%s)\n", i, pColSetData->pColData[i].nColIndex,
  596. (pColSetData->pColData[i].dwFlags == HDI_HIDDEN) ? "hidden" : "shown"));
  597. }
  598. DBGPRINT((DBG_SS_CERTMMC, "VISIBLE_COLUMNS structure:\n"));
  599. for (i=0; i<psMMCCols->nVisibleColumns; i++)
  600. {
  601. DBGPRINT((DBG_SS_CERTMMC, L"Col %i is shown\n", psMMCCols->rgVisibleCols[i]));
  602. }
  603. if (pColSetData)
  604. CoTaskMemFree(pColSetData);
  605. }
  606. #endif // DEBUG_COLUMNS_CHANGED
  607. // On click, we need to fix column data
  608. // This is analagous to the sort problem above -- we're given this notification
  609. // before we can properly call GetColumnSetData(). Refresh does this, so we
  610. // have to inform GetColumnSetData() of our true intent.
  611. // fill in a fake COLUMN_SET_DATA, make it override
  612. DWORD dwSize = sizeof(MMC_COLUMN_SET_DATA) + (psMMCCols->nVisibleColumns)*sizeof(MMC_COLUMN_DATA);
  613. pColSetData = (MMC_COLUMN_SET_DATA* )LocalAlloc(LMEM_FIXED|LMEM_ZEROINIT, dwSize);
  614. if (pColSetData)
  615. {
  616. pColSetData->cbSize = sizeof(MMC_COLUMN_SET_DATA);
  617. pColSetData->nNumCols = psMMCCols->nVisibleColumns;
  618. pColSetData->pColData = (MMC_COLUMN_DATA*) ((PBYTE)pColSetData + sizeof(MMC_COLUMN_SET_DATA)); // point just after struct
  619. MMC_COLUMN_DATA* pEntry = pColSetData->pColData;
  620. for (int i=0; i<pColSetData->nNumCols ; i++)
  621. {
  622. pEntry->nColIndex = psMMCCols->rgVisibleCols[i];
  623. pEntry++;
  624. }
  625. m_ColSetOverride.pColSetData = pColSetData;
  626. m_ColSetOverride.fClickOverride = TRUE;
  627. }
  628. // refresh to kick off requery: columns changed!
  629. OnRefresh(lpDataObject);
  630. // teardown
  631. m_ColSetOverride.fClickOverride = FALSE;
  632. if (m_ColSetOverride.pColSetData)
  633. LocalFree(m_ColSetOverride.pColSetData);
  634. }
  635. break;
  636. // Note - Future expansion of notify types possible
  637. default:
  638. hr = E_UNEXPECTED;
  639. break;
  640. }
  641. FREE_DATA(pInternal);
  642. break;
  643. }
  644. }
  645. return hr;
  646. }
  647. HRESULT CSnapin::OnUpdateView(LPDATAOBJECT pDataObject, LPARAM arg)
  648. {
  649. OnRefresh(pDataObject);
  650. return S_OK;
  651. }
  652. void CSnapin::OnRefresh(LPDATAOBJECT pDataObject)
  653. {
  654. CWaitCursor cwait; // Could be long operation
  655. CComponentDataImpl* pData = dynamic_cast<CComponentDataImpl*>(m_pComponentData);
  656. ASSERT(pData != NULL);
  657. INTERNAL* pInternal = ExtractInternalFormat(pDataObject);
  658. // only allow scope refresh
  659. if ((pInternal == NULL) || (pInternal->m_type == CCT_SCOPE))
  660. {
  661. // refresh toolbars
  662. pData->m_pCertMachine->RefreshServiceStatus();
  663. pData->UpdateScopeIcons();
  664. SmartEnableServiceControlButtons();
  665. }
  666. /*
  667. // Refresh the selected folder
  668. CFolder* pFolder = GetParentFolder(pInternal);
  669. RefreshFolder(pFolder);
  670. */
  671. // Instead, re-select the current folder (acts like refresh)
  672. // note side-effect: it causes race condition between redraw and
  673. // MMCN_COLUMN_CLICKED database query -- MMC asks to draw cols that don't exist
  674. if (m_pConsole && m_pCurrentlySelectedScopeFolder)
  675. m_pConsole->SelectScopeItem(m_pCurrentlySelectedScopeFolder->m_ScopeItem.ID);
  676. FREE_DATA(pInternal);
  677. }
  678. HRESULT CSnapin::OnContextHelp(LPDATAOBJECT pdtobj)
  679. {
  680. HRESULT hr = S_OK;
  681. CString cstrHelpFile;
  682. IDisplayHelp* pDisplayHelp = NULL;
  683. WCHAR szWindows[MAX_PATH];
  684. szWindows[0] = L'\0';
  685. hr = m_pConsole->QueryInterface (IID_IDisplayHelp, (void**)&pDisplayHelp);
  686. _JumpIfError(hr, Ret, "QI IDisplayHelp");
  687. if (0 == GetSystemWindowsDirectory(szWindows, MAX_PATH))
  688. {
  689. hr = myHLastError();
  690. _JumpError(hr, Ret, "GetSystemWindowsDirectory");
  691. }
  692. cstrHelpFile = szWindows;
  693. cstrHelpFile += HTMLHELP_COLLECTIONLINK_FILENAME;
  694. cstrHelpFile += L"::/sag_cs_topnode.htm";
  695. hr = pDisplayHelp->ShowTopic (T2OLE ((LPWSTR)(LPCWSTR)cstrHelpFile));
  696. _JumpIfError(hr, Ret, "ShowTopic");
  697. Ret:
  698. if (pDisplayHelp)
  699. pDisplayHelp->Release();
  700. return hr;
  701. }
  702. HRESULT CSnapin::QueryMultiSelectDataObject(MMC_COOKIE cookie, DATA_OBJECT_TYPES type,
  703. LPDATAOBJECT* ppDataObject)
  704. {
  705. const GUID* pguid;
  706. ASSERT(ppDataObject != NULL);
  707. if (ppDataObject == NULL)
  708. return E_POINTER;
  709. if (m_bVirtualView == TRUE)
  710. {
  711. ASSERT(GetVirtualFolder());
  712. switch(GetVirtualFolder()->GetType())
  713. {
  714. case SERVERFUNC_CRL_PUBLICATION:
  715. pguid = &cNodeTypeCRLPublication;
  716. break;
  717. case SERVERFUNC_ISSUED_CERTIFICATES:
  718. pguid = &cNodeTypeIssuedCerts;
  719. break;
  720. case SERVERFUNC_PENDING_CERTIFICATES:
  721. pguid = &cNodeTypePendingCerts;
  722. break;
  723. case SERVERFUNC_FAILED_CERTIFICATES:
  724. pguid = &cNodeTypeFailedCerts;
  725. break;
  726. case SERVERFUNC_ALIEN_CERTIFICATES:
  727. pguid = &cNodeTypeAlienCerts;
  728. break;
  729. default:
  730. return E_FAIL;
  731. }
  732. }
  733. CComObject<CDataObject>* pObject;
  734. CComObject<CDataObject>::CreateInstance(&pObject);
  735. ASSERT(pObject != NULL);
  736. if (NULL == pObject)
  737. return E_FAIL;
  738. // Save cookie and type for delayed rendering
  739. // fix type if unknown (is this valid?)
  740. if (type == CCT_UNINITIALIZED)
  741. type = CCT_RESULT;
  742. pObject->SetType(type);
  743. pObject->SetCookie(cookie);
  744. pObject->SetMultiSelDobj();
  745. CComponentDataImpl* pImpl = dynamic_cast<CComponentDataImpl*>(m_pComponentData);
  746. #ifdef _DEBUG
  747. pObject->SetComponentData(pImpl);
  748. #endif
  749. // Store the coclass with the data object
  750. pObject->SetClsid(pImpl->GetCoClassID());
  751. // right now we know we have just 1 objtype
  752. SMMCObjectTypes sGuidObjTypes;
  753. sGuidObjTypes.count = 1;
  754. CopyMemory(&sGuidObjTypes.guid[0], pguid, sizeof(GUID));
  755. pObject->SetMultiSelData(&sGuidObjTypes, sizeof(sGuidObjTypes));
  756. return pObject->QueryInterface(IID_IDataObject,
  757. reinterpret_cast<void**>(ppDataObject));
  758. }
  759. STDMETHODIMP CSnapin::QueryDataObject(MMC_COOKIE cookie, DATA_OBJECT_TYPES type,
  760. LPDATAOBJECT* ppDataObject)
  761. {
  762. HRESULT hr;
  763. if (cookie == MMC_MULTI_SELECT_COOKIE)
  764. {
  765. hr = QueryMultiSelectDataObject(cookie, type, ppDataObject);
  766. }
  767. else
  768. {
  769. // behavior: we may query for result or scope pane dataobjects
  770. // Delegate it to the IComponentData
  771. ASSERT(m_pComponentData != NULL);
  772. CComponentDataImpl* pImpl = dynamic_cast<CComponentDataImpl*>(m_pComponentData);
  773. ASSERT(pImpl != NULL);
  774. // Query for dataobj -- cookie is index
  775. hr = _QueryDataObject(cookie, type, m_dwViewID, pImpl, ppDataObject);
  776. }
  777. return hr;
  778. }
  779. /////////////////////////////////////////////////////////////////////////////
  780. // CSnapin's implementation specific members
  781. DEBUG_DECLARE_INSTANCE_COUNTER(CSnapin);
  782. CSnapin::CSnapin()
  783. : m_bIsDirty(TRUE), m_bInitializedC(false), m_bDestroyedC(false)
  784. {
  785. DEBUG_INCREMENT_INSTANCE_COUNTER(CSnapin);
  786. Construct();
  787. }
  788. CSnapin::~CSnapin()
  789. {
  790. #if DBG==1
  791. ASSERT(dbg_cRef == 0);
  792. #endif
  793. DEBUG_DECREMENT_INSTANCE_COUNTER(CSnapin);
  794. SAFE_RELEASE(m_pSvrMgrToolbar1);
  795. if (m_pControlbar)
  796. SAFE_RELEASE(m_pControlbar);
  797. // Make sure the interfaces have been released
  798. ASSERT(m_pConsole == NULL);
  799. ASSERT(m_pHeader == NULL);
  800. ASSERT(m_pSvrMgrToolbar1 == NULL);
  801. ASSERT(!m_bInitializedC || m_bDestroyedC);
  802. Construct();
  803. }
  804. void CSnapin::Construct()
  805. {
  806. #if DBG==1
  807. dbg_cRef = 0;
  808. #endif
  809. m_pConsole = NULL;
  810. m_pHeader = NULL;
  811. m_pResult = NULL;
  812. m_pImageResult = NULL;
  813. m_pComponentData = NULL;
  814. m_bVirtualView = FALSE;
  815. m_pCurrentlySelectedScopeFolder = NULL;
  816. m_pControlbar = NULL;
  817. m_pSvrMgrToolbar1 = NULL;
  818. m_pConsoleVerb = NULL;
  819. m_ColSortOverride.fClickOverride = FALSE;
  820. m_ColSetOverride.fClickOverride = FALSE;
  821. m_ColSetOverride.pColSetData = NULL;
  822. m_CustomViewID = VIEW_DEFAULT_LV;
  823. m_dwViewID = -1;
  824. m_cViewCalls = 0;
  825. }
  826. HRESULT CSnapin::SynchColumns(MMC_COOKIE cookie)
  827. {
  828. HRESULT hr = S_OK;
  829. CString* rgcstrCurSchemaHeading = NULL;
  830. LONG* rglCurSchemaType = NULL;
  831. BOOL* rgfCurSchemaIndexed = NULL;
  832. DWORD cCurSchemaEntries = 0;
  833. int i;
  834. BOOL fSchemaChanged = FALSE;
  835. CFolder* pFolder = reinterpret_cast<CFolder*>(cookie);
  836. CComponentDataImpl* pData = dynamic_cast<CComponentDataImpl*>(m_pComponentData);
  837. if ((pFolder == NULL) || (NULL == pData))
  838. {
  839. hr = E_POINTER;
  840. _JumpError(hr, Ret, "pFolder or pData");
  841. }
  842. // if CCompDataImpl.m_rgLastKnownSchema is empty
  843. // enumerate "Current Schema" and save in CCompDataImpl.m_rgLastKnownSchema
  844. // only resolve schema once per ccompdataimpl load
  845. if (!pData->m_fSchemaWasResolved) // really, "SchemaWasUpdated"
  846. {
  847. pData->m_fSchemaWasResolved = TRUE;
  848. // get new schema
  849. hr = GetCurrentColumnSchema(
  850. pFolder->m_pCertCA->m_strConfig,
  851. &rgcstrCurSchemaHeading,
  852. &rglCurSchemaType,
  853. &rgfCurSchemaIndexed,
  854. (LONG*) &cCurSchemaEntries);
  855. _JumpIfError(hr, Ret, "GetCurrentColumnSchema");
  856. if (cCurSchemaEntries != pData->GetSchemaEntries())
  857. {
  858. fSchemaChanged = TRUE;
  859. DBGPRINT((DBG_SS_CERTMMC, "Schema change detected: knew %i, now %i entries\n", pData->GetSchemaEntries(), cCurSchemaEntries));
  860. }
  861. else
  862. {
  863. // for each entry, compare headings
  864. // report any diffc
  865. for (DWORD iEntry=0; iEntry<cCurSchemaEntries; iEntry++)
  866. {
  867. LPCWSTR sz;
  868. hr = pData->GetDBSchemaEntry(iEntry, &sz, NULL, NULL);
  869. _JumpIfError(hr, Ret, "GetDbSchemaEntry");
  870. if (!rgcstrCurSchemaHeading[iEntry].IsEqual(sz))
  871. {
  872. fSchemaChanged = TRUE;
  873. DBGPRINT((DBG_SS_CERTMMC, "Schema change detected: entry %i changed\n", iEntry));
  874. break;
  875. }
  876. }
  877. }
  878. // boot old schema which only included strings.
  879. // now we have types and indexes
  880. DBGPRINT((DBG_SS_CERTMMC, "Updating saved schema\n"));
  881. hr = pData->SetDBSchema(rgcstrCurSchemaHeading, rglCurSchemaType, rgfCurSchemaIndexed, cCurSchemaEntries);
  882. _JumpIfError(hr, Ret, "SetDBSchema");
  883. // these are now owned by the class
  884. rgcstrCurSchemaHeading = NULL;
  885. rglCurSchemaType = NULL;
  886. rgfCurSchemaIndexed = NULL;
  887. cCurSchemaEntries = 0;
  888. if (fSchemaChanged)
  889. {
  890. DBGPRINT((DBG_SS_CERTMMC, "Resetting folders\n"));
  891. pData->ResetPersistedColumnInformation(); // create a new instance id (throws away all column width info)
  892. // whack every loaded folder
  893. POSITION pos = pData->m_scopeItemList.GetHeadPosition();
  894. while (pos)
  895. {
  896. CFolder* pTmp = pData->m_scopeItemList.GetNext(pos);
  897. ASSERT(pTmp);
  898. if (pTmp == NULL)
  899. hr = E_UNEXPECTED;
  900. _JumpIfError(hr, Ret, "GetNext(pos) returns NULL");
  901. // if we find a folder with the same CA
  902. if (pTmp->GetCA() == pFolder->GetCA())
  903. {
  904. switch (pTmp->GetType())
  905. {
  906. case SERVERFUNC_PENDING_CERTIFICATES:
  907. case SERVERFUNC_CRL_PUBLICATION:
  908. case SERVERFUNC_ISSUED_CERTIFICATES:
  909. case SERVERFUNC_FAILED_CERTIFICATES:
  910. case SERVERFUNC_ALIEN_CERTIFICATES:
  911. // clear out cached data, it is stale
  912. m_RowEnum.ResetColumnCount(pData->GetSchemaEntries());
  913. break;
  914. default:
  915. break;
  916. } // end case
  917. } // end if
  918. } // end while folders
  919. } // end if schema changed
  920. }
  921. Ret:
  922. if (rgcstrCurSchemaHeading)
  923. delete [] rgcstrCurSchemaHeading;
  924. if (rglCurSchemaType)
  925. delete [] rglCurSchemaType;
  926. if (rgfCurSchemaIndexed)
  927. delete [] rgfCurSchemaIndexed;
  928. return hr;
  929. }
  930. HRESULT CSnapin::GetColumnSetData(MMC_COOKIE cookie, MMC_COLUMN_SET_DATA** ppColSetData)
  931. {
  932. HRESULT hr;
  933. if (m_ColSetOverride.fClickOverride)
  934. {
  935. // give caller structure to free, but caller doesn't care that
  936. // he just gets a reference to our COLUMN_DATA array...
  937. *ppColSetData = (MMC_COLUMN_SET_DATA*)CoTaskMemAlloc(sizeof(MMC_COLUMN_SET_DATA));
  938. if (NULL != *ppColSetData)
  939. {
  940. CopyMemory(*ppColSetData, m_ColSetOverride.pColSetData, sizeof(MMC_COLUMN_SET_DATA));
  941. return S_OK;
  942. }
  943. // else fall through; worst case is "Err Invalid Index..." in UI
  944. }
  945. HGLOBAL hSNode2 = NULL;
  946. SColumnSetID* pColID = NULL;
  947. LPDATAOBJECT lpDataObject = NULL;
  948. hr = _QueryDataObject(cookie, CCT_SCOPE, m_dwViewID,
  949. reinterpret_cast<CComponentDataImpl*>(m_pComponentData), &lpDataObject);
  950. _JumpIfError(hr, Ret, "_QueryDataObject");
  951. hSNode2 = ExtractNodeID(lpDataObject);
  952. _JumpIfOutOfMemory(hr, Ret, hSNode2);
  953. pColID = (SColumnSetID*)GlobalLock(hSNode2);
  954. _JumpIfOutOfMemory(hr, Ret, pColID);
  955. hr = m_pViewData->GetColumnConfigData(pColID, ppColSetData);
  956. _PrintIfError(hr, "GetColumnConfigData");
  957. if (*ppColSetData == NULL)
  958. {
  959. hr = E_FAIL;
  960. _JumpError(hr, Ret, "*ppColSetData NULL");
  961. }
  962. // register this allocation
  963. myRegisterMemAlloc(*ppColSetData, -1, CSM_COTASKALLOC);
  964. Ret:
  965. if (hSNode2)
  966. {
  967. GlobalUnlock(hSNode2);
  968. GlobalFree(hSNode2);
  969. }
  970. if (lpDataObject)
  971. lpDataObject->Release();
  972. return hr;
  973. }
  974. HRESULT CSnapin::GetColumnSortData(MMC_COOKIE cookie, int* piColSortIdx, BOOL* pfAscending)
  975. {
  976. HRESULT hr;
  977. if (m_ColSortOverride.fClickOverride)
  978. {
  979. // remove sort
  980. if (m_ColSortOverride.colIdx == -1)
  981. return E_FAIL;
  982. *piColSortIdx = m_ColSortOverride.colIdx;
  983. *pfAscending = ((m_ColSortOverride.dwOptions & RSI_DESCENDING) == 0) ? TRUE : FALSE;
  984. return S_OK;
  985. }
  986. HGLOBAL hSNode2 = NULL;
  987. SColumnSetID* pColID = NULL;
  988. MMC_SORT_SET_DATA* pSortSetData = NULL;
  989. LPDATAOBJECT lpDataObject = NULL;
  990. hr = _QueryDataObject(cookie, CCT_SCOPE, m_dwViewID,
  991. reinterpret_cast<CComponentDataImpl*>(m_pComponentData), &lpDataObject);
  992. _JumpIfError(hr, Ret, "_QueryDataObject");
  993. hSNode2 = ExtractNodeID(lpDataObject);
  994. _JumpIfOutOfMemory(hr, Ret, hSNode2);
  995. pColID = (SColumnSetID*)GlobalLock(hSNode2);
  996. _JumpIfOutOfMemory(hr, Ret, pColID);
  997. hr = m_pViewData->GetColumnSortData(pColID, &pSortSetData);
  998. _JumpIfError(hr, Ret, "GetColumnSortData");
  999. if (NULL == pSortSetData)
  1000. {
  1001. hr = E_FAIL;
  1002. _JumpError(hr, Ret, "pSortSetData NULL");
  1003. }
  1004. myRegisterMemAlloc(pSortSetData, -1, CSM_COTASKALLOC);
  1005. ASSERT(pSortSetData->nNumItems <= 1);
  1006. if (pSortSetData->nNumItems == 0)
  1007. {
  1008. hr = E_FAIL;
  1009. _JumpError(hr, Ret, "pSortSetData no sort");
  1010. }
  1011. *piColSortIdx = pSortSetData->pSortData[0].nColIndex;
  1012. *pfAscending = ((pSortSetData->pSortData[0].dwSortOptions & RSI_DESCENDING) == 0) ? TRUE : FALSE;
  1013. Ret:
  1014. if (hSNode2)
  1015. {
  1016. GlobalUnlock(hSNode2);
  1017. GlobalFree(hSNode2);
  1018. }
  1019. if (lpDataObject)
  1020. lpDataObject->Release();
  1021. if (pSortSetData)
  1022. CoTaskMemFree(pSortSetData);
  1023. return hr;
  1024. }
  1025. HRESULT CSnapin::InsertAllColumns(MMC_COOKIE cookie, CertViewRowEnum* pCertViewRowEnum)
  1026. {
  1027. HRESULT hr = S_OK;
  1028. CFolder* pFolder = reinterpret_cast<CFolder*>(cookie);
  1029. IEnumCERTVIEWCOLUMN* pColEnum = NULL;
  1030. BOOL fColumnDataBad = FALSE;
  1031. LONG iResultColCount;
  1032. int iCachedColCount, iCache, i;
  1033. BSTR bstrColumn = NULL;
  1034. MMC_COLUMN_SET_DATA* pColConfigData = NULL;
  1035. CComponentDataImpl* pData = dynamic_cast<CComponentDataImpl*>(m_pComponentData);
  1036. if (NULL == pData)
  1037. {
  1038. hr = E_POINTER;
  1039. _JumpError(hr, Ret, "pData NULL");
  1040. }
  1041. ICertView* pICertView; // this is const, don't free
  1042. hr = pCertViewRowEnum->GetView(pFolder->GetCA(), &pICertView);
  1043. _JumpIfError(hr, Ret, "GetView");
  1044. // always reset our column cache map
  1045. hr = m_RowEnum.ResetColumnCount(pData->m_cLastKnownSchema);
  1046. _JumpIfError(hr, Ret, "ResetColumnCount");
  1047. // attempt to get column set data
  1048. hr = GetColumnSetData(cookie, &pColConfigData);
  1049. _PrintIfError2(hr, "GetColumnConfigData", E_FAIL);
  1050. // call SetColumnCacheInfo to update final Result Indexes
  1051. if ((hr != S_OK) || // given 1) canned view or
  1052. (pData->m_cLastKnownSchema != (unsigned int)pColConfigData->nNumCols) )
  1053. // 2) pColConfigData doesn't agree with schema
  1054. {
  1055. if (hr == S_OK)
  1056. fColumnDataBad = TRUE;
  1057. // get col enumerator
  1058. hr = pICertView->EnumCertViewColumn(TRUE, &pColEnum);
  1059. _JumpIfError(hr, Ret, "EnumCertViewColumn");
  1060. // get # of result cols
  1061. hr = pICertView->GetColumnCount(TRUE, &iResultColCount);
  1062. _JumpIfError(hr, Ret, "GetColumnCount");
  1063. // this doesn't agree with schema -- throw it away
  1064. if (pColConfigData)
  1065. {
  1066. CoTaskMemFree(pColConfigData);
  1067. pColConfigData = NULL;
  1068. }
  1069. ASSERT(pColConfigData == NULL);
  1070. // rig up a column set data as if we got it from mmc
  1071. pColConfigData = (MMC_COLUMN_SET_DATA*)CoTaskMemAlloc(sizeof(MMC_COLUMN_SET_DATA) + (sizeof(MMC_COLUMN_DATA)*pData->m_cLastKnownSchema));
  1072. _JumpIfOutOfMemory(hr, Ret, pColConfigData);
  1073. ZeroMemory(pColConfigData, sizeof(MMC_COLUMN_SET_DATA) + (sizeof(MMC_COLUMN_DATA)*pData->m_cLastKnownSchema));
  1074. pColConfigData->pColData = (MMC_COLUMN_DATA*) (((BYTE*)pColConfigData) + sizeof(MMC_COLUMN_SET_DATA)); // points to just after our struct
  1075. pColConfigData->cbSize = sizeof(MMC_COLUMN_SET_DATA);
  1076. pColConfigData->nNumCols = pData->m_cLastKnownSchema;
  1077. for (i=0; i<(int)pData->m_cLastKnownSchema; i++)
  1078. {
  1079. pColConfigData->pColData[i].nColIndex = i;
  1080. pColConfigData->pColData[i].dwFlags = HDI_HIDDEN;
  1081. }
  1082. for (i=0; i< iResultColCount; i++)
  1083. {
  1084. hr = pColEnum->Next((LONG*)&iCache);
  1085. _JumpIfError(hr, Ret, "Next");
  1086. hr = pColEnum->GetName(&bstrColumn);
  1087. _JumpIfError(hr, Ret, "GetName");
  1088. iCache = pData->FindColIdx(bstrColumn);
  1089. _JumpIfError(hr, Ret, "FindColIdx");
  1090. SysFreeString(bstrColumn);
  1091. bstrColumn = NULL;
  1092. // rig up column set data as if we got it from mmc
  1093. pColConfigData->pColData[iCache].dwFlags = AUTO_WIDTH;
  1094. hr = m_RowEnum.SetColumnCacheInfo(iCache, i);
  1095. _JumpIfError(hr, Ret, "SetColumnCacheInfo");
  1096. }
  1097. }
  1098. else
  1099. {
  1100. // get # of cols
  1101. iResultColCount = m_RowEnum.GetColumnCount();
  1102. // set col cache correctly
  1103. int iResultIdx = 0;
  1104. for (i=0; i< iResultColCount; i++)
  1105. {
  1106. BOOL fShown;
  1107. hr = IsColumnShown(pColConfigData, i, &fShown);
  1108. _JumpIfError(hr, Ret, "IsColumnShown");
  1109. // update idxViewCol
  1110. if (fShown)
  1111. {
  1112. hr = m_RowEnum.SetColumnCacheInfo(pColConfigData->pColData[i].nColIndex, iResultIdx);
  1113. _JumpIfError(hr, Ret, "SetColumnCacheInfo");
  1114. iResultIdx++;
  1115. }
  1116. }
  1117. }
  1118. hr = DoInsertAllColumns(pColConfigData);
  1119. _JumpIfError(hr, Ret, "DoInsertAllColumns");
  1120. Ret:
  1121. if (pColEnum)
  1122. pColEnum->Release();
  1123. if (bstrColumn)
  1124. SysFreeString(bstrColumn);
  1125. if(pColConfigData)
  1126. CoTaskMemFree(pColConfigData);
  1127. return hr;
  1128. }
  1129. HRESULT CSnapin::DoInsertAllColumns(MMC_COLUMN_SET_DATA* pCols)
  1130. {
  1131. HRESULT hr = S_OK;
  1132. CComponentDataImpl* pData = dynamic_cast<CComponentDataImpl*>(m_pComponentData);
  1133. int i;
  1134. if ((pCols == NULL) || (pData == NULL))
  1135. {
  1136. hr = E_POINTER;
  1137. _JumpError(hr, Ret, "pCols or pData");
  1138. }
  1139. for (i=0; i<pCols->nNumCols; i++)
  1140. {
  1141. LPCWSTR szCachedHeading, pszLocal, pszUnlocal;
  1142. BOOL fShown;
  1143. hr = IsColumnShown(pCols, i, &fShown);
  1144. _JumpIfError(hr, Ret, "IsColumnShown");
  1145. hr = pData->GetDBSchemaEntry(i, &pszUnlocal, NULL, NULL);
  1146. _JumpIfError(hr, Ret, "GetDBSchemaEntry");
  1147. // returns pointer to static data; don't bother to free
  1148. hr = myGetColumnDisplayName(
  1149. pszUnlocal,
  1150. &pszLocal);
  1151. _PrintIfError(hr, "myGetColumnDisplayName");
  1152. // if localized version not found, slap with raw name
  1153. if (pszLocal == NULL)
  1154. pszLocal = pszUnlocal;
  1155. m_pHeader->InsertColumn(i, pszLocal, LVCFMT_LEFT, fShown ? AUTO_WIDTH : HIDE_COLUMN);
  1156. }
  1157. Ret:
  1158. return hr;
  1159. }
  1160. HRESULT CSnapin::InitializeHeaders(MMC_COOKIE cookie)
  1161. {
  1162. ASSERT(m_pHeader);
  1163. HRESULT hr = S_OK;
  1164. BOOL fInsertedHeaders=FALSE;
  1165. USES_CONVERSION;
  1166. CFolder* pFolder = reinterpret_cast<CFolder*>(cookie);
  1167. MMC_COLUMN_SET_DATA* pColSetData = NULL;
  1168. // Put the correct headers depending on the cookie
  1169. if (pFolder == NULL)
  1170. {
  1171. // base scope
  1172. m_pHeader->InsertColumn(0, W2COLE(g_cResources.m_ColumnHead_Name), LVCFMT_LEFT, 180); // Name
  1173. m_pHeader->InsertColumn(1, W2COLE(g_cResources.m_ColumnHead_Description), LVCFMT_LEFT, 180); // Description
  1174. fInsertedHeaders = TRUE;
  1175. }
  1176. else
  1177. {
  1178. switch (pFolder->m_type)
  1179. {
  1180. case SERVERFUNC_ISSUED_CERTIFICATES:
  1181. case SERVERFUNC_CRL_PUBLICATION: // or server functions
  1182. case SERVERFUNC_PENDING_CERTIFICATES:
  1183. case SERVERFUNC_ALIEN_CERTIFICATES:
  1184. case SERVERFUNC_FAILED_CERTIFICATES:
  1185. {
  1186. LONG lCols;
  1187. ICertView* pICertView; // this is const, don't free
  1188. IEnumCERTVIEWCOLUMN* pColEnum = NULL;
  1189. m_dwViewErrorMsg = S_OK; // assume everything OK when initializing view
  1190. // although we don't allow unsetting this mode,
  1191. // we may inherit it from another snapin. Force report mode.
  1192. hr = m_pResult->SetViewMode(MMCLV_VIEWSTYLE_REPORT);
  1193. if (hr != S_OK)
  1194. break;
  1195. // force reload of view (otherwise: multiple restriction error)
  1196. ResetKnowResultRows();
  1197. m_RowEnum.ClearCachedCertView();
  1198. m_RowEnum.InvalidateCachedRowEnum();
  1199. hr = m_RowEnum.GetView(pFolder->GetCA(), &pICertView);
  1200. if (hr != S_OK)
  1201. break;
  1202. int iSortOrder = CVR_SORT_NONE;
  1203. int idxSortCol = -1;
  1204. ASSERT(pICertView != NULL);
  1205. VARIANT var;
  1206. VariantInit(&var);
  1207. {
  1208. BOOL fAscending;
  1209. hr = GetColumnSortData(cookie, &idxSortCol, &fAscending);
  1210. _PrintIfError2(hr, "GetColumnSortData", E_FAIL);
  1211. if (hr == S_OK)
  1212. {
  1213. if (fAscending)
  1214. iSortOrder = CVR_SORT_ASCEND;
  1215. else
  1216. iSortOrder = CVR_SORT_DESCEND;
  1217. }
  1218. }
  1219. // first restriction is always sort request
  1220. if (iSortOrder != CVR_SORT_NONE)
  1221. {
  1222. ASSERT( (iSortOrder == CVR_SORT_ASCEND) ||
  1223. (iSortOrder == CVR_SORT_DESCEND));
  1224. var.vt = VT_EMPTY;
  1225. if (S_OK == hr)
  1226. {
  1227. hr = pICertView->SetRestriction(
  1228. idxSortCol, // ColumnIndex
  1229. CVR_SEEK_NONE, // SeekOperator
  1230. iSortOrder, // SortOrder
  1231. &var); // pvarValue
  1232. }
  1233. VariantClear(&var);
  1234. }
  1235. // set restriction on rows to view
  1236. if (m_RowEnum.FAreQueryRestrictionsActive() &&
  1237. (m_RowEnum.GetQueryRestrictions() != NULL))
  1238. {
  1239. PQUERY_RESTRICTION pCurRestrict = m_RowEnum.GetQueryRestrictions();
  1240. while (pCurRestrict)
  1241. {
  1242. LONG idxCol;
  1243. hr = pICertView->GetColumnIndex(FALSE, pCurRestrict->szField, &idxCol);
  1244. if (hr == S_OK)
  1245. {
  1246. // set restriction if column found
  1247. hr = pICertView->SetRestriction(
  1248. idxCol, // Request Disposition's ColumnIndex
  1249. pCurRestrict->iOperation, // SeekOperator
  1250. CVR_SORT_NONE, // SortOrder
  1251. &pCurRestrict->varValue); // Value
  1252. }
  1253. // don't VarClear here!
  1254. pCurRestrict = pCurRestrict->pNext;
  1255. }
  1256. }
  1257. // set query restrictions
  1258. if (SERVERFUNC_CRL_PUBLICATION == pFolder->m_type)
  1259. {
  1260. // build special Revoked view
  1261. var.lVal = DB_DISP_REVOKED;
  1262. var.vt = VT_I4;
  1263. LONG idxCol;
  1264. hr = pICertView->GetColumnIndex(FALSE, wszPROPREQUESTDOT wszPROPREQUESTDISPOSITION, &idxCol);
  1265. if (hr != S_OK)
  1266. break;
  1267. hr = pICertView->SetRestriction(
  1268. idxCol, // Request Disposition's ColumnIndex
  1269. CVR_SEEK_EQ, // SeekOperator
  1270. CVR_SORT_NONE, // SortOrder
  1271. &var); // pvarValue
  1272. VariantClear(&var);
  1273. if (hr != S_OK)
  1274. break;
  1275. }
  1276. else if (SERVERFUNC_ISSUED_CERTIFICATES == pFolder->m_type)
  1277. {
  1278. var.lVal = DB_DISP_ISSUED;
  1279. var.vt = VT_I4;
  1280. LONG idxCol;
  1281. hr = pICertView->GetColumnIndex(FALSE, wszPROPREQUESTDOT wszPROPREQUESTDISPOSITION, &idxCol);
  1282. if (hr != S_OK)
  1283. break;
  1284. hr = pICertView->SetRestriction(
  1285. idxCol, // Request Disposition's ColumnIndex
  1286. CVR_SEEK_EQ, // SeekOperator
  1287. CVR_SORT_NONE, // SortOrder
  1288. &var); // pvarValue
  1289. VariantClear(&var);
  1290. if (hr != S_OK)
  1291. break;
  1292. }
  1293. else if (SERVERFUNC_PENDING_CERTIFICATES == pFolder->m_type)
  1294. {
  1295. var.lVal = DB_DISP_PENDING; //DB_DISP_QUEUE_MAX; // don't include active
  1296. var.vt = VT_I4;
  1297. LONG idxCol;
  1298. hr = pICertView->GetColumnIndex(FALSE, wszPROPREQUESTDOT wszPROPREQUESTDISPOSITION, &idxCol);
  1299. if (hr != S_OK)
  1300. break;
  1301. hr = pICertView->SetRestriction(
  1302. idxCol, // Request Disposition's ColumnIndex
  1303. CVR_SEEK_EQ, // SeekOperator
  1304. CVR_SORT_NONE, // SortOrder
  1305. &var); // pvarValue
  1306. VariantClear(&var);
  1307. if (hr != S_OK)
  1308. break;
  1309. }
  1310. else if (SERVERFUNC_FAILED_CERTIFICATES == pFolder->m_type)
  1311. {
  1312. var.lVal = DB_DISP_LOG_FAILED_MIN;
  1313. var.vt = VT_I4;
  1314. LONG idxCol;
  1315. hr = pICertView->GetColumnIndex(FALSE, wszPROPREQUESTDOT wszPROPREQUESTDISPOSITION, &idxCol);
  1316. if (hr != S_OK)
  1317. break;
  1318. hr = pICertView->SetRestriction(
  1319. idxCol, // Request Disposition's ColumnIndex
  1320. CVR_SEEK_GE, // SeekOperator
  1321. CVR_SORT_NONE, // SortOrder
  1322. &var); // pvarValue
  1323. VariantClear(&var);
  1324. if (hr != S_OK)
  1325. break;
  1326. }
  1327. else if (SERVERFUNC_ALIEN_CERTIFICATES == pFolder->m_type)
  1328. {
  1329. var.lVal = DB_DISP_FOREIGN;
  1330. var.vt = VT_I4;
  1331. LONG idxCol;
  1332. hr = pICertView->GetColumnIndex(FALSE, wszPROPREQUESTDOT wszPROPREQUESTDISPOSITION, &idxCol);
  1333. if (hr != S_OK)
  1334. break;
  1335. hr = pICertView->SetRestriction(
  1336. idxCol, // Request Disposition's ColumnIndex
  1337. CVR_SEEK_EQ, // SeekOperator
  1338. CVR_SORT_NONE, // SortOrder
  1339. &var); // pvarValue
  1340. VariantClear(&var);
  1341. if (hr != S_OK)
  1342. break;
  1343. }
  1344. else
  1345. {
  1346. ASSERT(FALSE); // do we ever get here??
  1347. break;
  1348. }
  1349. // RESOLVE schema changes here
  1350. hr = SynchColumns(cookie);
  1351. _PrintIfError(hr, "SynchColumns");
  1352. hr = GetColumnSetData(cookie, &pColSetData);
  1353. if ((hr != S_OK) || (pColSetData == NULL))
  1354. {
  1355. LONG lViewType;
  1356. // problem or no column set data? Revert to the default canned view
  1357. if (SERVERFUNC_PENDING_CERTIFICATES == pFolder->m_type)
  1358. lViewType = CV_COLUMN_QUEUE_DEFAULT;
  1359. else if (SERVERFUNC_FAILED_CERTIFICATES == pFolder->m_type)
  1360. lViewType = CV_COLUMN_LOG_FAILED_DEFAULT;
  1361. else if (SERVERFUNC_CRL_PUBLICATION == pFolder->m_type)
  1362. lViewType = pFolder->GetCA()->m_pParentMachine->FIsWhistlerMachine() ? CV_COLUMN_LOG_REVOKED_DEFAULT : CV_COLUMN_LOG_DEFAULT; // w2k doesn't understand revoked view
  1363. else if (SERVERFUNC_ALIEN_CERTIFICATES == pFolder->m_type)
  1364. lViewType = CV_COLUMN_LOG_DEFAULT;
  1365. else
  1366. lViewType = CV_COLUMN_LOG_DEFAULT;
  1367. hr = pICertView->SetResultColumnCount(lViewType);
  1368. if (hr != S_OK)
  1369. break;
  1370. }
  1371. else
  1372. {
  1373. // manual view
  1374. ULONG lColCount;
  1375. hr = CountShownColumns(pColSetData, &lColCount);
  1376. if (hr != S_OK)
  1377. break;
  1378. hr = pICertView->SetResultColumnCount(lColCount);
  1379. if (hr != S_OK)
  1380. break;
  1381. // for all non-hidden columns, add to Query
  1382. for (lColCount=0; lColCount<(ULONG)pColSetData->nNumCols; lColCount++)
  1383. {
  1384. BOOL fShown;
  1385. hr = IsColumnShown(pColSetData, lColCount, &fShown);
  1386. if ((hr != S_OK) || (!fShown))
  1387. continue;
  1388. hr = pICertView->SetResultColumn(pColSetData->pColData[lColCount].nColIndex);
  1389. if (hr != S_OK)
  1390. break;
  1391. }
  1392. }
  1393. // Open the view
  1394. IEnumCERTVIEWROW* pRowEnum; // don't free
  1395. hr = m_RowEnum.GetRowEnum(pFolder->GetCA(), &pRowEnum);
  1396. if (hr != S_OK)
  1397. break;
  1398. hr = InsertAllColumns(cookie, &m_RowEnum);
  1399. _PrintIfError(hr, "InsertAllColumns");
  1400. if (hr == S_OK)
  1401. fInsertedHeaders = TRUE;
  1402. // set description bar text
  1403. {
  1404. CString cstrStatusBar;
  1405. BOOL fFiltered = FALSE;
  1406. if (m_RowEnum.FAreQueryRestrictionsActive() &&
  1407. (m_RowEnum.GetQueryRestrictions() != NULL))
  1408. {
  1409. cstrStatusBar = g_cResources.m_szFilterApplied;
  1410. fFiltered = TRUE;
  1411. }
  1412. if (iSortOrder != CVR_SORT_NONE)
  1413. {
  1414. LPCWSTR pszTemplate = NULL;
  1415. if (iSortOrder == CVR_SORT_ASCEND)
  1416. pszTemplate = (LPCWSTR)g_cResources.m_szSortedAscendingTemplate;
  1417. if (iSortOrder == CVR_SORT_DESCEND)
  1418. pszTemplate = (LPCWSTR)g_cResources.m_szSortedDescendingTemplate;
  1419. if (pszTemplate)
  1420. {
  1421. // localize
  1422. LPCWSTR szUnlocalizedCol;
  1423. LPCWSTR szLocalizedCol;
  1424. hr = dynamic_cast<CComponentDataImpl*>(m_pComponentData)->GetDBSchemaEntry(idxSortCol, &szUnlocalizedCol, NULL, NULL);
  1425. if (hr == S_OK)
  1426. {
  1427. hr = myGetColumnDisplayName(
  1428. szUnlocalizedCol,
  1429. &szLocalizedCol);
  1430. if ((S_OK == hr) && (NULL != szLocalizedCol))
  1431. {
  1432. WCHAR rgszSortText[MAX_PATH+1];
  1433. ASSERT((MAX_PATH*sizeof(WCHAR)) > (WSZ_BYTECOUNT(pszTemplate) + WSZ_BYTECOUNT(szLocalizedCol)));
  1434. wsprintf(rgszSortText, pszTemplate, szLocalizedCol);
  1435. if (fFiltered)
  1436. cstrStatusBar += L"; ";
  1437. cstrStatusBar += rgszSortText;
  1438. }
  1439. }
  1440. }
  1441. }
  1442. // Progress: cstrStatusBar += L"|%69";
  1443. //m_pResult->SetDescBarText((LPWSTR)(LPCWSTR)cstrStatusBar);
  1444. m_pConsole->SetStatusText((LPWSTR)(LPCWSTR)cstrStatusBar);
  1445. }
  1446. break;
  1447. }
  1448. case SERVER_INSTANCE: // any issuing server instance
  1449. m_pHeader->InsertColumn(0, W2COLE(g_cResources.m_ColumnHead_Name), LVCFMT_LEFT, 260); // Name
  1450. fInsertedHeaders = TRUE;
  1451. break;
  1452. default:
  1453. // other scopes
  1454. m_pHeader->InsertColumn(0, W2COLE(g_cResources.m_ColumnHead_Name), LVCFMT_LEFT, 180); // Name
  1455. m_pHeader->InsertColumn(1, W2COLE(g_cResources.m_ColumnHead_Size), LVCFMT_LEFT, 90); // Size
  1456. m_pHeader->InsertColumn(2, W2COLE(g_cResources.m_ColumnHead_Type), LVCFMT_LEFT, 160); // Type
  1457. fInsertedHeaders = TRUE;
  1458. }
  1459. }
  1460. if (!fInsertedHeaders)
  1461. {
  1462. // insert error msg
  1463. CString cstrViewErrorMsg, cstrStatusText;
  1464. if ((pFolder != NULL ) && (!pFolder->GetCA()->m_pParentMachine->IsCertSvrServiceRunning()))
  1465. {
  1466. // handle server stopped msg
  1467. cstrViewErrorMsg = g_cResources.m_szStoppedServerMsg;
  1468. }
  1469. else
  1470. {
  1471. // handle any other error (except empty db)
  1472. cstrViewErrorMsg = myGetErrorMessageText(hr, TRUE);
  1473. }
  1474. cstrStatusText.Format(g_cResources.m_szStatusBarErrorFormat, cstrViewErrorMsg);
  1475. m_pHeader->InsertColumn(0, W2COLE(L" "), LVCFMT_LEFT, 500); // Error
  1476. m_pConsole->SetStatusText((LPWSTR)(LPCWSTR)cstrStatusText);
  1477. }
  1478. //Ret:
  1479. if (pColSetData)
  1480. CoTaskMemFree(pColSetData);
  1481. return hr;
  1482. }
  1483. LPCWSTR DescriptionStringFromFolderType(FOLDER_TYPES type)
  1484. {
  1485. ASSERT(g_cResources.m_fLoaded);
  1486. switch (type)
  1487. {
  1488. case SERVER_INSTANCE:
  1489. return (LPCWSTR) g_cResources.m_DescrStr_CA;
  1490. default:
  1491. break;
  1492. }
  1493. return (LPCWSTR)g_cResources.m_DescrStr_Unknown;
  1494. }
  1495. #define MMCVIEW_DB_MINPAGESIZE 32
  1496. #define MAX_VIEWABLE_STRING_LEN MAX_PATH
  1497. static WCHAR szVirtualStrBuf[MAX_VIEWABLE_STRING_LEN+1];
  1498. static DWORD cbVirtualStrBuf = sizeof(szVirtualStrBuf);
  1499. STDMETHODIMP CSnapin::GetDisplayInfo(LPRESULTDATAITEM pResult)
  1500. {
  1501. HRESULT hr = S_OK;
  1502. ASSERT(pResult != NULL);
  1503. if ((pResult) && (pResult->mask))
  1504. {
  1505. // a folder or a result?
  1506. if (pResult->bScopeItem == TRUE)
  1507. {
  1508. CFolder* pFolder = reinterpret_cast<CFolder*>(pResult->lParam);
  1509. ASSERT(pFolder);
  1510. if (pResult->mask & RDI_STR)
  1511. {
  1512. switch (pFolder->m_type)
  1513. {
  1514. case MACHINE_INSTANCE:
  1515. case SERVER_INSTANCE:
  1516. switch(pResult->nCol)
  1517. {
  1518. case 0:
  1519. pResult->str = pFolder->m_pszName;
  1520. break;
  1521. case 1:
  1522. pResult->str = (LPOLESTR)DescriptionStringFromFolderType(pFolder->m_type);
  1523. default:
  1524. break;
  1525. }
  1526. break;
  1527. case SERVERFUNC_CRL_PUBLICATION:
  1528. case SERVERFUNC_ISSUED_CERTIFICATES:
  1529. case SERVERFUNC_PENDING_CERTIFICATES:
  1530. case SERVERFUNC_FAILED_CERTIFICATES:
  1531. case SERVERFUNC_ALIEN_CERTIFICATES:
  1532. // just a single column here
  1533. pResult->str = pFolder->m_pszName;
  1534. default:
  1535. break;
  1536. }
  1537. ASSERT(pResult->str != NULL);
  1538. if (pResult->str == NULL)
  1539. pResult->str = (LPOLESTR)L"";
  1540. }
  1541. if (pResult->mask & RDI_IMAGE)
  1542. {
  1543. if (pResult->nState & TVIS_EXPANDED)
  1544. pResult->nImage = pFolder->m_ScopeItem.nOpenImage;
  1545. else
  1546. pResult->nImage = pFolder->m_ScopeItem.nImage;
  1547. }
  1548. }
  1549. else
  1550. {
  1551. RESULT_DATA* pData = NULL;
  1552. CFolder* pFolder = NULL;
  1553. // if non-virtual, lParam is the item pointer
  1554. if (m_bVirtualView)
  1555. pFolder = GetVirtualFolder();
  1556. else
  1557. {
  1558. pData= reinterpret_cast<RESULT_DATA*>(pResult->lParam);
  1559. pFolder = pData->pParentFolder;
  1560. ASSERT(pData->pParentFolder == m_pCurrentlySelectedScopeFolder);
  1561. }
  1562. if (pResult->mask & RDI_STR)
  1563. {
  1564. switch(pFolder->GetType())
  1565. {
  1566. case SERVERFUNC_CRL_PUBLICATION:
  1567. case SERVERFUNC_PENDING_CERTIFICATES:
  1568. case SERVERFUNC_ISSUED_CERTIFICATES:
  1569. case SERVERFUNC_FAILED_CERTIFICATES:
  1570. case SERVERFUNC_ALIEN_CERTIFICATES:
  1571. {
  1572. szVirtualStrBuf[0] = L'\0'; // zero
  1573. pResult->str = szVirtualStrBuf;
  1574. // have we had an error enumerating elts?
  1575. if (S_OK != m_dwViewErrorMsg)
  1576. {
  1577. // rtn err msg or blank
  1578. // ASSERT(pResult->nIndex == 0);
  1579. if (pResult->nIndex == 0)
  1580. pResult->str = (LPWSTR)(LPCWSTR)m_cstrViewErrorMsg;
  1581. break;
  1582. }
  1583. // Don't attempt to cache iViewCol -- we're asked
  1584. int iViewCol;
  1585. // if this request isn't the last one that came through, look it up
  1586. hr = m_RowEnum.GetColumnCacheInfo(
  1587. pResult->nCol,
  1588. &iViewCol);
  1589. _PrintIfError(hr, "GetColumnCacheInfo");
  1590. // HACKHACK
  1591. // if we get ErrorContinue, we should just take it
  1592. // in stride and return \0 (see GetColumnCacheInfo for details)
  1593. if (hr == HRESULT_FROM_WIN32(ERROR_CONTINUE))
  1594. break;
  1595. if (hr != S_OK)
  1596. {
  1597. // assume error
  1598. iViewCol = 0;
  1599. }
  1600. DWORD cbSize = cbVirtualStrBuf;
  1601. // protect ICertAdminD->EnumView from reentrant calls (see bug 339811)
  1602. if(2>InterlockedIncrement(&m_cViewCalls))
  1603. {
  1604. hr = GetCellContents(
  1605. &m_RowEnum,
  1606. pFolder->GetCA(),
  1607. pResult->nIndex,
  1608. pResult->nCol,
  1609. (PBYTE)szVirtualStrBuf,
  1610. &cbSize,
  1611. TRUE);
  1612. _PrintIfError2(hr, "GetCellContents", S_FALSE); // ignore end of db msg
  1613. }
  1614. InterlockedDecrement(&m_cViewCalls);
  1615. // only deal with 1st col
  1616. if (iViewCol != 0)
  1617. break;
  1618. // On Error
  1619. if ( (S_OK != hr) && (S_FALSE != hr) )
  1620. {
  1621. // stash error return
  1622. m_dwViewErrorMsg = hr;
  1623. if (!pFolder->GetCA()->m_pParentMachine->IsCertSvrServiceRunning())
  1624. {
  1625. // handle server stopped msg
  1626. // copy to stateful str
  1627. m_cstrViewErrorMsg = g_cResources.m_szStoppedServerMsg;
  1628. // copy to output
  1629. pResult->str = (LPWSTR)(LPCWSTR)g_cResources.m_szStoppedServerMsg;
  1630. }
  1631. else
  1632. {
  1633. // handle any other error (except empty db)
  1634. m_cstrViewErrorMsg = myGetErrorMessageText(hr, TRUE);
  1635. // truncate if necessary
  1636. ASSERT(MAX_VIEWABLE_STRING_LEN >= wcslen((LPWSTR)(LPCWSTR)m_cstrViewErrorMsg) );
  1637. if (MAX_VIEWABLE_STRING_LEN < wcslen((LPWSTR)(LPCWSTR)m_cstrViewErrorMsg) )
  1638. m_cstrViewErrorMsg.SetAt(MAX_VIEWABLE_STRING_LEN, L'\0');
  1639. pResult->str = (LPWSTR)(LPCWSTR)m_cstrViewErrorMsg;
  1640. }
  1641. // on error, just display this msg
  1642. if (!m_RowEnum.m_fKnowNumResultRows)
  1643. {
  1644. // upd view
  1645. SetKnowResultRows(1);
  1646. m_pResult->SetItemCount(1, MMCLV_UPDATE_NOSCROLL | MMCLV_UPDATE_NOINVALIDATEALL);
  1647. // don't destroy column widths!
  1648. // OLD: make col width large enough to hold msg
  1649. // m_pHeader->SetColumnWidth(0, CHARS_TO_MMCCOLUMNWIDTH(wcslen(pResult->str)));
  1650. }
  1651. break;
  1652. }
  1653. // if 1st col and don't know the final tally, might have to update best guess
  1654. if (hr == S_OK)
  1655. {
  1656. if (KnownResultRows() == (DWORD)(pResult->nIndex+1))
  1657. // if asking for the last element (ones based)
  1658. {
  1659. // next guess at end
  1660. BOOL fSetViewCount = FALSE;
  1661. DWORD dwNextEnd;
  1662. if (!m_RowEnum.m_fKnowNumResultRows) // only make guess if enum doesn't have a clue yet
  1663. {
  1664. // double where we are now, make sure we're at least moving MMCVIEW_DB_MINPAGESIZE rows
  1665. dwNextEnd = max( ((pResult->nIndex+1)*2), MMCVIEW_DB_MINPAGESIZE);
  1666. DBGPRINT((DBG_SS_CERTMMC, "RowEnum dwResultRows = %i, requested Index = %i. Creating Guess = %i\n", m_RowEnum.m_dwResultRows, pResult->nIndex, dwNextEnd));
  1667. // upd enumerator with our best guess
  1668. fSetViewCount = TRUE;
  1669. }
  1670. else if (KnownResultRows() != m_RowEnum.m_dwResultRows)
  1671. {
  1672. dwNextEnd = m_RowEnum.m_dwResultRows;
  1673. fSetViewCount = TRUE;
  1674. }
  1675. // upd view
  1676. if (fSetViewCount)
  1677. {
  1678. SetKnowResultRows(dwNextEnd);
  1679. m_pResult->SetItemCount(dwNextEnd, MMCLV_UPDATE_NOSCROLL | MMCLV_UPDATE_NOINVALIDATEALL);
  1680. }
  1681. } // if the enumerator doesn't have a clue yet
  1682. }
  1683. else
  1684. {
  1685. ASSERT(hr == S_FALSE);
  1686. // end-of-db should only come on first col
  1687. // if error while retrieving first elt in row, ASSUME end of DB
  1688. LONG lRetrievedIndex;
  1689. hr = m_RowEnum.GetRowMaxIndex(pFolder->GetCA(), &lRetrievedIndex);
  1690. if (S_OK != hr)
  1691. break;
  1692. DBGPRINT((DBG_SS_CERTMMC, "Hit end, setting max index to %i\n", lRetrievedIndex));
  1693. SetKnowResultRows(lRetrievedIndex);
  1694. m_pResult->SetItemCount(lRetrievedIndex, MMCLV_UPDATE_NOSCROLL | MMCLV_UPDATE_NOINVALIDATEALL);
  1695. // m_pResult->ModifyItemState(lRetrievedIndex-1, 0, (LVIS_FOCUSED | LVIS_SELECTED), 0); // set focus to last item
  1696. // BUG BUG MMC fails to re-select scope pane when we set selection here, so just set focus (build 2010)
  1697. if (lRetrievedIndex != 0)
  1698. m_pResult->ModifyItemState(lRetrievedIndex-1, 0, LVIS_FOCUSED, 0); // set focus to last item
  1699. }
  1700. } // end case
  1701. break;
  1702. case SERVER_INSTANCE:
  1703. default: // try this, no guarantee
  1704. if (NULL == pData)
  1705. break;
  1706. ASSERT(pResult->nCol < (int)pData->cStringArray);
  1707. pResult->str = (LPOLESTR)pData->szStringArray[pResult->nCol];
  1708. break;
  1709. }
  1710. ASSERT(pResult->str != NULL);
  1711. if (pResult->str == NULL)
  1712. pResult->str = (LPOLESTR)L"";
  1713. }
  1714. // MMC can request image and indent for virtual data
  1715. if (pResult->mask & RDI_IMAGE)
  1716. {
  1717. if ((pResult->nIndex >= (int)m_RowEnum.m_dwResultRows) || (hr != S_OK) || (S_OK != m_dwViewErrorMsg))
  1718. {
  1719. // MMC bug: using SetItemCount doesn't stick early enough to keep it from
  1720. // asking for icons for the first page.
  1721. pResult->nImage = IMGINDEX_NO_IMAGE;
  1722. }
  1723. else
  1724. {
  1725. switch(pFolder->GetType())
  1726. {
  1727. case SERVERFUNC_FAILED_CERTIFICATES:
  1728. case SERVERFUNC_CRL_PUBLICATION:
  1729. pResult->nImage = IMGINDEX_CRL;
  1730. break;
  1731. case SERVERFUNC_PENDING_CERTIFICATES:
  1732. pResult->nImage = IMGINDEX_PENDING_CERT;
  1733. break;
  1734. case SERVERFUNC_ISSUED_CERTIFICATES:
  1735. case SERVERFUNC_ALIEN_CERTIFICATES:
  1736. pResult->nImage = IMGINDEX_CERT;
  1737. break;
  1738. default:
  1739. // should never get here
  1740. ASSERT(0);
  1741. pResult->nImage = IMGINDEX_NO_IMAGE;
  1742. break;
  1743. } // end switch
  1744. } // end > rows test
  1745. }
  1746. }
  1747. }
  1748. return S_OK;
  1749. }
  1750. /////////////////////////////////////////////////////////////////////////////
  1751. // IExtendContextMenu Implementation
  1752. STDMETHODIMP CSnapin::AddMenuItems(LPDATAOBJECT pDataObject,
  1753. LPCONTEXTMENUCALLBACK pContextMenuCallback,
  1754. LONG *pInsertionAllowed)
  1755. {
  1756. dynamic_cast<CComponentDataImpl*>(m_pComponentData)->m_pCurSelFolder = m_pCurrentlySelectedScopeFolder;
  1757. HRESULT hr;
  1758. INTERNAL* pInternal = ExtractInternalFormat(pDataObject);
  1759. if (NULL == pInternal)
  1760. return S_OK;
  1761. BOOL bMultiSel = IsMMCMultiSelectDataObject(pDataObject);
  1762. BOOL fResultItem = (pInternal->m_type == CCT_RESULT);
  1763. CFolder* pFolder = m_pCurrentlySelectedScopeFolder;
  1764. FOLDER_TYPES folderType = NONE;
  1765. if (pFolder == NULL)
  1766. folderType = MACHINE_INSTANCE;
  1767. else
  1768. folderType = pFolder->GetType();
  1769. hr = dynamic_cast<CComponentDataImpl*>(m_pComponentData)->
  1770. AddMenuItems(pDataObject, pContextMenuCallback, pInsertionAllowed);
  1771. if (hr != S_OK)
  1772. goto Ret;
  1773. // Loop through and add each of the view items
  1774. if (*pInsertionAllowed & CCM_INSERTIONALLOWED_VIEW)
  1775. {
  1776. // fixup entries
  1777. MY_CONTEXTMENUITEM* pm = viewResultItems;
  1778. if (m_RowEnum.FAreQueryRestrictionsActive()) // filtered?
  1779. {
  1780. pm[ENUM_VIEW_FILTER].item.fFlags =
  1781. MFT_RADIOCHECK | MFS_CHECKED | MFS_ENABLED;
  1782. pm[ENUM_VIEW_ALL].item.fFlags =
  1783. MFS_ENABLED;
  1784. }
  1785. else
  1786. {
  1787. pm[ENUM_VIEW_FILTER].item.fFlags =
  1788. MFS_ENABLED;
  1789. pm[ENUM_VIEW_ALL].item.fFlags =
  1790. MFT_RADIOCHECK | MFS_CHECKED | MFS_ENABLED;
  1791. }
  1792. for (; pm->item.strName; pm++)
  1793. {
  1794. // show in both scope/result panes
  1795. // fResultItem
  1796. // Only support views in known containers
  1797. // for each task, insert if matches the current folder
  1798. if ((folderType == SERVERFUNC_CRL_PUBLICATION) ||
  1799. (folderType == SERVERFUNC_ISSUED_CERTIFICATES) ||
  1800. (folderType == SERVERFUNC_PENDING_CERTIFICATES) ||
  1801. (folderType == SERVERFUNC_ALIEN_CERTIFICATES) ||
  1802. (folderType == SERVERFUNC_FAILED_CERTIFICATES))
  1803. {
  1804. hr = pContextMenuCallback->AddItem(&pm->item);
  1805. _JumpIfError(hr, Ret, "AddItem");
  1806. }
  1807. }
  1808. }
  1809. if (*pInsertionAllowed & CCM_INSERTIONALLOWED_TASK)
  1810. {
  1811. // ptr to tasks
  1812. TASKITEM* pm = taskResultItemsSingleSel;
  1813. if (!bMultiSel)
  1814. {
  1815. // insert all other tasks per folder
  1816. for (; pm->myitem.item.strName; pm++)
  1817. {
  1818. // does it match scope/result type?
  1819. // if (value where we are !=
  1820. // whether or not the resultitem bit is set)
  1821. if (fResultItem != (0 != (pm->dwFlags & TASKITEM_FLAG_RESULTITEM)) )
  1822. continue;
  1823. // does it match area it should be in?
  1824. // for each task, insert if matches the current folder
  1825. if (folderType != pm->type)
  1826. continue;
  1827. // is this task supposed to be hidden?
  1828. if (MFS_HIDDEN == pm->myitem.item.fFlags)
  1829. continue;
  1830. hr = pContextMenuCallback->AddItem(&pm->myitem.item);
  1831. _JumpIfError(hr, Ret, "AddItem");
  1832. }
  1833. }
  1834. }
  1835. Ret:
  1836. FREE_DATA(pInternal);
  1837. return hr;
  1838. }
  1839. STDMETHODIMP CSnapin::Command(LONG nCommandID, LPDATAOBJECT pDataObject)
  1840. {
  1841. INTERNAL* pInternal = ExtractInternalFormat(pDataObject);
  1842. if (pInternal == NULL)
  1843. return E_FAIL;
  1844. BOOL fConfirmedAction = FALSE;
  1845. BOOL fMustRefresh = FALSE;
  1846. LONG lReasonCode = CRL_REASON_UNSPECIFIED;
  1847. HRESULT hr = S_OK;
  1848. CFolder* pFolder = GetParentFolder(pInternal);
  1849. ICertAdmin* pAdmin = NULL; // free this
  1850. CWaitCursor* pcwait = NULL; // some of these commands are multiselect and could take awhile.
  1851. // On those that are lengthy, this will be created and needs to be deleted at exit
  1852. if (pInternal->m_type == CCT_SCOPE)
  1853. {
  1854. // Handle view specific commands here
  1855. switch (nCommandID)
  1856. {
  1857. case MMCC_STANDARD_VIEW_SELECT:
  1858. m_CustomViewID = VIEW_DEFAULT_LV;
  1859. break;
  1860. case IDC_VIEW_ALLRECORDS:
  1861. {
  1862. if (NULL == pFolder)
  1863. break;
  1864. // if restricted view, change
  1865. if (m_RowEnum.FAreQueryRestrictionsActive())
  1866. {
  1867. // switch off active flag
  1868. m_RowEnum.SetQueryRestrictionsActive(FALSE);
  1869. // refresh just this folder
  1870. OnRefresh(pDataObject);
  1871. SetDirty();
  1872. }
  1873. break;
  1874. }
  1875. case IDC_VIEW_FILTER:
  1876. {
  1877. if (NULL == pFolder)
  1878. break;
  1879. HWND hwnd;
  1880. hr = m_pConsole->GetMainWindow(&hwnd);
  1881. ASSERT(hr == ERROR_SUCCESS);
  1882. if (hr != ERROR_SUCCESS)
  1883. hwnd = NULL; // should work
  1884. hr = ModifyQueryFilter(hwnd, &m_RowEnum, dynamic_cast<CComponentDataImpl*>(m_pComponentData));
  1885. // refresh only if successful
  1886. if (hr == ERROR_SUCCESS)
  1887. {
  1888. // refresh just this folder
  1889. OnRefresh(pDataObject);
  1890. SetDirty();
  1891. }
  1892. break;
  1893. }
  1894. default:
  1895. // Pass non-view specific commands to ComponentData
  1896. return dynamic_cast<CComponentDataImpl*>(m_pComponentData)->
  1897. Command(nCommandID, pDataObject);
  1898. }
  1899. }
  1900. else if (pInternal->m_type == CCT_RESULT)
  1901. {
  1902. // get this only ONCE, it's freed later
  1903. if ((nCommandID == IDC_RESUBMITREQUEST) ||
  1904. (nCommandID == IDC_DENYREQUEST) ||
  1905. (nCommandID == IDC_REVOKECERT) ||
  1906. (nCommandID == IDC_UNREVOKE_CERT))
  1907. {
  1908. if (pFolder == NULL)
  1909. {
  1910. hr = E_POINTER;
  1911. goto ExitCommand;
  1912. }
  1913. // have pAdmin allocated
  1914. hr = pFolder->GetCA()->m_pParentMachine->GetAdmin(&pAdmin);
  1915. if (S_OK != hr)
  1916. goto ExitCommand;
  1917. }
  1918. // snag the selected items
  1919. RESULTDATAITEM rdi;
  1920. rdi.mask = RDI_STATE;
  1921. rdi.nState = LVIS_SELECTED;
  1922. rdi.nIndex = -1;
  1923. // must sit outside loop so multi-select works
  1924. LPCWSTR szCol=NULL; // don't free
  1925. BOOL fSaveInstead = FALSE;
  1926. while(S_OK == m_pResult->GetNextItem(&rdi))
  1927. {
  1928. int iSel = rdi.nIndex;
  1929. // Handle each of the commands seperately
  1930. switch (nCommandID)
  1931. {
  1932. case IDC_VIEW_CERT_PROPERTIES:
  1933. {
  1934. if (NULL == pFolder)
  1935. break;
  1936. switch (pFolder->GetType())
  1937. {
  1938. case SERVERFUNC_ISSUED_CERTIFICATES:
  1939. case SERVERFUNC_CRL_PUBLICATION:
  1940. case SERVERFUNC_ALIEN_CERTIFICATES:
  1941. {
  1942. CertSvrCA* pCA = pFolder->GetCA();
  1943. CRYPTUI_VIEWCERTIFICATE_STRUCTW sViewCert;
  1944. ZeroMemory(&sViewCert, sizeof(sViewCert));
  1945. HCERTSTORE rghStores[2]; // don't close these stores
  1946. PCCRL_CONTEXT pCRL = NULL;
  1947. // get this cert
  1948. PBYTE pbCert = NULL;
  1949. DWORD cbCert;
  1950. hr = GetRowColContents(pFolder, rdi.nIndex, wszPROPRAWCERTIFICATE, &pbCert, &cbCert);
  1951. if (S_OK != hr)
  1952. break;
  1953. sViewCert.pCertContext = CertCreateCertificateContext(
  1954. CRYPT_ASN_ENCODING,
  1955. pbCert,
  1956. cbCert);
  1957. delete [] pbCert;
  1958. if (sViewCert.pCertContext == NULL)
  1959. break;
  1960. // get stores the CA sees
  1961. hr = pCA->GetRootCertStore(&rghStores[0]);
  1962. if (S_OK != hr)
  1963. break;
  1964. hr = pCA->GetCACertStore(&rghStores[1]);
  1965. if (S_OK != hr)
  1966. break;
  1967. hr = m_pConsole->GetMainWindow(&sViewCert.hwndParent);
  1968. if (S_OK != hr)
  1969. sViewCert.hwndParent = NULL; // should work
  1970. sViewCert.dwSize = sizeof(sViewCert);
  1971. sViewCert.dwFlags = CRYPTUI_ENABLE_REVOCATION_CHECKING | CRYPTUI_WARN_UNTRUSTED_ROOT | CRYPTUI_DISABLE_ADDTOSTORE;
  1972. // if we're opening remotely, don't open local stores
  1973. if (!FIsCurrentMachine(pCA->m_pParentMachine->m_strMachineName))
  1974. sViewCert.dwFlags |= CRYPTUI_DONT_OPEN_STORES;
  1975. sViewCert.cStores = 2;
  1976. sViewCert.rghStores = rghStores;
  1977. if (!CryptUIDlgViewCertificateW(&sViewCert, NULL))
  1978. hr = GetLastError();
  1979. VERIFY(CertFreeCertificateContext(sViewCert.pCertContext));
  1980. }
  1981. break;
  1982. default:
  1983. break;
  1984. }
  1985. }
  1986. break;
  1987. case IDC_RESUBMITREQUEST:
  1988. {
  1989. LPWSTR szReqID = NULL;
  1990. DWORD cbReqID;
  1991. LONG lReqID;
  1992. if (NULL == pFolder)
  1993. break;
  1994. if (pcwait == NULL) // this might take awhile
  1995. pcwait = new CWaitCursor;
  1996. // "Request.RequestID"
  1997. hr = GetRowColContents(pFolder, rdi.nIndex, wszPROPREQUESTDOT wszPROPREQUESTREQUESTID, (PBYTE*)&szReqID, &cbReqID, TRUE);
  1998. if (S_OK != hr)
  1999. break;
  2000. lReqID = _wtol(szReqID);
  2001. delete [] szReqID;
  2002. hr = CertAdminResubmitRequest(pFolder->GetCA(), pAdmin, lReqID);
  2003. if (hr != S_OK)
  2004. break;
  2005. // dirty pane: refresh
  2006. fMustRefresh = TRUE;
  2007. break;
  2008. }
  2009. case IDC_DENYREQUEST:
  2010. {
  2011. LPWSTR szReqID = NULL;
  2012. DWORD cbReqID;
  2013. LONG lReqID;
  2014. if (NULL == pFolder)
  2015. break;
  2016. // "Request.RequestID"
  2017. hr = GetRowColContents(pFolder, rdi.nIndex, wszPROPREQUESTDOT wszPROPREQUESTREQUESTID, (PBYTE*)&szReqID, &cbReqID, TRUE);
  2018. if (S_OK != hr)
  2019. break;
  2020. lReqID = _wtol(szReqID);
  2021. delete [] szReqID;
  2022. if (!fConfirmedAction)
  2023. {
  2024. // confirm this action
  2025. CString cstrMsg, cstrTitle;
  2026. cstrMsg.LoadString(IDS_CONFIRM_DENY_REQUEST);
  2027. cstrTitle.LoadString(IDS_DENY_REQUEST_TITLE);
  2028. int iRet;
  2029. if ((S_OK != m_pConsole->MessageBox(cstrMsg, cstrTitle, MB_YESNO, &iRet)) ||
  2030. (iRet != IDYES))
  2031. {
  2032. hr = ERROR_CANCELLED;
  2033. goto ExitCommand;
  2034. }
  2035. fConfirmedAction = TRUE;
  2036. }
  2037. if (pcwait == NULL) // this might take awhile
  2038. pcwait = new CWaitCursor;
  2039. hr = CertAdminDenyRequest(pFolder->GetCA(), pAdmin, lReqID);
  2040. if (hr != S_OK)
  2041. break;
  2042. // dirty pane: refresh
  2043. fMustRefresh = TRUE;
  2044. break;
  2045. }
  2046. case IDC_VIEW_ATTR_EXT:
  2047. {
  2048. IEnumCERTVIEWEXTENSION* pExtn = NULL;
  2049. IEnumCERTVIEWATTRIBUTE* pAttr = NULL;
  2050. LPWSTR szReqID = NULL;
  2051. DWORD cbReqID;
  2052. HWND hwnd;
  2053. ASSERT(pInternal->m_type == CCT_RESULT);
  2054. if (NULL == pFolder)
  2055. break;
  2056. hr = m_pConsole->GetMainWindow(&hwnd);
  2057. if (S_OK != hr)
  2058. hwnd = NULL; // should work
  2059. // "Request.RequestID"
  2060. hr = GetRowColContents(pFolder, rdi.nIndex, wszPROPREQUESTDOT wszPROPREQUESTREQUESTID, (PBYTE*)&szReqID, &cbReqID, TRUE);
  2061. if (S_OK != hr)
  2062. break;
  2063. // pollute the row enumerator we've got (doesn't alloc new IF)
  2064. hr = m_RowEnum.SetRowEnumPos(rdi.nIndex);
  2065. if (hr != S_OK)
  2066. break;
  2067. IEnumCERTVIEWROW* pRow;
  2068. hr = m_RowEnum.GetRowEnum(pFolder->GetCA(), &pRow);
  2069. if (hr != S_OK)
  2070. break;
  2071. hr = pRow->EnumCertViewAttribute(0, &pAttr);
  2072. if (hr != S_OK)
  2073. break;
  2074. hr = pRow->EnumCertViewExtension(0, &pExtn);
  2075. if (hr != S_OK)
  2076. break;
  2077. hr = ViewRowAttributesExtensions(hwnd, pAttr, pExtn, szReqID);
  2078. delete [] szReqID;
  2079. if (pExtn)
  2080. pExtn->Release();
  2081. if (pAttr)
  2082. pAttr->Release();
  2083. if (hr != S_OK)
  2084. break;
  2085. break;
  2086. }
  2087. case IDC_DUMP_ASN:
  2088. {
  2089. PBYTE pbReq = NULL;
  2090. DWORD cbReq;
  2091. CString cstrFileName;
  2092. LPCWSTR pszLocalizedCol = NULL;
  2093. ASSERT(pInternal->m_type == CCT_RESULT);
  2094. if (NULL == pFolder)
  2095. break;
  2096. CComponentDataImpl* pData = dynamic_cast<CComponentDataImpl*>(m_pComponentData);
  2097. HWND hwnd;
  2098. hr = m_pConsole->GetMainWindow(&hwnd);
  2099. if (S_OK != hr)
  2100. hwnd = NULL; // should work
  2101. if (!fConfirmedAction)
  2102. {
  2103. hr = ChooseBinaryColumnToDump(hwnd, pData, &szCol, &fSaveInstead);
  2104. if (hr != S_OK)
  2105. break;
  2106. if (szCol == NULL) // strangeness
  2107. {
  2108. hr = E_UNEXPECTED;
  2109. break;
  2110. }
  2111. fConfirmedAction = TRUE;
  2112. }
  2113. // "Request.RequestID"
  2114. hr = GetRowColContents(pFolder, rdi.nIndex, wszPROPREQUESTDOT wszPROPREQUESTREQUESTID, (PBYTE*)&pbReq, &cbReq, TRUE);
  2115. if (S_OK != hr)
  2116. break;
  2117. hr = myGetColumnDisplayName(szCol, &pszLocalizedCol);
  2118. if ((hr != S_OK) || (pszLocalizedCol == NULL))
  2119. pszLocalizedCol = L"";
  2120. cstrFileName = pszLocalizedCol;
  2121. cstrFileName += L" - ";
  2122. cstrFileName += (LPCWSTR)pbReq;
  2123. cstrFileName += L".tmp";
  2124. delete [] pbReq;
  2125. // get the request
  2126. hr = GetRowColContents(pFolder, rdi.nIndex, szCol, &pbReq, &cbReq);
  2127. if (S_OK != hr)
  2128. break;
  2129. hr = ViewRowRequestASN(hwnd, cstrFileName, pbReq, cbReq, fSaveInstead);
  2130. delete [] pbReq;
  2131. if (hr != S_OK)
  2132. break;
  2133. break;
  2134. }
  2135. case IDC_UNREVOKE_CERT:
  2136. {
  2137. ASSERT(pInternal->m_type == CCT_RESULT);
  2138. if (NULL == pFolder)
  2139. break;
  2140. LPWSTR szCertSerNum = NULL;
  2141. DWORD cbSerNum;
  2142. PBYTE pbRevocationReason = NULL;
  2143. DWORD cbRevocationReason;
  2144. HWND hwnd;
  2145. hr = m_pConsole->GetMainWindow(&hwnd);
  2146. if (S_OK != hr)
  2147. hwnd = NULL; // should work
  2148. hr = GetRowColContents(pFolder, rdi.nIndex, wszPROPREQUESTDOT wszPROPREQUESTREVOKEDREASON, &pbRevocationReason, &cbRevocationReason);
  2149. if (S_OK != hr)
  2150. break;
  2151. if ((cbRevocationReason != sizeof(DWORD)) || (*(DWORD*)pbRevocationReason != CRL_REASON_CERTIFICATE_HOLD))
  2152. {
  2153. delete [] pbRevocationReason;
  2154. DisplayCertSrvErrorWithContext(hwnd, S_OK, IDS_UNREVOKE_FAILED); // don't display hokey "invalid state" error, just nice text
  2155. hr = S_OK;
  2156. break;
  2157. }
  2158. delete [] pbRevocationReason;
  2159. // otherwise, continue
  2160. hr = GetRowColContents(pFolder, rdi.nIndex, wszPROPCERTIFICATESERIALNUMBER, (PBYTE*)&szCertSerNum, &cbSerNum);
  2161. if (S_OK != hr)
  2162. break;
  2163. // zero terminate
  2164. WCHAR szTmpSerNum[MAX_PATH+1];
  2165. CopyMemory(szTmpSerNum, szCertSerNum, cbSerNum);
  2166. ASSERT((cbSerNum & 0x1) == 0x00); // better be even!
  2167. szTmpSerNum[cbSerNum>>1] = 0x00;
  2168. delete [] szCertSerNum;
  2169. hr = CertAdminRevokeCert(pFolder->GetCA(), pAdmin, MAXDWORD, szTmpSerNum); // MAXDWORD == unrevoke
  2170. if (hr != S_OK)
  2171. break;
  2172. // dirty pane: refresh
  2173. fMustRefresh = TRUE;
  2174. break;
  2175. }
  2176. case IDC_REVOKECERT:
  2177. {
  2178. ASSERT(pInternal->m_type == CCT_RESULT);
  2179. if (NULL == pFolder)
  2180. break;
  2181. LPWSTR szCertSerNum = NULL;
  2182. DWORD cbSerNum;
  2183. hr = GetRowColContents(pFolder, rdi.nIndex, wszPROPCERTIFICATESERIALNUMBER, (PBYTE*)&szCertSerNum, &cbSerNum);
  2184. if (S_OK != hr)
  2185. break;
  2186. // zero terminate
  2187. WCHAR szTmpSerNum[MAX_PATH+1];
  2188. CopyMemory(szTmpSerNum, szCertSerNum, cbSerNum);
  2189. ASSERT((cbSerNum & 0x1) == 0x00); // better be even!
  2190. szTmpSerNum[cbSerNum>>1] = 0x00;
  2191. delete [] szCertSerNum;
  2192. if (!fConfirmedAction)
  2193. {
  2194. HWND hwnd;
  2195. hr = m_pConsole->GetMainWindow(&hwnd);
  2196. if (S_OK != hr)
  2197. hwnd = NULL; // should work
  2198. hr = GetUserConfirmRevocationReason(&lReasonCode, hwnd);
  2199. if (hr != S_OK)
  2200. goto ExitCommand;
  2201. fConfirmedAction = TRUE;
  2202. }
  2203. if (pcwait == NULL) // this might take awhile
  2204. pcwait = new CWaitCursor;
  2205. hr = CertAdminRevokeCert(pFolder->GetCA(), pAdmin, lReasonCode, szTmpSerNum);
  2206. if (hr != S_OK)
  2207. break;
  2208. // dirty pane: refresh
  2209. fMustRefresh = TRUE;
  2210. break;
  2211. }
  2212. default:
  2213. ASSERT(FALSE); // Unknown command!
  2214. break;
  2215. }
  2216. // if ever the user says stop, halt everything
  2217. if (((HRESULT)ERROR_CANCELLED) == hr)
  2218. goto ExitCommand;
  2219. } // end loop
  2220. } // if result
  2221. else
  2222. {
  2223. ASSERT(FALSE);
  2224. }
  2225. ExitCommand:
  2226. FREE_DATA(pInternal);
  2227. if (pcwait != NULL)
  2228. delete pcwait;
  2229. // might've been cached over multiple selections
  2230. if (pAdmin)
  2231. pAdmin->Release();
  2232. if ((hr != S_OK) && (hr != ERROR_CANCELLED) && (hr != HRESULT_FROM_WIN32(ERROR_CANCELLED)))
  2233. DisplayGenericCertSrvError(m_pConsole, hr);
  2234. // only do this once
  2235. if (fMustRefresh)
  2236. {
  2237. // notify views: refresh service toolbar buttons
  2238. m_pConsole->UpdateAllViews(
  2239. pDataObject,
  2240. 0,
  2241. 0);
  2242. }
  2243. return S_OK;
  2244. }
  2245. STDMETHODIMP CSnapin::GetClassID(CLSID *pClassID)
  2246. {
  2247. ASSERT(pClassID != NULL);
  2248. // Copy the CLSID for this snapin
  2249. *pClassID = CLSID_Snapin;
  2250. return E_NOTIMPL;
  2251. }
  2252. STDMETHODIMP CSnapin::IsDirty()
  2253. {
  2254. // Always save / Always dirty.
  2255. return ThisIsDirty() ? S_OK : S_FALSE;
  2256. }
  2257. STDMETHODIMP CSnapin::Load(IStream *pStm)
  2258. {
  2259. HRESULT hr;
  2260. ASSERT(m_bInitializedC);
  2261. ASSERT(pStm);
  2262. // Read the string
  2263. DWORD dwVer;
  2264. hr = ReadOfSize(pStm, &dwVer, sizeof(DWORD));
  2265. _JumpIfError(hr, Ret, "Load: dwVer");
  2266. ASSERT((VER_CSNAPIN_SAVE_STREAM_3 == dwVer) || (VER_CSNAPIN_SAVE_STREAM_2 == dwVer));
  2267. if ((VER_CSNAPIN_SAVE_STREAM_3 != dwVer) &&
  2268. (VER_CSNAPIN_SAVE_STREAM_2 != dwVer))
  2269. {
  2270. hr = STG_E_OLDFORMAT;
  2271. _JumpError(hr, Ret, "dwVer");
  2272. }
  2273. // version-dependent info
  2274. if (VER_CSNAPIN_SAVE_STREAM_3 == dwVer)
  2275. {
  2276. // View ID
  2277. hr = ReadOfSize(pStm, &m_dwViewID, sizeof(DWORD));
  2278. _JumpIfError(hr, Ret, "Load: m_dwViewID");
  2279. // row enum
  2280. hr = m_RowEnum.Load(pStm);
  2281. _JumpIfError(hr, Ret, "Load::m_RowEnum");
  2282. }
  2283. Ret:
  2284. ClearDirty();
  2285. return hr;
  2286. }
  2287. STDMETHODIMP CSnapin::Save(IStream *pStm, BOOL fClearDirty)
  2288. {
  2289. HRESULT hr;
  2290. ASSERT(m_bInitializedC);
  2291. ASSERT(pStm);
  2292. // Write the version
  2293. DWORD dwVer = VER_CSNAPIN_SAVE_STREAM_3;
  2294. hr = WriteOfSize(pStm, &dwVer, sizeof(DWORD));
  2295. _JumpIfError(hr, Ret, "Save: dwVer");
  2296. // View ID
  2297. hr = WriteOfSize(pStm, &m_dwViewID, sizeof(DWORD));
  2298. _JumpIfError(hr, Ret, "Save: m_dwViewID");
  2299. hr = m_RowEnum.Save(pStm, fClearDirty);
  2300. _JumpIfError(hr, Ret, "Save::m_RowEnum");
  2301. Ret:
  2302. if (fClearDirty)
  2303. ClearDirty();
  2304. return hr;
  2305. }
  2306. STDMETHODIMP CSnapin::GetSizeMax(ULARGE_INTEGER *pcbSize)
  2307. {
  2308. ASSERT(pcbSize);
  2309. DWORD cbSize;
  2310. cbSize = sizeof(DWORD); // Version
  2311. cbSize += sizeof(DWORD); // m_dwViewID
  2312. int iAdditionalSize = 0;
  2313. m_RowEnum.GetSizeMax(&iAdditionalSize);
  2314. cbSize += iAdditionalSize;
  2315. // Set the size of the string to be saved
  2316. ULISet32(*pcbSize, cbSize);
  2317. return S_OK;
  2318. }
  2319. ///////////////////////////////////////////////////////////////////////////////
  2320. // IExtendPropertySheet implementation
  2321. //
  2322. STDMETHODIMP CSnapin::CreatePropertyPages(LPPROPERTYSHEETCALLBACK lpProvider,
  2323. LONG_PTR handle,
  2324. LPDATAOBJECT lpIDataObject)
  2325. {
  2326. // no property pages
  2327. return S_OK;
  2328. }
  2329. STDMETHODIMP CSnapin::QueryPagesFor(LPDATAOBJECT lpDataObject)
  2330. {
  2331. // Get the node type and see if it's one of mine
  2332. // if (nodetype == one of mine)
  2333. // do this
  2334. // else
  2335. // see which node type it is and answer the question
  2336. BOOL bResult = FALSE;
  2337. return (bResult) ? S_OK : S_FALSE;
  2338. // Look at the data object and see if it an item in the scope pane
  2339. // return IsScopePaneNode(lpDataObject) ? S_OK : S_FALSE;
  2340. }
  2341. ///////////////////////////////////////////////////////////////////////////////
  2342. // IExtendControlbar implementation
  2343. //
  2344. STDMETHODIMP CSnapin::SetControlbar(LPCONTROLBAR pControlbar)
  2345. {
  2346. if (m_pControlbar)
  2347. SAFE_RELEASE(m_pControlbar);
  2348. if (pControlbar != NULL)
  2349. {
  2350. // Hold on to the controlbar interface.
  2351. m_pControlbar = pControlbar;
  2352. m_pControlbar->AddRef();
  2353. HRESULT hr=S_FALSE;
  2354. // SvrMgrToolbar1
  2355. if (!m_pSvrMgrToolbar1)
  2356. {
  2357. hr = m_pControlbar->Create(TOOLBAR, this, reinterpret_cast<LPUNKNOWN*>(&m_pSvrMgrToolbar1));
  2358. ASSERT(SUCCEEDED(hr));
  2359. // Add the bitmap
  2360. ASSERT(g_cResources.m_fLoaded);
  2361. hr = m_pSvrMgrToolbar1->AddBitmap(2, g_cResources.m_bmpSvrMgrToolbar1, 16, 16, RGB(192,192,192));
  2362. ASSERT(SUCCEEDED(hr));
  2363. // Add the buttons to the toolbar
  2364. for (int i=0; ((SvrMgrToolbar1Buttons[i].item.lpButtonText != NULL) && (SvrMgrToolbar1Buttons[i].item.lpTooltipText != NULL)); i++)
  2365. {
  2366. hr = m_pSvrMgrToolbar1->AddButtons(1, &SvrMgrToolbar1Buttons[i].item);
  2367. ASSERT(SUCCEEDED(hr));
  2368. }
  2369. }
  2370. }
  2371. return S_OK;
  2372. }
  2373. void CSnapin::OnButtonClick(LPDATAOBJECT pdtobj, int idBtn)
  2374. {
  2375. switch(idBtn)
  2376. {
  2377. case IDC_STOPSERVER:
  2378. case IDC_STARTSERVER:
  2379. // bubble this to our other handler
  2380. dynamic_cast<CComponentDataImpl*>(m_pComponentData)->
  2381. Command(idBtn, pdtobj);
  2382. break;
  2383. default:
  2384. {
  2385. ASSERT(FALSE);
  2386. }
  2387. break;
  2388. }
  2389. }
  2390. STDMETHODIMP CSnapin::ControlbarNotify(MMC_NOTIFY_TYPE event, LPARAM arg, LPARAM param)
  2391. {
  2392. HRESULT hr=S_FALSE;
  2393. switch (event)
  2394. {
  2395. case MMCN_BTN_CLICK:
  2396. OnButtonClick(reinterpret_cast<LPDATAOBJECT>(arg), (INT)param);
  2397. break;
  2398. case MMCN_DESELECT_ALL:
  2399. case MMCN_SELECT:
  2400. HandleExtToolbars((event == MMCN_DESELECT_ALL), arg, param);
  2401. break;
  2402. case MMCN_MENU_BTNCLICK:
  2403. HandleExtMenus(arg, param);
  2404. break;
  2405. default:
  2406. break;
  2407. }
  2408. return S_OK;
  2409. }
  2410. // This compares two data objects to see if they are the same object.
  2411. // return
  2412. // S_OK if equal otherwise S_FALSE
  2413. //
  2414. // Note: check to make sure both objects belong to the snap-in.
  2415. //
  2416. STDMETHODIMP CSnapin::CompareObjects(LPDATAOBJECT lpDataObjectA, LPDATAOBJECT lpDataObjectB)
  2417. {
  2418. return S_FALSE;
  2419. }
  2420. // This compare is used to sort the items in the listview
  2421. //
  2422. // Parameters:
  2423. //
  2424. // lUserParam - user param passed in when IResultData::Sort() was called
  2425. // cookieA - first item to compare
  2426. // cookieB - second item to compare
  2427. // pnResult [in, out]- contains the col on entry,
  2428. // -1, 0, 1 based on comparison for return value.
  2429. //
  2430. // Note: Assume sort is ascending when comparing -- mmc reverses the result if it needs to
  2431. STDMETHODIMP CSnapin::Compare(LPARAM lUserParam, MMC_COOKIE cookieA, MMC_COOKIE cookieB, int* pnResult)
  2432. {
  2433. HRESULT hr;
  2434. if (pnResult == NULL)
  2435. {
  2436. ASSERT(FALSE);
  2437. return E_POINTER;
  2438. }
  2439. // check col range
  2440. LONG nCol = (LONG) *pnResult;
  2441. ASSERT(nCol >=0);
  2442. *pnResult = 0;
  2443. USES_CONVERSION;
  2444. LPWSTR szStringA;
  2445. LPWSTR szStringB;
  2446. RESULT_DATA* pDataA = reinterpret_cast<RESULT_DATA*>(cookieA);
  2447. RESULT_DATA* pDataB = reinterpret_cast<RESULT_DATA*>(cookieB);
  2448. ASSERT(pDataA != NULL && pDataB != NULL);
  2449. ASSERT(nCol < (int)pDataA->cStringArray);
  2450. ASSERT(nCol < (int)pDataB->cStringArray);
  2451. szStringA = OLE2T(pDataA->szStringArray[nCol]);
  2452. szStringB = OLE2T(pDataB->szStringArray[nCol]);
  2453. ASSERT(szStringA != NULL);
  2454. ASSERT(szStringB != NULL);
  2455. if ((szStringA == NULL) || (szStringB == NULL))
  2456. return E_POINTER;
  2457. // return simple strcmp
  2458. *pnResult = wcscmp(szStringA, szStringB);
  2459. return S_OK;
  2460. }
  2461. STDMETHODIMP CSnapin::FindItem(LPRESULTFINDINFO pFindInfo, int* pnFoundIndex)
  2462. {
  2463. // not implemented: S_FALSE == no find
  2464. return S_FALSE;
  2465. }
  2466. STDMETHODIMP CSnapin::CacheHint(int nStartIndex, int nEndIndex)
  2467. {
  2468. return S_OK;
  2469. }
  2470. STDMETHODIMP CSnapin::SortItems(int nColumn, DWORD dwSortOptions, LPARAM lUserParam)
  2471. {
  2472. HRESULT hr;
  2473. LPCWSTR pszHeading;
  2474. BOOL fIndexed = FALSE;
  2475. CComponentDataImpl* pCompData;
  2476. CFolder* pFolder;
  2477. // if non-virtual, report "we don't allow sort"
  2478. if (!m_bVirtualView)
  2479. goto Ret;
  2480. pCompData = dynamic_cast<CComponentDataImpl*>(m_pComponentData);
  2481. if (pCompData == NULL)
  2482. goto Ret;
  2483. pFolder = GetVirtualFolder();
  2484. if (pFolder == NULL)
  2485. goto Ret;
  2486. // responding S_OK to this allows ^ and down arrow display
  2487. hr = pCompData->GetDBSchemaEntry(nColumn, &pszHeading, NULL, &fIndexed);
  2488. _JumpIfError(hr, Ret, "GetDBSchemaEntry");
  2489. if (fIndexed)
  2490. {
  2491. // special case: disallow sort on serial# in failed, pending folders
  2492. // this column has "ignore null" bit set, and sort results in {} set.
  2493. if ((pFolder->GetType() == SERVERFUNC_FAILED_CERTIFICATES) ||
  2494. (pFolder->GetType() == SERVERFUNC_PENDING_CERTIFICATES))
  2495. {
  2496. // if serial number click, act like not indexed -- NO SORT
  2497. if (0 == wcscmp(pszHeading, wszPROPCERTIFICATESERIALNUMBER))
  2498. fIndexed = FALSE;
  2499. }
  2500. }
  2501. Ret:
  2502. // S_FALSE == no sort
  2503. return fIndexed ? S_OK : S_FALSE;
  2504. }
  2505. #define HIDEVERB(__x__) \
  2506. do { \
  2507. m_pConsoleVerb->SetVerbState(__x__, HIDDEN, TRUE); \
  2508. m_pConsoleVerb->SetVerbState(__x__, ENABLED, FALSE); \
  2509. } while(0)
  2510. #define SHOWVERB(__x__) \
  2511. do { \
  2512. m_pConsoleVerb->SetVerbState(__x__, HIDDEN, FALSE); \
  2513. m_pConsoleVerb->SetVerbState(__x__, ENABLED, TRUE); \
  2514. } while(0)
  2515. void CSnapin::HandleStandardVerbs(bool bDeselectAll, LPARAM arg,
  2516. LPDATAOBJECT lpDataObject)
  2517. {
  2518. // You should crack the data object and enable/disable/hide standard
  2519. // commands appropriately. The standard commands are reset everytime you get
  2520. // called. So you must reset them back.
  2521. if (m_CustomViewID != VIEW_DEFAULT_LV)
  2522. {
  2523. // UNDONE: When is this executed?
  2524. SHOWVERB(MMC_VERB_REFRESH);
  2525. SHOWVERB(MMC_VERB_PROPERTIES);
  2526. return;
  2527. }
  2528. if (!bDeselectAll && lpDataObject == NULL)
  2529. return;
  2530. WORD bScope = LOWORD(arg);
  2531. WORD bSelect = HIWORD(arg);
  2532. BOOL bMultiSel = IsMMCMultiSelectDataObject(lpDataObject);
  2533. //
  2534. // Derive internal, pfolder
  2535. //
  2536. INTERNAL* pInternal = lpDataObject ? ExtractInternalFormat(lpDataObject) : NULL;
  2537. // if scope item, derive parent folder from pInternal.
  2538. // if result item, recall parent folder from saved state
  2539. CFolder* pFolder = (bScope) ? ::GetParentFolder(pInternal) : GetParentFolder(pInternal);
  2540. //
  2541. // set state appropriately
  2542. //
  2543. if (bDeselectAll || !bSelect)
  2544. {
  2545. // deselection notification
  2546. // verbs cleared for us, right?
  2547. }
  2548. else if (m_pConsoleVerb && pInternal) // selected
  2549. {
  2550. _MMC_CONSOLE_VERB verbDefault = MMC_VERB_NONE;
  2551. // unsupported properties
  2552. HIDEVERB(MMC_VERB_OPEN);
  2553. HIDEVERB(MMC_VERB_COPY);
  2554. HIDEVERB(MMC_VERB_PASTE);
  2555. HIDEVERB(MMC_VERB_DELETE);
  2556. HIDEVERB(MMC_VERB_PRINT);
  2557. HIDEVERB(MMC_VERB_RENAME); // could easily be supported, but was removed (bug 217502)
  2558. // MMC_VERB_REFRESH is supported
  2559. // MMC_VERB_PROPERTIES is supported
  2560. if (pInternal->m_type == CCT_SCOPE)
  2561. {
  2562. // selected scope item
  2563. // Standard functionality support by scope items
  2564. SHOWVERB(MMC_VERB_REFRESH);
  2565. // Disable properties for static node,
  2566. // enable properties only for server instance, crl
  2567. if ((pInternal->m_cookie != 0) &&
  2568. ((SERVER_INSTANCE == pFolder->m_type) ||
  2569. (SERVERFUNC_CRL_PUBLICATION == pFolder->m_type)) )
  2570. {
  2571. SHOWVERB(MMC_VERB_PROPERTIES);
  2572. }
  2573. else
  2574. HIDEVERB(MMC_VERB_PROPERTIES);
  2575. // default folder verb is open
  2576. verbDefault = MMC_VERB_OPEN;
  2577. }
  2578. else
  2579. {
  2580. // selected result item
  2581. // Standard functionality supported by result items
  2582. SHOWVERB(MMC_VERB_REFRESH);
  2583. HIDEVERB(MMC_VERB_PROPERTIES);
  2584. }
  2585. m_pConsoleVerb->SetDefaultVerb(verbDefault);
  2586. }
  2587. FREE_DATA(pInternal);
  2588. }
  2589. void CSnapin::SmartEnableServiceControlButtons()
  2590. {
  2591. BOOL fSvcRunning;
  2592. CComponentDataImpl* pCompData = dynamic_cast<CComponentDataImpl*>(m_pComponentData);
  2593. if (pCompData)
  2594. {
  2595. fSvcRunning = pCompData->m_pCertMachine->IsCertSvrServiceRunning();
  2596. if (m_pSvrMgrToolbar1)
  2597. {
  2598. m_pSvrMgrToolbar1->SetButtonState(SvrMgrToolbar1Buttons[ENUM_BUTTON_STARTSVC].item.idCommand, ENABLED, !fSvcRunning);
  2599. m_pSvrMgrToolbar1->SetButtonState(SvrMgrToolbar1Buttons[ENUM_BUTTON_STOPSVC].item.idCommand, ENABLED, fSvcRunning);
  2600. }
  2601. }
  2602. }
  2603. void CSnapin::HandleExtToolbars(bool bDeselectAll, LPARAM arg, LPARAM param)
  2604. {
  2605. INTERNAL* pInternal = NULL;
  2606. HRESULT hr;
  2607. BOOL bScope = (BOOL) LOWORD(arg);
  2608. BOOL bSelect = (BOOL) HIWORD(arg);
  2609. if (param)
  2610. pInternal = ExtractInternalFormat(reinterpret_cast<LPDATAOBJECT>(param));
  2611. // Deselection Notification?
  2612. if (bDeselectAll || bSelect == FALSE)
  2613. return;
  2614. ASSERT(bSelect == TRUE);
  2615. bool bFileExBtn = false;
  2616. if (pInternal == NULL)
  2617. return;
  2618. CFolder* pFolder = GetParentFolder(pInternal);
  2619. if (bScope == TRUE)
  2620. {
  2621. // special stuff to do at SCOPE level?
  2622. }
  2623. else // result item selected: result or subfolder
  2624. {
  2625. // special stuff to do at RESULTS level
  2626. if (pInternal->m_type == CCT_RESULT)
  2627. {
  2628. bFileExBtn = true;
  2629. // UNDONE: what to do here with SvrMgrToolbar1Buttons1?
  2630. // For now, do nothing: allow them to remain in same state
  2631. }
  2632. }
  2633. CComponentDataImpl* pData = dynamic_cast<CComponentDataImpl*>(m_pComponentData);
  2634. ASSERT(pData != NULL);
  2635. if ((IsPrimaryImpl() == TRUE) &&
  2636. (IsAllowedStartStop(pFolder, pData->m_pCertMachine)) )
  2637. {
  2638. // Attach the SvrMgrToolbar1 to the window
  2639. hr = m_pControlbar->Attach(TOOLBAR, (LPUNKNOWN) m_pSvrMgrToolbar1);
  2640. ASSERT(SUCCEEDED(hr));
  2641. }
  2642. else
  2643. {
  2644. // Detach the SvrMgrToolbar1 to the window
  2645. hr = m_pControlbar->Detach((LPUNKNOWN) m_pSvrMgrToolbar1);
  2646. ASSERT(SUCCEEDED(hr));
  2647. }
  2648. SmartEnableServiceControlButtons();
  2649. FREE_DATA(pInternal);
  2650. }
  2651. // dropdown menu addition
  2652. void CSnapin::HandleExtMenus(LPARAM arg, LPARAM param)
  2653. {
  2654. }
  2655. CFolder* CSnapin::GetVirtualFolder()
  2656. {
  2657. ASSERT(m_bVirtualView);
  2658. return m_pCurrentlySelectedScopeFolder;
  2659. }