/*
* 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>
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
BOOL CALLBACK PromptUserDlgProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam);
BOOL 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 >= 0 && 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;
}
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()
{
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 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 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 = 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;
uIDVerbMin=(UINT)*lphMenu;
}
if (!InsertMenu(hMenu, uPos, uFlags, uIDVerbMin, szBuffer))
{
AVMError:
InsertMenu(hMenu, uPos, MF_GRAYED | uFlags,
uIDVerbMin, szNoObjectCmd);
fResult = FALSE;
}
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:
*
*/
BOOL 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 (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
BOOL 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));
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;
}