Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1440 lines
43 KiB

/****************************** Module Header ******************************\
* Module Name: msgbox.c
*
* Copyright (c) 1985-91, 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
#define DU_BTNWIDTH 50 // D.U. of button width, minimum
LPBYTE MB_UpdateDlgHdr(LPDLGTEMPLATE lpDlgTmp, long lStyle, BYTE bItemCount,
int iX, int iY, int iCX, int iCY, LPWSTR lpszCaption, int iCaptionLen);
LPBYTE MB_UpdateDlgItem(LPDLGITEMTEMPLATE lpDlgItem, int iCtrlId, long lStyle,
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);
#define MB_MASKSHIFT 4
LPWSTR iconsnd[] =
{
L".Default", // MB_OK
L"SystemHand", // MB_ICONHAND
L"SystemQuestion", // MB_ICONQUESTION
L"SystemExclamation", // MB_ICONEXCLAMATION
L"SystemAsterisk" // MB_ICONASTERISK
};
WCHAR szEmpty[] = L"";
/*
* Note: the following define is used for parameter validation in
* MessageBox. MB_LASTVALIDTYPE must be redefined if any
* new message box types (bounded by MB_TYPEMASK) are added
* to winuser.h.
*/
#define MB_LASTVALIDTYPE MB_RETRYCANCEL
/***************************************************************************\
* 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 = LOWORD(lValue);
HelpInfo.MousePos.y = HIWORD(lValue);
// Check if there is an app supplied callback.
if(lpfnCallback != NULL) {
(*lpfnCallback)(&HelpInfo);
} else {
SendMessage(hwnd, WM_HELP, 0, (LPARAM)&HelpInfo);
}
}
/***************************************************************************\
* MessageBox (API)
*
* History:
* 11-20-90 DarrinM Ported from Win 3.0 sources.
\***************************************************************************/
int MessageBoxA(
HWND hwndOwner,
LPCSTR lpszText,
LPCSTR lpszCaption,
UINT wStyle)
{
return MessageBoxExA(hwndOwner, lpszText, lpszCaption, wStyle, 0);
}
int MessageBoxW(
HWND hwndOwner,
LPCWSTR lpszText,
LPCWSTR lpszCaption,
UINT wStyle)
{
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)
{
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;
}
}
retval = MessageBoxExW(hwndOwner,
lpwszText,
lpwszCaption,
wStyle,
wLanguageId);
UserLocalFree(lpwszText);
if (lpwszCaption)
UserLocalFree(lpwszCaption);
return retval;
}
int MessageBoxExW(
HWND hwndOwner,
LPCWSTR lpszText,
LPCWSTR lpszCaption,
UINT wStyle,
WORD wLanguageId)
{
MSGBOXDATA MsgBoxParams;
#ifdef DEBUG
/*
* 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;
return MessageBoxWorker(&MsgBoxParams);
}
/**************************************************************************\
* MessageBoxIndirect (API)
*
* 09-30-94 FritzS Created
\**************************************************************************/
int MessageBoxIndirectA(
LPMSGBOXPARAMSA lpmbp)
{
int retval;
MSGBOXDATA MsgBoxParams;
LPWSTR lpwszText = NULL;
LPWSTR lpwszCaption = NULL;
if (lpmbp->cbSize != sizeof(MSGBOXPARAMS)) {
RIPMSG0(RIP_WARNING, "MessageBoxIndirect: Invalid cbSize");
}
RtlZeroMemory(&MsgBoxParams, sizeof(MsgBoxParams));
RtlCopyMemory(&MsgBoxParams, lpmbp, sizeof(MSGBOXPARAMS));
if (HIWORD(MsgBoxParams.lpszText)) {
if (!MBToWCS((LPSTR)MsgBoxParams.lpszText, -1, &lpwszText, -1, TRUE))
return 0;
MsgBoxParams.lpszText = lpwszText;
}
if (HIWORD(MsgBoxParams.lpszCaption)) {
if (!MBToWCS((LPSTR)MsgBoxParams.lpszCaption, -1, &lpwszCaption, -1, TRUE)) {
UserLocalFree(lpwszText);
return 0;
}
MsgBoxParams.lpszCaption = lpwszCaption;
}
retval = MessageBoxWorker(&MsgBoxParams);
if (lpwszText)
UserLocalFree(lpwszText);
if (lpwszCaption)
UserLocalFree(lpwszCaption);
return retval;
}
int MessageBoxIndirectW(
LPMSGBOXPARAMSW lpmbp)
{
MSGBOXDATA MsgBoxParams;
if (lpmbp->cbSize != sizeof(MSGBOXPARAMS)) {
RIPMSG0(RIP_WARNING, "MessageBoxIndirect: Invalid cbSize");
}
RtlZeroMemory(&MsgBoxParams, sizeof(MsgBoxParams));
RtlCopyMemory(&MsgBoxParams, lpmbp, sizeof(MSGBOXPARAMS));
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;
#ifdef DEBUG
if (dwStyle & ~MB_VALID) {
RIPMSG2(RIP_WARNING, "MessageBoxWorker: Invalid flags, %#lx & ~%#lx != 0",
dwStyle, MB_VALID);
}
#endif
/*
* 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) && (GetClientInfo()->dwExpWinVer < VER40)) {
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,
FALSE);
}
/*
* Make sure we have a valid window handle.
*/
if (pMsgBoxParams->hwndOwner && !IsWindow(pMsgBoxParams->hwndOwner)) {
RIPERR0(ERROR_INVALID_WINDOW_HANDLE, RIP_VERBOSE, "");
return 0;
}
/*
* If lpszCaption is NULL, then use "Error!" string as the caption
* string.
* LATER: IanJa localize according to wLanguageId
*/
if (pMsgBoxParams->lpszCaption == NULL) {
if (pMsgBoxParams->wLanguageId == 0) {
pMsgBoxParams->lpszCaption = szERROR;
} else {
RtlLoadStringOrError(hmodUser,
STR_ERROR,
szErrorBuf,
sizeof(szErrorBuf)/sizeof(WCHAR),
RT_STRING,
prescalls,
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);
}
}
}
/*
* 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++) {
/*
* Pick up the string for the button.
*/
if (pMsgBoxParams->wLanguageId == 0) {
apstrButton[i] = GETGPSIMBPSTR(SEBbuttons[wBtnBeg + i] - SEB_OK);
} 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...
*/
RtlLoadStringOrError(hmodUser,
gpsi->mpAllMBbtnStringsToSTR[SEBbuttons[wBtnBeg + i] - SEB_OK],
szButtonBuf,
sizeof(szButtonBuf)/sizeof(WCHAR),
RT_STRING,
prescalls,
pMsgBoxParams->wLanguageId);
/*
* If it didn't find the string, use the default language.
*/
if (*szButtonBuf) {
apstrButton[i] = TextAlloc(szButtonBuf);
} else {
apstrButton[i] = TextAlloc(GETGPSIMBPSTR(SEBbuttons[wBtnBeg + i] - SEB_OK));
RIPMSG2(RIP_WARNING, "MessageBoxWorker: string resource %#lx for language %#lx not found",
gpsi->mpAllMBbtnStringsToSTR[SEBbuttons[wBtnBeg + i] - SEB_OK],
pMsgBoxParams->wLanguageId);
}
}
aidButton[i] = rgReturn[wBtnBeg + i];
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.
*/
NtUserSetUserStartupInfoFlags(NtUserGetUserStartupInfoFlags() & ~STARTF_USESHOWWINDOW);
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 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;
dwStyleMsg = lpmb->dwStyle;
if (!HIWORD(lpmb->lpszCaption)) {
// won't ever be NULL because MessageBox sticks "Error!" in in that case
if (hInstMsg && (hCaption = LocalAlloc(LPTR, MAX_RES_STRING * sizeof(WCHAR)))) {
lpsz = (LPWSTR) hCaption;
LoadString(hInstMsg, LOWORD(lpmb->lpszCaption), lpsz, MAX_RES_STRING);
} else
lpsz = NULL;
lpmb->lpszCaption = lpsz ? lpsz : szEmpty;
}
if (!HIWORD(lpmb->lpszText)) {
// NULL not allowed
if (hInstMsg && (hText = LocalAlloc(LPTR, MAX_RES_STRING * sizeof(WCHAR)))) {
lpsz = (LPWSTR) hText;
LoadString(hInstMsg, LOWORD(lpmb->lpszText), lpsz, MAX_RES_STRING);
} else
lpsz = NULL;
lpmb->lpszText = lpsz ? lpsz : szEmpty;
}
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(GetClientInfo()->dwExpWinVer <= VER31)
{
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)))
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, 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.
//
CopyRect(&rcWork, &gpsi->rcWork);
cxMBMax = MultDiv(rcWork.right - rcWork.left, 5, 8);
cxFoo = 2*XPixFromXDU(DU_OUTERMARGIN, gpsi->cxMsgFontChar);
SelectObject(hdc, gpsi->hMsgFont);
//
// If the text doesn't fit in 5/8, try 7/8 of the screen
//
//#if defined(JAPAN) || defined(KOREA)
ReSize:
//#endif
//
// 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)
{
CopyRect(&rcWork, &rcScreen);
cxMBMax = MultDiv(rcWork.right - rcWork.left, 7, 8);
goto ReSize;
}
}
if (hFontOld)
SelectFont(hdc, hFontOld);
NtUserReleaseDC(NULL, hdc);
// Find the window position
xMB = (rcWork.left + rcWork.right - cxBox) / 2 + (gpsi->cntMBox * SYSMET(CXSIZE));
xMB = max(xMB, 0);
yMB = (rcWork.top + rcWork.bottom - cyBox) / 2 + (gpsi->cntMBox * SYSMET(CYSIZE));
yMB = max(yMB, 0);
// 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 = rcScreen.bottom - SYSMET(CYEDGE) - cyBox;
}
wTextLen = wcslen(lpmb->lpszText);
// Find out the memory required for the Dlg template and try to alloc it
hTemplate = LocalAlloc(LMEM_ZEROINIT, 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,
(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,
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
sizeof(OrdNum)/sizeof(WCHAR), // 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_OUTERMARGIN, gpsi->cxMsgFontChar);
}
MB_UpdateDlgItem((LPDLGITEMTEMPLATE)lpDlgTmp, -1, dwStyleText, xText,
YPixFromYDU(DU_OUTERMARGIN, gpsi->cyMsgFontChar) + cxFoo,
cxText, cyText,
(LPWSTR)lpmb->lpszText, wTextLen, STATICCODE);
}
// The dialog template is ready
NtUserCallNoParam(SFI_INCRMBOX);
try {
//
// Set the normal cursor
//
hcurOld = NtUserSetCursor(LoadCursor(NULL, IDC_ARROW));
lpmb->lpszIcon = (LPWSTR) hIcon; // BUGBUG - How to diff this from a resource?
if (!(lpmb->dwStyle & MB_USERICON))
{
UNICODE_STRING strSound;
int wBeep = (LOWORD(lpmb->dwStyle & MB_ICONMASK)) >> MB_MASKSHIFT;
if (!(wBeep >= (sizeof(iconsnd) / sizeof(WCHAR *)))) {
RtlInitUnicodeString(&strSound, iconsnd[wBeep]);
NtUserPlayEventSound(&strSound);
}
}
iRetVal = (int)InternalDialogBox(hmodUser, hTemplate, 0L, hwndOwner,
MB_DlgProcW, (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;
} finally {
NtUserCallNoParam(SFI_DECRMBOX);
}
//
// 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_UpdateDlgHdr
*
* History:
* 11-20-90 DarrinM Ported from Win 3.0 sources.
\***************************************************************************/
LPBYTE MB_UpdateDlgHdr(
LPDLGTEMPLATE lpDlgTmp,
long lStyle,
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 = 0;
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),
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,
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 = 0;
/*
* 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) {
/*
* 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 )
{
UINT cbLen;
UINT cbT;
UINT i;
UINT wCount;
wCount = lpmb->cButtons;
/*
* Start with dialog header's size.
*/
cbLen = (UINT)NextWordBoundary(sizeof(DLGTEMPLATE) + sizeof(WCHAR));
cbLen = (UINT)NextWordBoundary(cbLen + sizeof(WCHAR));
cbLen += wcslen(lpmb->lpszCaption) * sizeof(WCHAR) + sizeof(WCHAR);
cbLen += sizeof(WORD); // Font height
cbLen = (UINT)NextDWordBoundary(cbLen);
/*
* Check if an Icon is present.
*/
if (lpmb->dwStyle & MB_ICONMASK)
cbLen += (UINT)NextDWordBoundary(sizeof(DLGITEMTEMPLATE) + 7 * sizeof(WCHAR));
/*
* Find the number of buttons in the msg box.
*/
for (i = 0; i < wCount; i++) {
cbLen = (UINT)NextWordBoundary(cbLen + sizeof(DLGITEMTEMPLATE) +
(2 * sizeof(WCHAR)));
cbT = (wcslen(lpmb->ppszButtonText[i]) + 1) * sizeof(WCHAR);
cbLen = (UINT)NextWordBoundary(cbLen + cbT);
cbLen += sizeof(WCHAR);
cbLen = (UINT)NextDWordBoundary(cbLen);
}
/*
* Add in the space required for the text message (if there is one).
*/
if (lpmb->lpszText != NULL) {
cbLen = (UINT)NextWordBoundary(cbLen + sizeof(DLGITEMTEMPLATE) +
(2 * sizeof(WCHAR)));
cbT = (wcslen(lpmb->lpszText) + 1) * sizeof(WCHAR);
cbLen = (UINT)NextWordBoundary(cbLen + cbT);
cbLen += sizeof(WCHAR);
cbLen = (UINT)NextDWordBoundary(cbLen);
}
return 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 (UINT)IDI_HAND;
case MB_ICONQUESTION:
return (UINT)IDI_QUESTION;
case MB_ICONEXCLAMATION:
return (UINT)IDI_EXCLAMATION;
case MB_ICONASTERISK:
return (UINT)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.
\***************************************************************************/
LONG MB_DlgProcWorker(
HWND hwndDlg,
UINT wMsg,
DWORD wParam,
LONG lParam,
BOOL fAnsi)
{
HWND hwndT;
int iCount;
LPMSGBOXDATA lpmb;
HWND hwndOwner;
PVOID lpfnCallback;
PWND pwnd;
switch (wMsg) {
case WM_CTLCOLORDLG:
case WM_CTLCOLORSTATIC:
if ((pwnd = ValidateHwnd(hwndDlg)) == NULL)
return 0L;
return DefWindowProcWorker(pwnd, WM_CTLCOLORMSGBOX,
wParam, lParam, fAnsi);
case WM_INITDIALOG:
lpmb = (LPMSGBOXDATA)lParam;
SetWindowLong(hwndDlg, GWL_USERDATA, (DWORD)lParam);
if (lpmb->dwStyle & MB_HELP) {
NtUserSetWindowContextHelpId(hwndDlg, lpmb->dwContextHelpId);
//See if there is an app supplied callback.
if(lpmb->lpfnMsgBoxCallback)
SetProp(hwndDlg, MAKEINTATOM(atomMsgBoxCallback),
lpmb->lpfnMsgBoxCallback);
}
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);
#ifdef LATER
// darrinm - 06/17/91
// SYSMODAL dialogs are history for now.
/*
* Check if the Dialog box is a Sys Modal Dialog Box
*/
if (GetWindowLong(hwndDlg, GWL_STYLE) & DS_SYSMODAL, FALSE)
SetSysModalWindow(hwndDlg);
#endif
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);
//
// 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);
UserAssert(hwndDlg != NULL);
if (hwndDlg != NULL)
// hwndDlg->hMenu = (HMENU)IDCANCEL;
SetWindowLong(hwndDlg, GWL_ID, IDCANCEL);
}
/*
* 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:
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
if(!(lpfnCallback = (PVOID)GetProp(hwndDlg,
MAKEINTATOM(atomMsgBoxCallback)))) {
// If not, see if we need to inform the parent.
hwndOwner = GetWindow(hwndDlg, GW_OWNER);
#ifdef LATER
// Chicagoism
if (hwndOwner && hwndOwner == GetDesktopWindow())
hwndOwner = NULL;
#endif
}
// 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;
default:
return FALSE;
}
return TRUE;
}
LONG WINAPI MB_DlgProcA(
HWND hwnd,
UINT message,
WPARAM wParam,
LPARAM lParam)
{
return MB_DlgProcWorker(hwnd, message, wParam, lParam, TRUE);
}
LONG WINAPI MB_DlgProcW(
HWND hwnd,
UINT message,
WPARAM wParam,
LPARAM lParam)
{
return MB_DlgProcWorker(hwnd, message, wParam, lParam, FALSE);
}
/***************************************************************************\
* 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;
PTHREADINFO pti;
/*
* Get the hwnd list. It is returned in a block of memory
* allocated with LocalAlloc.
*/
if ((cHwnd = BuildHwndList(NULL, NULL, FALSE, 0, &phwndList)) == 0) {
return;
}
pti = PtiCurrent();
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 (GETPTI(pwnd) == pti && !TestWF(pwnd, WFDISABLED) &&
DIFFWOWHANDLE(hwnd, hwndDlg)) {
NtUserEnableWindow(hwnd, FALSE);
} else {
*phwnd = NULL;
}
}
SetProp(hwndDlg, MAKEINTATOM(atomBwlProp), (HANDLE)phwndList);
}
/***************************************************************************\
* EndTaskModalDialog
*
* History:
* 11-20-90 DarrinM Ported from Win 3.0 sources.
\***************************************************************************/
void EndTaskModalDialog(
HWND hwndDlg)
{
HWND *phwnd;
HWND *phwndList;
HWND hwnd;
phwndList = (HWND *)GetProp(hwndDlg, MAKEINTATOM(atomBwlProp));
if (phwndList == NULL)
return;
RemoveProp(hwndDlg, MAKEINTATOM(atomBwlProp));
for (phwnd = phwndList; *phwnd != (HWND)1; phwnd++) {
if ((hwnd = *phwnd) != NULL) {
NtUserEnableWindow(hwnd, TRUE);
}
}
UserLocalFree(phwndList);
}