windows-nt/Source/XPSP1/NT/ds/security/cryptoapi/ui/cryptext/cryptpko.cpp

1241 lines
37 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
//--------------------------------------------------------------
// 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; dwIndex<dwPage; dwIndex++)
{
//add the callback functions to release the refcount
//pPage[dwIndex].dwFlags |= PSP_USECALLBACK;
//pPage[dwIndex].pfnCallback=SignPKOPageCallBack;
//pPage[dwIndex].pcRefParent=(UINT *)this;
hpage = CreatePropertySheetPageU(&(pPage[dwIndex]));
((IShellPropSheetExt *)this)->AddRef();
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;
}