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.
619 lines
21 KiB
619 lines
21 KiB
/**********************************************************************************
|
|
*
|
|
*
|
|
* contxtmnu.c - contains functions for handling/creating context menu extension
|
|
*
|
|
* Created - 9/97 - vikramm
|
|
*
|
|
**********************************************************************************/
|
|
#include "_apipch.h"
|
|
|
|
static const TCHAR szActionPropsRegKey[] = TEXT("Software\\Microsoft\\WAB\\WAB4\\ExtContext");
|
|
BOOL fContextExtCoinit = FALSE;
|
|
|
|
//$$//////////////////////////////////////////////////////////////////////
|
|
//
|
|
// UninitContextExtInfo
|
|
//
|
|
// OLE Unintialization
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void UninitContextExtInfo()
|
|
{
|
|
if(fContextExtCoinit)
|
|
{
|
|
CoUninitialize();
|
|
fContextExtCoinit = FALSE;
|
|
}
|
|
}
|
|
|
|
/*
|
|
- FreeActionItemList
|
|
-
|
|
* Frees up the Action Items list cached on the IAB object
|
|
*
|
|
*/
|
|
void FreeActionItemList(LPIAB lpIAB)
|
|
{
|
|
LPWABACTIONITEM lpItem = lpIAB->lpActionList;
|
|
while(lpItem)
|
|
{
|
|
lpIAB->lpActionList = lpItem->lpNext;
|
|
SafeRelease(lpItem->lpWABExtInit);
|
|
SafeRelease(lpItem->lpContextMenu);
|
|
LocalFree(lpItem);
|
|
lpItem = lpIAB->lpActionList;
|
|
}
|
|
lpIAB->lpActionList = NULL;
|
|
}
|
|
|
|
|
|
/*
|
|
- HrUpdateActionItemList
|
|
-
|
|
* Apps can register with the WAB for rt-click and toolbar Action items
|
|
* We load a list of registered action items here upfront and cache it on
|
|
* the IAB object.
|
|
*
|
|
*/
|
|
|
|
HRESULT HrUpdateActionItemList(LPIAB lpIAB)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
HKEY hKey = NULL;
|
|
LPWABACTIONITEM lpList = NULL;
|
|
DWORD dwIndex = 0, dwSize = 0;
|
|
int nCmdID = IDM_EXTENDED_START, nActionItems = 0;
|
|
|
|
EnterCriticalSection(&lpIAB->cs);
|
|
|
|
if(lpIAB->lpActionList)
|
|
FreeActionItemList(lpIAB);
|
|
|
|
lpIAB->lpActionList = NULL;
|
|
|
|
//
|
|
// We will look in the registry under HKLM\Software\Microsoft\WAB\WAB4\Actions
|
|
// If this key exists, we get all the key values under it - these key values
|
|
// are all GUIDs
|
|
// The format for this key is
|
|
//
|
|
// HKLM\Software\Microsoft\WAB\WAB4\Action Extensions
|
|
// GUID1
|
|
// GUID2
|
|
// GUID3 etc
|
|
//
|
|
|
|
if(ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
szActionPropsRegKey,
|
|
0, KEY_READ,&hKey))
|
|
{
|
|
goto out;
|
|
}
|
|
|
|
{
|
|
// Enumerate the GUIDs under this key one by one
|
|
//
|
|
TCHAR szGUIDName[MAX_PATH];
|
|
DWORD dwGUIDIndex = 0, dwGUIDSize = CharSizeOf(szGUIDName), dwType = 0;
|
|
|
|
*szGUIDName = '\0';
|
|
|
|
while(ERROR_SUCCESS == RegEnumValue(hKey, dwGUIDIndex,
|
|
szGUIDName, &dwGUIDSize,
|
|
0, &dwType,
|
|
NULL, NULL))
|
|
{
|
|
// The values under this entry are all GUIDs
|
|
// Read the GUID string and translate it into a GUID
|
|
//
|
|
GUID guidTmp = {0};
|
|
WCHAR szW[MAX_PATH];
|
|
StrCpyNW(szW, szGUIDName, ARRAYSIZE(szW));
|
|
if( !(HR_FAILED(hr = CLSIDFromString(szW, &guidTmp))) )
|
|
{
|
|
LPWABACTIONITEM lpTemp = LocalAlloc(LMEM_ZEROINIT, sizeof(WABACTIONITEM));
|
|
if(!lpTemp)
|
|
{
|
|
hr = MAPI_E_NOT_ENOUGH_MEMORY;
|
|
goto out;
|
|
}
|
|
// Temporarily cache the GUID
|
|
CopyMemory(&(lpTemp->guidContextMenu), &guidTmp, sizeof(GUID));
|
|
lpTemp->lpNext = lpList;
|
|
lpList = lpTemp;
|
|
}
|
|
|
|
dwGUIDIndex++;
|
|
*szGUIDName = '\0';
|
|
dwGUIDSize = CharSizeOf(szGUIDName);
|
|
}
|
|
}
|
|
|
|
if(lpList)
|
|
{
|
|
// If we have a list of GUIDs from the registry, we now
|
|
// need to open CoCreateInstance them one by one and get a handle
|
|
// to their method pointers
|
|
LPWABACTIONITEM lpItem = lpList;
|
|
|
|
if (CoInitialize(NULL) == S_FALSE)
|
|
CoUninitialize(); // Already initialized, undo the extra.
|
|
else
|
|
fContextExtCoinit = TRUE;
|
|
|
|
while(lpItem)
|
|
{
|
|
hr = CoCreateInstance( &(lpItem->guidContextMenu),
|
|
NULL,
|
|
CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER,
|
|
&IID_IContextMenu,
|
|
(LPVOID *)&(lpItem->lpContextMenu));
|
|
if(lpItem->lpContextMenu && !HR_FAILED(hr))
|
|
{
|
|
// Found an IContextMenu object, aslo want a IWABExtInit object
|
|
hr = lpItem->lpContextMenu->lpVtbl->QueryInterface(lpItem->lpContextMenu,
|
|
&IID_IWABExtInit,
|
|
(LPVOID *)&(lpItem->lpWABExtInit));
|
|
if(HR_FAILED(hr) || !lpItem->lpWABExtInit)
|
|
{
|
|
// Can't work without an IWABExtInit object
|
|
SafeRelease(lpItem->lpContextMenu);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = S_OK; //ignore error
|
|
lpItem->lpContextMenu = NULL;
|
|
}
|
|
lpItem = lpItem->lpNext;
|
|
}
|
|
}
|
|
|
|
lpIAB->lpActionList = lpList;
|
|
|
|
hr = S_OK;
|
|
out:
|
|
if(hKey)
|
|
RegCloseKey(hKey);
|
|
|
|
LeaveCriticalSection(&lpIAB->cs);
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*
|
|
- GetActionAdrList
|
|
-
|
|
* Based on the parameters for a particular rt-click action,
|
|
* scans the entries in the list view and creates an adrlist
|
|
* for the entries
|
|
*
|
|
* If only one entry is selected and it is an LDAP entry, then
|
|
* also creates an LDAP URL representing that entry .. this way
|
|
* if we are displaying properties or doing actions on a single
|
|
* entry, the property sheet extenstions can determine if they
|
|
* want to do anything extra for the entry. People most interested
|
|
* in this are the NTDS
|
|
*
|
|
* For now,we only look at the selected items in the list view
|
|
*
|
|
lpAdrBook - IAB object
|
|
hWndLV - the list view on which this action was initiated
|
|
*lppAdrList - created AdrList
|
|
*lpURL - returned URL
|
|
*lpbIsNTDSEntry - flag NTDS entries so they can be special treated
|
|
|
|
Note performance suffers for a large number of entries so we want to
|
|
really only return a list of entryids
|
|
*/
|
|
HRESULT HrGetActionAdrList(LPADRBOOK lpAdrBook,
|
|
HWND hWndLV,
|
|
LPADRLIST * lppAdrList,
|
|
LPTSTR * lppURL, BOOL * lpbIsNTDSEntry)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LPADRLIST lpAdrList = NULL;
|
|
int i = 0, iItemIndex = 0, nIndex= 0;
|
|
int nSel = ListView_GetSelectedCount(hWndLV);
|
|
SCODE sc;
|
|
if(!nSel)
|
|
goto out;
|
|
|
|
sc = MAPIAllocateBuffer(sizeof(ADRLIST) + nSel * sizeof(ADRENTRY), &lpAdrList);
|
|
|
|
if(sc)
|
|
{
|
|
hr = ResultFromScode(sc);
|
|
goto out;
|
|
}
|
|
|
|
// Get index of selected item
|
|
iItemIndex = ListView_GetNextItem(hWndLV,-1,LVNI_SELECTED);
|
|
|
|
while(iItemIndex != -1)
|
|
{
|
|
LPRECIPIENT_INFO lpItem = GetItemFromLV(hWndLV, iItemIndex);
|
|
|
|
if(lpItem)
|
|
{
|
|
ULONG ulObjType = 0;
|
|
LPSPropValue lpProps = NULL;
|
|
LPMAILUSER lpEntry = NULL;
|
|
ULONG cValues = 0;
|
|
|
|
if(lpItem->cbEntryID && lpItem->lpEntryID)
|
|
{
|
|
if (hr = lpAdrBook->lpVtbl->OpenEntry(lpAdrBook,
|
|
lpItem->cbEntryID,
|
|
lpItem->lpEntryID,
|
|
NULL, // interface
|
|
0, // flags
|
|
&ulObjType,
|
|
(LPUNKNOWN *)&lpEntry))
|
|
{
|
|
goto out;
|
|
}
|
|
hr = lpEntry->lpVtbl->GetProps( lpEntry, NULL, MAPI_UNICODE,
|
|
&cValues, &lpProps);
|
|
if(HR_FAILED(hr))
|
|
{
|
|
UlRelease(lpEntry);
|
|
goto out;
|
|
}
|
|
lpAdrList->aEntries[nIndex].cValues = cValues;
|
|
lpAdrList->aEntries[nIndex].rgPropVals = lpProps;
|
|
nIndex++;
|
|
|
|
UlRelease(lpEntry);
|
|
|
|
if(nSel == 1 && lppURL)
|
|
{
|
|
CreateLDAPURLFromEntryID(lpItem->cbEntryID, lpItem->lpEntryID,
|
|
lppURL, lpbIsNTDSEntry);
|
|
}
|
|
}
|
|
}
|
|
iItemIndex = ListView_GetNextItem(hWndLV,iItemIndex,LVNI_SELECTED);
|
|
}
|
|
|
|
lpAdrList->cEntries = nIndex;
|
|
*lppAdrList = lpAdrList;
|
|
lpAdrList = NULL;
|
|
hr = S_OK;
|
|
|
|
out:
|
|
if (lpAdrList)
|
|
MAPIFreeBuffer(lpAdrList);
|
|
|
|
return hr;
|
|
}
|
|
|
|
extern void MAILUSERAssociateContextData(LPMAILUSER lpMailUser, LPWABEXTDISPLAY lpWEC);
|
|
/*
|
|
- HrCreateContextDataStruct
|
|
-
|
|
* Creates the data necessary to initialize a ContextMenu implementor
|
|
* This structure is passed into the IWABExtInit::Initialize call
|
|
*
|
|
hWndLV - ListView containing the WAB entries
|
|
lppWABExt - returned data
|
|
*/
|
|
HRESULT HrCreateContextDataStruct( LPIAB lpIAB,
|
|
HWND hWndLV,
|
|
LPWABEXTDISPLAY * lppWABExt)
|
|
{
|
|
LPADRLIST lpAdrList = NULL;
|
|
LPWABEXTDISPLAY lpWEC = NULL;
|
|
LPMAILUSER lpMailUser = NULL;
|
|
LPTSTR lpURL = NULL;
|
|
BOOL bIsNTDSEntry = FALSE;
|
|
|
|
HRESULT hr = E_FAIL;
|
|
|
|
// Get an AdrList Corresponding to the LV contents
|
|
hr = HrGetActionAdrList((LPADRBOOK)lpIAB, hWndLV, &lpAdrList, &lpURL, &bIsNTDSEntry);
|
|
if(HR_FAILED(hr) || !lpAdrList || !lpAdrList->cEntries)
|
|
goto out; //dont bother invoking
|
|
|
|
// Create a dummy mailuser so callers can call GetIDsFromNames
|
|
// on this dummy mailuser - saves them the trouble of creating entries
|
|
// just to call GetIDsFromNames
|
|
hr = HrCreateNewObject((LPADRBOOK)lpIAB, NULL, MAPI_MAILUSER, CREATE_CHECK_DUP_STRICT, (LPMAPIPROP *) &lpMailUser);
|
|
if(HR_FAILED(hr))
|
|
goto out; //dont bother invoking
|
|
|
|
lpWEC = LocalAlloc(LMEM_ZEROINIT, sizeof(WABEXTDISPLAY));
|
|
if(!lpWEC)
|
|
{
|
|
hr = MAPI_E_NOT_ENOUGH_MEMORY;
|
|
goto out;
|
|
}
|
|
|
|
lpWEC->cbSize = sizeof(WABEXTDISPLAY);
|
|
lpWEC->ulFlags = WAB_CONTEXT_ADRLIST; // indicates ADRLIST is valid and in the lpv member
|
|
lpWEC->lpAdrBook = (LPADRBOOK) lpIAB;
|
|
lpWEC->lpWABObject = (LPWABOBJECT) lpIAB->lpWABObject;
|
|
lpWEC->lpPropObj = (LPMAPIPROP) lpMailUser;
|
|
lpWEC->lpv = (LPVOID) lpAdrList;
|
|
|
|
if(lpURL && lstrlen(lpURL))
|
|
{
|
|
lpWEC->lpsz = lpURL;
|
|
lpWEC->ulFlags |= WAB_DISPLAY_LDAPURL;
|
|
lpWEC->ulFlags |= MAPI_UNICODE;
|
|
if(bIsNTDSEntry)
|
|
lpWEC->ulFlags |= WAB_DISPLAY_ISNTDS;
|
|
}
|
|
|
|
// We associate this entire WABEXT structure with the mailuser
|
|
// so that when we get the IMailUser release, we can go ahead and clean
|
|
// up all the WABEXT memory .. since there is no other good time that we can
|
|
// free the memory since we won't know who is doing what withthe structure.
|
|
// Freeing it at IMailUser::Release time works out quite well
|
|
MAILUSERAssociateContextData(lpMailUser, lpWEC);
|
|
|
|
//
|
|
// Cache this mailUser on the IAB object
|
|
//
|
|
// At any given point of time, we are going to cache one ContextMenu related MailUser
|
|
// This is because we set this up before QueryCommandMenu and then we dont know whether
|
|
// or not the user actually managed to select a menu item, or went off and did something new.
|
|
// We set the data on a MailUser and we don't release the MailUser till the next time we are
|
|
// here. If someone is currently using the MailUser, they will addref it - the memory attached
|
|
// to the MailUser will be freed up with the last caller so we dont leak it ..
|
|
// If we never come back here, the mailuser will be released at shutdown
|
|
//
|
|
UlRelease(lpIAB->lpCntxtMailUser);
|
|
lpIAB->lpCntxtMailUser = lpMailUser;
|
|
|
|
*lppWABExt = lpWEC;
|
|
hr = S_OK;
|
|
out:
|
|
|
|
if(HR_FAILED(hr))
|
|
{
|
|
UlRelease(lpMailUser);
|
|
if(lpAdrList)
|
|
FreePadrlist(lpAdrList);
|
|
if(lpWEC)
|
|
LocalFree(lpWEC);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
//$$////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// AddExtendedMenuItems - Creates a list of extension menu items and adds them
|
|
// to the specified menu
|
|
//
|
|
// hMenuAction - menu on which to add this item
|
|
// bUpdateStatus - if TRUE, means only find the existing item in the menu and update
|
|
// its status - if FALSE, means add to the menu
|
|
// bAddSendMailToItems - if TRUE, means attempt to modify the SendMailTo menu item
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
void AddExtendedMenuItems( LPADRBOOK lpAdrBook,
|
|
HWND hWndLV,
|
|
HMENU hMenuAction,
|
|
BOOL bUpdateStatus,
|
|
BOOL bAddSendMailToItems)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LPWABEXTDISPLAY lpWEC = NULL;
|
|
LPIAB lpIAB = (LPIAB) lpAdrBook;
|
|
|
|
// Intialize the context menu extensions
|
|
if(!lpIAB->lpActionList)
|
|
HrUpdateActionItemList(lpIAB);
|
|
|
|
if(bUpdateStatus)
|
|
{
|
|
// This is only set to true from the call from ui_abook.c which means this
|
|
// is the Tools Menu item we are talking about.
|
|
// To update the status of the Tools menu item, we need to remove all the
|
|
// items we added before and then re-add them
|
|
// For indexing purposes, we will assume that the last pre-configured item in
|
|
// this list is the Internet Call item (since this menu list is quite variable)
|
|
|
|
// First get the position of the IDM_TOOLS_INTERNET_CALL item
|
|
int i, nPos = -1, nId = 0;
|
|
int nCmdCount = GetMenuItemCount(hMenuAction); // Append all items at end of this menu
|
|
for(i=0;i<nCmdCount;i++)
|
|
{
|
|
if(GetMenuItemID(hMenuAction, i) == IDM_TOOLS_INTERNET_CALL)
|
|
{
|
|
nPos = i;
|
|
break;
|
|
}
|
|
}
|
|
if(nPos >= 0 && nPos < nCmdCount-1)
|
|
{
|
|
for(i=nPos+1;i<nCmdCount;i++)
|
|
{
|
|
DeleteMenu(hMenuAction, nPos+1, MF_BYPOSITION);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Do any special treatment we need to do for SendMailTo
|
|
AddExtendedSendMailToItems(lpAdrBook, hWndLV, hMenuAction, bAddSendMailToItems);
|
|
|
|
|
|
// Before we can call QueryContextMenu - we must already have a list of all
|
|
// the selected items from the ListView and provide such items to the ContextMenu
|
|
// implementors so that they can decide how to handle the data being provided to them
|
|
// (e.g. they may want to disable their item for multi-selections etc)...
|
|
//
|
|
HrCreateContextDataStruct(lpIAB, hWndLV, &lpWEC);
|
|
|
|
if(lpIAB->lpActionList && lpWEC && lpWEC->lpv)
|
|
{
|
|
LPWABACTIONITEM lpItem = lpIAB->lpActionList;
|
|
int nCmdIdPos = GetMenuItemCount(hMenuAction); // Append all items at end of this menu
|
|
while(lpItem)
|
|
{
|
|
if(lpItem->lpContextMenu && lpItem->lpWABExtInit)// && !bUpdateStatus)
|
|
{
|
|
int nNumCmd = 0;
|
|
// Get the menu item added to this menu
|
|
hr = lpItem->lpWABExtInit->lpVtbl->Initialize(lpItem->lpWABExtInit, lpWEC);
|
|
if(!HR_FAILED(hr))
|
|
{
|
|
hr = lpItem->lpContextMenu->lpVtbl->QueryContextMenu(lpItem->lpContextMenu,
|
|
hMenuAction,
|
|
nCmdIdPos,
|
|
lpItem->nCmdIdFirst ? lpItem->nCmdIdFirst : IDM_EXTENDED_START+nCmdIdPos,
|
|
IDM_EXTENDED_END,
|
|
CMF_NODEFAULT | CMF_NORMAL);
|
|
if(!HR_FAILED(hr))
|
|
{
|
|
nNumCmd = HRESULT_CODE(hr);
|
|
if(nNumCmd)
|
|
{
|
|
// Record the range of IDs taken up by this menu ext implementor
|
|
if(!lpItem->nCmdIdFirst)
|
|
lpItem->nCmdIdFirst = nCmdIdPos+IDM_EXTENDED_START;
|
|
if(!lpItem->nCmdIdLast)
|
|
lpItem->nCmdIdLast = lpItem->nCmdIdFirst + nNumCmd - 1;
|
|
}
|
|
// Update the next available starting pos
|
|
nCmdIdPos = nCmdIdPos+nNumCmd;
|
|
}
|
|
}
|
|
}
|
|
lpItem = lpItem->lpNext;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
- ProcessActionCommands
|
|
-
|
|
* Process a WM_COMMAND message to see if it matches any of the extended
|
|
* rt-click action items ...
|
|
*
|
|
* Also process SendMailTo extended email-address mail processing here since
|
|
* this is a convenient place to do so ..
|
|
*
|
|
*/
|
|
LRESULT ProcessActionCommands(LPIAB lpIAB, HWND hWndLV, HWND hWnd,
|
|
UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
int nCmdID = GET_WM_COMMAND_ID(wParam, lParam);
|
|
int i = 0;
|
|
|
|
switch(nCmdID)
|
|
{
|
|
case IDM_DIALDLG_START:
|
|
HrExecDialDlg(hWndLV, (LPADRBOOK)lpIAB);
|
|
return 0;
|
|
break;
|
|
case IDM_LVCONTEXT_INTERNET_CALL:
|
|
case IDM_TOOLS_INTERNET_CALL:
|
|
HrShellExecInternetCall((LPADRBOOK)lpIAB, hWndLV);
|
|
return 0;
|
|
break;
|
|
|
|
case IDM_LVCONTEXT_SENDMAIL:
|
|
case IDM_FILE_SENDMAIL:
|
|
HrSendMailToSelectedContacts(hWndLV, (LPADRBOOK)lpIAB, 0);
|
|
break;
|
|
}
|
|
|
|
if( (nCmdID>=IDM_SENDMAILTO_START) && (nCmdID<=IDM_SENDMAILTO_START+IDM_SENDMAILTO_MAX))
|
|
{
|
|
HrSendMailToSelectedContacts(hWndLV, (LPADRBOOK)lpIAB, nCmdID - IDM_SENDMAILTO_START);
|
|
return 0;
|
|
}
|
|
|
|
// Check if this is any of the context menu extensions ..
|
|
if(lpIAB->lpActionList)
|
|
{
|
|
LPWABACTIONITEM lpListItem = lpIAB->lpActionList;
|
|
while(lpListItem)
|
|
{
|
|
if(nCmdID >= lpListItem->nCmdIdFirst && nCmdID <= lpListItem->nCmdIdLast)
|
|
{
|
|
CMINVOKECOMMANDINFO cmici = {0};
|
|
cmici.cbSize = sizeof(CMINVOKECOMMANDINFO);
|
|
cmici.fMask = 0;
|
|
cmici.hwnd = hWnd;
|
|
cmici.lpVerb = (LPCSTR) IntToPtr(nCmdID - lpListItem->nCmdIdFirst);
|
|
cmici.lpParameters = NULL;
|
|
cmici.lpDirectory = NULL;
|
|
cmici.nShow = SW_SHOWNORMAL;
|
|
|
|
lpListItem->lpContextMenu->lpVtbl->InvokeCommand(lpListItem->lpContextMenu,
|
|
&cmici);
|
|
return 0;
|
|
}
|
|
lpListItem = lpListItem->lpNext;
|
|
}
|
|
}
|
|
return DefWindowProc(hWnd,uMsg,wParam,lParam);
|
|
}
|
|
|
|
|
|
/*
|
|
- GetContextMenuExtCommandString
|
|
-
|
|
* gets the status bar helptext for context menu extensions
|
|
*
|
|
*/
|
|
void GetContextMenuExtCommandString(LPIAB lpIAB, int nCmdId, LPTSTR sz, ULONG cbsz)
|
|
{
|
|
int nStringID = 0;
|
|
|
|
switch(nCmdId)
|
|
{
|
|
case IDM_DIALDLG_START:
|
|
nStringID = idsMenuDialer;
|
|
break;
|
|
case IDM_LVCONTEXT_INTERNET_CALL:
|
|
case IDM_TOOLS_INTERNET_CALL:
|
|
nStringID = idsMenuInternetCall;
|
|
break;
|
|
case IDM_LVCONTEXT_SENDMAIL:
|
|
case IDM_FILE_SENDMAIL:
|
|
nStringID = idsMenuSendMail;
|
|
break;
|
|
}
|
|
if(nStringID)
|
|
{
|
|
LoadString(hinstMapiX, nStringID, sz, cbsz);
|
|
return;
|
|
}
|
|
|
|
if(lpIAB->lpActionList)
|
|
{
|
|
LPWABACTIONITEM lpListItem = lpIAB->lpActionList;
|
|
while(lpListItem)
|
|
{
|
|
if(nCmdId >= lpListItem->nCmdIdFirst && nCmdId <= lpListItem->nCmdIdLast)
|
|
{
|
|
char szC[MAX_PATH];
|
|
ULONG cbszC = CharSizeOf(szC);
|
|
lpListItem->lpContextMenu->lpVtbl->GetCommandString(lpListItem->lpContextMenu,
|
|
nCmdId - lpListItem->nCmdIdFirst,
|
|
GCS_HELPTEXT,
|
|
NULL,
|
|
szC,
|
|
cbszC);
|
|
{
|
|
LPTSTR lp = ConvertAtoW(szC);
|
|
if(lp)
|
|
{
|
|
StrCpyN(sz, lp, cbsz);
|
|
LocalFreeAndNull(&lp);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
lpListItem = lpListItem->lpNext;
|
|
}
|
|
}
|
|
}
|