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.

1240 lines
37 KiB

  1. //--------------------------------------------------------------
  2. // Copyright (C) Microsoft Corporation, 1996 - 1999
  3. //
  4. // File: CryptPKO.cpp
  5. //
  6. // content: Implements the IContextMenu member functions necessary to support
  7. // the context menu portioins of this shell extension. Context menu
  8. // shell extensions are called when the user right clicks on a file
  9. // History: 16-09-1997 xiaohs created
  10. //
  11. //--------------------------------------------------------------
  12. #include "stdafx.h"
  13. #include "cryptext.h"
  14. #include "private.h"
  15. #include "CryptPKO.h"
  16. //QueryContextMenu is called twice by the Shell.
  17. //we have to set the flag.
  18. BOOL g_fDefaultCalled=FALSE;
  19. HRESULT I_InvokeCommand(LPWSTR pwszFileName, UINT idCmd, BOOL fDefault)
  20. {
  21. DWORD dwContentType=0;
  22. DWORD dwFormatType=0;
  23. HCERTSTORE hCertStore=NULL;
  24. HCRYPTMSG hMsg=NULL;
  25. const void *pvContext=NULL;
  26. UINT idsFileName=0;
  27. HRESULT hr = E_FAIL;
  28. CRYPTUI_VIEWCERTIFICATE_STRUCT CertViewStruct;
  29. CRYPTUI_VIEWCRL_STRUCT CRLViewStruct;
  30. CRYPTUI_WIZ_IMPORT_SRC_INFO importSubject;
  31. //get the content type of the file
  32. //we care about every file type except for the signed doc
  33. if(!CryptQueryObject(CERT_QUERY_OBJECT_FILE,
  34. pwszFileName,
  35. CERT_QUERY_CONTENT_FLAG_ALL,
  36. CERT_QUERY_FORMAT_FLAG_ALL,
  37. 0,
  38. NULL,
  39. &dwContentType,
  40. &dwFormatType,
  41. &hCertStore,
  42. &hMsg,
  43. &pvContext))
  44. {
  45. I_NoticeBox(
  46. GetLastError(),
  47. 0,
  48. NULL,
  49. IDS_MSG_TITLE,
  50. IDS_PKO_NAME,
  51. IDS_MSG_INVALID_FILE,
  52. MB_OK|MB_ICONINFORMATION);
  53. goto CLEANUP;
  54. }
  55. //make sure idCmd is the correct valud for different types
  56. //we are guaranteed that idCmd is 1 or 0
  57. if(CERT_QUERY_CONTENT_CERT != dwContentType &&
  58. CERT_QUERY_CONTENT_CTL != dwContentType &&
  59. CERT_QUERY_CONTENT_CRL != dwContentType &&
  60. CERT_QUERY_CONTENT_PKCS7_SIGNED != dwContentType)
  61. {
  62. if(1==idCmd)
  63. {
  64. hr=E_INVALIDARG;
  65. goto CLEANUP;
  66. }
  67. }
  68. switch (dwContentType)
  69. {
  70. case CERT_QUERY_CONTENT_CERT:
  71. if(idCmd==0)
  72. {
  73. //call the Certificate Common Dialogue
  74. memset(&CertViewStruct, 0, sizeof(CRYPTUI_VIEWCERTIFICATE_STRUCT));
  75. CertViewStruct.dwSize=sizeof(CRYPTUI_VIEWCERTIFICATE_STRUCT);
  76. CertViewStruct.pCertContext=(PCCERT_CONTEXT)pvContext;
  77. CryptUIDlgViewCertificate(&CertViewStruct, NULL);
  78. }
  79. else
  80. {
  81. memset(&importSubject, 0, sizeof(CRYPTUI_WIZ_IMPORT_SRC_INFO));
  82. importSubject.dwSize=sizeof(CRYPTUI_WIZ_IMPORT_SRC_INFO);
  83. importSubject.dwSubjectChoice=CRYPTUI_WIZ_IMPORT_SUBJECT_CERT_CONTEXT;
  84. importSubject.pCertContext=(PCCERT_CONTEXT)pvContext;
  85. CryptUIWizImport(0,
  86. NULL,
  87. NULL,
  88. &importSubject,
  89. NULL);
  90. }
  91. break;
  92. case CERT_QUERY_CONTENT_CTL:
  93. if(idCmd==0)
  94. I_ViewCTL((PCCTL_CONTEXT)pvContext);
  95. else
  96. {
  97. //we do not need to install a catalog file
  98. if(!IsCatalog((PCCTL_CONTEXT)pvContext))
  99. {
  100. memset(&importSubject, 0, sizeof(CRYPTUI_WIZ_IMPORT_SRC_INFO));
  101. importSubject.dwSize=sizeof(CRYPTUI_WIZ_IMPORT_SRC_INFO);
  102. importSubject.dwSubjectChoice=CRYPTUI_WIZ_IMPORT_SUBJECT_CTL_CONTEXT;
  103. importSubject.pCTLContext=(PCCTL_CONTEXT)pvContext;
  104. CryptUIWizImport(0,
  105. NULL,
  106. NULL,
  107. &importSubject,
  108. NULL);
  109. }
  110. }
  111. break;
  112. case CERT_QUERY_CONTENT_CRL:
  113. if(idCmd==0)
  114. {
  115. //call the CRL view dialogue
  116. memset(&CRLViewStruct, 0, sizeof(CRYPTUI_VIEWCRL_STRUCT));
  117. CRLViewStruct.dwSize=sizeof(CRYPTUI_VIEWCRL_STRUCT);
  118. CRLViewStruct.pCRLContext=(PCCRL_CONTEXT)pvContext;
  119. CryptUIDlgViewCRL(&CRLViewStruct);
  120. }
  121. else
  122. {
  123. memset(&importSubject, 0, sizeof(CRYPTUI_WIZ_IMPORT_SRC_INFO));
  124. importSubject.dwSize=sizeof(CRYPTUI_WIZ_IMPORT_SRC_INFO);
  125. importSubject.dwSubjectChoice=CRYPTUI_WIZ_IMPORT_SUBJECT_CRL_CONTEXT;
  126. importSubject.pCRLContext=(PCCRL_CONTEXT)pvContext;
  127. CryptUIWizImport(0,
  128. NULL,
  129. NULL,
  130. &importSubject,
  131. NULL);
  132. }
  133. break;
  134. case CERT_QUERY_CONTENT_SERIALIZED_STORE:
  135. idsFileName=IDS_SERIALIZED_STORE;
  136. case CERT_QUERY_CONTENT_SERIALIZED_CERT:
  137. if(0 == idsFileName)
  138. idsFileName=IDS_SERIALIZED_CERT;
  139. case CERT_QUERY_CONTENT_SERIALIZED_CTL:
  140. if(0 == idsFileName)
  141. idsFileName=IDS_SERIALIZED_STL;
  142. case CERT_QUERY_CONTENT_SERIALIZED_CRL:
  143. if(0 == idsFileName)
  144. idsFileName=IDS_SERIALIZED_CRL;
  145. if(!FIsWinNT5())
  146. {
  147. I_NoticeBox(
  148. 0,
  149. 0,
  150. NULL,
  151. IDS_MSG_VALID_TITLE,
  152. idsFileName,
  153. IDS_MSG_VALID_SIGN_FILE,
  154. MB_OK|MB_ICONINFORMATION);
  155. }
  156. else
  157. {
  158. LauchCertMgr(pwszFileName);
  159. }
  160. break;
  161. case CERT_QUERY_CONTENT_PKCS7_SIGNED:
  162. if(idCmd==0)
  163. {
  164. if(!FIsWinNT5())
  165. {
  166. I_NoticeBox(
  167. 0,
  168. 0,
  169. NULL,
  170. IDS_MSG_VALID_TITLE,
  171. IDS_PKCS7_NAME,
  172. IDS_MSG_VALID_SIGN_FILE,
  173. MB_OK|MB_ICONINFORMATION);
  174. }
  175. else
  176. {
  177. LauchCertMgr(pwszFileName);
  178. }
  179. }
  180. else
  181. {
  182. //we are doing the import
  183. memset(&importSubject, 0, sizeof(CRYPTUI_WIZ_IMPORT_SRC_INFO));
  184. importSubject.dwSize=sizeof(CRYPTUI_WIZ_IMPORT_SRC_INFO);
  185. importSubject.dwSubjectChoice=CRYPTUI_WIZ_IMPORT_SUBJECT_FILE;
  186. importSubject.pwszFileName=pwszFileName;
  187. CryptUIWizImport(0,
  188. NULL,
  189. NULL,
  190. &importSubject,
  191. NULL);
  192. }
  193. break;
  194. case CERT_QUERY_CONTENT_PKCS7_SIGNED_EMBED:
  195. I_NoticeBox(
  196. 0,
  197. 0,
  198. NULL,
  199. IDS_MSG_VALID_TITLE,
  200. IDS_SIGN_NAME,
  201. IDS_MSG_VALID_SIGN_FILE,
  202. MB_OK|MB_ICONINFORMATION);
  203. break;
  204. case CERT_QUERY_CONTENT_PFX:
  205. memset(&importSubject, 0, sizeof(CRYPTUI_WIZ_IMPORT_SRC_INFO));
  206. importSubject.dwSize=sizeof(CRYPTUI_WIZ_IMPORT_SRC_INFO);
  207. importSubject.dwSubjectChoice=CRYPTUI_WIZ_IMPORT_SUBJECT_FILE;
  208. importSubject.pwszFileName=pwszFileName;
  209. CryptUIWizImport(0,
  210. NULL,
  211. NULL,
  212. &importSubject,
  213. NULL);
  214. break;
  215. case CERT_QUERY_CONTENT_PKCS7_UNSIGNED:
  216. I_NoticeBox(
  217. 0,
  218. 0,
  219. NULL,
  220. IDS_MSG_VALID_TITLE,
  221. IDS_PKCS7_UNSIGNED_NAME,
  222. IDS_MSG_VALID_FILE,
  223. MB_OK|MB_ICONINFORMATION);
  224. break;
  225. case CERT_QUERY_CONTENT_PKCS10:
  226. I_NoticeBox(
  227. 0,
  228. 0,
  229. NULL,
  230. IDS_MSG_VALID_TITLE,
  231. IDS_P10_NAME,
  232. IDS_MSG_VALID_FILE,
  233. MB_OK|MB_ICONINFORMATION);
  234. break;
  235. default:
  236. break;
  237. }
  238. hr=S_OK;
  239. CLEANUP:
  240. //relaset the stores and reset the local parameters
  241. if(hCertStore)
  242. CertCloseStore(hCertStore, 0);
  243. if(hMsg)
  244. CryptMsgClose(hMsg);
  245. if(pvContext)
  246. {
  247. if(dwContentType == CERT_QUERY_CONTENT_CERT ||
  248. dwContentType == CERT_QUERY_CONTENT_SERIALIZED_CERT)
  249. CertFreeCertificateContext((PCCERT_CONTEXT)pvContext);
  250. else
  251. {
  252. if(dwContentType == CERT_QUERY_CONTENT_CTL ||
  253. dwContentType == CERT_QUERY_CONTENT_SERIALIZED_CTL)
  254. CertFreeCTLContext((PCCTL_CONTEXT)pvContext);
  255. else
  256. {
  257. if(dwContentType == CERT_QUERY_CONTENT_CRL ||
  258. dwContentType == CERT_QUERY_CONTENT_SERIALIZED_CRL)
  259. CertFreeCRLContext((PCCRL_CONTEXT)pvContext);
  260. }
  261. }
  262. }
  263. return hr;
  264. }
  265. /////////////////////////////////////////////////////////////////////////////
  266. // CCryptPKO
  267. //--------------------------------------------------------------
  268. //
  269. // FUNCTION: GAKPageCallback(HWND, UINT, LPPROPSHEETPAGE)
  270. //
  271. // PURPOSE: Callback procedure for the property page
  272. //
  273. // PARAMETERS:
  274. // hWnd - Reserved (will always be NULL)
  275. // uMessage - Action flag: Are we being created or released
  276. // ppsp - The page that is being created or destroyed
  277. //
  278. // RETURN VALUE:
  279. //
  280. // Depends on message.
  281. //
  282. // For PSPCB_CREATE it's TRUE to let the page be created
  283. // or false to prevent it from being created.
  284. // For PSPCB_RELEASE the return value is ignored.
  285. //
  286. // COMMENTS:
  287. //
  288. BOOL CALLBACK
  289. SignPKOPageCallBack(HWND hWnd,
  290. UINT uMessage,
  291. void *pvCallBack)
  292. {
  293. switch(uMessage)
  294. {
  295. case PSPCB_CREATE:
  296. return TRUE;
  297. case PSPCB_RELEASE:
  298. if (pvCallBack)
  299. {
  300. ((IShellPropSheetExt *)(pvCallBack))->Release();
  301. }
  302. return TRUE;
  303. }
  304. return TRUE;
  305. }
  306. //--------------------------------------------------------------
  307. //
  308. // Constructor
  309. //
  310. //--------------------------------------------------------------
  311. CCryptPKO::CCryptPKO()
  312. {
  313. m_pDataObj=NULL;
  314. }
  315. //--------------------------------------------------------------
  316. //
  317. // Destructor
  318. //
  319. //--------------------------------------------------------------
  320. CCryptPKO::~CCryptPKO()
  321. {
  322. if (m_pDataObj)
  323. m_pDataObj->Release();
  324. }
  325. //--------------------------------------------------------------
  326. // FUNCTION: CCryptSig::AddPages(LPFNADDPROPSHEETPAGE, LPARAM)
  327. //
  328. // PURPOSE: Called by the shell just before the property sheet is displayed.
  329. //
  330. // PARAMETERS:
  331. // lpfnAddPage - Pointer to the Shell's AddPage function
  332. // lParam - Passed as second parameter to lpfnAddPage
  333. //
  334. // RETURN VALUE:
  335. //
  336. // NOERROR in all cases. If for some reason our pages don't get added,
  337. // the Shell still needs to bring up the Properties... sheet.
  338. //
  339. // COMMENTS:
  340. //--------------------------------------------------------------
  341. STDMETHODIMP CCryptPKO::AddPages(LPFNADDPROPSHEETPAGE lpfnAddPage, LPARAM lParam)
  342. {
  343. HPROPSHEETPAGE hpage;
  344. PROPSHEETPAGEW *pPage=NULL;
  345. DWORD dwPage=0;
  346. DWORD dwIndex=0;
  347. FORMATETC fmte = {CF_HDROP,
  348. (DVTARGETDEVICE FAR *)NULL,
  349. DVASPECT_CONTENT,
  350. -1,
  351. TYMED_HGLOBAL
  352. };
  353. STGMEDIUM stgm;
  354. UINT ucFiles=0;
  355. WCHAR wszFileName[_MAX_PATH];
  356. HCRYPTMSG hMsg=NULL;
  357. HRESULT hr=E_FAIL;
  358. DWORD dwExceptionCode=0;
  359. CRYPTUI_VIEWSIGNATURES_STRUCTW sigView;
  360. //get the file name that user clicked on. We do not add context menu
  361. //if user has selected more than one file
  362. if (m_pDataObj)
  363. hr = m_pDataObj->GetData(&fmte, &stgm);
  364. if (!SUCCEEDED(hr))
  365. return NOERROR;
  366. ucFiles = stgm.hGlobal ?
  367. DragQueryFileU((HDROP) stgm.hGlobal, 0xFFFFFFFFL , 0, 0) : 0;
  368. if ((!ucFiles) || (ucFiles >= 2))
  369. {
  370. ReleaseStgMedium(&stgm);
  371. return NOERROR; // Shouldn't happen, but it's not important
  372. }
  373. if(0==DragQueryFileU((HDROP) stgm.hGlobal, 0, wszFileName,
  374. sizeof wszFileName/ sizeof wszFileName[0]))
  375. {
  376. ReleaseStgMedium(&stgm);
  377. return NOERROR;
  378. }
  379. //get the content type of the file. We only cares about
  380. //the signed document in binary format
  381. if(!CryptQueryObject(CERT_QUERY_OBJECT_FILE,
  382. wszFileName,
  383. CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED,
  384. CERT_QUERY_FORMAT_FLAG_BASE64_ENCODED,
  385. 0,
  386. NULL,
  387. NULL,
  388. NULL,
  389. NULL,
  390. &hMsg,
  391. NULL))
  392. {
  393. //can not recognize the object. Fine
  394. goto CLEANUP;
  395. }
  396. //add the property sheet page
  397. memset(&sigView, 0, sizeof(CRYPTUI_VIEWSIGNATURES_STRUCTW));
  398. sigView.dwSize=sizeof(CRYPTUI_VIEWSIGNATURES_STRUCTW);
  399. sigView.choice=hMsg_Chosen;
  400. sigView.u.hMsg=hMsg;
  401. sigView.szFileName=wszFileName;
  402. sigView.pPropPageCallback=SignPKOPageCallBack;
  403. sigView.pvCallbackData=this;
  404. if(!CryptUIGetViewSignaturesPagesW(
  405. &sigView,
  406. &pPage,
  407. &dwPage))
  408. goto CLEANUP;
  409. __try {
  410. for(dwIndex=0; dwIndex<dwPage; dwIndex++)
  411. {
  412. //add the callback functions to release the refcount
  413. //pPage[dwIndex].dwFlags |= PSP_USECALLBACK;
  414. //pPage[dwIndex].pfnCallback=SignPKOPageCallBack;
  415. //pPage[dwIndex].pcRefParent=(UINT *)this;
  416. hpage = CreatePropertySheetPageU(&(pPage[dwIndex]));
  417. ((IShellPropSheetExt *)this)->AddRef();
  418. if (hpage)
  419. {
  420. if (!lpfnAddPage(hpage, lParam))
  421. {
  422. DestroyPropertySheetPage(hpage);
  423. ((IShellPropSheetExt *)this)->Release();
  424. }
  425. }
  426. }
  427. } __except(EXCEPTION_EXECUTE_HANDLER) {
  428. dwExceptionCode = GetExceptionCode();
  429. goto CLEANUP;
  430. }
  431. CLEANUP:
  432. ReleaseStgMedium(&stgm);
  433. if(pPage)
  434. CryptUIFreeViewSignaturesPagesW(pPage, dwPage);
  435. if(hMsg)
  436. CryptMsgClose(hMsg);
  437. return NOERROR;
  438. }
  439. //--------------------------------------------------------------
  440. // FUNCTION: CCryptSig::ReplacePage(UINT, LPFNADDPROPSHEETPAGE, LPARAM)
  441. //
  442. // PURPOSE: Called by the shell only for Control Panel property sheet
  443. // extensions
  444. //
  445. // PARAMETERS:
  446. // uPageID - ID of page to be replaced
  447. // lpfnReplaceWith - Pointer to the Shell's Replace function
  448. // lParam - Passed as second parameter to lpfnReplaceWith
  449. //
  450. // RETURN VALUE:
  451. //
  452. // E_FAIL, since we don't support this function. It should never be
  453. // called.
  454. // COMMENTS:
  455. //--------------------------------------------------------------
  456. STDMETHODIMP CCryptPKO::ReplacePage(UINT uPageID,
  457. LPFNADDPROPSHEETPAGE lpfnReplaceWith,
  458. LPARAM lParam)
  459. {
  460. return E_FAIL;
  461. }
  462. //--------------------------------------------------------------
  463. // FUNCTION: CCryptPKO::QueryContextMenu(HMENU, UINT, UINT, UINT, UINT)
  464. //
  465. // PURPOSE: Called by the shell just before the context menu is displayed.
  466. //
  467. // PARAMETERS:
  468. // hMenu - Handle to the context menu
  469. // indexMenu - Index of where to begin inserting menu items
  470. // idCmdFirst - Lowest value for new menu ID's
  471. // idCmtLast - Highest value for new menu ID's
  472. // uFlags - Specifies the context of the menu event
  473. //
  474. // RETURN VALUE:
  475. // We always return NOERROR unless when we succeeded, when
  476. // we have to return HRESULT structure in which, if the method
  477. // is successful, the code member contains the menu identifier
  478. // offset of the last menu item added plus one.
  479. //--------------------------------------------------------------
  480. STDMETHODIMP CCryptPKO::QueryContextMenu(HMENU hMenu,
  481. UINT indexMenu,
  482. UINT idCmdFirst,
  483. UINT idCmdLast,
  484. UINT uFlags)
  485. {
  486. DWORD dwContentType=0;
  487. DWORD dwFormatType=0;
  488. FORMATETC fmte = {CF_HDROP,
  489. (DVTARGETDEVICE FAR *)NULL,
  490. DVASPECT_CONTENT,
  491. -1,
  492. TYMED_HGLOBAL
  493. };
  494. STGMEDIUM stgm;
  495. HRESULT hr = E_FAIL;
  496. UINT ucFiles=0;
  497. WCHAR wszFileName[_MAX_PATH];
  498. WCHAR wszOpen[MAX_COMMAND_LENGTH];
  499. WCHAR wszAdd[MAX_COMMAND_LENGTH];
  500. WCHAR wszViewSig[MAX_COMMAND_LENGTH];
  501. UINT idCmd = idCmdFirst;
  502. UINT idCmdDefault=idCmdFirst;
  503. MENUITEMINFOA MenuItemInfo;
  504. void *pContext=NULL;
  505. //init the menuInfo for setting the default menu
  506. memset(&MenuItemInfo, 0, sizeof(MENUITEMINFOA));
  507. MenuItemInfo.cbSize=sizeof(MENUITEMINFOA);
  508. MenuItemInfo.fMask=MIIM_STATE;
  509. MenuItemInfo.fState=MFS_DEFAULT;
  510. //get the file name that user clicked on. We do not add context menu
  511. //if user has selected more than one file
  512. if (m_pDataObj)
  513. hr = m_pDataObj->GetData(&fmte, &stgm);
  514. if (!SUCCEEDED(hr))
  515. return NOERROR;
  516. ucFiles = stgm.hGlobal ?
  517. DragQueryFileU((HDROP) stgm.hGlobal, 0xFFFFFFFFL , 0, 0) : 0;
  518. if ((!ucFiles) || (ucFiles >= 2))
  519. return NOERROR; // Shouldn't happen, but it's not important
  520. if(0==DragQueryFileU((HDROP) stgm.hGlobal, 0, wszFileName,
  521. sizeof wszFileName/ sizeof wszFileName[0]))
  522. return NOERROR;
  523. //if user double click on a file, we need the take the
  524. //default action
  525. /* if(uFlags & CMF_DEFAULTONLY)
  526. {
  527. //QueryContextMenu is called twice by the Shell.
  528. //we have to set the flag.
  529. if(FALSE==g_fDefaultCalled)
  530. {
  531. hr=I_InvokeCommand(pwszFileName, 0, TRUE);
  532. g_fDefaultCalled=TRUE;
  533. }
  534. else
  535. g_fDefaultCalled=FALSE;
  536. idCmd=idCmdFirst;
  537. goto CLEANUP;
  538. } */
  539. //decide if we need to add the context menu
  540. if (!(
  541. ((uFlags & 0x000F) == CMF_NORMAL)||
  542. (uFlags & CMF_VERBSONLY) ||
  543. (uFlags & CMF_EXPLORE) ||
  544. (uFlags & CMF_DEFAULTONLY)
  545. ))
  546. goto CLEANUP;
  547. //load the string
  548. if(!LoadStringU(g_hmodThisDll, IDS_MENU_OPEN, wszOpen, sizeof(wszOpen)/sizeof(wszOpen[0]))||
  549. !LoadStringU(g_hmodThisDll, IDS_MENU_VIEWSIG, wszViewSig, sizeof(wszViewSig)/sizeof(wszViewSig[0]))
  550. )
  551. goto CLEANUP;
  552. //get the content type of the file
  553. //we care about every file type and every format type
  554. if(!CryptQueryObject(CERT_QUERY_OBJECT_FILE,
  555. wszFileName,
  556. CERT_QUERY_CONTENT_FLAG_ALL,
  557. CERT_QUERY_FORMAT_FLAG_ALL,
  558. 0,
  559. NULL,
  560. &dwContentType,
  561. &dwFormatType,
  562. NULL,
  563. NULL,
  564. (const void **)&pContext))
  565. {
  566. //add the open menu
  567. if(0==InsertMenuU(hMenu,
  568. indexMenu++,
  569. MF_STRING|MF_BYPOSITION,
  570. idCmd++,
  571. wszOpen))
  572. goto CLEANUP;
  573. // if there is no default verb, set open as default
  574. if (GetMenuDefaultItem(hMenu, MF_BYPOSITION, 0) == -1)
  575. {
  576. // use indexMenu - 1 since we incremented indexMenu in the InsertMenu
  577. SetMenuDefaultItem(hMenu, indexMenu -1, MF_BYPOSITION);
  578. }
  579. //set the open to be the default menu item
  580. idCmdDefault=idCmd-1;
  581. //no need for error checking
  582. /* SetMenuItemInfoA(hMenu,
  583. idCmdDefault,
  584. FALSE,
  585. &MenuItemInfo); */
  586. goto CLEANUP;
  587. }
  588. switch (dwContentType)
  589. {
  590. case CERT_QUERY_CONTENT_CERT:
  591. case CERT_QUERY_CONTENT_PKCS7_SIGNED:
  592. //get the correct wording for the second menu item based
  593. // on the content
  594. if(!LoadStringU(g_hmodThisDll, IDS_MENU_INSTALL_CERT, wszAdd, sizeof(wszAdd)/sizeof(wszAdd[0])))
  595. goto CLEANUP;
  596. case CERT_QUERY_CONTENT_CTL:
  597. if(CERT_QUERY_CONTENT_CTL == dwContentType)
  598. {
  599. if(!LoadStringU(g_hmodThisDll, IDS_MENU_INSTALL_STL, wszAdd, sizeof(wszAdd)/sizeof(wszAdd[0])))
  600. goto CLEANUP;
  601. }
  602. case CERT_QUERY_CONTENT_CRL:
  603. if(CERT_QUERY_CONTENT_CRL == dwContentType)
  604. {
  605. if(!LoadStringU(g_hmodThisDll, IDS_MENU_INSTALL_CRL, wszAdd, sizeof(wszAdd)/sizeof(wszAdd[0])))
  606. goto CLEANUP;
  607. }
  608. //make sure we can add at least two items
  609. if(2 > (idCmdLast-idCmdFirst))
  610. goto CLEANUP;
  611. //add the open menu
  612. if(0==InsertMenuU(hMenu,
  613. indexMenu++,
  614. MF_STRING|MF_BYPOSITION,
  615. idCmd++,
  616. wszOpen))
  617. goto CLEANUP;
  618. //set the open to be the default menu item
  619. idCmdDefault=idCmd-1;
  620. //no need for error checking
  621. //set the default menu item
  622. SetMenuItemInfoA(hMenu,
  623. idCmdDefault,
  624. FALSE,
  625. &MenuItemInfo);
  626. //add the add menu
  627. //do not put "install" for the catalog files
  628. if( !((CERT_QUERY_CONTENT_CTL == dwContentType)
  629. && IsCatalog((PCCTL_CONTEXT)pContext))
  630. )
  631. {
  632. if(0==InsertMenuU(hMenu,
  633. indexMenu++,
  634. MF_STRING|MF_BYPOSITION,
  635. idCmd++,
  636. wszAdd))
  637. goto CLEANUP;
  638. }
  639. break;
  640. case CERT_QUERY_CONTENT_SERIALIZED_STORE:
  641. case CERT_QUERY_CONTENT_SERIALIZED_CERT:
  642. case CERT_QUERY_CONTENT_SERIALIZED_CTL:
  643. case CERT_QUERY_CONTENT_SERIALIZED_CRL:
  644. //add the open menu
  645. if(0==InsertMenuU(hMenu,
  646. indexMenu++,
  647. MF_STRING|MF_BYPOSITION,
  648. idCmd++,
  649. wszOpen))
  650. goto CLEANUP;
  651. //set the open to be the default menu item
  652. idCmdDefault=idCmd-1;
  653. //no need for error checking
  654. SetMenuItemInfoA(hMenu,
  655. idCmdDefault,
  656. FALSE,
  657. &MenuItemInfo);
  658. break;
  659. case CERT_QUERY_CONTENT_PFX:
  660. if(!LoadStringU(g_hmodThisDll, IDS_MENU_INSTALL_PFX, wszAdd, sizeof(wszAdd)/sizeof(wszAdd[0])))
  661. goto CLEANUP;
  662. //add the install menu
  663. if(0==InsertMenuU(hMenu,
  664. indexMenu++,
  665. MF_STRING|MF_BYPOSITION,
  666. idCmd++,
  667. wszAdd))
  668. goto CLEANUP;
  669. //set the add to be the default menu item
  670. idCmdDefault=idCmd-1;
  671. //no need for error checking
  672. SetMenuItemInfoA(hMenu,
  673. idCmdDefault,
  674. FALSE,
  675. &MenuItemInfo);
  676. break;
  677. case CERT_QUERY_CONTENT_PKCS7_SIGNED_EMBED:
  678. //signed data case is handled by the property sheet extension
  679. default:
  680. //we do not worry about CERT_QUERY_CONTENT_PKCS7_UNSIGNED or
  681. //CERT_QUERY_CONTENT_PKCS10 or CERT_QUERY_CONTENT_PFX for now
  682. //add the open menu
  683. if(0==InsertMenuU(hMenu,
  684. indexMenu++,
  685. MF_STRING|MF_BYPOSITION,
  686. idCmd++,
  687. wszOpen))
  688. goto CLEANUP;
  689. //set the open to be the default menu item
  690. idCmdDefault=idCmd-1;
  691. // if there is no default verb, set open as default
  692. if (GetMenuDefaultItem(hMenu, MF_BYPOSITION, 0) == -1)
  693. {
  694. // use indexMenu - 1 since we incremented indexMenu in the InsertMenu
  695. SetMenuDefaultItem(hMenu, indexMenu -1, MF_BYPOSITION);
  696. }
  697. break;
  698. }
  699. CLEANUP:
  700. if(idCmd-idCmdFirst)
  701. {
  702. //Must return number of menu items we added.
  703. hr=ResultFromShort(idCmd-idCmdFirst);
  704. }
  705. else
  706. //do not care if error happens. No menu items have been added
  707. hr=NOERROR;
  708. if(pContext)
  709. {
  710. if(dwContentType == CERT_QUERY_CONTENT_CERT ||
  711. dwContentType == CERT_QUERY_CONTENT_SERIALIZED_CERT)
  712. CertFreeCertificateContext((PCCERT_CONTEXT)pContext);
  713. else
  714. {
  715. if(dwContentType == CERT_QUERY_CONTENT_CTL ||
  716. dwContentType == CERT_QUERY_CONTENT_SERIALIZED_CTL)
  717. CertFreeCTLContext((PCCTL_CONTEXT)pContext);
  718. else
  719. {
  720. if(dwContentType == CERT_QUERY_CONTENT_CRL ||
  721. dwContentType == CERT_QUERY_CONTENT_SERIALIZED_CRL)
  722. CertFreeCRLContext((PCCRL_CONTEXT)pContext);
  723. }
  724. }
  725. }
  726. return hr;
  727. }
  728. //--------------------------------------------------------------
  729. // FUNCTION: CCryptPKO::InvokeCommand(LPCMINVOKECOMMANDINFO)
  730. //
  731. // PURPOSE: Called by the shell after the user has selected on of the
  732. // menu items that was added in QueryContextMenu().
  733. //
  734. // PARAMETERS:
  735. // lpcmi - Pointer to an CMINVOKECOMMANDINFO structure
  736. //
  737. // RETURN VALUE:
  738. //
  739. //--------------------------------------------------------------
  740. STDMETHODIMP CCryptPKO::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi)
  741. {
  742. FORMATETC fmte = {CF_HDROP,
  743. (DVTARGETDEVICE FAR *)NULL,
  744. DVASPECT_CONTENT,
  745. -1,
  746. TYMED_HGLOBAL
  747. };
  748. STGMEDIUM stgm;
  749. HRESULT hr = E_FAIL;
  750. UINT ucFiles=0;
  751. WCHAR wszFileName[_MAX_PATH];
  752. UINT idCmd=0;
  753. //get the file name that user clicked on. We do not add context menu
  754. //if user has selected more than one file
  755. if (m_pDataObj)
  756. hr = m_pDataObj->GetData(&fmte, &stgm);
  757. if (!SUCCEEDED(hr))
  758. return hr;
  759. //get the number of files that user clicked on
  760. ucFiles = stgm.hGlobal ?
  761. DragQueryFileU((HDROP) stgm.hGlobal, 0xFFFFFFFFL , 0, 0) : 0;
  762. if ((!ucFiles) || (ucFiles >= 2))
  763. return E_INVALIDARG; // Shouldn't happen, but it's not important
  764. if(0==DragQueryFileU((HDROP) stgm.hGlobal, 0, wszFileName,
  765. sizeof wszFileName/ sizeof wszFileName[0]))
  766. return E_FAIL;
  767. //get the offset of the command item that was selected by the user
  768. //If HIWORD(lpcmi->lpVerb) then we have been called programmatically
  769. //and lpVerb is a command that should be invoked. Otherwise, the shell
  770. //has called us, and LOWORD(lpcmi->lpVerb) is the menu ID the user has
  771. //selected. Actually, it's (menu ID - idCmdFirst) from QueryContextMenu().
  772. if (HIWORD((DWORD_PTR)lpcmi->lpVerb))
  773. {
  774. hr=E_INVALIDARG;
  775. goto CLEANUP;
  776. }
  777. else
  778. idCmd = LOWORD(lpcmi->lpVerb);
  779. //exit if idCmd is not 0 or 1
  780. if(idCmd >= 2)
  781. {
  782. hr=E_INVALIDARG;
  783. goto CLEANUP;
  784. }
  785. hr=I_InvokeCommand(wszFileName, idCmd, FALSE);
  786. CLEANUP:
  787. return hr;
  788. }
  789. //--------------------------------------------------------------
  790. // FUNCTION: CCryptPKO::GetCommandString
  791. //
  792. //--------------------------------------------------------------
  793. void CopyBuffer(UINT uFlags, LPSTR pszName, UINT cchMax, LPWSTR wszString)
  794. {
  795. UINT cbSize=0;
  796. LPSTR szString=NULL;
  797. LPWSTR pwszName=NULL;
  798. if(uFlags == GCS_HELPTEXTW)
  799. {
  800. pwszName=(LPWSTR)pszName;
  801. cbSize=wcslen(wszString)+1;
  802. if(cbSize <= cchMax)
  803. wcsncpy(pwszName, wszString,cbSize);
  804. else
  805. {
  806. wcsncpy(pwszName, wszString, cchMax-1);
  807. *(pwszName+cchMax-1)=L'\0';
  808. }
  809. }
  810. else
  811. {
  812. if((wszString!=NULL) && MkMBStr(NULL, 0, wszString, &szString))
  813. {
  814. cbSize=strlen(szString)+1;
  815. if(cbSize <= cchMax)
  816. strncpy(pszName, szString,cbSize);
  817. else
  818. {
  819. strncpy(pszName, szString, cchMax-1);
  820. *(pszName+cchMax-1)='\0';
  821. }
  822. }
  823. if(szString)
  824. FreeMBStr(NULL, szString);
  825. }
  826. }
  827. //--------------------------------------------------------------
  828. // FUNCTION: CCryptPKO::GetCommandString
  829. //
  830. //--------------------------------------------------------------
  831. STDMETHODIMP CCryptPKO::GetCommandString(UINT_PTR idCmd,
  832. UINT uFlags,
  833. UINT FAR *reserved,
  834. LPSTR pszName,
  835. UINT cchMax)
  836. {
  837. DWORD dwContentType=0;
  838. DWORD dwFormatType=0;
  839. FORMATETC fmte = {CF_HDROP,
  840. (DVTARGETDEVICE FAR *)NULL,
  841. DVASPECT_CONTENT,
  842. -1,
  843. TYMED_HGLOBAL
  844. };
  845. STGMEDIUM stgm;
  846. HRESULT hr = E_FAIL;
  847. UINT ucFiles=0;
  848. WCHAR wszFileName[_MAX_PATH];
  849. WCHAR wszOpenString[MAX_COMMAND_LENGTH];
  850. WCHAR wszAddString[MAX_COMMAND_LENGTH];
  851. if(uFlags!=GCS_HELPTEXTA && uFlags != GCS_HELPTEXTW)
  852. return E_INVALIDARG;
  853. if( 0 == cchMax)
  854. return E_INVALIDARG;
  855. //init
  856. if(uFlags==GCS_HELPTEXTA)
  857. *pszName='\0';
  858. else
  859. *((LPWSTR)pszName)=L'\0';
  860. //get the file name that user clicked on. We do not add context menu
  861. //if user has selected more than one file
  862. if (m_pDataObj)
  863. hr = m_pDataObj->GetData(&fmte, &stgm);
  864. if (!SUCCEEDED(hr))
  865. return hr;
  866. //get the number of files that user clicked on
  867. ucFiles = stgm.hGlobal ?
  868. DragQueryFileU((HDROP) stgm.hGlobal, 0xFFFFFFFFL , 0, 0) : 0;
  869. if ((!ucFiles) || (ucFiles >= 2))
  870. return E_INVALIDARG; // Shouldn't happen, but it's not important
  871. if(0==DragQueryFileU((HDROP) stgm.hGlobal, 0, wszFileName,
  872. sizeof wszFileName/ sizeof wszFileName[0]))
  873. return E_FAIL;
  874. //exit if idCmd is not 0 or 1
  875. if(idCmd >= 2)
  876. {
  877. hr=E_INVALIDARG;
  878. goto CLEANUP;
  879. }
  880. //load the string
  881. if(!LoadStringU(g_hmodThisDll, IDS_HELP_OPEN, wszOpenString, sizeof(wszOpenString)/sizeof(wszOpenString[0])))
  882. {
  883. hr=E_FAIL;
  884. goto CLEANUP;
  885. }
  886. //get the content type of the file
  887. //we care about every file type except for the signed doc
  888. if(!CryptQueryObject(CERT_QUERY_OBJECT_FILE,
  889. wszFileName,
  890. CERT_QUERY_CONTENT_FLAG_ALL,
  891. CERT_QUERY_FORMAT_FLAG_ALL,
  892. 0,
  893. NULL,
  894. &dwContentType,
  895. &dwFormatType,
  896. NULL,
  897. NULL,
  898. NULL))
  899. {
  900. //can not recognize the object. Fine
  901. hr=E_FAIL;
  902. goto CLEANUP;
  903. }
  904. //make sure idCmd is the correct valud for different types
  905. //we are guaranteed that idCmd is 1 or 0
  906. if(CERT_QUERY_CONTENT_CERT != dwContentType &&
  907. CERT_QUERY_CONTENT_CTL != dwContentType &&
  908. CERT_QUERY_CONTENT_CRL != dwContentType &&
  909. CERT_QUERY_CONTENT_PKCS7_SIGNED != dwContentType)
  910. {
  911. if(1==idCmd)
  912. {
  913. hr=E_INVALIDARG;
  914. goto CLEANUP;
  915. }
  916. }
  917. switch (dwContentType)
  918. {
  919. case CERT_QUERY_CONTENT_CERT:
  920. case CERT_QUERY_CONTENT_PKCS7_SIGNED:
  921. if(!LoadStringU(g_hmodThisDll, IDS_HELP_INSTALL_CERT, wszAddString, sizeof(wszAddString)/sizeof(wszAddString[0])))
  922. {
  923. hr=E_FAIL;
  924. goto CLEANUP;
  925. }
  926. case CERT_QUERY_CONTENT_CTL:
  927. if(CERT_QUERY_CONTENT_CTL == dwContentType)
  928. {
  929. if(!LoadStringU(g_hmodThisDll, IDS_HELP_INSTALL_STL, wszAddString, sizeof(wszAddString)/sizeof(wszAddString[0])))
  930. {
  931. hr=E_FAIL;
  932. goto CLEANUP;
  933. }
  934. }
  935. case CERT_QUERY_CONTENT_CRL:
  936. if(CERT_QUERY_CONTENT_CRL == dwContentType)
  937. {
  938. if(!LoadStringU(g_hmodThisDll, IDS_HELP_INSTALL_CRL, wszAddString, sizeof(wszAddString)/sizeof(wszAddString[0])))
  939. {
  940. hr=E_FAIL;
  941. goto CLEANUP;
  942. }
  943. }
  944. //helper string for Open
  945. if(idCmd==0)
  946. {
  947. CopyBuffer(uFlags, pszName, cchMax, wszOpenString);
  948. }
  949. //helper string for add
  950. if(idCmd==1)
  951. {
  952. CopyBuffer(uFlags, pszName, cchMax, wszAddString);
  953. }
  954. break;
  955. case CERT_QUERY_CONTENT_SERIALIZED_STORE:
  956. case CERT_QUERY_CONTENT_SERIALIZED_CERT:
  957. case CERT_QUERY_CONTENT_SERIALIZED_CTL:
  958. case CERT_QUERY_CONTENT_SERIALIZED_CRL:
  959. //helper string for Open
  960. CopyBuffer(uFlags, pszName, cchMax, wszOpenString);
  961. break;
  962. case CERT_QUERY_CONTENT_PFX:
  963. if(!LoadStringU(g_hmodThisDll, IDS_HELP_INSTALL_PFX, wszAddString, sizeof(wszAddString)/sizeof(wszAddString[0])))
  964. {
  965. hr=E_FAIL;
  966. goto CLEANUP;
  967. }
  968. CopyBuffer(uFlags, pszName, cchMax, wszAddString);
  969. break;
  970. case CERT_QUERY_CONTENT_PKCS7_SIGNED_EMBED:
  971. default:
  972. CopyBuffer(uFlags, pszName, cchMax, wszOpenString);
  973. break;
  974. }
  975. hr=NOERROR;
  976. CLEANUP:
  977. return hr;
  978. }
  979. //--------------------------------------------------------------
  980. // FUNCTION: CCryptPKO::Initialize(LPCITEMIDLIST, LPDATAOBJECT, HKEY)
  981. //
  982. // PURPOSE: Called by the shell when initializing a context menu or property
  983. // sheet extension.
  984. //
  985. // PARAMETERS:
  986. // pIDFolder - Specifies the parent folder
  987. // pDataObj - Spefifies the set of items selected in that folder.
  988. // hRegKey - Specifies the type of the focused item in the selection.
  989. //
  990. // RETURN VALUE:
  991. //
  992. // NOERROR in all cases.
  993. //--------------------------------------------------------------
  994. STDMETHODIMP CCryptPKO::Initialize(LPCITEMIDLIST pIDFolder,
  995. LPDATAOBJECT pDataObj,
  996. HKEY hRegKey)
  997. {
  998. // Initialize can be called more than once
  999. if (m_pDataObj)
  1000. m_pDataObj->Release();
  1001. // duplicate the object pointer and registry handle
  1002. if (pDataObj)
  1003. {
  1004. m_pDataObj = pDataObj;
  1005. pDataObj->AddRef();
  1006. }
  1007. return NOERROR;
  1008. }