//-------------------------------------------------------------- // Copyright (C) Microsoft Corporation, 1996 - 1999 // // File: CryptSig.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 // // CryptSig.cpp : Implementation of CCryptSig //-------------------------------------------------------------- #include "stdafx.h" #include "cryptext.h" #include "private.h" #include "CryptSig.h" //-------------------------------------------------------------- // CCryptSig //-------------------------------------------------------------- // // 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 SignPageCallBack(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 // //-------------------------------------------------------------- CCryptSig::CCryptSig() { m_pDataObj=NULL; } //-------------------------------------------------------------- // // Destructor // //-------------------------------------------------------------- CCryptSig::~CCryptSig() { 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 CCryptSig::AddPages(LPFNADDPROPSHEETPAGE lpfnAddPage, LPARAM lParam) { HPROPSHEETPAGE hpage; PROPSHEETPAGEW *pPage=NULL; DWORD dwPage=0; DWORD dwIndex=0; DWORD dwSignerCount=0; DWORD cbSize=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; DWORD dwAttr=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; } //we ignore the case when the file is off-line if(0xFFFFFFFF == (dwAttr=GetFileAttributesU(wszFileName))) { ReleaseStgMedium(&stgm); return NOERROR; } if(FILE_ATTRIBUTE_OFFLINE & dwAttr) { 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_BINARY, 0, NULL, NULL, NULL, NULL, &hMsg, NULL)) { //can not recognize the object. Fine goto CLEANUP; } //make sure that we have at least on signer cbSize = sizeof(dwSignerCount); if(!CryptMsgGetParam(hMsg, CMSG_SIGNER_COUNT_PARAM, 0, &dwSignerCount, &cbSize)) goto CLEANUP; if(0==dwSignerCount) goto CLEANUP; //Call Reid's function to 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=SignPageCallBack; 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 CCryptSig::ReplacePage(UINT uPageID, LPFNADDPROPSHEETPAGE lpfnReplaceWith, LPARAM lParam) { return E_FAIL; } //-------------------------------------------------------------- // FUNCTION: CCryptSig::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 CCryptSig::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; }