//-------------------------------------------------------------- // Copyright (C) Microsoft Corporation, 1996 - 1999 // // File: CryptPKO.cpp // // content: Implements the IContextMenu member functions necessary to support // the context menu portioins of this shell extension. Context menu // shell extensions are called when the user right clicks on a file // History: 16-09-1997 xiaohs created // //-------------------------------------------------------------- #include "stdafx.h" #include "cryptext.h" #include "private.h" #include "CryptPKO.h" //QueryContextMenu is called twice by the Shell. //we have to set the flag. BOOL g_fDefaultCalled=FALSE; HRESULT I_InvokeCommand(LPWSTR pwszFileName, UINT idCmd, BOOL fDefault) { DWORD dwContentType=0; DWORD dwFormatType=0; HCERTSTORE hCertStore=NULL; HCRYPTMSG hMsg=NULL; const void *pvContext=NULL; UINT idsFileName=0; HRESULT hr = E_FAIL; CRYPTUI_VIEWCERTIFICATE_STRUCT CertViewStruct; CRYPTUI_VIEWCRL_STRUCT CRLViewStruct; CRYPTUI_WIZ_IMPORT_SRC_INFO importSubject; //get the content type of the file //we care about every file type except for the signed doc if(!CryptQueryObject(CERT_QUERY_OBJECT_FILE, pwszFileName, CERT_QUERY_CONTENT_FLAG_ALL, CERT_QUERY_FORMAT_FLAG_ALL, 0, NULL, &dwContentType, &dwFormatType, &hCertStore, &hMsg, &pvContext)) { I_NoticeBox( GetLastError(), 0, NULL, IDS_MSG_TITLE, IDS_PKO_NAME, IDS_MSG_INVALID_FILE, MB_OK|MB_ICONINFORMATION); goto CLEANUP; } //make sure idCmd is the correct valud for different types //we are guaranteed that idCmd is 1 or 0 if(CERT_QUERY_CONTENT_CERT != dwContentType && CERT_QUERY_CONTENT_CTL != dwContentType && CERT_QUERY_CONTENT_CRL != dwContentType && CERT_QUERY_CONTENT_PKCS7_SIGNED != dwContentType) { if(1==idCmd) { hr=E_INVALIDARG; goto CLEANUP; } } switch (dwContentType) { case CERT_QUERY_CONTENT_CERT: if(idCmd==0) { //call the Certificate Common Dialogue memset(&CertViewStruct, 0, sizeof(CRYPTUI_VIEWCERTIFICATE_STRUCT)); CertViewStruct.dwSize=sizeof(CRYPTUI_VIEWCERTIFICATE_STRUCT); CertViewStruct.pCertContext=(PCCERT_CONTEXT)pvContext; CryptUIDlgViewCertificate(&CertViewStruct, NULL); } else { memset(&importSubject, 0, sizeof(CRYPTUI_WIZ_IMPORT_SRC_INFO)); importSubject.dwSize=sizeof(CRYPTUI_WIZ_IMPORT_SRC_INFO); importSubject.dwSubjectChoice=CRYPTUI_WIZ_IMPORT_SUBJECT_CERT_CONTEXT; importSubject.pCertContext=(PCCERT_CONTEXT)pvContext; CryptUIWizImport(0, NULL, NULL, &importSubject, NULL); } break; case CERT_QUERY_CONTENT_CTL: if(idCmd==0) I_ViewCTL((PCCTL_CONTEXT)pvContext); else { //we do not need to install a catalog file if(!IsCatalog((PCCTL_CONTEXT)pvContext)) { memset(&importSubject, 0, sizeof(CRYPTUI_WIZ_IMPORT_SRC_INFO)); importSubject.dwSize=sizeof(CRYPTUI_WIZ_IMPORT_SRC_INFO); importSubject.dwSubjectChoice=CRYPTUI_WIZ_IMPORT_SUBJECT_CTL_CONTEXT; importSubject.pCTLContext=(PCCTL_CONTEXT)pvContext; CryptUIWizImport(0, NULL, NULL, &importSubject, NULL); } } break; case CERT_QUERY_CONTENT_CRL: if(idCmd==0) { //call the CRL view dialogue memset(&CRLViewStruct, 0, sizeof(CRYPTUI_VIEWCRL_STRUCT)); CRLViewStruct.dwSize=sizeof(CRYPTUI_VIEWCRL_STRUCT); CRLViewStruct.pCRLContext=(PCCRL_CONTEXT)pvContext; CryptUIDlgViewCRL(&CRLViewStruct); } else { memset(&importSubject, 0, sizeof(CRYPTUI_WIZ_IMPORT_SRC_INFO)); importSubject.dwSize=sizeof(CRYPTUI_WIZ_IMPORT_SRC_INFO); importSubject.dwSubjectChoice=CRYPTUI_WIZ_IMPORT_SUBJECT_CRL_CONTEXT; importSubject.pCRLContext=(PCCRL_CONTEXT)pvContext; CryptUIWizImport(0, NULL, NULL, &importSubject, NULL); } break; case CERT_QUERY_CONTENT_SERIALIZED_STORE: idsFileName=IDS_SERIALIZED_STORE; case CERT_QUERY_CONTENT_SERIALIZED_CERT: if(0 == idsFileName) idsFileName=IDS_SERIALIZED_CERT; case CERT_QUERY_CONTENT_SERIALIZED_CTL: if(0 == idsFileName) idsFileName=IDS_SERIALIZED_STL; case CERT_QUERY_CONTENT_SERIALIZED_CRL: if(0 == idsFileName) idsFileName=IDS_SERIALIZED_CRL; if(!FIsWinNT5()) { I_NoticeBox( 0, 0, NULL, IDS_MSG_VALID_TITLE, idsFileName, IDS_MSG_VALID_SIGN_FILE, MB_OK|MB_ICONINFORMATION); } else { LauchCertMgr(pwszFileName); } break; case CERT_QUERY_CONTENT_PKCS7_SIGNED: if(idCmd==0) { if(!FIsWinNT5()) { I_NoticeBox( 0, 0, NULL, IDS_MSG_VALID_TITLE, IDS_PKCS7_NAME, IDS_MSG_VALID_SIGN_FILE, MB_OK|MB_ICONINFORMATION); } else { LauchCertMgr(pwszFileName); } } else { //we are doing the import memset(&importSubject, 0, sizeof(CRYPTUI_WIZ_IMPORT_SRC_INFO)); importSubject.dwSize=sizeof(CRYPTUI_WIZ_IMPORT_SRC_INFO); importSubject.dwSubjectChoice=CRYPTUI_WIZ_IMPORT_SUBJECT_FILE; importSubject.pwszFileName=pwszFileName; CryptUIWizImport(0, NULL, NULL, &importSubject, NULL); } break; case CERT_QUERY_CONTENT_PKCS7_SIGNED_EMBED: I_NoticeBox( 0, 0, NULL, IDS_MSG_VALID_TITLE, IDS_SIGN_NAME, IDS_MSG_VALID_SIGN_FILE, MB_OK|MB_ICONINFORMATION); break; case CERT_QUERY_CONTENT_PFX: memset(&importSubject, 0, sizeof(CRYPTUI_WIZ_IMPORT_SRC_INFO)); importSubject.dwSize=sizeof(CRYPTUI_WIZ_IMPORT_SRC_INFO); importSubject.dwSubjectChoice=CRYPTUI_WIZ_IMPORT_SUBJECT_FILE; importSubject.pwszFileName=pwszFileName; CryptUIWizImport(0, NULL, NULL, &importSubject, NULL); break; case CERT_QUERY_CONTENT_PKCS7_UNSIGNED: I_NoticeBox( 0, 0, NULL, IDS_MSG_VALID_TITLE, IDS_PKCS7_UNSIGNED_NAME, IDS_MSG_VALID_FILE, MB_OK|MB_ICONINFORMATION); break; case CERT_QUERY_CONTENT_PKCS10: I_NoticeBox( 0, 0, NULL, IDS_MSG_VALID_TITLE, IDS_P10_NAME, IDS_MSG_VALID_FILE, MB_OK|MB_ICONINFORMATION); break; default: break; } hr=S_OK; CLEANUP: //relaset the stores and reset the local parameters if(hCertStore) CertCloseStore(hCertStore, 0); if(hMsg) CryptMsgClose(hMsg); if(pvContext) { if(dwContentType == CERT_QUERY_CONTENT_CERT || dwContentType == CERT_QUERY_CONTENT_SERIALIZED_CERT) CertFreeCertificateContext((PCCERT_CONTEXT)pvContext); else { if(dwContentType == CERT_QUERY_CONTENT_CTL || dwContentType == CERT_QUERY_CONTENT_SERIALIZED_CTL) CertFreeCTLContext((PCCTL_CONTEXT)pvContext); else { if(dwContentType == CERT_QUERY_CONTENT_CRL || dwContentType == CERT_QUERY_CONTENT_SERIALIZED_CRL) CertFreeCRLContext((PCCRL_CONTEXT)pvContext); } } } return hr; } ///////////////////////////////////////////////////////////////////////////// // CCryptPKO //-------------------------------------------------------------- // // FUNCTION: GAKPageCallback(HWND, UINT, LPPROPSHEETPAGE) // // PURPOSE: Callback procedure for the property page // // PARAMETERS: // hWnd - Reserved (will always be NULL) // uMessage - Action flag: Are we being created or released // ppsp - The page that is being created or destroyed // // RETURN VALUE: // // Depends on message. // // For PSPCB_CREATE it's TRUE to let the page be created // or false to prevent it from being created. // For PSPCB_RELEASE the return value is ignored. // // COMMENTS: // BOOL CALLBACK SignPKOPageCallBack(HWND hWnd, UINT uMessage, void *pvCallBack) { switch(uMessage) { case PSPCB_CREATE: return TRUE; case PSPCB_RELEASE: if (pvCallBack) { ((IShellPropSheetExt *)(pvCallBack))->Release(); } return TRUE; } return TRUE; } //-------------------------------------------------------------- // // Constructor // //-------------------------------------------------------------- CCryptPKO::CCryptPKO() { m_pDataObj=NULL; } //-------------------------------------------------------------- // // Destructor // //-------------------------------------------------------------- CCryptPKO::~CCryptPKO() { if (m_pDataObj) m_pDataObj->Release(); } //-------------------------------------------------------------- // FUNCTION: CCryptSig::AddPages(LPFNADDPROPSHEETPAGE, LPARAM) // // PURPOSE: Called by the shell just before the property sheet is displayed. // // PARAMETERS: // lpfnAddPage - Pointer to the Shell's AddPage function // lParam - Passed as second parameter to lpfnAddPage // // RETURN VALUE: // // NOERROR in all cases. If for some reason our pages don't get added, // the Shell still needs to bring up the Properties... sheet. // // COMMENTS: //-------------------------------------------------------------- STDMETHODIMP CCryptPKO::AddPages(LPFNADDPROPSHEETPAGE lpfnAddPage, LPARAM lParam) { HPROPSHEETPAGE hpage; PROPSHEETPAGEW *pPage=NULL; DWORD dwPage=0; DWORD dwIndex=0; FORMATETC fmte = {CF_HDROP, (DVTARGETDEVICE FAR *)NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; STGMEDIUM stgm; UINT ucFiles=0; WCHAR wszFileName[_MAX_PATH]; HCRYPTMSG hMsg=NULL; HRESULT hr=E_FAIL; DWORD dwExceptionCode=0; CRYPTUI_VIEWSIGNATURES_STRUCTW sigView; //get the file name that user clicked on. We do not add context menu //if user has selected more than one file if (m_pDataObj) hr = m_pDataObj->GetData(&fmte, &stgm); if (!SUCCEEDED(hr)) return NOERROR; ucFiles = stgm.hGlobal ? DragQueryFileU((HDROP) stgm.hGlobal, 0xFFFFFFFFL , 0, 0) : 0; if ((!ucFiles) || (ucFiles >= 2)) { ReleaseStgMedium(&stgm); return NOERROR; // Shouldn't happen, but it's not important } if(0==DragQueryFileU((HDROP) stgm.hGlobal, 0, wszFileName, sizeof wszFileName/ sizeof wszFileName[0])) { ReleaseStgMedium(&stgm); return NOERROR; } //get the content type of the file. We only cares about //the signed document in binary format if(!CryptQueryObject(CERT_QUERY_OBJECT_FILE, wszFileName, CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED, CERT_QUERY_FORMAT_FLAG_BASE64_ENCODED, 0, NULL, NULL, NULL, NULL, &hMsg, NULL)) { //can not recognize the object. Fine goto CLEANUP; } //add the property sheet page memset(&sigView, 0, sizeof(CRYPTUI_VIEWSIGNATURES_STRUCTW)); sigView.dwSize=sizeof(CRYPTUI_VIEWSIGNATURES_STRUCTW); sigView.choice=hMsg_Chosen; sigView.u.hMsg=hMsg; sigView.szFileName=wszFileName; sigView.pPropPageCallback=SignPKOPageCallBack; sigView.pvCallbackData=this; if(!CryptUIGetViewSignaturesPagesW( &sigView, &pPage, &dwPage)) goto CLEANUP; __try { for(dwIndex=0; dwIndexAddRef(); if (hpage) { if (!lpfnAddPage(hpage, lParam)) { DestroyPropertySheetPage(hpage); ((IShellPropSheetExt *)this)->Release(); } } } } __except(EXCEPTION_EXECUTE_HANDLER) { dwExceptionCode = GetExceptionCode(); goto CLEANUP; } CLEANUP: ReleaseStgMedium(&stgm); if(pPage) CryptUIFreeViewSignaturesPagesW(pPage, dwPage); if(hMsg) CryptMsgClose(hMsg); return NOERROR; } //-------------------------------------------------------------- // FUNCTION: CCryptSig::ReplacePage(UINT, LPFNADDPROPSHEETPAGE, LPARAM) // // PURPOSE: Called by the shell only for Control Panel property sheet // extensions // // PARAMETERS: // uPageID - ID of page to be replaced // lpfnReplaceWith - Pointer to the Shell's Replace function // lParam - Passed as second parameter to lpfnReplaceWith // // RETURN VALUE: // // E_FAIL, since we don't support this function. It should never be // called. // COMMENTS: //-------------------------------------------------------------- STDMETHODIMP CCryptPKO::ReplacePage(UINT uPageID, LPFNADDPROPSHEETPAGE lpfnReplaceWith, LPARAM lParam) { return E_FAIL; } //-------------------------------------------------------------- // FUNCTION: CCryptPKO::QueryContextMenu(HMENU, UINT, UINT, UINT, UINT) // // PURPOSE: Called by the shell just before the context menu is displayed. // // PARAMETERS: // hMenu - Handle to the context menu // indexMenu - Index of where to begin inserting menu items // idCmdFirst - Lowest value for new menu ID's // idCmtLast - Highest value for new menu ID's // uFlags - Specifies the context of the menu event // // RETURN VALUE: // We always return NOERROR unless when we succeeded, when // we have to return HRESULT structure in which, if the method // is successful, the code member contains the menu identifier // offset of the last menu item added plus one. //-------------------------------------------------------------- STDMETHODIMP CCryptPKO::QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags) { DWORD dwContentType=0; DWORD dwFormatType=0; FORMATETC fmte = {CF_HDROP, (DVTARGETDEVICE FAR *)NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; STGMEDIUM stgm; HRESULT hr = E_FAIL; UINT ucFiles=0; WCHAR wszFileName[_MAX_PATH]; WCHAR wszOpen[MAX_COMMAND_LENGTH]; WCHAR wszAdd[MAX_COMMAND_LENGTH]; WCHAR wszViewSig[MAX_COMMAND_LENGTH]; UINT idCmd = idCmdFirst; UINT idCmdDefault=idCmdFirst; MENUITEMINFOA MenuItemInfo; void *pContext=NULL; //init the menuInfo for setting the default menu memset(&MenuItemInfo, 0, sizeof(MENUITEMINFOA)); MenuItemInfo.cbSize=sizeof(MENUITEMINFOA); MenuItemInfo.fMask=MIIM_STATE; MenuItemInfo.fState=MFS_DEFAULT; //get the file name that user clicked on. We do not add context menu //if user has selected more than one file if (m_pDataObj) hr = m_pDataObj->GetData(&fmte, &stgm); if (!SUCCEEDED(hr)) return NOERROR; ucFiles = stgm.hGlobal ? DragQueryFileU((HDROP) stgm.hGlobal, 0xFFFFFFFFL , 0, 0) : 0; if ((!ucFiles) || (ucFiles >= 2)) return NOERROR; // Shouldn't happen, but it's not important if(0==DragQueryFileU((HDROP) stgm.hGlobal, 0, wszFileName, sizeof wszFileName/ sizeof wszFileName[0])) return NOERROR; //if user double click on a file, we need the take the //default action /* if(uFlags & CMF_DEFAULTONLY) { //QueryContextMenu is called twice by the Shell. //we have to set the flag. if(FALSE==g_fDefaultCalled) { hr=I_InvokeCommand(pwszFileName, 0, TRUE); g_fDefaultCalled=TRUE; } else g_fDefaultCalled=FALSE; idCmd=idCmdFirst; goto CLEANUP; } */ //decide if we need to add the context menu if (!( ((uFlags & 0x000F) == CMF_NORMAL)|| (uFlags & CMF_VERBSONLY) || (uFlags & CMF_EXPLORE) || (uFlags & CMF_DEFAULTONLY) )) goto CLEANUP; //load the string if(!LoadStringU(g_hmodThisDll, IDS_MENU_OPEN, wszOpen, sizeof(wszOpen)/sizeof(wszOpen[0]))|| !LoadStringU(g_hmodThisDll, IDS_MENU_VIEWSIG, wszViewSig, sizeof(wszViewSig)/sizeof(wszViewSig[0])) ) goto CLEANUP; //get the content type of the file //we care about every file type and every format type if(!CryptQueryObject(CERT_QUERY_OBJECT_FILE, wszFileName, CERT_QUERY_CONTENT_FLAG_ALL, CERT_QUERY_FORMAT_FLAG_ALL, 0, NULL, &dwContentType, &dwFormatType, NULL, NULL, (const void **)&pContext)) { //add the open menu if(0==InsertMenuU(hMenu, indexMenu++, MF_STRING|MF_BYPOSITION, idCmd++, wszOpen)) goto CLEANUP; // if there is no default verb, set open as default if (GetMenuDefaultItem(hMenu, MF_BYPOSITION, 0) == -1) { // use indexMenu - 1 since we incremented indexMenu in the InsertMenu SetMenuDefaultItem(hMenu, indexMenu -1, MF_BYPOSITION); } //set the open to be the default menu item idCmdDefault=idCmd-1; //no need for error checking /* SetMenuItemInfoA(hMenu, idCmdDefault, FALSE, &MenuItemInfo); */ goto CLEANUP; } switch (dwContentType) { case CERT_QUERY_CONTENT_CERT: case CERT_QUERY_CONTENT_PKCS7_SIGNED: //get the correct wording for the second menu item based // on the content if(!LoadStringU(g_hmodThisDll, IDS_MENU_INSTALL_CERT, wszAdd, sizeof(wszAdd)/sizeof(wszAdd[0]))) goto CLEANUP; case CERT_QUERY_CONTENT_CTL: if(CERT_QUERY_CONTENT_CTL == dwContentType) { if(!LoadStringU(g_hmodThisDll, IDS_MENU_INSTALL_STL, wszAdd, sizeof(wszAdd)/sizeof(wszAdd[0]))) goto CLEANUP; } case CERT_QUERY_CONTENT_CRL: if(CERT_QUERY_CONTENT_CRL == dwContentType) { if(!LoadStringU(g_hmodThisDll, IDS_MENU_INSTALL_CRL, wszAdd, sizeof(wszAdd)/sizeof(wszAdd[0]))) goto CLEANUP; } //make sure we can add at least two items if(2 > (idCmdLast-idCmdFirst)) goto CLEANUP; //add the open menu if(0==InsertMenuU(hMenu, indexMenu++, MF_STRING|MF_BYPOSITION, idCmd++, wszOpen)) goto CLEANUP; //set the open to be the default menu item idCmdDefault=idCmd-1; //no need for error checking //set the default menu item SetMenuItemInfoA(hMenu, idCmdDefault, FALSE, &MenuItemInfo); //add the add menu //do not put "install" for the catalog files if( !((CERT_QUERY_CONTENT_CTL == dwContentType) && IsCatalog((PCCTL_CONTEXT)pContext)) ) { if(0==InsertMenuU(hMenu, indexMenu++, MF_STRING|MF_BYPOSITION, idCmd++, wszAdd)) goto CLEANUP; } break; case CERT_QUERY_CONTENT_SERIALIZED_STORE: case CERT_QUERY_CONTENT_SERIALIZED_CERT: case CERT_QUERY_CONTENT_SERIALIZED_CTL: case CERT_QUERY_CONTENT_SERIALIZED_CRL: //add the open menu if(0==InsertMenuU(hMenu, indexMenu++, MF_STRING|MF_BYPOSITION, idCmd++, wszOpen)) goto CLEANUP; //set the open to be the default menu item idCmdDefault=idCmd-1; //no need for error checking SetMenuItemInfoA(hMenu, idCmdDefault, FALSE, &MenuItemInfo); break; case CERT_QUERY_CONTENT_PFX: if(!LoadStringU(g_hmodThisDll, IDS_MENU_INSTALL_PFX, wszAdd, sizeof(wszAdd)/sizeof(wszAdd[0]))) goto CLEANUP; //add the install menu if(0==InsertMenuU(hMenu, indexMenu++, MF_STRING|MF_BYPOSITION, idCmd++, wszAdd)) goto CLEANUP; //set the add to be the default menu item idCmdDefault=idCmd-1; //no need for error checking SetMenuItemInfoA(hMenu, idCmdDefault, FALSE, &MenuItemInfo); break; case CERT_QUERY_CONTENT_PKCS7_SIGNED_EMBED: //signed data case is handled by the property sheet extension default: //we do not worry about CERT_QUERY_CONTENT_PKCS7_UNSIGNED or //CERT_QUERY_CONTENT_PKCS10 or CERT_QUERY_CONTENT_PFX for now //add the open menu if(0==InsertMenuU(hMenu, indexMenu++, MF_STRING|MF_BYPOSITION, idCmd++, wszOpen)) goto CLEANUP; //set the open to be the default menu item idCmdDefault=idCmd-1; // if there is no default verb, set open as default if (GetMenuDefaultItem(hMenu, MF_BYPOSITION, 0) == -1) { // use indexMenu - 1 since we incremented indexMenu in the InsertMenu SetMenuDefaultItem(hMenu, indexMenu -1, MF_BYPOSITION); } break; } CLEANUP: if(idCmd-idCmdFirst) { //Must return number of menu items we added. hr=ResultFromShort(idCmd-idCmdFirst); } else //do not care if error happens. No menu items have been added hr=NOERROR; if(pContext) { if(dwContentType == CERT_QUERY_CONTENT_CERT || dwContentType == CERT_QUERY_CONTENT_SERIALIZED_CERT) CertFreeCertificateContext((PCCERT_CONTEXT)pContext); else { if(dwContentType == CERT_QUERY_CONTENT_CTL || dwContentType == CERT_QUERY_CONTENT_SERIALIZED_CTL) CertFreeCTLContext((PCCTL_CONTEXT)pContext); else { if(dwContentType == CERT_QUERY_CONTENT_CRL || dwContentType == CERT_QUERY_CONTENT_SERIALIZED_CRL) CertFreeCRLContext((PCCRL_CONTEXT)pContext); } } } return hr; } //-------------------------------------------------------------- // FUNCTION: CCryptPKO::InvokeCommand(LPCMINVOKECOMMANDINFO) // // PURPOSE: Called by the shell after the user has selected on of the // menu items that was added in QueryContextMenu(). // // PARAMETERS: // lpcmi - Pointer to an CMINVOKECOMMANDINFO structure // // RETURN VALUE: // //-------------------------------------------------------------- STDMETHODIMP CCryptPKO::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi) { FORMATETC fmte = {CF_HDROP, (DVTARGETDEVICE FAR *)NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; STGMEDIUM stgm; HRESULT hr = E_FAIL; UINT ucFiles=0; WCHAR wszFileName[_MAX_PATH]; UINT idCmd=0; //get the file name that user clicked on. We do not add context menu //if user has selected more than one file if (m_pDataObj) hr = m_pDataObj->GetData(&fmte, &stgm); if (!SUCCEEDED(hr)) return hr; //get the number of files that user clicked on ucFiles = stgm.hGlobal ? DragQueryFileU((HDROP) stgm.hGlobal, 0xFFFFFFFFL , 0, 0) : 0; if ((!ucFiles) || (ucFiles >= 2)) return E_INVALIDARG; // Shouldn't happen, but it's not important if(0==DragQueryFileU((HDROP) stgm.hGlobal, 0, wszFileName, sizeof wszFileName/ sizeof wszFileName[0])) return E_FAIL; //get the offset of the command item that was selected by the user //If HIWORD(lpcmi->lpVerb) then we have been called programmatically //and lpVerb is a command that should be invoked. Otherwise, the shell //has called us, and LOWORD(lpcmi->lpVerb) is the menu ID the user has //selected. Actually, it's (menu ID - idCmdFirst) from QueryContextMenu(). if (HIWORD((DWORD_PTR)lpcmi->lpVerb)) { hr=E_INVALIDARG; goto CLEANUP; } else idCmd = LOWORD(lpcmi->lpVerb); //exit if idCmd is not 0 or 1 if(idCmd >= 2) { hr=E_INVALIDARG; goto CLEANUP; } hr=I_InvokeCommand(wszFileName, idCmd, FALSE); CLEANUP: return hr; } //-------------------------------------------------------------- // FUNCTION: CCryptPKO::GetCommandString // //-------------------------------------------------------------- void CopyBuffer(UINT uFlags, LPSTR pszName, UINT cchMax, LPWSTR wszString) { UINT cbSize=0; LPSTR szString=NULL; LPWSTR pwszName=NULL; if(uFlags == GCS_HELPTEXTW) { pwszName=(LPWSTR)pszName; cbSize=wcslen(wszString)+1; if(cbSize <= cchMax) wcsncpy(pwszName, wszString,cbSize); else { wcsncpy(pwszName, wszString, cchMax-1); *(pwszName+cchMax-1)=L'\0'; } } else { if((wszString!=NULL) && MkMBStr(NULL, 0, wszString, &szString)) { cbSize=strlen(szString)+1; if(cbSize <= cchMax) strncpy(pszName, szString,cbSize); else { strncpy(pszName, szString, cchMax-1); *(pszName+cchMax-1)='\0'; } } if(szString) FreeMBStr(NULL, szString); } } //-------------------------------------------------------------- // FUNCTION: CCryptPKO::GetCommandString // //-------------------------------------------------------------- STDMETHODIMP CCryptPKO::GetCommandString(UINT_PTR idCmd, UINT uFlags, UINT FAR *reserved, LPSTR pszName, UINT cchMax) { DWORD dwContentType=0; DWORD dwFormatType=0; FORMATETC fmte = {CF_HDROP, (DVTARGETDEVICE FAR *)NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; STGMEDIUM stgm; HRESULT hr = E_FAIL; UINT ucFiles=0; WCHAR wszFileName[_MAX_PATH]; WCHAR wszOpenString[MAX_COMMAND_LENGTH]; WCHAR wszAddString[MAX_COMMAND_LENGTH]; if(uFlags!=GCS_HELPTEXTA && uFlags != GCS_HELPTEXTW) return E_INVALIDARG; if( 0 == cchMax) return E_INVALIDARG; //init if(uFlags==GCS_HELPTEXTA) *pszName='\0'; else *((LPWSTR)pszName)=L'\0'; //get the file name that user clicked on. We do not add context menu //if user has selected more than one file if (m_pDataObj) hr = m_pDataObj->GetData(&fmte, &stgm); if (!SUCCEEDED(hr)) return hr; //get the number of files that user clicked on ucFiles = stgm.hGlobal ? DragQueryFileU((HDROP) stgm.hGlobal, 0xFFFFFFFFL , 0, 0) : 0; if ((!ucFiles) || (ucFiles >= 2)) return E_INVALIDARG; // Shouldn't happen, but it's not important if(0==DragQueryFileU((HDROP) stgm.hGlobal, 0, wszFileName, sizeof wszFileName/ sizeof wszFileName[0])) return E_FAIL; //exit if idCmd is not 0 or 1 if(idCmd >= 2) { hr=E_INVALIDARG; goto CLEANUP; } //load the string if(!LoadStringU(g_hmodThisDll, IDS_HELP_OPEN, wszOpenString, sizeof(wszOpenString)/sizeof(wszOpenString[0]))) { hr=E_FAIL; goto CLEANUP; } //get the content type of the file //we care about every file type except for the signed doc if(!CryptQueryObject(CERT_QUERY_OBJECT_FILE, wszFileName, CERT_QUERY_CONTENT_FLAG_ALL, CERT_QUERY_FORMAT_FLAG_ALL, 0, NULL, &dwContentType, &dwFormatType, NULL, NULL, NULL)) { //can not recognize the object. Fine hr=E_FAIL; goto CLEANUP; } //make sure idCmd is the correct valud for different types //we are guaranteed that idCmd is 1 or 0 if(CERT_QUERY_CONTENT_CERT != dwContentType && CERT_QUERY_CONTENT_CTL != dwContentType && CERT_QUERY_CONTENT_CRL != dwContentType && CERT_QUERY_CONTENT_PKCS7_SIGNED != dwContentType) { if(1==idCmd) { hr=E_INVALIDARG; goto CLEANUP; } } switch (dwContentType) { case CERT_QUERY_CONTENT_CERT: case CERT_QUERY_CONTENT_PKCS7_SIGNED: if(!LoadStringU(g_hmodThisDll, IDS_HELP_INSTALL_CERT, wszAddString, sizeof(wszAddString)/sizeof(wszAddString[0]))) { hr=E_FAIL; goto CLEANUP; } case CERT_QUERY_CONTENT_CTL: if(CERT_QUERY_CONTENT_CTL == dwContentType) { if(!LoadStringU(g_hmodThisDll, IDS_HELP_INSTALL_STL, wszAddString, sizeof(wszAddString)/sizeof(wszAddString[0]))) { hr=E_FAIL; goto CLEANUP; } } case CERT_QUERY_CONTENT_CRL: if(CERT_QUERY_CONTENT_CRL == dwContentType) { if(!LoadStringU(g_hmodThisDll, IDS_HELP_INSTALL_CRL, wszAddString, sizeof(wszAddString)/sizeof(wszAddString[0]))) { hr=E_FAIL; goto CLEANUP; } } //helper string for Open if(idCmd==0) { CopyBuffer(uFlags, pszName, cchMax, wszOpenString); } //helper string for add if(idCmd==1) { CopyBuffer(uFlags, pszName, cchMax, wszAddString); } break; case CERT_QUERY_CONTENT_SERIALIZED_STORE: case CERT_QUERY_CONTENT_SERIALIZED_CERT: case CERT_QUERY_CONTENT_SERIALIZED_CTL: case CERT_QUERY_CONTENT_SERIALIZED_CRL: //helper string for Open CopyBuffer(uFlags, pszName, cchMax, wszOpenString); break; case CERT_QUERY_CONTENT_PFX: if(!LoadStringU(g_hmodThisDll, IDS_HELP_INSTALL_PFX, wszAddString, sizeof(wszAddString)/sizeof(wszAddString[0]))) { hr=E_FAIL; goto CLEANUP; } CopyBuffer(uFlags, pszName, cchMax, wszAddString); break; case CERT_QUERY_CONTENT_PKCS7_SIGNED_EMBED: default: CopyBuffer(uFlags, pszName, cchMax, wszOpenString); break; } hr=NOERROR; CLEANUP: return hr; } //-------------------------------------------------------------- // FUNCTION: CCryptPKO::Initialize(LPCITEMIDLIST, LPDATAOBJECT, HKEY) // // PURPOSE: Called by the shell when initializing a context menu or property // sheet extension. // // PARAMETERS: // pIDFolder - Specifies the parent folder // pDataObj - Spefifies the set of items selected in that folder. // hRegKey - Specifies the type of the focused item in the selection. // // RETURN VALUE: // // NOERROR in all cases. //-------------------------------------------------------------- STDMETHODIMP CCryptPKO::Initialize(LPCITEMIDLIST pIDFolder, LPDATAOBJECT pDataObj, HKEY hRegKey) { // Initialize can be called more than once if (m_pDataObj) m_pDataObj->Release(); // duplicate the object pointer and registry handle if (pDataObj) { m_pDataObj = pDataObj; pDataObj->AddRef(); } return NOERROR; }