NT4/private/ole2ui32/common.cpp
2020-09-30 17:12:29 +02:00

686 lines
23 KiB
C++

/*
* COMMON.CPP
*
* Standardized (and centralized) pieces of each OLEDLG dialog function:
*
* UStandardValidation Validates standard fields in each dialog structure
* UStandardInvocation Invokes a dialog through DialogBoxIndirectParam
* LpvStandardInit Common WM_INITDIALOG processing
* LpvStandardEntry Common code to execute on dialog proc entry.
* UStandardHook Centralized hook calling function.
* StandardCleanup Common exit/cleanup code.
* StandardShowDlgItem Show-Enable/Hide-Disable dialog item
* StandardEnableDlgItem Enable/Disable dialog item
* StandardResizeDlgY Resize dialog to fit controls
*
* Copyright (c)1992 Microsoft Corporation, All Right Reserved
*/
#include "precomp.h"
#include "common.h"
#include "utility.h"
OLEDBGDATA
/*
* UStandardValidation
*
* Purpose:
* Performs validation on the standard pieces of any dialog structure,
* that is, the fields defined in the OLEUISTANDARD structure.
*
* Parameters:
* lpUI const LPOLEUISTANDARD pointing to the shared data of
* all structs.
* cbExpect const UINT structure size desired by the caller.
* phDlgMem const HGLOBAL FAR * in which to store a loaded customized
* template, if one exists.
* (This may be NULL in which case the template pointer isn't
* needed by the calling function and should be released.)
*
* Return Value:
* UINT OLEUI_SUCCESS if all validation succeeded. Otherwise
* it will be one of the standard error codes.
*/
UINT WINAPI UStandardValidation(LPOLEUISTANDARD lpUI, const UINT cbExpect,
HGLOBAL* phMemDlg)
{
/*
* 1. Validate non-NULL pointer parameter. Note: We don't validate
* phDlg since it's not passed from an external source.
*/
if (NULL == lpUI)
return OLEUI_ERR_STRUCTURENULL;
// 2. Validate that the structure is readable and writable.
if (IsBadWritePtr(lpUI, cbExpect))
return OLEUI_ERR_STRUCTUREINVALID;
// 3. Validate the structure size
if (cbExpect != lpUI->cbStruct)
return OLEUI_ERR_CBSTRUCTINCORRECT;
// 4. Validate owner-window handle. NULL is considered valid.
if (NULL != lpUI->hWndOwner && !IsWindow(lpUI->hWndOwner))
return OLEUI_ERR_HWNDOWNERINVALID;
// 5. Validate the dialog caption. NULL is considered valid.
if (NULL != lpUI->lpszCaption && IsBadReadPtr(lpUI->lpszCaption, 1))
return OLEUI_ERR_LPSZCAPTIONINVALID;
// 6. Validate the hook pointer. NULL is considered valid.
if (NULL != lpUI->lpfnHook && IsBadCodePtr((FARPROC)lpUI->lpfnHook))
return OLEUI_ERR_LPFNHOOKINVALID;
/*
* 7. If hInstance is non-NULL, we have to also check lpszTemplate.
* Otherwise, lpszTemplate is not used and requires no validation.
* lpszTemplate cannot be NULL if used.
*/
HGLOBAL hMem = NULL;
if (NULL != lpUI->hInstance)
{
//Best we can try is one character
if (NULL == lpUI->lpszTemplate || (HIWORD(lpUI->lpszTemplate) != 0 &&
IsBadReadPtr(lpUI->lpszTemplate, 1)))
return OLEUI_ERR_LPSZTEMPLATEINVALID;
HRSRC hRes = FindResource(lpUI->hInstance, lpUI->lpszTemplate, RT_DIALOG);
if (NULL == hRes)
return OLEUI_ERR_FINDTEMPLATEFAILURE;
hMem = LoadResource(lpUI->hInstance, hRes);
if (NULL == hMem)
return OLEUI_ERR_LOADTEMPLATEFAILURE;
}
// 8. If hResource is non-NULL, be sure we can lock it.
if (NULL != lpUI->hResource)
{
if ((LPSTR)NULL == LockResource(lpUI->hResource))
return OLEUI_ERR_HRESOURCEINVALID;
}
/*
* Here we have hMem==NULL if we should use the standard template
* or the one in lpUI->hResource. If hMem is non-NULL, then we
* loaded one from the calling application's resources which the
* caller of this function has to free if it sees any other error.
*/
if (NULL != phMemDlg)
{
*phMemDlg = hMem;
}
return OLEUI_SUCCESS;
}
/*
* UStandardInvocation
*
* Purpose:
* Provides standard template loading and calling on DialogBoxIndirectParam
* for all the OLE UI dialogs.
*
* Parameters:
* lpDlgProc DLGPROC of the dialog function.
* lpUI LPOLEUISTANDARD containing the dialog structure.
* hMemDlg HGLOBAL containing the dialog template. If this
* is NULL and lpUI->hResource is NULL, then we load
* the standard template given the name in lpszStdTemplate
* lpszStdTemplate LPCSTR standard template to load if hMemDlg is NULL
* and lpUI->hResource is NULL.
*
* Return Value:
* UINT OLEUI_SUCCESS if all is well, otherwise and error
* code.
*/
UINT WINAPI UStandardInvocation(
DLGPROC lpDlgProc, LPOLEUISTANDARD lpUI, HGLOBAL hMemDlg, LPTSTR lpszStdTemplate)
{
// Make sure we have a template, then lock it down
HGLOBAL hTemplate = hMemDlg;
if (NULL == hTemplate)
hTemplate = lpUI->hResource;
if (NULL == hTemplate)
{
HRSRC hRes = FindResource(_g_hOleStdResInst, (LPCTSTR) lpszStdTemplate, RT_DIALOG);
if (NULL == hRes)
return OLEUI_ERR_FINDTEMPLATEFAILURE;
hTemplate = LoadResource(_g_hOleStdResInst, hRes);
if (NULL == hTemplate)
return OLEUI_ERR_LOADTEMPLATEFAILURE;
}
/*
* hTemplate has the template to use, so now we can invoke the dialog.
* Since we have exported all of our dialog procedures using the
* _keyword, we do not need to call MakeProcInstance,
* we can ue the dialog procedure address directly.
*/
int iRet = DialogBoxIndirectParam(_g_hOleStdResInst, (LPCDLGTEMPLATE)hTemplate,
lpUI->hWndOwner, lpDlgProc, (LPARAM)lpUI);
if (-1 == iRet)
return OLEUI_ERR_DIALOGFAILURE;
// Return the code from EndDialog, generally OLEUI_OK or OLEUI_CANCEL
return (UINT)iRet;
}
/*
* LpvStandardInit
*
* Purpose:
* Default actions for WM_INITDIALOG handling in the dialog, allocating
* a dialog-specific structure, setting that memory as a dialog property,
* and creating a small font if necessary setting that font as a property.
*
* Parameters:
* hDlg HWND of the dialog
* cbStruct UINT size of dialog-specific structure to allocate.
* fCreateFont BOOL indicating if we need to create a small Helv
* font for this dialog.
* phFont HFONT FAR * in which to place a created font. Can be
* NULL if fCreateFont is FALSE.
*
* Return Value:
* LPVOID Pointer to global memory allocated for the dialog.
* The memory will have been set as a dialog property
* using the STRUCTUREPROP label.
*/
LPVOID WINAPI LpvStandardInit(HWND hDlg, UINT cbStruct, HFONT* phFont)
{
// Must have at least sizeof(void*) bytes in cbStruct
if (sizeof(void*) > cbStruct)
{
PostMessage(hDlg, uMsgEndDialog, OLEUI_ERR_GLOBALMEMALLOC, 0L);
return NULL;
}
HGLOBAL gh = GlobalAlloc(GHND, cbStruct);
if (NULL == gh)
{
PostMessage(hDlg, uMsgEndDialog, OLEUI_ERR_GLOBALMEMALLOC, 0L);
return NULL;
}
LPVOID lpv = GlobalLock(gh);
SetProp(hDlg, STRUCTUREPROP, gh);
if (phFont != NULL)
*phFont = NULL;
if (!bWin4 && phFont != NULL)
{
// Create the non-bold font for result and file texts. We call
HFONT hFont = (HFONT)SendMessage(hDlg, WM_GETFONT, 0, 0L);
LOGFONT lf;
GetObject(hFont, sizeof(LOGFONT), &lf);
lf.lfWeight = FW_NORMAL;
// Attempt to create the font. If this fails, then we return no font.
*phFont = CreateFontIndirect(&lf);
// If we couldn't create the font, we'll do with the default.
if (NULL != *phFont)
SetProp(hDlg, FONTPROP, (HANDLE)*phFont);
}
// Setup the context help mode (WS_EX_CONTEXTHELP)
if (bWin4)
{
DWORD dwExStyle = GetWindowLong(hDlg, GWL_EXSTYLE);
dwExStyle |= WS_EX_CONTEXTHELP;
SetWindowLong(hDlg, GWL_EXSTYLE, dwExStyle);
}
return lpv;
}
typedef struct COMMON
{
OLEUISTANDARD* pStandard;
UINT nIDD;
} COMMON, *PCOMMON, FAR* LPCOMMON;
/*
* LpvStandardEntry
*
* Purpose:
* Retrieves the dialog's structure property and calls the hook
* as necessary. This should be called on entry into all dialog
* procedures.
*
* Parameters:
* hDlg HWND of the dialog
* iMsg UINT message to the dialog
* wParam, lParam WPARAM, LPARAM message parameters
* puHookResult UINT FAR * in which this function stores the return value
* from the hook if it is called. If no hook is available,
* this will be FALSE.
*
* Return Value:
* LPVOID Pointer to the dialog's extra structure held in the
* STRUCTUREPROP property.
*/
LPVOID WINAPI LpvStandardEntry(HWND hDlg, UINT iMsg,
WPARAM wParam, LPARAM lParam, UINT FAR * puHookResult)
{
// This will fail under WM_INITDIALOG, where we allocate using StandardInit
LPVOID lpv = NULL;
HGLOBAL gh = GetProp(hDlg, STRUCTUREPROP);
if (NULL != puHookResult && NULL != gh)
{
*puHookResult = 0;
// gh was locked previously, lock and unlock to get lpv
lpv = GlobalLock(gh);
GlobalUnlock(gh);
// Call the hook for all messages except WM_INITDIALOG
if (NULL != lpv && WM_INITDIALOG != iMsg)
*puHookResult = UStandardHook(lpv, hDlg, iMsg, wParam, lParam);
// Default processing for various messages
LPCOMMON lpCommon = (LPCOMMON)lpv;
if (*puHookResult == 0 && NULL != lpv)
{
switch (iMsg)
{
// handle standard Win4 help messages
case WM_HELP:
{
HWND hWnd = (HWND)((LPHELPINFO)lParam)->hItemHandle;
StandardHelp(hWnd, lpCommon->nIDD);
break;
}
case WM_CONTEXTMENU:
StandardContextMenu(wParam, lParam, lpCommon->nIDD);
break;
// make readonly edits have gray background
case WM_CTLCOLOREDIT:
if (bWin4 && (GetWindowLong((HWND)lParam, GWL_STYLE)
& ES_READONLY))
{
*puHookResult = SendMessage(hDlg, WM_CTLCOLORSTATIC,
wParam, lParam);
}
break;
}
}
}
return lpv;
}
/*
* UStandardHook
*
* Purpose:
* Provides a generic hook calling function assuming that all private
* dialog structures have a far pointer to their assocated public
* structure as the first field, and that the first part of the public
* structure matches an OLEUISTANDARD.
*
* Parameters:
* pv PVOID to the dialog structure.
* hDlg HWND to send with the call to the hook.
* iMsg UINT message to send to the hook.
* wParam, lParam WPARAM, LPARAM message parameters
*
* Return Value:
* UINT Return value from the hook, zero to indicate that
* default action should occur, nonzero to specify
* that the hook did process the message. In some
* circumstances it will be important for the hook to
* return a non-trivial non-zero value here, such as
* a brush from WM_CTLCOLOR, in which case the caller
* should return that value from the dialog procedure.
*/
UINT WINAPI UStandardHook(LPVOID lpv, HWND hDlg, UINT iMsg,
WPARAM wParam, LPARAM lParam)
{
UINT uRet = 0;
LPOLEUISTANDARD lpUI = *((LPOLEUISTANDARD FAR *)lpv);
if (NULL != lpUI && NULL != lpUI->lpfnHook)
{
/*
* In order for the hook to have the proper DS, they should be
* compiling with -GA -GEs so and usin __to get everything
* set up properly.
*/
uRet = (*lpUI->lpfnHook)(hDlg, iMsg, wParam, lParam);
}
return uRet;
}
/*
* StandardCleanup
*
* Purpose:
* Removes properties and reverses any other standard initiazation
* done through StandardSetup.
*
* Parameters:
* lpv LPVOID containing the private dialog structure.
* hDlg HWND of the dialog closing.
*
* Return Value:
* None
*/
void WINAPI StandardCleanup(LPVOID lpv, HWND hDlg)
{
HFONT hFont=(HFONT)GetProp(hDlg, FONTPROP);
if (NULL != hFont)
{
DeleteObject(hFont);
RemoveProp(hDlg, FONTPROP);
}
HGLOBAL gh = RemoveProp(hDlg, STRUCTUREPROP);
if (gh != NULL)
{
GlobalUnlock(gh);
GlobalFree(gh);
}
}
/* StandardShowDlgItem
* -------------------
* Show & Enable or Hide & Disable a dialog item as appropriate.
* it is NOT sufficient to simply hide the item; it must be disabled
* too or the keyboard accelerator still functions.
*/
void WINAPI StandardShowDlgItem(HWND hDlg, int idControl, int nCmdShow)
{
HWND hItem = GetDlgItem(hDlg, idControl);
if (hItem != NULL)
{
ShowWindow(hItem, nCmdShow);
EnableWindow(hItem, nCmdShow != SW_HIDE);
}
}
/* StandardEnableDlgItem
* -------------------
* Enable/Disable a dialog item. If the item does not exist
* this call is a noop.
*/
void WINAPI StandardEnableDlgItem(HWND hDlg, int idControl, BOOL bEnable)
{
HWND hItem = GetDlgItem(hDlg, idControl);
if (hItem != NULL)
EnableWindow(hItem, bEnable);
}
/* StandardResizeDlgY
* ------------------
* Resize a dialog to fit around the visible controls. This is used
* for dialogs which remove controls from the bottom of the dialogs.
* A good example of this is the convert dialog, which when CF_HIDERESULTS
* is selected, removes the "results box" at the bottom of the dialog.
* This implementation currently
*/
BOOL WINAPI StandardResizeDlgY(HWND hDlg)
{
RECT rect;
// determine maxY by looking at all child windows on the dialog
int maxY = 0;
HWND hChild = GetWindow(hDlg, GW_CHILD);
while (hChild != NULL)
{
if (GetWindowLong(hChild, GWL_STYLE) & WS_VISIBLE)
{
GetWindowRect(hChild, &rect);
if (rect.bottom > maxY)
maxY = rect.bottom;
}
hChild = GetWindow(hChild, GW_HWNDNEXT);
}
if (maxY > 0)
{
// get current font that the dialog is using
HFONT hFont = (HFONT)SendMessage(hDlg, WM_GETFONT, 0, 0);
if (hFont == NULL)
hFont = (HFONT)GetStockObject(SYSTEM_FONT);
OleDbgAssert(hFont != NULL);
// calculate height of the font in pixels
HDC hDC = GetDC(NULL);
hFont = (HFONT)SelectObject(hDC, hFont);
TEXTMETRIC tm;
GetTextMetrics(hDC, &tm);
SelectObject(hDC, hFont);
ReleaseDC(NULL, hDC);
// determine if window is too large and resize if necessary
GetWindowRect(hDlg, &rect);
if (rect.bottom > maxY + tm.tmHeight)
{
// window is too large -- resize it
rect.bottom = maxY + tm.tmHeight;
SetWindowPos(hDlg, NULL,
0, 0, rect.right-rect.left, rect.bottom-rect.top,
SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
return TRUE;
}
}
return FALSE;
}
/////////////////////////////////////////////////////////////////////////////
// Support for Windows 95 help
// BUGBUG - probably need to rename
#define HELPFILE TEXT("mfcuix.hlp")
LPDWORD LoadHelpInfo(UINT nIDD)
{
HRSRC hrsrc = FindResource(_g_hOleStdResInst, MAKEINTRESOURCE(nIDD),
MAKEINTRESOURCE(RT_HELPINFO));
if (hrsrc == NULL)
return NULL;
HGLOBAL hHelpInfo = LoadResource(_g_hOleStdResInst, hrsrc);
if (hHelpInfo == NULL)
return NULL;
LPDWORD lpdwHelpInfo = (LPDWORD)LockResource(hHelpInfo);
return lpdwHelpInfo;
}
void WINAPI StandardHelp(HWND hWnd, UINT nIDD)
{
LPDWORD lpdwHelpInfo = LoadHelpInfo(nIDD);
if (lpdwHelpInfo == NULL)
{
OleDbgOut1(TEXT("Warning: unable to load help information (RT_HELPINFO)\n"));
return;
}
WinHelp(hWnd, HELPFILE, HELP_WM_HELP, (DWORD)lpdwHelpInfo);
}
void WINAPI StandardContextMenu(WPARAM wParam, LPARAM, UINT nIDD)
{
LPDWORD lpdwHelpInfo = LoadHelpInfo(nIDD);
if (lpdwHelpInfo == NULL)
{
OleDbgOut1(TEXT("Warning: unable to load help information (RT_HELPINFO)\n"));
return;
}
WinHelp((HWND)wParam, HELPFILE, HELP_CONTEXTMENU, (DWORD)lpdwHelpInfo);
}
/////////////////////////////////////////////////////////////////////////////
// StandardPropertySheet (stub for Windows 95 API PropertySheet)
typedef void (WINAPI* LPFNINITCOMMONCONTROLS)(VOID);
int WINAPI StandardInitCommonControls()
{
TASKDATA* pTaskData = GetTaskData();
OleDbgAssert(pTaskData != NULL);
if (pTaskData->hInstCommCtrl == NULL)
{
pTaskData->hInstCommCtrl = LoadLibrary(TEXT("comctl32.dll"));
if (pTaskData->hInstCommCtrl == NULL)
goto Error;
LPFNINITCOMMONCONTROLS lpfnInitCommonControls = (LPFNINITCOMMONCONTROLS)
GetProcAddress(pTaskData->hInstCommCtrl, "InitCommonControls");
if (lpfnInitCommonControls == NULL)
goto ErrorFreeLibrary;
(*lpfnInitCommonControls)();
}
return 0;
ErrorFreeLibrary:
if (pTaskData->hInstCommCtrl != NULL)
{
FreeLibrary(pTaskData->hInstCommCtrl);
pTaskData->hInstCommCtrl = NULL;
}
Error:
return -1;
}
typedef int (WINAPI* LPFNPROPERTYSHEET)(LPCPROPSHEETHEADER);
int WINAPI StandardPropertySheet(LPPROPSHEETHEADER lpPS, BOOL fWide)
{
int nResult = StandardInitCommonControls();
if (nResult < 0)
return nResult;
TASKDATA* pTaskData = GetTaskData();
OleDbgAssert(pTaskData != NULL);
LPFNPROPERTYSHEET lpfnPropertySheet;
if (fWide)
{
lpfnPropertySheet = (LPFNPROPERTYSHEET)GetProcAddress(pTaskData->hInstCommCtrl, "PropertySheetW");
}
else
{
lpfnPropertySheet = (LPFNPROPERTYSHEET)GetProcAddress(pTaskData->hInstCommCtrl, "PropertySheetA");
}
if (lpfnPropertySheet == NULL)
return -1;
nResult = (*lpfnPropertySheet)(lpPS);
return nResult;
}
typedef HICON (WINAPI* LPFNEXTRACTICON)(HINSTANCE, LPCTSTR, UINT);
HICON StandardExtractIcon(HINSTANCE hInst, LPCTSTR lpszExeFileName, UINT nIconIndex)
{
TASKDATA* pTaskData = GetTaskData();
OleDbgAssert(pTaskData != NULL);
LPFNEXTRACTICON lpfnExtractIcon;
if (pTaskData->hInstShell == NULL)
{
pTaskData->hInstShell = LoadLibrary(TEXT("shell32.dll"));
if (pTaskData->hInstShell == NULL)
goto Error;
}
lpfnExtractIcon = (LPFNEXTRACTICON)
#ifdef UNICODE
GetProcAddress(pTaskData->hInstShell, "ExtractIconW");
#else
GetProcAddress(pTaskData->hInstShell, "ExtractIconA");
#endif
if (lpfnExtractIcon == NULL)
goto ErrorFreeLibrary;
return (*lpfnExtractIcon)(hInst, lpszExeFileName, nIconIndex);
ErrorFreeLibrary:
if (pTaskData->hInstShell != NULL)
{
FreeLibrary(pTaskData->hInstShell);
pTaskData->hInstShell = NULL;
}
Error:
return NULL;
}
typedef BOOL (WINAPI* LPFNGETOPENFILENAME)(LPOPENFILENAME);
BOOL StandardGetOpenFileName(LPOPENFILENAME lpofn)
{
TASKDATA* pTaskData = GetTaskData();
OleDbgAssert(pTaskData != NULL);
LPFNGETOPENFILENAME lpfnGetOpenFileName;
if (pTaskData->hInstComDlg == NULL)
{
pTaskData->hInstComDlg = LoadLibrary(TEXT("comdlg32.dll"));
if (pTaskData->hInstComDlg == NULL)
goto Error;
}
lpfnGetOpenFileName = (LPFNGETOPENFILENAME)
#ifdef UNICODE
GetProcAddress(pTaskData->hInstComDlg, "GetOpenFileNameW");
#else
GetProcAddress(pTaskData->hInstComDlg, "GetOpenFileNameA");
#endif
if (lpfnGetOpenFileName == NULL)
goto ErrorFreeLibrary;
return (*lpfnGetOpenFileName)(lpofn);
ErrorFreeLibrary:
if (pTaskData->hInstComDlg != NULL)
{
FreeLibrary(pTaskData->hInstComDlg);
pTaskData->hInstComDlg = NULL;
}
Error:
return FALSE;
}
typedef short (WINAPI* LPFNGETFILETITLE)(LPCTSTR, LPTSTR, WORD);
short StandardGetFileTitle(LPCTSTR lpszFile, LPTSTR lpszTitle, WORD cbBuf)
{
TASKDATA* pTaskData = GetTaskData();
OleDbgAssert(pTaskData != NULL);
LPFNGETFILETITLE lpfnGetFileTitle;
if (pTaskData->hInstComDlg == NULL)
{
pTaskData->hInstComDlg = LoadLibrary(TEXT("comdlg32.dll"));
if (pTaskData->hInstComDlg == NULL)
goto Error;
}
lpfnGetFileTitle = (LPFNGETFILETITLE)
#ifdef UNICODE
GetProcAddress(pTaskData->hInstComDlg, "GetFileTitleW");
#else
GetProcAddress(pTaskData->hInstComDlg, "GetFileTitleA");
#endif
if (lpfnGetFileTitle == NULL)
goto ErrorFreeLibrary;
return (*lpfnGetFileTitle)(lpszFile, lpszTitle, cbBuf);
ErrorFreeLibrary:
if (pTaskData->hInstComDlg != NULL)
{
FreeLibrary(pTaskData->hInstComDlg);
pTaskData->hInstComDlg = NULL;
}
Error:
return -1;
}