mirror of https://github.com/tongzx/nt5src
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.
1071 lines
38 KiB
1071 lines
38 KiB
/*
|
|
* OLE2UI.CPP
|
|
*
|
|
* Contains initialization routines and miscellaneous API implementations for
|
|
* the OLE 2.0 User Interface Support Library.
|
|
*
|
|
* Copyright (c)1992 Microsoft Corporation, All Right Reserved
|
|
*/
|
|
|
|
#include "precomp.h"
|
|
#include "common.h"
|
|
#include "utility.h"
|
|
#include "resimage.h"
|
|
#include "iconbox.h"
|
|
#include <commdlg.h>
|
|
#include <stdarg.h>
|
|
#include "strcache.h"
|
|
|
|
OLEDBGDATA
|
|
|
|
// Registered messages for use with all the dialogs, registered in LibMain
|
|
UINT uMsgHelp;
|
|
UINT uMsgEndDialog;
|
|
UINT uMsgBrowse;
|
|
UINT uMsgChangeIcon;
|
|
UINT uMsgFileOKString;
|
|
UINT uMsgCloseBusyDlg;
|
|
UINT uMsgConvert;
|
|
UINT uMsgChangeSource;
|
|
UINT uMsgAddControl;
|
|
UINT uMsgBrowseOFN;
|
|
|
|
// local function prototypes
|
|
INT_PTR CALLBACK PromptUserDlgProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam);
|
|
INT_PTR CALLBACK UpdateLinksDlgProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam);
|
|
|
|
// local definition
|
|
#define WM_U_UPDATELINK (WM_USER+0x2000)
|
|
#define WM_U_SHOWWINDOW (WM_USER+0x2001)
|
|
|
|
// local structure definition
|
|
typedef struct tagUPDATELINKS
|
|
{
|
|
LPOLEUILINKCONTAINER lpOleUILinkCntr; // pointer to Link Container
|
|
UINT cLinks; // total number of links
|
|
UINT cUpdated; // number of links updated
|
|
DWORD dwLink; // pointer to link
|
|
BOOL fError; // error flag
|
|
LPTSTR lpszTitle; // caption for dialog box
|
|
} UPDATELINKS, *PUPDATELINKS, FAR *LPUPDATELINKS;
|
|
|
|
|
|
/*
|
|
* OleUIInitialize
|
|
*
|
|
* NOTE: This function should only be called by your application IF it is
|
|
* using the static-link version of this library. If the DLL version is
|
|
* being used, this function is automatically called from the OLEDLG DLL's
|
|
* LibMain.
|
|
*
|
|
* Purpose:
|
|
* Initializes the OLE UI Library. Registers the OLE clipboard formats
|
|
* used in the Paste Special dialog, registers private custom window
|
|
* messages, and registers window classes of the "Result Image"
|
|
* and "Icon Box" custom controls used in the UI dialogs.
|
|
*
|
|
* Parameters:
|
|
*
|
|
* hInstance HINSTANCE of the module where the UI library resources
|
|
* and Dialog Procedures are contained. If you are calling
|
|
* this function yourself, this should be the instance handle
|
|
* of your application.
|
|
*
|
|
* hPrevInst HINSTANCE of the previous application instance.
|
|
* This is the parameter passed in to your WinMain. For
|
|
* the DLL version, this should always be set to zero (for
|
|
* WIN16 DLLs).
|
|
*
|
|
* Return Value:
|
|
* BOOL TRUE if initialization was successful.
|
|
* FALSE otherwise.
|
|
*/
|
|
|
|
#pragma code_seg(".text$initseg")
|
|
|
|
BOOL bWin4; // TRUE if running Windows4 or greater
|
|
BOOL bSharedData; // TRUE if running Win32s (it has shared data)
|
|
|
|
static DWORD tlsIndex= (DWORD)-1;
|
|
static TASKDATA taskData;
|
|
|
|
STDAPI_(TASKDATA*) GetTaskData()
|
|
{
|
|
TASKDATA* pData;
|
|
if (tlsIndex == (DWORD)-1)
|
|
pData = &taskData;
|
|
else
|
|
pData = (TASKDATA*)TlsGetValue(tlsIndex);
|
|
return pData;
|
|
}
|
|
|
|
DWORD WINAPI _AfxTlsAlloc()
|
|
{
|
|
DWORD dwResult = TlsAlloc();
|
|
DWORD dwVersion = GetVersion();
|
|
if ((dwVersion & 0x80000000) && (BYTE)dwVersion <= 3)
|
|
{
|
|
while (dwResult <= 2)
|
|
dwResult = TlsAlloc();
|
|
}
|
|
return dwResult;
|
|
}
|
|
|
|
static int nInitCount;
|
|
|
|
STDAPI_(BOOL) OleUIUnInitialize();
|
|
|
|
STDAPI_(BOOL) OleUIInitialize(HINSTANCE hInstance,
|
|
HINSTANCE hPrevInst)
|
|
{
|
|
OleDbgOut1(TEXT("OleUIInitialize called.\r\n"));
|
|
|
|
// Cache information about the windows version we are running
|
|
DWORD dwVersion = GetVersion();
|
|
bWin4 = LOBYTE(dwVersion) >= 4;
|
|
bSharedData = !bWin4 && (dwVersion & 0x80000000);
|
|
|
|
if (nInitCount == 0)
|
|
{
|
|
if (bSharedData)
|
|
{
|
|
// allocate thread local storage on Win32s
|
|
tlsIndex = _AfxTlsAlloc();
|
|
if (tlsIndex == (DWORD)-1)
|
|
return FALSE;
|
|
}
|
|
}
|
|
++nInitCount;
|
|
|
|
// Setup process local storage if necessary
|
|
if (tlsIndex != (DWORD)-1)
|
|
{
|
|
void* pData = LocalAlloc(LPTR, sizeof(TASKDATA));
|
|
if (pData == NULL)
|
|
{
|
|
if (nInitCount == 0)
|
|
{
|
|
OleUIUnInitialize();
|
|
return FALSE;
|
|
}
|
|
}
|
|
TlsSetValue(tlsIndex, pData);
|
|
}
|
|
|
|
// Initialize OleStd functions
|
|
OleStdInitialize(hInstance, hInstance);
|
|
|
|
// Register messages we need for the dialogs.
|
|
uMsgHelp = RegisterWindowMessage(SZOLEUI_MSG_HELP);
|
|
uMsgEndDialog = RegisterWindowMessage(SZOLEUI_MSG_ENDDIALOG);
|
|
uMsgBrowse = RegisterWindowMessage(SZOLEUI_MSG_BROWSE);
|
|
uMsgChangeIcon = RegisterWindowMessage(SZOLEUI_MSG_CHANGEICON);
|
|
uMsgFileOKString = RegisterWindowMessage(FILEOKSTRING);
|
|
uMsgCloseBusyDlg = RegisterWindowMessage(SZOLEUI_MSG_CLOSEBUSYDIALOG);
|
|
uMsgConvert = RegisterWindowMessage(SZOLEUI_MSG_CONVERT);
|
|
uMsgChangeSource = RegisterWindowMessage(SZOLEUI_MSG_CHANGESOURCE);
|
|
uMsgAddControl = RegisterWindowMessage(SZOLEUI_MSG_ADDCONTROL);
|
|
uMsgBrowseOFN = RegisterWindowMessage(SZOLEUI_MSG_BROWSE_OFN);
|
|
|
|
if (!FResultImageInitialize(hInstance, hPrevInst))
|
|
{
|
|
OleDbgOut1(TEXT("OleUIInitialize: FResultImageInitialize failed. Terminating.\r\n"));
|
|
return 0;
|
|
}
|
|
if (!FIconBoxInitialize(hInstance, hPrevInst))
|
|
{
|
|
OleDbgOut1(TEXT("OleUIInitialize: FIconBoxInitialize failed. Terminating.\r\n"));
|
|
return 0;
|
|
}
|
|
|
|
#if USE_STRING_CACHE==1
|
|
// It is ok if this fails. InsertObject dialog can do without the cache
|
|
// support. InsertObjCacheUninit will cleanup as appropriate.
|
|
if (!InsertObjCacheInitialize())
|
|
{
|
|
OleDbgOut1(TEXT("OleUIInitiallize: InsertObjCacheInit failed."));
|
|
}
|
|
#endif
|
|
return TRUE;
|
|
}
|
|
|
|
#pragma code_seg()
|
|
|
|
|
|
/*
|
|
* OleUIUnInitialize
|
|
*
|
|
* NOTE: This function should only be called by your application IF it is using
|
|
* the static-link version of this library. If the DLL version is being used,
|
|
* this function is automatically called from the DLL's LibMain.
|
|
*
|
|
* Purpose:
|
|
* Uninitializes OLE UI libraries. Deletes any resources allocated by the
|
|
* library.
|
|
*
|
|
* Return Value:
|
|
* BOOL TRUE if successful, FALSE if not. Current implementation always
|
|
* returns TRUE.
|
|
*/
|
|
STDAPI_(BOOL) OleUIUnInitialize()
|
|
{
|
|
#if USE_STRING_CACHE==1
|
|
InsertObjCacheUninitialize();
|
|
#endif
|
|
IconBoxUninitialize();
|
|
ResultImageUninitialize();
|
|
|
|
// Cleanup thread local storage
|
|
if (tlsIndex != (DWORD)-1)
|
|
{
|
|
TASKDATA* pData = (TASKDATA*)TlsGetValue(tlsIndex);
|
|
TlsSetValue(tlsIndex, NULL);
|
|
if (pData != NULL)
|
|
{
|
|
if (pData->hInstCommCtrl != NULL)
|
|
FreeLibrary(pData->hInstCommCtrl);
|
|
if (pData->hInstShell != NULL)
|
|
FreeLibrary(pData->hInstShell);
|
|
if (pData->hInstComDlg != NULL)
|
|
FreeLibrary(pData->hInstComDlg);
|
|
LocalFree(pData);
|
|
}
|
|
}
|
|
|
|
// Last chance cleanup
|
|
if (nInitCount == 1)
|
|
{
|
|
// cleanup thread local storage
|
|
if (tlsIndex != (DWORD)-1)
|
|
{
|
|
TlsFree(tlsIndex);
|
|
tlsIndex = (DWORD)-1;
|
|
}
|
|
}
|
|
if (nInitCount != 0)
|
|
--nInitCount;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*
|
|
* OleUIAddVerbMenu
|
|
*
|
|
* Purpose:
|
|
* Add the Verb menu for the specified object to the given menu. If the
|
|
* object has one verb, we directly add the verb to the given menu. If
|
|
* the object has multiple verbs we create a cascading sub-menu.
|
|
*
|
|
* Parameters:
|
|
* lpObj LPOLEOBJECT pointing to the selected object. If this
|
|
* is NULL, then we create a default disabled menu item.
|
|
*
|
|
* lpszShortType LPTSTR with short type name (AuxName==2) corresponding
|
|
* to the lpOleObj. if the string is NOT known, then NULL
|
|
* may be passed. if NULL is passed, then
|
|
* IOleObject::GetUserType will be called to retrieve it.
|
|
* if the caller has the string handy, then it is faster
|
|
* to pass it in.
|
|
*
|
|
* hMenu HMENU in which to make modifications.
|
|
*
|
|
* uPos Position of the menu item
|
|
*
|
|
* uIDVerbMin UINT_PTR ID value at which to start the verbs.
|
|
* verb_0 = wIDMVerbMin + verb_0
|
|
* verb_1 = wIDMVerbMin + verb_1
|
|
* verb_2 = wIDMVerbMin + verb_2
|
|
* etc.
|
|
* uIDVerbMax UINT_PTR maximum ID value allowed for object verbs.
|
|
* if uIDVerbMax==0 then any ID value is allowed
|
|
*
|
|
* bAddConvert BOOL specifying whether or not to add a "Convert" item
|
|
* to the bottom of the menu (with a separator).
|
|
*
|
|
* idConvert UINT ID value to use for the Convert menu item, if
|
|
* bAddConvert is TRUE.
|
|
*
|
|
* lphMenu HMENU FAR * of the cascading verb menu if it's created.
|
|
* If there is only one verb, this will be filled with NULL.
|
|
*
|
|
*
|
|
* Return Value:
|
|
* BOOL TRUE if lpObj was valid and we added at least one verb
|
|
* to the menu. FALSE if lpObj was NULL and we created
|
|
* a disabled default menu item
|
|
*/
|
|
|
|
STDAPI_(BOOL) OleUIAddVerbMenu(LPOLEOBJECT lpOleObj,
|
|
LPCTSTR lpszShortType,
|
|
HMENU hMenu, UINT uPos,
|
|
UINT uIDVerbMin, UINT uIDVerbMax,
|
|
BOOL bAddConvert, UINT idConvert,
|
|
HMENU FAR *lphMenu)
|
|
{
|
|
LPPERSISTSTORAGE lpPS=NULL;
|
|
LPENUMOLEVERB lpEnumOleVerb = NULL;
|
|
OLEVERB oleverb;
|
|
LPCTSTR lpszShortTypeName = lpszShortType;
|
|
LPTSTR lpszVerbName = NULL;
|
|
HRESULT hrErr;
|
|
BOOL fStatus;
|
|
BOOL fIsLink = FALSE;
|
|
BOOL fResult = TRUE;
|
|
BOOL fAddConvertItem = FALSE;
|
|
int cVerbs = 0;
|
|
UINT uFlags = MF_BYPOSITION;
|
|
static BOOL fFirstTime = TRUE;
|
|
static TCHAR szBuffer[OLEUI_OBJECTMENUMAX];
|
|
static TCHAR szNoObjectCmd[OLEUI_OBJECTMENUMAX];
|
|
static TCHAR szObjectCmd1Verb[OLEUI_OBJECTMENUMAX];
|
|
static TCHAR szLinkCmd1Verb[OLEUI_OBJECTMENUMAX];
|
|
static TCHAR szObjectCmdNVerb[OLEUI_OBJECTMENUMAX];
|
|
static TCHAR szLinkCmdNVerb[OLEUI_OBJECTMENUMAX];
|
|
static TCHAR szUnknown[OLEUI_OBJECTMENUMAX];
|
|
static TCHAR szEdit[OLEUI_OBJECTMENUMAX];
|
|
static TCHAR szConvert[OLEUI_OBJECTMENUMAX];
|
|
|
|
// Set fAddConvertItem flag
|
|
if (bAddConvert & (idConvert != 0))
|
|
fAddConvertItem = TRUE;
|
|
|
|
// only need to load the strings the 1st time
|
|
if (fFirstTime)
|
|
{
|
|
if (0 == LoadString(_g_hOleStdResInst, IDS_OLE2UIEDITNOOBJCMD,
|
|
szNoObjectCmd, OLEUI_OBJECTMENUMAX))
|
|
return FALSE;
|
|
if (0 == LoadString(_g_hOleStdResInst, IDS_OLE2UIEDITLINKCMD_1VERB,
|
|
szLinkCmd1Verb, OLEUI_OBJECTMENUMAX))
|
|
return FALSE;
|
|
if (0 == LoadString(_g_hOleStdResInst, IDS_OLE2UIEDITOBJECTCMD_1VERB,
|
|
szObjectCmd1Verb, OLEUI_OBJECTMENUMAX))
|
|
return FALSE;
|
|
|
|
if (0 == LoadString(_g_hOleStdResInst, IDS_OLE2UIEDITLINKCMD_NVERB,
|
|
szLinkCmdNVerb, OLEUI_OBJECTMENUMAX))
|
|
return FALSE;
|
|
if (0 == LoadString(_g_hOleStdResInst, IDS_OLE2UIEDITOBJECTCMD_NVERB,
|
|
szObjectCmdNVerb, OLEUI_OBJECTMENUMAX))
|
|
return FALSE;
|
|
|
|
if (0 == LoadString(_g_hOleStdResInst, IDS_OLE2UIUNKNOWN,
|
|
szUnknown, OLEUI_OBJECTMENUMAX))
|
|
return FALSE;
|
|
|
|
if (0 == LoadString(_g_hOleStdResInst, IDS_OLE2UIEDIT,
|
|
szEdit, OLEUI_OBJECTMENUMAX))
|
|
return FALSE;
|
|
|
|
if (0 == LoadString(_g_hOleStdResInst, IDS_OLE2UICONVERT,
|
|
szConvert, OLEUI_OBJECTMENUMAX) && fAddConvertItem)
|
|
return FALSE;
|
|
|
|
fFirstTime = FALSE;
|
|
}
|
|
|
|
// Delete whatever menu may happen to be here already.
|
|
DeleteMenu(hMenu, uPos, uFlags);
|
|
|
|
if (lphMenu == NULL || IsBadWritePtr(lphMenu, sizeof(HMENU)))
|
|
{
|
|
goto AVMError;
|
|
}
|
|
*lphMenu=NULL;
|
|
|
|
if ((!lpOleObj) || IsBadReadPtr(lpOleObj, sizeof (IOleObject)))
|
|
goto AVMError;
|
|
|
|
if ((!lpszShortTypeName) || IsBadReadPtr(lpszShortTypeName, sizeof(TCHAR)))
|
|
{
|
|
// get the Short form of the user type name for the menu
|
|
OLEDBG_BEGIN2(TEXT("IOleObject::GetUserType called\r\n"))
|
|
#if defined(WIN32) && !defined(UNICODE)
|
|
LPOLESTR wszShortTypeName = NULL;
|
|
lpszShortTypeName = NULL;
|
|
hrErr = lpOleObj->GetUserType(
|
|
USERCLASSTYPE_SHORT,
|
|
&wszShortTypeName);
|
|
if (NULL != wszShortTypeName)
|
|
{
|
|
UINT uLen = WTOALEN(wszShortTypeName);
|
|
lpszShortTypeName = (LPTSTR) OleStdMalloc(uLen);
|
|
if (NULL != lpszShortTypeName)
|
|
{
|
|
WTOA((char *)lpszShortTypeName, wszShortTypeName, uLen);
|
|
}
|
|
OleStdFree(wszShortTypeName);
|
|
}
|
|
#else
|
|
hrErr = lpOleObj->GetUserType(
|
|
USERCLASSTYPE_SHORT,
|
|
(LPTSTR FAR*)&lpszShortTypeName);
|
|
#endif
|
|
OLEDBG_END2
|
|
|
|
if (NOERROR != hrErr) {
|
|
OleDbgOutHResult(TEXT("IOleObject::GetUserType returned"), hrErr);
|
|
}
|
|
}
|
|
|
|
// check if the object is a link
|
|
fIsLink = OleStdIsOleLink((LPUNKNOWN)lpOleObj);
|
|
|
|
// Get the verb enumerator from the OLE object
|
|
OLEDBG_BEGIN2(TEXT("IOleObject::EnumVerbs called\r\n"))
|
|
hrErr = lpOleObj->EnumVerbs(
|
|
(LPENUMOLEVERB FAR*)&lpEnumOleVerb
|
|
);
|
|
OLEDBG_END2
|
|
|
|
if (NOERROR != hrErr) {
|
|
OleDbgOutHResult(TEXT("IOleObject::EnumVerbs returned"), hrErr);
|
|
}
|
|
|
|
if (!(*lphMenu = CreatePopupMenu()))
|
|
goto AVMError;
|
|
|
|
// loop through all verbs
|
|
while (lpEnumOleVerb != NULL)
|
|
{
|
|
hrErr = lpEnumOleVerb->Next(
|
|
1,
|
|
(LPOLEVERB)&oleverb,
|
|
NULL
|
|
);
|
|
if (NOERROR != hrErr)
|
|
break; // DONE! no more verbs
|
|
|
|
/* OLE2NOTE: negative verb numbers and verbs that do not
|
|
** indicate ONCONTAINERMENU should NOT be put on the verb menu
|
|
*/
|
|
if (oleverb.lVerb < 0 ||
|
|
! (oleverb.grfAttribs & OLEVERBATTRIB_ONCONTAINERMENU))
|
|
{
|
|
/* OLE2NOTE: we must still free the verb name string */
|
|
if (oleverb.lpszVerbName)
|
|
OleStdFree(oleverb.lpszVerbName);
|
|
continue;
|
|
}
|
|
|
|
// we must free the previous verb name string
|
|
if (lpszVerbName)
|
|
OleStdFree(lpszVerbName);
|
|
|
|
#if defined(WIN32) && !defined(UNICODE)
|
|
lpszVerbName = NULL;
|
|
if (NULL != oleverb.lpszVerbName)
|
|
{
|
|
UINT uLen = WTOALEN(oleverb.lpszVerbName);
|
|
lpszVerbName = (LPTSTR) OleStdMalloc(uLen);
|
|
if (NULL != lpszVerbName)
|
|
{
|
|
WTOA(lpszVerbName, oleverb.lpszVerbName, uLen);
|
|
}
|
|
OleStdFree(oleverb.lpszVerbName);
|
|
}
|
|
#else
|
|
lpszVerbName = oleverb.lpszVerbName;
|
|
#endif
|
|
if ( 0 == uIDVerbMax ||
|
|
(uIDVerbMax >= uIDVerbMin+(UINT)oleverb.lVerb) )
|
|
{
|
|
fStatus = InsertMenu(
|
|
*lphMenu,
|
|
(UINT)-1,
|
|
MF_BYPOSITION | (UINT)oleverb.fuFlags,
|
|
uIDVerbMin+(UINT)oleverb.lVerb,
|
|
lpszVerbName
|
|
);
|
|
if (! fStatus)
|
|
goto AVMError;
|
|
|
|
cVerbs++;
|
|
}
|
|
}
|
|
|
|
// Add the separator and "Convert" menu item.
|
|
if (fAddConvertItem)
|
|
{
|
|
if (0 == cVerbs)
|
|
{
|
|
LPTSTR lpsz;
|
|
|
|
// if object has no verbs, then use "Convert" as the obj's verb
|
|
lpsz = lpszVerbName = OleStdCopyString(szConvert);
|
|
uIDVerbMin = (UINT)idConvert;
|
|
|
|
// remove "..." from "Convert..." string; it will be added later
|
|
if (lpsz)
|
|
{
|
|
while(*lpsz && *lpsz != '.')
|
|
lpsz = CharNext(lpsz);
|
|
*lpsz = '\0';
|
|
}
|
|
}
|
|
|
|
if (cVerbs > 0)
|
|
{
|
|
fStatus = InsertMenu(*lphMenu,
|
|
(UINT)-1,
|
|
MF_BYPOSITION | MF_SEPARATOR,
|
|
(UINT)0,
|
|
(LPCTSTR)NULL);
|
|
if (! fStatus)
|
|
goto AVMError;
|
|
}
|
|
|
|
/* add convert menu */
|
|
fStatus = InsertMenu(*lphMenu,
|
|
(UINT)-1,
|
|
MF_BYPOSITION,
|
|
idConvert,
|
|
(LPCTSTR)szConvert);
|
|
if (! fStatus)
|
|
goto AVMError;
|
|
|
|
cVerbs++;
|
|
}
|
|
|
|
|
|
/*
|
|
* Build the appropriate menu based on the number of verbs found
|
|
*
|
|
*/
|
|
if (cVerbs == 0)
|
|
{
|
|
// there are NO verbs (not even Convert...). set the menu to be
|
|
// "<short type> &Object/Link" and gray it out.
|
|
wsprintf(
|
|
szBuffer,
|
|
(fIsLink ? szLinkCmdNVerb : szObjectCmdNVerb),
|
|
(lpszShortTypeName ? lpszShortTypeName : TEXT(""))
|
|
);
|
|
uFlags |= MF_GRAYED;
|
|
|
|
fResult = FALSE;
|
|
DestroyMenu(*lphMenu);
|
|
*lphMenu = NULL;
|
|
|
|
}
|
|
else if (cVerbs == 1)
|
|
{
|
|
//One verb without Convert, one item.
|
|
LPTSTR lpsz = (fIsLink ? szLinkCmd1Verb : szObjectCmd1Verb);
|
|
|
|
// strip ampersands from lpszVerbName to ensure that
|
|
// the right character is used as the menu key
|
|
LPTSTR pchIn;
|
|
LPTSTR pchOut;
|
|
pchIn = pchOut = lpszVerbName;
|
|
while (*pchIn)
|
|
{
|
|
while (*pchIn && '&' == *pchIn)
|
|
{
|
|
pchIn++;
|
|
}
|
|
*pchOut = *pchIn;
|
|
pchOut++;
|
|
pchIn++;
|
|
}
|
|
*pchOut = 0;
|
|
|
|
FormatString2(szBuffer, lpsz, lpszVerbName, lpszShortTypeName);
|
|
|
|
// if only "verb" is "Convert..." then append the ellipses
|
|
if (fAddConvertItem)
|
|
lstrcat(szBuffer, TEXT("..."));
|
|
|
|
DestroyMenu(*lphMenu);
|
|
*lphMenu=NULL;
|
|
}
|
|
else
|
|
{
|
|
|
|
//Multiple verbs or one verb with Convert, add the cascading menu
|
|
wsprintf(
|
|
szBuffer,
|
|
(fIsLink ? szLinkCmdNVerb: szObjectCmdNVerb),
|
|
(lpszShortTypeName ? lpszShortTypeName : TEXT(""))
|
|
);
|
|
uFlags |= MF_ENABLED | MF_POPUP;
|
|
#ifdef _WIN64
|
|
//
|
|
// Sundown: Checking with JerrySh for the validity of the HMENU truncation...........
|
|
// If not valid, this'd require modifying the prototype of this function for
|
|
// uIDVerbMin & uIDVerbMax and modifying sdk\inc\oledlg.h exposed interface.
|
|
//
|
|
OleDbgAssert( !(((ULONG_PTR)*lphMenu) >> 32) )
|
|
#endif // _WIN64
|
|
uIDVerbMin=(UINT)HandleToUlong(*lphMenu);
|
|
}
|
|
|
|
if (!InsertMenu(hMenu, uPos, uFlags, uIDVerbMin, szBuffer))
|
|
{
|
|
AVMError:
|
|
InsertMenu(hMenu, uPos, MF_GRAYED | uFlags,
|
|
uIDVerbMin, szNoObjectCmd);
|
|
fResult = FALSE;
|
|
}
|
|
|
|
// Redraw the menu bar, if possible
|
|
HWND hWndActive = GetActiveWindow();
|
|
HMENU hMenuActive = GetMenu(hWndActive);
|
|
|
|
if(hMenuActive == hMenu)
|
|
{
|
|
DrawMenuBar(hWndActive);
|
|
}
|
|
|
|
if (lpszVerbName)
|
|
OleStdFree(lpszVerbName);
|
|
if (!lpszShortType && lpszShortTypeName)
|
|
OleStdFree((LPVOID)lpszShortTypeName);
|
|
if (lpEnumOleVerb)
|
|
lpEnumOleVerb->Release();
|
|
return fResult;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Support for special error prompts
|
|
|
|
typedef struct tagPROMPTUSER
|
|
{
|
|
va_list argptr;
|
|
UINT nIDD; // dialog/help ID
|
|
LPTSTR szTitle;
|
|
} PROMPTUSER, *PPROMPTUSER, FAR* LPPROMPTUSER;
|
|
|
|
/* PromptUserDlgProc
|
|
* -----------------
|
|
*
|
|
* Purpose:
|
|
* Dialog procedure used by OleUIPromptUser(). Returns when a button is
|
|
* clicked in the dialog box and the button id is return.
|
|
*
|
|
* Parameters:
|
|
* hDlg
|
|
* iMsg
|
|
* wParam
|
|
* lParam
|
|
*
|
|
* Returns:
|
|
*
|
|
*/
|
|
INT_PTR CALLBACK PromptUserDlgProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
switch (iMsg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
{
|
|
SendDlgItemMessage(hDlg, IDC_PU_ICON,
|
|
STM_SETICON, (WPARAM)LoadIcon(NULL, IDI_EXCLAMATION), 0L);
|
|
|
|
LPPROMPTUSER lpPU = (LPPROMPTUSER)lParam;
|
|
SetProp(hDlg, STRUCTUREPROP, lpPU);
|
|
SetWindowText(hDlg, lpPU->szTitle);
|
|
|
|
TCHAR szFormat[256];
|
|
GetDlgItemText(hDlg, IDC_PU_TEXT, szFormat,
|
|
sizeof(szFormat)/sizeof(TCHAR));
|
|
TCHAR szBuf[256];
|
|
wvsprintf(szBuf, szFormat, lpPU->argptr);
|
|
SetDlgItemText(hDlg, IDC_PU_TEXT, szBuf);
|
|
}
|
|
return TRUE;
|
|
|
|
case WM_COMMAND:
|
|
EndDialog(hDlg, wParam);
|
|
return TRUE;
|
|
|
|
default:
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: OleUIPromptUserInternal
|
|
//
|
|
// Synopsis: internal entry point to start the PromptUser dialog
|
|
// Used to support both ANSI and Unicode entrypoints
|
|
//
|
|
// Arguments: [nTemplate] - dialog template ID
|
|
// [szTitle] - the title string
|
|
// [hwndParent] - the dialog's parent window
|
|
// [arglist] - variable argument list
|
|
//
|
|
// History: 12-01-94 stevebl Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
int OleUIPromptUserInternal(int nTemplate, HWND hwndParent, LPTSTR szTitle, va_list arglist)
|
|
{
|
|
PROMPTUSER pu;
|
|
pu.szTitle = szTitle;
|
|
pu.argptr = arglist;
|
|
pu.nIDD = nTemplate;
|
|
return ((int)DialogBoxParam(_g_hOleStdResInst, MAKEINTRESOURCE(nTemplate), hwndParent,
|
|
PromptUserDlgProc, (LPARAM)&pu));
|
|
}
|
|
|
|
/* OleUIPromptUser
|
|
* ---------------
|
|
*
|
|
* Purpose:
|
|
* Popup a dialog box with the specified template and returned the
|
|
* response (button id) from the user.
|
|
*
|
|
* Parameters:
|
|
* nTemplate resource number of the dialog
|
|
* hwndParent parent of the dialog box
|
|
* ... title of the dialog box followed by argument list
|
|
* for the format string in the static control
|
|
* (IDC_PU_TEXT) of the dialog box.
|
|
* The caller has to make sure that the correct number
|
|
* and type of argument are passed in.
|
|
*
|
|
* Returns:
|
|
* button id selected by the user (template dependent)
|
|
*
|
|
* Comments:
|
|
* the following message dialog boxes are supported:
|
|
*
|
|
* IDD_LINKSOURCEUNAVAILABLE -- Link source is unavailable
|
|
* VARARG Parameters:
|
|
* None.
|
|
* Used for the following error codes:
|
|
* OLE_E_CANT_BINDTOSOURCE
|
|
* STG_E_PATHNOTFOUND
|
|
* (sc >= MK_E_FIRST) && (sc <= MK_E_LAST) -- any Moniker error
|
|
* any unknown error if object is a link
|
|
*
|
|
* IDD_SERVERNOTFOUND -- server registered but NOT found
|
|
* VARARG Parameters:
|
|
* LPSTR lpszUserType -- user type name of object
|
|
* Used for the following error codes:
|
|
* CO_E_APPNOTFOUND
|
|
* CO_E_APPDIDNTREG
|
|
* any unknown error if object is an embedded object
|
|
*
|
|
* IDD_SERVERNOTREG -- server NOT registered
|
|
* VARARG Parameters:
|
|
* LPSTR lpszUserType -- user type name of object
|
|
* Used for the following error codes:
|
|
* REGDB_E_CLASSNOTREG
|
|
* OLE_E_STATIC -- static object with no server registered
|
|
*
|
|
* IDD_LINKTYPECHANGED -- class of link source changed since last binding
|
|
* VARARG Parameters:
|
|
* LPSTR lpszUserType -- user type name of ole link source
|
|
* Used for the following error codes:
|
|
* OLE_E_CLASSDIFF
|
|
*
|
|
* IDD_LINKTYPECHANGED -- class of link source changed since last binding
|
|
* VARARG Parameters:
|
|
* LPSTR lpszUserType -- user type name of ole link source
|
|
* Used for the following error codes:
|
|
* OLE_E_CLASSDIFF
|
|
*
|
|
* IDD_OUTOFMEMORY -- out of memory
|
|
* VARARG Parameters:
|
|
* None.
|
|
* Used for the following error codes:
|
|
* E_OUTOFMEMORY
|
|
*
|
|
*/
|
|
|
|
int FAR CDECL OleUIPromptUser(int nTemplate, HWND hwndParent, ...)
|
|
{
|
|
va_list arglist;
|
|
va_start(arglist, hwndParent);
|
|
LPTSTR szTitle = va_arg(arglist, LPTSTR);
|
|
int nRet = OleUIPromptUserInternal(nTemplate, hwndParent, szTitle, arglist);
|
|
va_end(arglist);
|
|
|
|
return nRet;
|
|
}
|
|
|
|
/* UpdateLinksDlgProc
|
|
* ------------------
|
|
*
|
|
* Purpose:
|
|
* Dialog procedure used by OleUIUpdateLinks(). It will enumerate all
|
|
* all links in the container and updates all automatic links.
|
|
* Returns when the Stop Button is clicked in the dialog box or when all
|
|
* links are updated
|
|
*
|
|
* Parameters:
|
|
* hDlg
|
|
* iMsg
|
|
* wParam
|
|
* lParam pointer to the UPDATELINKS structure
|
|
*
|
|
* Returns:
|
|
*
|
|
*/
|
|
|
|
#define UPDATELINKS_STARTDELAY 2000 // delay before 1st link updates
|
|
|
|
INT_PTR CALLBACK UpdateLinksDlgProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
LPUPDATELINKS FAR* lplpUL = NULL;
|
|
HANDLE gh;
|
|
static BOOL fAbort = FALSE;
|
|
|
|
// Process the temination message
|
|
if (iMsg == uMsgEndDialog)
|
|
{
|
|
gh = RemoveProp(hDlg, STRUCTUREPROP);
|
|
if (NULL != gh)
|
|
{
|
|
GlobalUnlock(gh);
|
|
GlobalFree(gh);
|
|
}
|
|
EndDialog(hDlg, wParam);
|
|
return TRUE;
|
|
}
|
|
|
|
switch (iMsg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
{
|
|
gh = GlobalAlloc(GHND, sizeof(LPUPDATELINKS));
|
|
SetProp(hDlg, STRUCTUREPROP, gh);
|
|
|
|
if (NULL == gh)
|
|
{
|
|
PostMessage(hDlg, uMsgEndDialog, OLEUI_ERR_GLOBALMEMALLOC,0L);
|
|
return FALSE;
|
|
}
|
|
|
|
fAbort = FALSE;
|
|
lplpUL = (LPUPDATELINKS FAR*)GlobalLock(gh);
|
|
|
|
if (!lplpUL)
|
|
{
|
|
PostMessage(hDlg, uMsgEndDialog, OLEUI_ERR_GLOBALMEMALLOC,0L);
|
|
return FALSE;
|
|
}
|
|
|
|
if (bWin4)
|
|
{
|
|
if (StandardInitCommonControls() >= 0)
|
|
{
|
|
// get rect of the existing "progress" control
|
|
RECT rect;
|
|
GetWindowRect(GetDlgItem(hDlg, IDC_UL_METER), &rect);
|
|
ScreenToClient(hDlg, ((POINT*)&rect)+0);
|
|
ScreenToClient(hDlg, ((POINT*)&rect)+1);
|
|
|
|
// create progress control in that rect
|
|
HWND hProgress = CreateWindowEx(
|
|
0, PROGRESS_CLASS, NULL, WS_CHILD|WS_VISIBLE,
|
|
rect.left, rect.top,
|
|
rect.right-rect.left, rect.bottom-rect.top, hDlg,
|
|
(HMENU)IDC_UL_PROGRESS, _g_hOleStdInst, NULL);
|
|
if (hProgress != NULL)
|
|
{
|
|
// initialize the progress control
|
|
SendMessage(hProgress, PBM_SETRANGE, 0, MAKELONG(0, 100));
|
|
|
|
// hide the other "meter" control
|
|
StandardShowDlgItem(hDlg, IDC_UL_METER, SW_HIDE);
|
|
}
|
|
}
|
|
}
|
|
|
|
*lplpUL = (LPUPDATELINKS)lParam;
|
|
if ((*lplpUL)->lpszTitle)
|
|
{
|
|
SetWindowText(hDlg, (*lplpUL)->lpszTitle);
|
|
}
|
|
SetTimer(hDlg, 1, UPDATELINKS_STARTDELAY, NULL);
|
|
return TRUE;
|
|
}
|
|
|
|
case WM_TIMER:
|
|
KillTimer(hDlg, 1);
|
|
gh = GetProp(hDlg, STRUCTUREPROP);
|
|
|
|
if (NULL!=gh)
|
|
{
|
|
// gh was locked previously, lock and unlock to get lplpUL
|
|
lplpUL = (LPUPDATELINKS*)GlobalLock(gh);
|
|
GlobalUnlock(gh);
|
|
}
|
|
if (! fAbort && lplpUL)
|
|
PostMessage(hDlg, WM_U_UPDATELINK, 0, (LPARAM)(*lplpUL));
|
|
else
|
|
PostMessage(hDlg,uMsgEndDialog,OLEUI_CANCEL,0L);
|
|
|
|
return 0;
|
|
|
|
case WM_COMMAND: // Stop button
|
|
fAbort = TRUE;
|
|
SendMessage(hDlg, uMsgEndDialog, OLEUI_OK, 0L);
|
|
return TRUE;
|
|
|
|
case WM_U_UPDATELINK:
|
|
{
|
|
HRESULT hErr;
|
|
int nPercent;
|
|
RECT rc;
|
|
TCHAR szPercent[5]; // 0% to 100%
|
|
HBRUSH hbr;
|
|
HDC hDC;
|
|
HWND hwndMeter;
|
|
MSG msg;
|
|
DWORD dwUpdateOpt;
|
|
LPUPDATELINKS lpUL = (LPUPDATELINKS)lParam;
|
|
|
|
lpUL->dwLink=lpUL->lpOleUILinkCntr->GetNextLink(lpUL->dwLink);
|
|
|
|
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
|
|
{
|
|
if (! IsDialogMessage(hDlg, &msg))
|
|
{
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
}
|
|
|
|
if (fAbort)
|
|
return FALSE;
|
|
|
|
if (!lpUL->dwLink)
|
|
{
|
|
// all links processed
|
|
SendMessage(hDlg, uMsgEndDialog, OLEUI_OK, 0L);
|
|
return TRUE;
|
|
}
|
|
|
|
hErr = lpUL->lpOleUILinkCntr->GetLinkUpdateOptions(
|
|
lpUL->dwLink, (LPDWORD)&dwUpdateOpt);
|
|
|
|
if ((hErr == NOERROR) && (dwUpdateOpt == OLEUPDATE_ALWAYS))
|
|
{
|
|
hErr = lpUL->lpOleUILinkCntr->UpdateLink(lpUL->dwLink, FALSE, FALSE);
|
|
lpUL->fError |= (hErr != NOERROR);
|
|
lpUL->cUpdated++;
|
|
|
|
nPercent = (lpUL->cLinks > 0) ? (lpUL->cUpdated * 100 / lpUL->cLinks) : 100;
|
|
if (nPercent <= 100)
|
|
{
|
|
// update percentage
|
|
wsprintf(szPercent, TEXT("%d%%"), nPercent);
|
|
SetDlgItemText(hDlg, IDC_UL_PERCENT, szPercent);
|
|
|
|
HWND hProgress = GetDlgItem(hDlg, IDC_UL_PROGRESS);
|
|
if (hProgress == NULL)
|
|
{
|
|
// update indicator
|
|
hwndMeter = GetDlgItem(hDlg, IDC_UL_METER);
|
|
GetClientRect(hwndMeter, (LPRECT)&rc);
|
|
InflateRect((LPRECT)&rc, -1, -1);
|
|
rc.right = (rc.right - rc.left) * nPercent / 100 + rc.left;
|
|
hbr = CreateSolidBrush(GetSysColor(COLOR_HIGHLIGHT));
|
|
if (hbr)
|
|
{
|
|
hDC = GetDC(hwndMeter);
|
|
if (hDC)
|
|
{
|
|
FillRect(hDC, (LPRECT)&rc, hbr);
|
|
ReleaseDC(hwndMeter, hDC);
|
|
}
|
|
DeleteObject(hbr);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// update the progress indicator
|
|
SendMessage(hProgress, PBM_SETPOS, nPercent, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
|
|
{
|
|
if (! IsDialogMessage(hDlg, &msg))
|
|
{
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
}
|
|
PostMessage(hDlg, WM_U_UPDATELINK, 0, lParam);
|
|
}
|
|
return TRUE;
|
|
|
|
case WM_U_SHOWWINDOW:
|
|
ShowWindow(hDlg, SW_SHOW);
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/* OleUIUpdateLinkS
|
|
* ----------------
|
|
*
|
|
* Purpose:
|
|
* Update all links in the Link Container and popup a dialog box which
|
|
* shows the progress of the updating.
|
|
* The process is stopped when the user press Stop button or when all
|
|
* links are processed.
|
|
*
|
|
* Parameters:
|
|
* lpOleUILinkCntr pointer to Link Container
|
|
* hwndParent parent window of the dialog
|
|
* lpszTitle title of the dialog box
|
|
* cLinks total number of links
|
|
*
|
|
* Returns:
|
|
* TRUE all links updated successfully or user aborted dialog
|
|
* FALSE oherwise
|
|
*/
|
|
STDAPI_(BOOL) OleUIUpdateLinks(
|
|
LPOLEUILINKCONTAINER lpOleUILinkCntr, HWND hwndParent, LPTSTR lpszTitle, int cLinks)
|
|
{
|
|
LPUPDATELINKS lpUL = (LPUPDATELINKS)OleStdMalloc(sizeof(UPDATELINKS));
|
|
if (lpUL == NULL)
|
|
return FALSE;
|
|
|
|
BOOL fError = TRUE;
|
|
|
|
|
|
// Validate interface.
|
|
if (NULL == lpOleUILinkCntr || IsBadReadPtr(lpOleUILinkCntr, sizeof(IOleUILinkContainer)))
|
|
goto Error;
|
|
|
|
|
|
// Validate parent-window handle. NULL is considered valid.
|
|
if (NULL != hwndParent && !IsWindow(hwndParent))
|
|
goto Error;
|
|
|
|
// Validate the dialog title. NULL is considered valid.
|
|
if (NULL != lpszTitle && IsBadReadPtr(lpszTitle, 1))
|
|
goto Error;
|
|
|
|
if (cLinks < 0)
|
|
goto Error;
|
|
|
|
OleDbgAssert(lpOleUILinkCntr && hwndParent && lpszTitle && (cLinks>0));
|
|
OleDbgAssert(lpUL);
|
|
|
|
lpUL->lpOleUILinkCntr = lpOleUILinkCntr;
|
|
lpUL->cLinks = cLinks;
|
|
lpUL->cUpdated = 0;
|
|
lpUL->dwLink = 0;
|
|
lpUL->fError = FALSE;
|
|
lpUL->lpszTitle = lpszTitle;
|
|
|
|
DialogBoxParam(_g_hOleStdResInst, MAKEINTRESOURCE(IDD_UPDATELINKS),
|
|
hwndParent, UpdateLinksDlgProc, (LPARAM)lpUL);
|
|
|
|
fError = lpUL->fError;
|
|
Error:
|
|
OleStdFree((LPVOID)lpUL);
|
|
|
|
return !fError;
|
|
}
|