|
|
/****************************** Module Header ******************************\
* Module Name: msgbox.c * * Copyright (c) 1985 - 1999, Microsoft Corporation * * This module contains the MessageBox API and related functions. * * History: * 10-23-90 DarrinM Created. * 02-08-91 IanJa HWND revalidation added \***************************************************************************/
#include "precomp.h"
#pragma hdrstop
//
// Dimension constants -- D.U. == dialog units
//
#define DU_OUTERMARGIN 7
#define DU_INNERMARGIN 10
#define DU_BTNGAP 4 // D.U. of space between buttons
#define DU_BTNHEIGHT 14 // D.U. of button height
// This is used only in kernel\inctlpan.c, so move it there
//
// #define DU_BTNWIDTH 50 // D.U. of button width, minimum
//
LPBYTE MB_UpdateDlgHdr(LPDLGTEMPLATE lpDlgTmp, long lStyle, long lExtendedStyle, BYTE bItemCount, int iX, int iY, int iCX, int iCY, LPWSTR lpszCaption, int iCaptionLen); LPBYTE MB_UpdateDlgItem(LPDLGITEMTEMPLATE lpDlgItem, int iCtrlId, long lStyle, long lExtendedStyle, int iX, int iY, int iCX, int iCY, LPWSTR lpszText, UINT wTextLen, int iControlClass); UINT MB_GetIconOrdNum(UINT rgBits); LPBYTE MB_AddPushButtons( LPDLGITEMTEMPLATE lpDlgTmp, LPMSGBOXDATA lpmb, UINT wLEdge, UINT wBEdge); UINT MB_FindDlgTemplateSize( LPMSGBOXDATA lpmb ); int MessageBoxWorker(LPMSGBOXDATA pMsgBoxParams); VOID EndTaskModalDialog(HWND hwndDlg); VOID StartTaskModalDialog(HWND hwndDlg);
#ifdef _JANUS_
#include "strid.h"
#include <imagehlp.h>
// constant strings
CONST WCHAR szEMIKey[] = L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Error Message Instrument\\"; CONST WCHAR szEMIEnable[] = L"EnableLogging"; CONST WCHAR szEMISeverity[] = L"LogSeverity"; CONST WCHAR szDMREnable[] = L"EnableDefaultReply"; CONST WCHAR szEventKey[] = L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\EventLog\\Application\\Error Instrument\\"; CONST WCHAR szEventMsgFile[] = L"EventMessageFile"; CONST WCHAR szEventType[] = L"TypesSupported";
#define TITLE_SIZE 64
#define DATETIME_SIZE 32
#define EMI_SEVERITY_ALL 0
#define EMI_SEVERITY_USER 1
#define EMI_SEVERITY_INFORMATION 2
#define EMI_SEVERITY_QUESTION 3
#define EMI_SEVERITY_WARNING 4
#define EMI_SEVERITY_ERROR 5
#define EMI_SEVERITY_MAX_VALUE 5
// element of error message
PVOID gpReturnAddr = 0; HANDLE gdwEMIThreadID = 0; typedef struct _ERROR_ELEMENT { WCHAR ProcessName[MAX_PATH]; WCHAR WindowTitle[TITLE_SIZE]; DWORD dwStyle; DWORD dwErrorCode; WCHAR CallerModuleName[MAX_PATH]; PVOID BaseAddr; DWORD dwImageSize; PVOID ReturnAddr; LPWSTR lpszCaption; LPWSTR lpszText; } ERROR_ELEMENT, *LPERROR_ELEMENT;
BOOL ErrorMessageInst(LPMSGBOXDATA pMsgBoxParams); BOOL InitInstrument(LPDWORD lpEMIControl);
// eventlog stuff
HANDLE gEventSource; NTSTATUS CreateLogSource(); BOOL LogMessageBox(LPERROR_ELEMENT lpErrEle);
#define EMIGETRETURNADDRESS() \
{ \ if (gfEMIEnable) { \ if (InterlockedCompareExchangePointer(&gdwEMIThreadID, \ GETTHREADID(), \ 0) \ == 0) { \ gpReturnAddr = (PVOID) 1; \ } \ } \ }
// _ReturnAddress();
#else
#define EMIGETRETURNADDRESS()
#endif //_JANUS_
#define MB_MASKSHIFT 4
static CONST WCHAR szEmpty[] = L""; WCHAR szERROR[10];
/***************************************************************************\
* SendHelpMessage * * \***************************************************************************/ VOID SendHelpMessage( HWND hwnd, int iType, int iCtrlId, HANDLE hItemHandle, DWORD dwContextId, MSGBOXCALLBACK lpfnCallback) { HELPINFO HelpInfo; long lValue;
HelpInfo.cbSize = sizeof(HELPINFO); HelpInfo.iContextType = iType; HelpInfo.iCtrlId = iCtrlId; HelpInfo.hItemHandle = hItemHandle; HelpInfo.dwContextId = dwContextId;
lValue = NtUserGetMessagePos(); HelpInfo.MousePos.x = GET_X_LPARAM(lValue); HelpInfo.MousePos.y = GET_Y_LPARAM(lValue);
// Check if there is an app supplied callback.
if (lpfnCallback != NULL) { if (IsWOWProc(lpfnCallback)) { (*pfnWowMsgBoxIndirectCallback)(PtrToUlong(lpfnCallback), &HelpInfo); } else { (*lpfnCallback)(&HelpInfo); } } else { SendMessage(hwnd, WM_HELP, 0, (LPARAM)&HelpInfo); } }
/***************************************************************************\
* ServiceMessageBox * * \***************************************************************************/
CONST int aidReturn[] = { 0, 0, IDABORT, IDCANCEL, IDIGNORE, IDNO, IDOK, IDRETRY, IDYES };
int ServiceMessageBox( LPCWSTR pText, LPCWSTR pCaption, UINT wType, DWORD dwTimeout) { NTSTATUS Status; ULONG_PTR Parameters[4]; ULONG Response = ResponseNotHandled; UNICODE_STRING Text, Caption;
/*
* For Terminal Services we must decided the session in which this message * box should be displayed. We do this by looking at the impersonation token * and use the session on which the client is running. */ if (ISTS()) { HANDLE TokenHandle; ULONG ClientSessionId; ULONG ProcessSessionId; ULONG ReturnLength; BOOLEAN bResult;
/*
* Obtain access to the impersonation token if it's present. */ Status = NtOpenThreadToken ( GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, TRUE, &TokenHandle ); if (NT_SUCCESS(Status)) { /*
* Query the Session ID out of the Token */ Status = NtQueryInformationToken ( TokenHandle, TokenSessionId, (PVOID)&ClientSessionId, sizeof(ClientSessionId), &ReturnLength ); CloseHandle(TokenHandle); if (NT_SUCCESS(Status)) { /*
* Get the process session Id. Use the Kernel32 API first because * the PEB is writable in case someone is hacking it. */ if (!ProcessIdToSessionId(GetCurrentProcessId(), &ProcessSessionId)) { ProcessSessionId = NtCurrentPeb()->SessionId; }
if (ClientSessionId != ProcessSessionId) { /*
* This message box was intended for session other than the * one on which this process is running. Forward it to the * right session with WinStationSendMessage(). */ /*
* Handle case where Caption or Title is NULL */ if (pCaption == NULL) { pCaption = szEmpty; } if (pText == NULL) { pText = szEmpty; }
/*
* MessageBoxTimeout assumes the timeout value is in milliseconds, * but WinStationSendMessageW uses seconds. */ if (dwTimeout != INFINITE) { dwTimeout /= 1000; } bResult = WinStationSendMessageW(SERVERNAME_CURRENT, ClientSessionId, (LPWSTR)pCaption, wcslen(pCaption) * sizeof(WCHAR), (LPWSTR)pText, wcslen(pText) * sizeof(WCHAR), wType, dwTimeout, &Response, FALSE // always wait
); if (bResult != TRUE) { Response = aidReturn[ResponseNotHandled]; } else { if (Response == IDTIMEOUT || Response == IDERROR) { Response = aidReturn[ResponseNotHandled]; } }
return (int)Response; } } } }
/*
* MessageBox is for this session, go call CSR. */ RtlInitUnicodeString(&Text, pText); RtlInitUnicodeString(&Caption, pCaption); Parameters[0] = (ULONG_PTR)&Text; Parameters[1] = (ULONG_PTR)&Caption; Parameters[2] = wType; Parameters[3] = dwTimeout;
/*
* Compatibility: Pass the override bit to make sure this box always shows */ Status = NtRaiseHardError(STATUS_SERVICE_NOTIFICATION | HARDERROR_OVERRIDE_ERRORMODE, ARRAY_SIZE(Parameters), 3, Parameters, OptionOk, &Response);
if (!NT_SUCCESS(Status)) { RIPNTERR0(Status, RIP_VERBOSE, ""); }
return aidReturn[Response]; }
/***************************************************************************\
* MessageBox (API) * * History: * 11-20-90 DarrinM Ported from Win 3.0 sources. \***************************************************************************/ int MessageBoxA( HWND hwndOwner, LPCSTR lpszText, LPCSTR lpszCaption, UINT wStyle) { EMIGETRETURNADDRESS(); return MessageBoxExA(hwndOwner, lpszText, lpszCaption, wStyle, 0); }
int MessageBoxW( HWND hwndOwner, LPCWSTR lpszText, LPCWSTR lpszCaption, UINT wStyle) { EMIGETRETURNADDRESS(); return MessageBoxExW(hwndOwner, lpszText, lpszCaption, wStyle, 0); }
/***************************************************************************\
* MessageBoxEx (API) * * History: * 11-20-90 DarrinM Ported from Win 3.0 sources. \***************************************************************************/ int MessageBoxExA( HWND hwndOwner, LPCSTR lpszText, LPCSTR lpszCaption, UINT wStyle, WORD wLanguageId) { return MessageBoxTimeoutA(hwndOwner, lpszText, lpszCaption, wStyle, wLanguageId, INFINITE); }
int MessageBoxExW( HWND hwndOwner, LPCWSTR lpszText, LPCWSTR lpszCaption, UINT wStyle, WORD wLanguageId) { return MessageBoxTimeoutW(hwndOwner, lpszText, lpszCaption, wStyle, wLanguageId, INFINITE); }
/***************************************************************************\
* MessageBoxTimeout (API) * * History: * 04-28-2001 JasonSch Wrote it. \***************************************************************************/ int MessageBoxTimeoutW( HWND hwndOwner, LPCWSTR lpszText, LPCWSTR lpszCaption, UINT wStyle, WORD wLanguageId, DWORD dwTimeout) { MSGBOXDATA MsgBoxParams;
#if DBG
/*
* MB_USERICON is valid for MessageBoxIndirect only. * MessageBoxWorker validates the other style bits */ if (wStyle & MB_USERICON) { RIPMSG0(RIP_WARNING, "MessageBoxExW: Invalid flag: MB_USERICON"); } #endif
RtlZeroMemory(&MsgBoxParams, sizeof(MsgBoxParams)); MsgBoxParams.cbSize = sizeof(MSGBOXPARAMS); MsgBoxParams.hwndOwner = hwndOwner; MsgBoxParams.hInstance = NULL; MsgBoxParams.lpszText = lpszText; MsgBoxParams.lpszCaption = lpszCaption; MsgBoxParams.dwStyle = wStyle; MsgBoxParams.wLanguageId = wLanguageId; MsgBoxParams.dwTimeout = dwTimeout;
EMIGETRETURNADDRESS(); return MessageBoxWorker(&MsgBoxParams); }
int MessageBoxTimeoutA( HWND hwndOwner, LPCSTR lpszText, LPCSTR lpszCaption, UINT wStyle, WORD wLanguageId, DWORD dwTimeout) { int retval; LPWSTR lpwszText = NULL; LPWSTR lpwszCaption = NULL;
if (lpszText) { if (!MBToWCS(lpszText, -1, &lpwszText, -1, TRUE)) return 0; }
if (lpszCaption) { if (!MBToWCS(lpszCaption, -1, &lpwszCaption, -1, TRUE)) { UserLocalFree(lpwszText); return 0; } }
EMIGETRETURNADDRESS(); retval = MessageBoxTimeoutW(hwndOwner, lpwszText, lpwszCaption, wStyle, wLanguageId, dwTimeout);
UserLocalFree(lpwszText); if (lpwszCaption) { UserLocalFree(lpwszCaption); }
return retval; }
#define MessageBoxIndirectInit(MsgBoxParams, lpmbp) \
do { \ if (lpmbp->cbSize != sizeof(MSGBOXPARAMS)) { \ RIPMSG1(RIP_WARNING, \ "MessageBoxIndirect: Invalid cbSize 0x%x", \ lpmbp->cbSize); \ } \ \ RtlZeroMemory(&MsgBoxParams, sizeof(MSGBOXDATA)); \ RtlCopyMemory(&MsgBoxParams, lpmbp, sizeof(MSGBOXPARAMS)); \ } while (FALSE);
/**************************************************************************\
* MessageBoxIndirect (API) * * 09-30-1994 FritzS Created. \**************************************************************************/ int MessageBoxIndirectA( CONST MSGBOXPARAMSA *lpmbp) { int retval; MSGBOXDATA MsgBoxParams; LPWSTR lpwszText = NULL; LPWSTR lpwszCaption = NULL;
MessageBoxIndirectInit(MsgBoxParams, lpmbp);
if (IS_PTR(MsgBoxParams.lpszText)) { if (!MBToWCS((LPSTR)MsgBoxParams.lpszText, -1, &lpwszText, -1, TRUE)) { return 0; } MsgBoxParams.lpszText = lpwszText; } if (IS_PTR(MsgBoxParams.lpszCaption)) { if (!MBToWCS((LPSTR)MsgBoxParams.lpszCaption, -1, &lpwszCaption, -1, TRUE)) { UserLocalFree(lpwszText); return 0; } MsgBoxParams.lpszCaption = lpwszCaption; }
EMIGETRETURNADDRESS(); retval = MessageBoxWorker(&MsgBoxParams);
if (lpwszText) { UserLocalFree(lpwszText); } if (lpwszCaption) { UserLocalFree(lpwszCaption); }
return retval; }
int MessageBoxIndirectW( CONST MSGBOXPARAMSW *lpmbp) { MSGBOXDATA MsgBoxParams;
MessageBoxIndirectInit(MsgBoxParams, lpmbp);
EMIGETRETURNADDRESS(); return MessageBoxWorker(&MsgBoxParams); }
/***************************************************************************\
* MessageBoxWorker (API) * * History: * 03-10-93 JohnL Created \***************************************************************************/
int MessageBoxWorker( LPMSGBOXDATA pMsgBoxParams) { DWORD dwStyle = pMsgBoxParams->dwStyle; UINT wBtnCnt; UINT wDefButton; UINT i; UINT wBtnBeg; WCHAR szErrorBuf[64]; LPWSTR apstrButton[4]; int aidButton[4]; BOOL fCancel = FALSE; int retValue; PMBSTRING pMBString;
#if DBG
if (dwStyle & ~MB_VALID) { RIPMSG2(RIP_WARNING, "MessageBoxWorker: Invalid flags, %#lx & ~%#lx != 0", dwStyle, MB_VALID); } #endif
/*
* dwTimeout == 0 means wait forever. This is mostly for compat reasons. */ if (pMsgBoxParams->dwTimeout == 0) { pMsgBoxParams->dwTimeout = INFINITE; }
/*
* Be sure that MBStrings are already loaded. */ UserAssert(gpsi->MBStrings[0].szName[0] != TEXT('\0'));
#ifdef _JANUS_
/*
* Error message instrument start here * Check EMI enable */
if (gfEMIEnable) { if (!ErrorMessageInst(pMsgBoxParams)) RIPMSG0(RIP_WARNING, "MessageBoxWorker: Fail to instrument error msg"); };
/*
* Default Message Return: on unattended systems the default button * can be returned automatically without putting up the message box */
if (gfDMREnable) { /*
* validate the style and default button as in the main code path */
/*
* Validate the "type" of message box requested. */ if ((dwStyle & MB_TYPEMASK) > MB_LASTVALIDTYPE) { RIPERR0(ERROR_INVALID_MSGBOX_STYLE, RIP_VERBOSE, ""); return 0; }
wBtnCnt = mpTypeCcmd[dwStyle & MB_TYPEMASK] + ((dwStyle & MB_HELP) ? 1 : 0);
/*
* Set the default button value */ wDefButton = (dwStyle & (UINT)MB_DEFMASK) / (UINT)(MB_DEFMASK & (MB_DEFMASK >> 3));
if (wDefButton >= wBtnCnt) /* Check if valid */ wDefButton = 0; /* Set the first button if error */
/*
* return the default button */
wBtnBeg = mpTypeIich[dwStyle & (UINT)MB_TYPEMASK]; pMBString = &gpsi->MBStrings[ SEBbuttons[wBtnBeg + wDefButton] ]; return pMBString->uID; } #endif // _JANUS_
/*
* If lpszCaption is NULL, then use "Error!" string as the caption * string. * LATER: IanJa localize according to wLanguageId */ if (pMsgBoxParams->lpszCaption == NULL) { /*
* Load the default error string if we haven't done it yet */ if (*szERROR == 0) { LoadStringW(hmodUser, STR_ERROR, szERROR, ARRAY_SIZE(szERROR)); } if (pMsgBoxParams->wLanguageId == 0) { pMsgBoxParams->lpszCaption = szERROR; } else { LoadStringOrError(hmodUser, STR_ERROR, szErrorBuf, sizeof(szErrorBuf)/sizeof(WCHAR), pMsgBoxParams->wLanguageId);
/*
* If it didn't find the string, use the default language */ if (*szErrorBuf) { pMsgBoxParams->lpszCaption = szErrorBuf; } else { pMsgBoxParams->lpszCaption = szERROR;
RIPMSG1(RIP_WARNING, "MessageBoxWorker: STR_ERROR string resource for language %#lx not found", pMsgBoxParams->wLanguageId); } } }
/*
* MB_SERVICE_NOTIFICATION had to be redefined because * Win95 defined MB_TOPMOST using the same value. * So for old apps, we map it to the new value */
if ((dwStyle & MB_TOPMOST) && !Is400Compat(GetClientInfo()->dwExpWinVer)) { dwStyle &= ~MB_TOPMOST; dwStyle |= MB_SERVICE_NOTIFICATION; pMsgBoxParams->dwStyle = dwStyle;
RIPMSG1(RIP_WARNING, "MessageBoxWorker: MB_SERVICE_NOTIFICATION flag mapped. New dwStyle:%#lx", dwStyle); }
/*
* For backward compatiblity, use MB_SERVICE_NOTIFICATION if * it's going to the default desktop. */ if (dwStyle & (MB_DEFAULT_DESKTOP_ONLY | MB_SERVICE_NOTIFICATION)) {
/*
* Allow services to put up popups without getting * access to the current desktop. */ if (pMsgBoxParams->hwndOwner != NULL) { RIPERR0(ERROR_INVALID_PARAMETER, RIP_VERBOSE, ""); return 0; }
return ServiceMessageBox(pMsgBoxParams->lpszText, pMsgBoxParams->lpszCaption, dwStyle & ~MB_SERVICE_NOTIFICATION, pMsgBoxParams->dwTimeout); }
/*
* Make sure we have a valid window handle. */ if (pMsgBoxParams->hwndOwner && !IsWindow(pMsgBoxParams->hwndOwner)) { RIPERR0(ERROR_INVALID_WINDOW_HANDLE, RIP_VERBOSE, ""); return 0; }
/*
* Validate the "type" of message box requested. */ if ((dwStyle & MB_TYPEMASK) > MB_LASTVALIDTYPE) { RIPERR0(ERROR_INVALID_MSGBOX_STYLE, RIP_VERBOSE, ""); return 0; }
wBtnCnt = mpTypeCcmd[dwStyle & MB_TYPEMASK] + ((dwStyle & MB_HELP) ? 1 : 0);
/*
* Set the default button value */ wDefButton = (dwStyle & (UINT)MB_DEFMASK) / (UINT)(MB_DEFMASK & (MB_DEFMASK >> 3));
if (wDefButton >= wBtnCnt) /* Check if valid */ wDefButton = 0; /* Set the first button if error */
/*
* Calculate the strings to use in the message box */ wBtnBeg = mpTypeIich[dwStyle & (UINT)MB_TYPEMASK]; for (i=0; i<wBtnCnt; i++) {
pMBString = &gpsi->MBStrings[SEBbuttons[wBtnBeg + i]]; /*
* Pick up the string for the button. */ if (pMsgBoxParams->wLanguageId == 0) { apstrButton[i] = KPWSTR_TO_PWSTR(pMBString->szName); } else { WCHAR szButtonBuf[64]; // LATER is it possible to have button text greater than 64 chars
/*
* BUG: gpsi->wMaxBtnSize might be too short for the length of this string... */ LoadStringOrError(hmodUser, pMBString->uStr, szButtonBuf, ARRAY_SIZE(szButtonBuf), pMsgBoxParams->wLanguageId);
/*
* If it didn't find the string, use the default language. */ if (*szButtonBuf) { apstrButton[i] = TextAlloc(szButtonBuf); } else { apstrButton[i] = TextAlloc(KPWSTR_TO_PWSTR(pMBString->szName));
RIPMSG2(RIP_WARNING, "MessageBoxWorker: string resource %#lx for language %#lx not found", pMBString->uStr, pMsgBoxParams->wLanguageId); } } aidButton[i] = pMBString->uID; if (aidButton[i] == IDCANCEL) { fCancel = TRUE; } }
/*
* Hackery: There are some apps that use MessageBox as initial error * indicators, such as mplay32, and we want this messagebox to be * visible regardless of waht was specified in the StartupInfo->wShowWindow * field. ccMail for instance starts all of its embedded objects hidden * but on win 3.1 the error message would show because they don't have * the startup info. */ NtUserModifyUserStartupInfoFlags(STARTF_USESHOWWINDOW, 0);
pMsgBoxParams->pidButton = aidButton; pMsgBoxParams->ppszButtonText = apstrButton; pMsgBoxParams->DefButton = wDefButton; pMsgBoxParams->cButtons = wBtnCnt; pMsgBoxParams->CancelId = ((dwStyle & MB_TYPEMASK) == 0) ? IDOK : (fCancel ? IDCANCEL : 0); retValue = SoftModalMessageBox(pMsgBoxParams);
if (pMsgBoxParams->wLanguageId != 0) { for (i = 0; i < wBtnCnt; i++) { UserLocalFree(apstrButton[i]); } }
return retValue; }
#define MAX_RES_STRING 256
/***************************************************************************\
* SoftModalMessageBox \***************************************************************************/ int SoftModalMessageBox( LPMSGBOXDATA lpmb) { LPBYTE lpDlgTmp; int cyIcon, cxIcon; int cxButtons; int cxMBMax; int cxText, cyText, xText; int cxBox, cyBox; int cxFoo, cxCaption; int xMB, yMB; HDC hdc; DWORD wIconOrdNum; DWORD wCaptionLen; DWORD wTextLen; WORD OrdNum[2]; // Must be an array or WORDs
RECT rc; RECT rcWork; HCURSOR hcurOld; DWORD dwStyleMsg, dwStyleText; DWORD dwExStyleMsg = 0; DWORD dwStyleDlg; HWND hwndOwner; LPWSTR lpsz; int iRetVal = 0; HICON hIcon; HGLOBAL hTemplate = NULL; HGLOBAL hCaption = NULL; HGLOBAL hText = NULL; HINSTANCE hInstMsg = lpmb->hInstance; SIZE size; HFONT hFontOld = NULL; int cntMBox; PMONITOR pMonitor;
ConnectIfNecessary(0);
dwStyleMsg = lpmb->dwStyle;
if (dwStyleMsg & MB_RIGHT) { dwExStyleMsg |= WS_EX_RIGHT; }
if (!IS_PTR(lpmb->lpszCaption)) { /*
* Won't ever be NULL because MessageBox sticks "Error!" on error. */ if (hInstMsg && (hCaption = UserLocalAlloc(HEAP_ZERO_MEMORY, MAX_RES_STRING * sizeof(WCHAR)))) { lpsz = (LPWSTR)hCaption; LoadString(hInstMsg, PTR_TO_ID(lpmb->lpszCaption), lpsz, MAX_RES_STRING); } else { lpsz = NULL; }
lpmb->lpszCaption = lpsz ? lpsz : szEmpty; }
if (!IS_PTR(lpmb->lpszText)) { // NULL not allowed
if (hInstMsg && (hText = UserLocalAlloc(HEAP_ZERO_MEMORY, MAX_RES_STRING * sizeof(WCHAR)))) { lpsz = (LPWSTR)hText; LoadString(hInstMsg, PTR_TO_ID(lpmb->lpszText), lpsz, MAX_RES_STRING); } else { lpsz = NULL; }
lpmb->lpszText = lpsz ? lpsz : szEmpty; }
//
// Mirroring of MessageBox'es is only enabled if :-
//
// * MB_RTLREADING style has been specified in the MessageBox styles OR
// * The first two code points of the MessageBox text are Right-To-Left
// marks (RLMs = U+200f).
// The feature of enable RTL mirroring if two consecutive RLMs are found
// in the MB text is to acheive a no-code-change for localization of
// of MessageBoxes for BiDi Apps. [samera]
//
if ((dwStyleMsg & MB_RTLREADING) || (lpmb->lpszText != NULL && (lpmb->lpszText[0] == UNICODE_RLM) && (lpmb->lpszText[1] == UNICODE_RLM))) { //
// Set Mirroring so that MessageBox and its child controls
// get mirrored. Otherwise, the message box and its child controls
// are Left-To-Right.
//
dwExStyleMsg |= WS_EX_LAYOUTRTL;
//
// And turn off any conflicting flags.
//
dwExStyleMsg &= ~WS_EX_RIGHT; if (dwStyleMsg & MB_RTLREADING) { dwStyleMsg &= ~MB_RTLREADING; dwStyleMsg ^= MB_RIGHT; } }
if ((dwStyleMsg & MB_ICONMASK) == MB_USERICON) hIcon = LoadIcon(hInstMsg, lpmb->lpszIcon); else hIcon = NULL;
// For compatibility reasons, we still allow the message box to come up.
hwndOwner = lpmb->hwndOwner;
// For PowerBuilder4.0, we must make their messageboxes owned popups. Or, else
// they get WM_ACTIVATEAPP and they install multiple keyboard hooks and get into
// infinite loop later.
// Bug #15896 -- WIN95B -- 2/17/95 -- SANKAR --
if (!hwndOwner) { WCHAR pwszLibFileName[MAX_PATH]; static WCHAR szPB040[] = L"PB040"; // Module name of PowerBuilder4.0
WCHAR *pw1;
//Is this a win3.1 or older app?
if (!Is400Compat(GETAPPVER())) { if (GetModuleFileName(NULL, pwszLibFileName, sizeof(pwszLibFileName)/sizeof(WCHAR)) == 0) goto getthedc; pw1 = pwszLibFileName + wcslen(pwszLibFileName) - 1; while (pw1 > pwszLibFileName) { if (*pw1 == TEXT('.')) *pw1-- = 0; else if (*pw1 == TEXT(':')) {pw1++; break;} else if (*pw1 == TEXT('\\')) {pw1++; break;} else pw1--; } // Is this the PowerBuilder 4.0 module?
if (!_wcsicmp(pw1, szPB040)) hwndOwner = NtUserGetForegroundWindow(); // Make the MsgBox owned.
} } getthedc: // Check if we're out of cache DCs until robustness...
if (!(hdc = NtUserGetDCEx(NULL, NULL, DCX_WINDOW | DCX_CACHE))) {
/*
* The above call might fail for TIF_RESTRICTED processes * so check for the DC from the owner window */ if (!(hdc = NtUserGetDCEx(hwndOwner, NULL, DCX_WINDOW | DCX_CACHE))) goto SMB_Exit; }
// Figure out the types and dimensions of buttons
cxButtons = (lpmb->cButtons * gpsi->wMaxBtnSize) + ((lpmb->cButtons - 1) * XPixFromXDU(DU_BTNGAP, gpsi->cxMsgFontChar));
// Ditto for the icon, if there is one. If not, cxIcon & cyIcon are 0.
if (wIconOrdNum = MB_GetIconOrdNum(dwStyleMsg)) { cxIcon = SYSMET(CXICON) + XPixFromXDU(DU_INNERMARGIN, gpsi->cxMsgFontChar); cyIcon = SYSMET(CYICON); } else cxIcon = cyIcon = 0;
hFontOld = SelectObject(hdc, KHFONT_TO_HFONT(gpsi->hCaptionFont));
// Find the max between the caption text and the buttons
wCaptionLen = wcslen(lpmb->lpszCaption); GetTextExtentPoint(hdc, lpmb->lpszCaption, wCaptionLen, &size); cxCaption = size.cx + 2*SYSMET(CXSIZE);
//
// The max width of the message box is 5/8 of the work area for most
// countries. We will then try 6/8 and 7/8 if it won't fit. Then
// we will use whole screen.
//
pMonitor = GetDialogMonitor(hwndOwner, MONITOR_DEFAULTTOPRIMARY); CopyRect(&rcWork, KPRECT_TO_PRECT(&pMonitor->rcWork)); cxMBMax = MultDiv(rcWork.right - rcWork.left, 5, 8);
cxFoo = 2*XPixFromXDU(DU_OUTERMARGIN, gpsi->cxMsgFontChar);
SelectObject(hdc, KHFONT_TO_HFONT(gpsi->hMsgFont));
//
// If the text doesn't fit in 5/8, try 7/8 of the screen
//
ReSize: //
// The message box is as big as needed to hold the caption/text/buttons,
// but not bigger than the maximum width.
//
cxBox = cxMBMax - 2*SYSMET(CXFIXEDFRAME);
// Ask DrawText for the right cx and cy
rc.left = 0; rc.top = 0; rc.right = cxBox - cxFoo - cxIcon; rc.bottom = rcWork.bottom - rcWork.top; cyText = DrawTextExW(hdc, (LPWSTR)lpmb->lpszText, -1, &rc, DT_CALCRECT | DT_WORDBREAK | DT_EXPANDTABS | DT_NOPREFIX | DT_EXTERNALLEADING | DT_EDITCONTROL, NULL); //
// Make sure we have enough width to hold the buttons, in addition to
// the icon+text. Always force the buttons. If they don't fit, it's
// because the working area is small.
//
//
// The buttons are centered underneath the icon/text.
//
cxText = rc.right - rc.left + cxIcon + cxFoo; cxBox = min(cxBox, max(cxText, cxCaption)); cxBox = max(cxBox, cxButtons + cxFoo); cxText = cxBox - cxFoo - cxIcon;
//
// Now we know the text width for sure. Really calculate how high the
// text will be.
//
rc.left = 0; rc.top = 0; rc.right = cxText; rc.bottom = rcWork.bottom - rcWork.top; cyText = DrawTextExW(hdc, (LPWSTR)lpmb->lpszText, -1, &rc, DT_CALCRECT | DT_WORDBREAK | DT_EXPANDTABS | DT_NOPREFIX | DT_EXTERNALLEADING | DT_EDITCONTROL, NULL);
// Find the window size.
cxBox += 2*SYSMET(CXFIXEDFRAME); cyBox = 2*SYSMET(CYFIXEDFRAME) + SYSMET(CYCAPTION) + YPixFromYDU(2*DU_OUTERMARGIN + DU_INNERMARGIN + DU_BTNHEIGHT, gpsi->cyMsgFontChar);
cyBox += max(cyIcon, cyText);
//
// If the message box doesn't fit on the working area, we'll try wider
// sizes successively: 6/8 of work then 7/8 of screen.
//
if (cyBox > rcWork.bottom - rcWork.top) { int cxTemp;
cxTemp = MultDiv(rcWork.right - rcWork.left, 6, 8);
if (cxMBMax == MultDiv(rcWork.right - rcWork.left, 5, 8)) { cxMBMax = cxTemp; goto ReSize; } else if (cxMBMax == cxTemp) { // then let's try with rcMonitor
CopyRect(&rcWork, KPRECT_TO_PRECT(&pMonitor->rcMonitor)); cxMBMax = MultDiv(rcWork.right - rcWork.left, 7, 8); goto ReSize; } }
if (hFontOld) { SelectFont(hdc, hFontOld); } NtUserReleaseDC(NULL, hdc);
// Find the window position
cntMBox = GetClientInfo()->pDeskInfo->cntMBox;
xMB = (rcWork.left + rcWork.right - cxBox) / 2 + (cntMBox * SYSMET(CXSIZE)); xMB = max(xMB, rcWork.left); yMB = (rcWork.top + rcWork.bottom - cyBox) / 2 + (cntMBox * SYSMET(CYSIZE)); yMB = max(yMB, rcWork.top);
//
// Bottom, right justify if we're going off the screen--but leave a
// little gap.
//
if (xMB + cxBox > rcWork.right) { xMB = rcWork.right - SYSMET(CXEDGE) - cxBox; }
//
// Pin to the working area. If it won't fit, then pin to the screen
// height. Bottom justify it at least if too big even for that, so
// that the buttons are visible.
//
if (yMB + cyBox > rcWork.bottom) { yMB = rcWork.bottom - SYSMET(CYEDGE) - cyBox; if (yMB < rcWork.top) { yMB = pMonitor->rcMonitor.bottom - SYSMET(CYEDGE) - cyBox; } }
wTextLen = wcslen(lpmb->lpszText);
// Find out the memory required for the Dlg template and try to alloc it
hTemplate = UserLocalAlloc(HEAP_ZERO_MEMORY, MB_FindDlgTemplateSize(lpmb)); if (!hTemplate) { goto SMB_Exit; }
lpDlgTmp = (LPBYTE)hTemplate;
//
// Setup the dialog style for the message box
//
dwStyleDlg = WS_POPUPWINDOW | WS_CAPTION | DS_ABSALIGN | DS_NOIDLEMSG | DS_SETFONT | DS_3DLOOK;
if ((dwStyleMsg & MB_MODEMASK) == MB_SYSTEMMODAL) { dwStyleDlg |= DS_SYSMODAL | DS_SETFOREGROUND; } else { dwStyleDlg |= DS_MODALFRAME | WS_SYSMENU; }
if (dwStyleMsg & MB_SETFOREGROUND) { dwStyleDlg |= DS_SETFOREGROUND; }
// Add the Header of the Dlg Template
// BOGUS !!! don't ADD bools
lpDlgTmp = MB_UpdateDlgHdr((LPDLGTEMPLATE) lpDlgTmp, dwStyleDlg, dwExStyleMsg, (BYTE) (lpmb->cButtons + (wIconOrdNum != 0) + (lpmb->lpszText != NULL)), xMB, yMB, cxBox, cyBox, (LPWSTR)lpmb->lpszCaption, wCaptionLen);
//
// Center the buttons
//
cxFoo = (cxBox - 2*SYSMET(CXFIXEDFRAME) - cxButtons) / 2;
lpDlgTmp = MB_AddPushButtons((LPDLGITEMTEMPLATE)lpDlgTmp, lpmb, cxFoo, cyBox - SYSMET(CYCAPTION) - (2 * SYSMET(CYFIXEDFRAME)) - YPixFromYDU(DU_OUTERMARGIN, gpsi->cyMsgFontChar));
// Add Icon, if any, to the Dlg template
//
// The icon is always top justified. If the text is shorter than the
// height of the icon, we center it. Otherwise the text will start at
// the top.
//
if (wIconOrdNum) { OrdNum[0] = 0xFFFF; // To indicate that an Ordinal number follows
OrdNum[1] = (WORD) wIconOrdNum;
lpDlgTmp = MB_UpdateDlgItem((LPDLGITEMTEMPLATE)lpDlgTmp, IDUSERICON, // Control Id
SS_ICON | WS_GROUP | WS_CHILD | WS_VISIBLE, 0, XPixFromXDU(DU_OUTERMARGIN, gpsi->cxMsgFontChar), // X co-ordinate
YPixFromYDU(DU_OUTERMARGIN, gpsi->cyMsgFontChar), // Y co-ordinate
0, 0, // For Icons, CX and CY are ignored, can be zero
OrdNum, // Ordinal number of Icon
ARRAY_SIZE(OrdNum), // Length of OrdNum
STATICCODE); }
// Add the Text of the Message to the Dlg Template
if (lpmb->lpszText) { //
// Center the text if shorter than the icon.
//
if (cyText >= cyIcon) cxFoo = 0; else cxFoo = (cyIcon - cyText) / 2;
dwStyleText = SS_NOPREFIX | WS_GROUP | WS_CHILD | WS_VISIBLE | SS_EDITCONTROL; if (dwStyleMsg & MB_RIGHT) { dwStyleText |= SS_RIGHT; xText = cxBox - (SYSMET(CXSIZE) + cxText); } else { dwStyleText |= SS_LEFT; xText = cxIcon + XPixFromXDU(DU_INNERMARGIN, gpsi->cxMsgFontChar); }
MB_UpdateDlgItem((LPDLGITEMTEMPLATE)lpDlgTmp, -1, dwStyleText, dwExStyleMsg, xText, YPixFromYDU(DU_OUTERMARGIN, gpsi->cyMsgFontChar) + cxFoo, cxText, cyText, (LPWSTR)lpmb->lpszText, wTextLen, STATICCODE); }
// The dialog template is ready
//
// Set the normal cursor
//
hcurOld = NtUserSetCursor(LoadCursor(NULL, IDC_ARROW));
lpmb->lpszIcon = (LPWSTR) hIcon;
if (!(lpmb->dwStyle & MB_USERICON)) { int wBeep = (LOWORD(lpmb->dwStyle & MB_ICONMASK)) >> MB_MASKSHIFT; if (wBeep < USER_SOUND_MAX) { NtUserCallOneParam(wBeep, SFI_PLAYEVENTSOUND); } }
iRetVal = (int)InternalDialogBox(hmodUser, hTemplate, hwndOwner, MB_DlgProc, (LPARAM) lpmb, FALSE);
//
// Fix up return value
if (iRetVal == -1) iRetVal = 0; /* Messagebox should also return error */
//
// If the messagebox contains only OK button, then its ID is changed as
// IDCANCEL in MB_DlgProc; So, we must change it back to IDOK irrespective
// of whether ESC is pressed or Carriage return is pressed;
//
if (((dwStyleMsg & MB_TYPEMASK) == MB_OK) && iRetVal) iRetVal = IDOK;
//
// Restore the previous cursor
//
if (hcurOld) NtUserSetCursor(hcurOld);
SMB_Exit: if (hTemplate) { UserLocalFree(hTemplate); }
if (hCaption) { UserLocalFree(hCaption); }
if (hText) { UserLocalFree(hText); }
return iRetVal; }
/***************************************************************************\
* MB_CopyToClipboard * * Called in response to WM_COPY, it will save the title, message and button's * texts to the clipboard in CF_UNICODETEXT format. * * --------------------------- * Caption * --------------------------- * Text * --------------------------- * Button1 ... ButtonN * --------------------------- * * * History: * 08-03-97 MCostea Created \***************************************************************************/ VOID MB_CopyToClipboard( HWND hwndDlg) { LPCWSTR lpszRead; LPWSTR lpszAll, lpszWrite; HANDLE hData; static CONST WCHAR szLine[] = L"---------------------------\r\n"; UINT cBufSize, i, cWrote; LPMSGBOXDATA lpmb;
if (!(lpmb = (LPMSGBOXDATA)GetWindowLongPtr(hwndDlg, GWLP_USERDATA))) { return; }
if (!OpenClipboard(hwndDlg)) { return; }
/*
* Calculate the buffer size: * - the message text can be all \n, that will become \r\n * - there are a few extra \r\n (that's why 8) */ cBufSize = (lpmb->lpszCaption ? wcslen(lpmb->lpszCaption) : 0) + (lpmb->lpszText ? 2*wcslen(lpmb->lpszText) : 0) + 4*sizeof(szLine) + lpmb->cButtons * gpsi->wMaxBtnSize + 8;
cBufSize *= sizeof(WCHAR);
if (!(hData = UserGlobalAlloc(LHND, (LONG)(cBufSize))) ) { goto CloseClip; }
USERGLOBALLOCK(hData, lpszAll); UserAssert(lpszAll);
cWrote = wsprintf(lpszAll, L"%s%s\r\n%s", szLine, lpmb->lpszCaption ? lpmb->lpszCaption : L"", szLine);
lpszWrite = lpszAll + cWrote; lpszRead = lpmb->lpszText; /*
* Change \n to \r\n in the text */ for (i = 0; *lpszRead; i++) {
if (*lpszRead == L'\n') *lpszWrite++ = L'\r';
*lpszWrite++ = *lpszRead++; }
cWrote = wsprintf(lpszWrite, L"\r\n%s", szLine); lpszWrite += cWrote;
/*
* Remove & from the button texts */ for (i = 0; i<lpmb->cButtons; i++) {
lpszRead = lpmb->ppszButtonText[i]; while (*lpszRead) { if (*lpszRead != L'&') { *lpszWrite++ = *lpszRead; } lpszRead++; } *lpszWrite++ = L' '; *lpszWrite++ = L' '; *lpszWrite++ = L' '; } wsprintf(lpszWrite, L"\r\n%s\0", szLine);
USERGLOBALUNLOCK(hData);
NtUserEmptyClipboard(); /*
* If we just called EmptyClipboard in the context of a 16 bit * app then we also have to tell WOW to nix its 16 handle copy of * clipboard data. WOW does its own clipboard caching because * some 16 bit apps use clipboard data even after the clipboard * has been emptied. See the note in the server code. * * Note: this is another place (besides client\editec.c) where * EmptyClipboard is called* for a 16 bit app not going through WOW. * If we added others we might want to move this into EmptyClipboard * and have two versions. */ if (GetClientInfo()->CI_flags & CI_16BIT) { pfnWowEmptyClipBoard(); }
SetClipboardData(CF_UNICODETEXT, hData);
CloseClip: NtUserCloseClipboard();
}
/***************************************************************************\
* MB_UpdateDlgHdr * * History: * 11-20-90 DarrinM Ported from Win 3.0 sources. \***************************************************************************/
LPBYTE MB_UpdateDlgHdr( LPDLGTEMPLATE lpDlgTmp, long lStyle, long lExtendedStyle, BYTE bItemCount, int iX, int iY, int iCX, int iCY, LPWSTR lpszCaption, int cchCaptionLen) { LPTSTR lpStr; RECT rc;
/*
* Adjust the rectangle dimensions. */ rc.left = iX + SYSMET(CXFIXEDFRAME); rc.top = iY + SYSMET(CYFIXEDFRAME); rc.right = iX + iCX - SYSMET(CXFIXEDFRAME); rc.bottom = iY + iCY - SYSMET(CYFIXEDFRAME);
/*
* Adjust for the caption. */ rc.top += SYSMET(CYCAPTION);
lpDlgTmp->style = lStyle; lpDlgTmp->dwExtendedStyle = lExtendedStyle; lpDlgTmp->cdit = bItemCount; lpDlgTmp->x = XDUFromXPix(rc.left, gpsi->cxMsgFontChar); lpDlgTmp->y = YDUFromYPix(rc.top, gpsi->cyMsgFontChar); lpDlgTmp->cx = XDUFromXPix(rc.right - rc.left, gpsi->cxMsgFontChar); lpDlgTmp->cy = YDUFromYPix(rc.bottom - rc.top, gpsi->cyMsgFontChar);
/*
* Move pointer to variable length fields. No menu resource for * message box, a zero window class (means dialog box class). */ lpStr = (LPWSTR)(lpDlgTmp + 1); *lpStr++ = 0; // Menu
lpStr = (LPWSTR)NextWordBoundary(lpStr); *lpStr++ = 0; // Class
lpStr = (LPWSTR)NextWordBoundary(lpStr);
/*
* NOTE: iCaptionLen may be less than the length of the Caption string; * So, DO NOT USE lstrcpy(); */ RtlCopyMemory(lpStr, lpszCaption, cchCaptionLen*sizeof(WCHAR)); lpStr += cchCaptionLen; *lpStr++ = TEXT('\0'); // Null terminate the caption str
/*
* Font height of 0x7FFF means use the message box font */ *lpStr++ = 0x7FFF;
return NextDWordBoundary(lpStr); }
/***************************************************************************\
* MB_AddPushButtons * * History: * 11-20-90 DarrinM Ported from Win 3.0 sources. \***************************************************************************/
LPBYTE MB_AddPushButtons( LPDLGITEMTEMPLATE lpDlgTmp, LPMSGBOXDATA lpmb, UINT wLEdge, UINT wBEdge) { UINT wYValue; UINT i; UINT wHeight; UINT wCount = lpmb->cButtons;
wHeight = YPixFromYDU(DU_BTNHEIGHT, gpsi->cyMsgFontChar);
wYValue = wBEdge - wHeight; // Y co-ordinate for push buttons
for (i = 0; i < wCount; i++) {
lpDlgTmp = (LPDLGITEMTEMPLATE)MB_UpdateDlgItem( lpDlgTmp, /* Ptr to template */ lpmb->pidButton[i], /* Control Id */ WS_TABSTOP | WS_CHILD | WS_VISIBLE | (i == 0 ? WS_GROUP : 0) | ((UINT)i == lpmb->DefButton ? BS_DEFPUSHBUTTON : BS_PUSHBUTTON), 0, wLEdge, /* X co-ordinate */ wYValue, /* Y co-ordinate */ gpsi->wMaxBtnSize, /* CX */ wHeight, /* CY */ lpmb->ppszButtonText[i], /* String for button */ (UINT)wcslen(lpmb->ppszButtonText[i]),/* Length */ BUTTONCODE);
/*
* Get the X co-ordinate for the next Push button */ wLEdge += gpsi->wMaxBtnSize + XPixFromXDU(DU_BTNGAP, gpsi->cxMsgFontChar); }
return (LPBYTE)lpDlgTmp; }
/***************************************************************************\
* MB_UpdateDlgItem * * History: * 11-20-90 DarrinM Ported from Win 3.0 sources. \***************************************************************************/
LPBYTE MB_UpdateDlgItem( LPDLGITEMTEMPLATE lpDlgItem, int iCtrlId, long lStyle, long lExtendedStyle, int iX, int iY, int iCX, int iCY, LPWSTR lpszText, UINT cchTextLen, int iControlClass) { LPWSTR lpStr; BOOL fIsOrdNum;
lpDlgItem->x = XDUFromXPix(iX, gpsi->cxMsgFontChar); lpDlgItem->y = YDUFromYPix(iY, gpsi->cyMsgFontChar); lpDlgItem->cx = XDUFromXPix(iCX,gpsi->cxMsgFontChar); lpDlgItem->cy = YDUFromYPix(iCY,gpsi->cyMsgFontChar); lpDlgItem->id = (WORD)iCtrlId; lpDlgItem->style = lStyle; lpDlgItem->dwExtendedStyle = lExtendedStyle;
/*
* We have to avoid the following nasty rounding off problem: * (e.g) If iCX=192 and cxSysFontChar=9, then cx becomes 85; When the * static text is drawn, from 85 dlg units we get 191 pixels; So, the text * is truncated; * So, to avoid this, check if this is a static text and if so, * add one more dialog unit to cx and cy; * --Fix for Bug #4481 --SANKAR-- 09-29-89-- */
/*
* Also, make sure we only do this to static text items. davidds */
/*
* Now static text uses SS_NOPREFIX = 0x80; * So, test the lStyle field only with 0x0F instead of 0xFF; * Fix for Bugs #5933 and 5935 --SANKAR-- 11-28-89 */ if (iControlClass == STATICCODE && (((lStyle & 0x0F) == SS_LEFT) || ((lStyle & 0x0F) == SS_RIGHT))) {
/*
* This is static text */ lpDlgItem->cx++; lpDlgItem->cy++; }
/*
* Move ptr to the variable fields */ lpStr = (LPWSTR)(lpDlgItem + 1);
/*
* Store the Control Class value */ *lpStr++ = 0xFFFF; *lpStr++ = (BYTE)iControlClass; lpStr = (LPWSTR)NextWordBoundary(lpStr); // WORD-align lpszText
/*
* Check if the String contains Ordinal number or not */ fIsOrdNum = ((*lpszText == 0xFFFF) && (cchTextLen == sizeof(DWORD)/sizeof(WCHAR)));
/*
* NOTE: cchTextLen may be less than the length of lpszText. So, * DO NOT USE lstrcpy() for the copy. */ RtlCopyMemory(lpStr, lpszText, cchTextLen*sizeof(WCHAR)); lpStr = lpStr + cchTextLen; if (!fIsOrdNum) { *lpStr = TEXT('\0'); // NULL terminate the string
lpStr = (LPWSTR)NextWordBoundary(lpStr + 1); }
*lpStr++ = 0; // sizeof control data (there is none)
return NextDWordBoundary(lpStr); }
/***************************************************************************\
* MB_FindDlgTemplateSize * * This routine computes the amount of memory that will be needed for the * messagebox's dialog template structure. The dialog template has several * required and optional records. The dialog manager expects each record to * be DWORD aligned so any necessary padding is also accounted for. * * (header - required) * DLGTEMPLATE (header) + 1 menu byte + 1 pad + 1 class byte + 1 pad * szCaption + 0 term + DWORD alignment * * (static icon control - optional) * DLGITEMTEMPLATE + 1 class byte + 1 pad + (0xFF00 + icon ordinal # [szText]) + * UINT alignment + 1 control data length byte (0) + DWORD alignment * * (pushbutton controls - variable, but at least one required) * DLGITEMTEMPLATE + 1 class byte + 1 pad + length of button text + * UINT alignment + 1 control data length byte (0) + DWORD alignment * * (static text control - optional) * DLGITEMTEMPLATE + 1 class byte + 1 pad + length of text + * UINT alignment + 1 control data length byte (0) + DWORD alignment * * History: * 11-20-90 DarrinM Ported from Win 3.0 sources. \***************************************************************************/ UINT MB_FindDlgTemplateSize( LPMSGBOXDATA lpmb) { ULONG_PTR cbLen; UINT cbT; UINT i; UINT wCount;
wCount = lpmb->cButtons;
/*
* Start with dialog header's size. */ cbLen = (ULONG_PTR)NextWordBoundary(sizeof(DLGTEMPLATE) + sizeof(WCHAR)); cbLen = (ULONG_PTR)NextWordBoundary(cbLen + sizeof(WCHAR)); cbLen += wcslen(lpmb->lpszCaption) * sizeof(WCHAR) + sizeof(WCHAR); cbLen += sizeof(WORD); // Font height
cbLen = (ULONG_PTR)NextDWordBoundary(cbLen);
/*
* Check if an Icon is present. */ if (lpmb->dwStyle & MB_ICONMASK) cbLen += (ULONG_PTR)NextDWordBoundary(sizeof(DLGITEMTEMPLATE) + 7 * sizeof(WCHAR));
/*
* Find the number of buttons in the msg box. */ for (i = 0; i < wCount; i++) { cbLen = (ULONG_PTR)NextWordBoundary(cbLen + sizeof(DLGITEMTEMPLATE) + (2 * sizeof(WCHAR))); cbT = (wcslen(lpmb->ppszButtonText[i]) + 1) * sizeof(WCHAR); cbLen = (ULONG_PTR)NextWordBoundary(cbLen + cbT); cbLen += sizeof(WCHAR); cbLen = (ULONG_PTR)NextDWordBoundary(cbLen); }
/*
* Add in the space required for the text message (if there is one). */ if (lpmb->lpszText != NULL) { cbLen = (ULONG_PTR)NextWordBoundary(cbLen + sizeof(DLGITEMTEMPLATE) + (2 * sizeof(WCHAR))); cbT = (wcslen(lpmb->lpszText) + 1) * sizeof(WCHAR); cbLen = (ULONG_PTR)NextWordBoundary(cbLen + cbT); cbLen += sizeof(WCHAR); cbLen = (ULONG_PTR)NextDWordBoundary(cbLen); }
return (UINT)cbLen; }
/***************************************************************************\
* MB_GetIconOrdNum * * History: * 11-20-90 DarrinM Ported from Win 3.0 sources. \***************************************************************************/
UINT MB_GetIconOrdNum( UINT rgBits) { switch (rgBits & MB_ICONMASK) { case MB_USERICON: case MB_ICONHAND: return PtrToUlong(IDI_HAND);
case MB_ICONQUESTION: return PtrToUlong(IDI_QUESTION);
case MB_ICONEXCLAMATION: return PtrToUlong(IDI_EXCLAMATION);
case MB_ICONASTERISK: return PtrToUlong(IDI_ASTERISK); }
return 0; }
/***************************************************************************\
* MB_GetString * * History: * 1-24-95 JerrySh Created. \***************************************************************************/ LPWSTR MB_GetString( UINT wBtn) { if (wBtn < MAX_SEB_STYLES) return GETGPSIMBPSTR(wBtn);
RIPMSG1(RIP_ERROR, "Invalid wBtn: %d", wBtn);
return NULL; }
/***************************************************************************\
* MB_DlgProc * * Returns: TRUE - message processed * FALSE - message not processed * * History: * 11-20-90 DarrinM Ported from Win 3.0 sources. \***************************************************************************/ INT_PTR MB_DlgProc( HWND hwndDlg, UINT wMsg, WPARAM wParam, LPARAM lParam) { HWND hwndT; int iCount; LPMSGBOXDATA lpmb; HWND hwndOwner; PVOID lpfnCallback; PWND pwnd; BOOL bTimedOut = FALSE;
switch (wMsg) { case WM_CTLCOLORDLG: case WM_CTLCOLORSTATIC: if ((pwnd = ValidateHwnd(hwndDlg)) == NULL) return 0L; return DefWindowProcWorker(pwnd, WM_CTLCOLORMSGBOX, wParam, lParam, FALSE);
case WM_TIMER: if (!bTimedOut) { bTimedOut = TRUE; EndTaskModalDialog(hwndDlg); EndDialog(hwndDlg, IDTIMEOUT); } break;
case WM_NCDESTROY: if ((lpmb = (LPMSGBOXDATA)GetWindowLongPtr(hwndDlg, GWLP_USERDATA))) { if (lpmb->dwTimeout != INFINITE) { NtUserKillTimer(hwndDlg, 0); lpmb->dwTimeout = INFINITE; } } if ((pwnd = ValidateHwnd(hwndDlg)) == NULL) { return 0L; } return DefWindowProcWorker(pwnd, wMsg, wParam, lParam, FALSE);
case WM_INITDIALOG:
lpmb = (LPMSGBOXDATA)lParam; SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (ULONG_PTR)lParam);
NtUserCallHwnd(hwndDlg, SFI_SETMSGBOX);
if (lpmb->dwStyle & MB_HELP) { NtUserSetWindowContextHelpId(hwndDlg, lpmb->dwContextHelpId); }
if (lpmb->dwStyle & MB_TOPMOST) { NtUserSetWindowPos(hwndDlg, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); }
if (lpmb->dwStyle & MB_USERICON) { SendDlgItemMessage(hwndDlg, IDUSERICON, STM_SETICON, (WPARAM)(lpmb->lpszIcon), 0); iCount = ALERT_SYSTEM_WARNING; } else { /*
* Generate an alert notification */ switch (lpmb->dwStyle & MB_ICONMASK) { case MB_ICONWARNING: iCount = ALERT_SYSTEM_WARNING; break;
case MB_ICONQUESTION: iCount = ALERT_SYSTEM_QUERY; break;
case MB_ICONERROR: iCount = ALERT_SYSTEM_ERROR; break;
case MB_ICONINFORMATION: default: iCount = ALERT_SYSTEM_INFORMATIONAL; break; } }
NotifyWinEvent(EVENT_SYSTEM_ALERT, hwndDlg, OBJID_ALERT, iCount);
if (lpmb->hwndOwner == NULL && (lpmb->dwStyle & MB_MODEMASK) == MB_TASKMODAL) { StartTaskModalDialog(hwndDlg); }
/*
* Set focus on the default button */ hwndT = GetWindow(hwndDlg, GW_CHILD); iCount = lpmb->DefButton; while (iCount--) hwndT = GetWindow(hwndT, GW_HWNDNEXT);
NtUserSetFocus(hwndT);
//
// Need the dialog's HWND later, but we reuse hwndDlg.
//
hwndT = hwndDlg;
//
// If this dialogbox does not contain a IDCANCEL button, then
// remove the CLOSE command from the system menu.
// Bug #4445, --SANKAR-- 09-13-89 --
//
if (lpmb->CancelId == 0) { HMENU hMenu;
if (hMenu = NtUserGetSystemMenu(hwndDlg, FALSE)) { NtUserDeleteMenu(hMenu, SC_CLOSE, (UINT)MF_BYCOMMAND); } }
if ((lpmb->dwStyle & MB_TYPEMASK) == MB_OK) { //
// Make the ID of OK button to be CANCEL, because we want
// the ESC to terminate the dialogbox; GetDlgItem32() will
// not fail, because this is MB_OK messagebox!
//
hwndDlg = GetDlgItem(hwndDlg, IDOK);
if (hwndDlg != NULL) { // hwndDlg->hMenu = (HMENU)IDCANCEL;
SetWindowLongPtr(hwndDlg, GWLP_ID, IDCANCEL); } else { RIPMSG0(RIP_WARNING, "MB_DlgProc- IDOK control not found"); } }
if (lpmb->dwTimeout != INFINITE) { if (NtUserSetTimer(hwndT, 0, lpmb->dwTimeout, NULL) == 0) { /*
* Couldn't create the timer, so "clear" out the timeout value * for future reference. */ lpmb->dwTimeout = INFINITE; } }
/*
* We have changed the input focus */ return FALSE;
case WM_HELP: // When user hits an F1 key, it results in this message.
// It is possible that this MsgBox has a callback instead of a
// parent. So, we must behave as if the user hit the HELP button.
goto MB_GenerateHelp;
case WM_COMMAND: switch (LOWORD(wParam)) { case IDOK: case IDCANCEL: //
// Check if a control exists with the given ID; This
// check is needed because DlgManager returns IDCANCEL
// blindly when ESC is pressed even if a button with
// IDCANCEL is not present.
// Bug #4445 --SANKAR--09-13-1989--
//
if (!GetDlgItem(hwndDlg, LOWORD(wParam))) return FALSE;
// else FALL THRO....This is intentional.
case IDABORT: case IDIGNORE: case IDNO: case IDRETRY: case IDYES: case IDTRYAGAIN: case IDCONTINUE: EndTaskModalDialog(hwndDlg); EndDialog(hwndDlg, LOWORD(wParam)); break; case IDHELP: MB_GenerateHelp: // Generate the WM_HELP message and send it to owner or callback
hwndOwner = NULL;
// Check if there is an app supplied callback for this MsgBox
lpmb = (LPMSGBOXDATA)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); if ((lpfnCallback = lpmb->lpfnMsgBoxCallback) == NULL) { // If not, see if we need to inform the parent.
hwndOwner = GetWindow(hwndDlg, GW_OWNER); }
/*
* See if we need to generate the Help message or call back. */ if (hwndOwner || lpfnCallback) { SendHelpMessage(hwndOwner, HELPINFO_WINDOW, IDHELP, hwndDlg, NtUserGetWindowContextHelpId(hwndDlg), lpfnCallback); } break;
default: return FALSE; break; } break;
case WM_COPY: MB_CopyToClipboard(hwndDlg); break;
default: return FALSE; }
return TRUE; }
/***************************************************************************\
* StartTaskModalDialog * * History: * 11-20-90 DarrinM Ported from Win 3.0 sources. \***************************************************************************/ VOID StartTaskModalDialog( HWND hwndDlg) { int cHwnd; HWND *phwnd; HWND *phwndList, *phwndEnd; HWND hwnd; PWND pwnd; LPMSGBOXDATA lpmb;
/*
* Get the hwnd list. It is returned in a block of memory allocated with * UserLocalAlloc. */ if ((cHwnd = BuildHwndList(NULL, NULL, FALSE, GetCurrentThreadId(), &phwndList)) == 0) { return; }
lpmb = (LPMSGBOXDATA)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); lpmb->phwndList = phwndList;
phwndEnd = phwndList + cHwnd; for (phwnd = phwndList; phwnd < phwndEnd; phwnd++) { if ((hwnd = *phwnd) == NULL || (pwnd = RevalidateHwnd(hwnd)) == NULL) continue;
/*
* if the window belongs to the current task and is enabled, disable * it. All other windows are NULL'd out, to prevent their being * enabled later */ if (!TestWF(pwnd, WFDISABLED) && DIFFWOWHANDLE(hwnd, hwndDlg)) { NtUserEnableWindow(hwnd, FALSE); } else { *phwnd = NULL; } } }
/***************************************************************************\
* EndTaskModalDialog * * History: * 11-20-90 DarrinM Ported from Win 3.0 sources. \***************************************************************************/ VOID EndTaskModalDialog( HWND hwndDlg) { HWND *phwnd; HWND *phwndList; HWND hwnd; LPMSGBOXDATA lpmb;
lpmb = (LPMSGBOXDATA)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); phwndList = lpmb->phwndList; if (phwndList == NULL) { return; }
lpmb->phwndList = NULL;
for (phwnd = phwndList; *phwnd != (HWND)1; phwnd++) { if ((hwnd = *phwnd) != NULL) { NtUserEnableWindow(hwnd, TRUE); } }
UserLocalFree(phwndList); }
#ifdef _JANUS_
/***************************************************************************\
* ErrorMessageInst * * Instrument routine for recording error msg * * Returns: TRUE - Instrument error msg Success * FALSE - Fail * * History: * 8-5-98 Chienho Created \***************************************************************************/
BOOL ErrorMessageInst( LPMSGBOXDATA pMsgBoxParams) { ERROR_ELEMENT ErrEle; WCHAR *pwcs; PVOID ImageBase; PIMAGE_NT_HEADERS NtHeaders; BOOL rc; WCHAR szUnknown[32];
/*
* Check if the MessageBox style is within the logged severity level */ switch (pMsgBoxParams->dwStyle & MB_ICONMASK) { case MB_ICONHAND: /*
* when EMI is enabled, we at least log error messages */ break; case MB_ICONEXCLAMATION: if (gdwEMIControl > EMI_SEVERITY_WARNING) { rc = TRUE; goto End; } break; case MB_ICONQUESTION: if (gdwEMIControl > EMI_SEVERITY_QUESTION) { rc = TRUE; goto End; } break; case MB_ICONASTERISK: if (gdwEMIControl > EMI_SEVERITY_INFORMATION) { rc = TRUE; goto End; } break; case MB_USERICON: if (gdwEMIControl > EMI_SEVERITY_USER) { rc = TRUE; goto End; } break; default: if (gdwEMIControl > EMI_SEVERITY_ALL) { rc = TRUE; goto End; } break; }
if (gdwEMIThreadID != GETTHREADID()) { rc = FALSE; goto End; } RtlZeroMemory(&ErrEle, sizeof(ErrEle));
/*
* get last error first, check with FormatMessage??? */ ErrEle.dwErrorCode = GetLastError();
/*
* get return address */
ErrEle.ReturnAddr = gpReturnAddr;
/*
* get the process image name */ GetCurrentProcessName(ErrEle.ProcessName, ARRAY_SIZE(ErrEle.ProcessName));
/*
* Load the "unknown" string */ LoadString(hmodUser, STR_UNKNOWN, szUnknown, ARRAYSIZE(szUnknown));
/*
* get the window title */ GetWindowTextW(pMsgBoxParams->hwndOwner, ErrEle.WindowTitle, TITLE_SIZE); if (!(*(ErrEle.WindowTitle))) { lstrcpy(ErrEle.WindowTitle, szUnknown); }
/*
* get messagebox data */ ErrEle.lpszText = (LPWSTR)pMsgBoxParams->lpszText; ErrEle.lpszCaption = (LPWSTR)pMsgBoxParams->lpszCaption; ErrEle.dwStyle = pMsgBoxParams->dwStyle;
/*
* resolve the module name of caller */ if (!RtlPcToFileHeader((PVOID)ErrEle.ReturnAddr, &ImageBase)) { RIPMSG0(RIP_WARNING, "ErrorMessageInst: Can't find Caller"); ErrEle.BaseAddr = (PVOID)-1; ErrEle.dwImageSize = -1; lstrcpy(ErrEle.CallerModuleName, szUnknown); } else { ErrEle.BaseAddr = ImageBase; if (GetModuleFileName((HMODULE)ImageBase, ErrEle.CallerModuleName, MAX_PATH)) { pwcs = wcsrchr(ErrEle.CallerModuleName, TEXT('\\')); if (pwcs) { pwcs++; lstrcpy(ErrEle.CallerModuleName, pwcs); } } else { lstrcpy(ErrEle.CallerModuleName, szUnknown); } NtHeaders = RtlImageNtHeader(ImageBase); if (NtHeaders == NULL) { ErrEle.dwImageSize = -1; } else { ErrEle.dwImageSize = NtHeaders->OptionalHeader.SizeOfImage; } } /*
* Register the event if we haven't done so already. * Since RegisterEventSource is supported by a service, we must not hold * any locks while making this call. Hence we might have several threads * registering the event simultaneously. */
if (!gEventSource) { gEventSource = RegisterEventSourceW(NULL, L"Error Instrument"); if (!gEventSource) { ErrEle.dwErrorCode = GetLastError(); rc = FALSE; } }
/*
* report event */ if (gEventSource) { rc = LogMessageBox(&ErrEle); }
/*
* allow to process another event log again */
InterlockedExchangePointer(&gdwEMIThreadID, 0);
End: return rc; }
/***************************************************************************\
* InitInstrument * * Returns: TRUE - Initialization Success * FALSE - Initialization Fail * \***************************************************************************/ BOOL InitInstrument( LPDWORD lpEMIControl) { NTSTATUS Status; HKEY hKeyEMI = NULL; UNICODE_STRING UnicodeStringEMIKey; UNICODE_STRING UnicodeStringEnable; UNICODE_STRING UnicodeStringStyle; OBJECT_ATTRIBUTES ObjA; DWORD EMIEnable = 0; //means disable
DWORD EMISeverity; struct { KEY_VALUE_PARTIAL_INFORMATION; LARGE_INTEGER; } EMIValueInfo; DWORD dwDisposition;
RtlInitUnicodeString(&UnicodeStringEMIKey, szEMIKey); InitializeObjectAttributes(&ObjA, &UnicodeStringEMIKey, OBJ_CASE_INSENSITIVE, NULL, NULL);
Status = NtOpenKey(&hKeyEMI, KEY_READ, &ObjA); if (!NT_SUCCESS(Status)) { /*
* Key doesn't exist, assume disable */ return FALSE; }
/*
* read the logging enable and setting */ RtlInitUnicodeString(&UnicodeStringEnable, szEMIEnable); Status = NtQueryValueKey(hKeyEMI, &UnicodeStringEnable, KeyValuePartialInformation, &EMIValueInfo, sizeof(EMIValueInfo), &dwDisposition);
if (NT_SUCCESS(Status)) {
RtlCopyMemory(&EMIEnable, &EMIValueInfo.Data, sizeof(EMIEnable));
RtlInitUnicodeString(&UnicodeStringStyle, szEMISeverity); Status = NtQueryValueKey(hKeyEMI, &UnicodeStringStyle, KeyValuePartialInformation, &EMIValueInfo, sizeof(EMIValueInfo), &dwDisposition);
if (NT_SUCCESS(Status)) { RtlCopyMemory(&EMISeverity, &EMIValueInfo.Data, sizeof(EMISeverity)); /*
* Validate data */ if (EMISeverity > EMI_SEVERITY_MAX_VALUE) { EMISeverity = EMI_SEVERITY_MAX_VALUE; } } else { /*
* default severity for instrument */ EMISeverity = EMI_SEVERITY_WARNING; } *lpEMIControl = EMISeverity; }
/*
* read default message reply enable */ RtlInitUnicodeString(&UnicodeStringEnable, szDMREnable); Status = NtQueryValueKey(hKeyEMI, &UnicodeStringEnable, KeyValuePartialInformation, &EMIValueInfo, sizeof(EMIValueInfo), &dwDisposition);
if (NT_SUCCESS(Status)) { RtlCopyMemory(&gfDMREnable, &EMIValueInfo.Data, sizeof(gfDMREnable)); }
NtClose(hKeyEMI);
if (EMIEnable) {
/*
* add eventlog file */ if (NT_SUCCESS(CreateLogSource())) { return TRUE; } } return FALSE; }
/***************************************************************************\
* CreateLogSource * * Create the event source for eventlog * Return : NTSTATUS * \***************************************************************************/ NTSTATUS CreateLogSource() { NTSTATUS Status; UNICODE_STRING UnicodeStringEventKey; OBJECT_ATTRIBUTES ObjA; HKEY hKeyEvent = NULL; UNICODE_STRING UnicodeString; DWORD dwDisposition;
RtlInitUnicodeString(&UnicodeStringEventKey, szEventKey); InitializeObjectAttributes(&ObjA, &UnicodeStringEventKey, OBJ_CASE_INSENSITIVE, NULL, NULL);
if (NT_SUCCESS(Status = NtOpenKey(&hKeyEvent, KEY_READ, &ObjA))) {
struct { KEY_VALUE_PARTIAL_INFORMATION KeyInfo; WCHAR awchMsgFileName[256]; } MsgFile;
RtlInitUnicodeString(&UnicodeString, szEventMsgFile);
Status = NtQueryValueKey(hKeyEvent, &UnicodeString, KeyValuePartialInformation, &MsgFile, sizeof MsgFile, &dwDisposition); if (NT_SUCCESS(Status)) { Status = lstrcmpi((LPWSTR)MsgFile.KeyInfo.Data, L"%SystemRoot%\\System32\\user32.dll"); } NtClose(hKeyEvent); }
return Status; }
/***************************************************************************\
* LogMessageBox * * Output error message record into eventlog * \***************************************************************************/ BOOL LogMessageBox( LPERROR_ELEMENT lpErrEle) { LPWSTR lps[8]; DWORD dwData[2]; WCHAR BaseAddress[19]; WCHAR ImageSize[19]; WCHAR ReturnAddress[19]; PTOKEN_USER pTokenUser = NULL; PSID pSid = NULL; BOOL rc;
lps[0] = lpErrEle->ProcessName; lps[1] = lpErrEle->WindowTitle; lps[2] = lpErrEle->lpszCaption; lps[3] = lpErrEle->lpszText; lps[4] = lpErrEle->CallerModuleName; wsprintf(BaseAddress, L"%-#16p", lpErrEle->BaseAddr); lps[5] = BaseAddress; wsprintf(ImageSize, L"%-#16lX", lpErrEle->dwImageSize); lps[6] = ImageSize; wsprintf(ReturnAddress, L"%-#16p", lpErrEle->ReturnAddr); lps[7] = ReturnAddress;
dwData[0] = lpErrEle->dwStyle; dwData[1] = lpErrEle->dwErrorCode;
if (GetUserSid(&pTokenUser)) { pSid = pTokenUser->User.Sid; }
UserAssert(gEventSource != NULL); rc = ReportEventW(gEventSource, EVENTLOG_INFORMATION_TYPE, 0, STATUS_LOG_ERROR_MSG, pSid, ARRAY_SIZE(lps), sizeof(dwData), lps, dwData);
if (pTokenUser) { VirtualFree(pTokenUser, 0, MEM_RELEASE); }
return rc; } #endif
|