#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <ntstatus.h>
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <conapi.h>
#include "insignia.h"
#include "host_def.h"
/*
* SoftPC Revision 2.0
*
* Title : General Error Handler
*
* Description : General purpose error handler. It handles both
* general SoftPC errors (error numbers 0 - 999) and
* host specific errors (error numbers >= 1000)
*
* Author(s) : Dave Bartlett (based on module by John Shanly)
*
* Parameters : int used to index an array of error messages
* held in message.c, and a bit mask indicating
* the user's possible options:
* Quit, Reset, Continue, Setup
*
*/
#include <sys/types.h>
#include <string.h>
#include <malloc.h>
#include <stdio.h>
#include "xt.h"
#include CpuH
#include "sas.h"
#include "bios.h"
#include "ios.h"
#include "gvi.h"
#include "error.h"
#include "config.h"
#include "dterm.h"
#include "host_rrr.h"
#include "host_nls.h"
#include "nt_graph.h"
#include "nt_uis.h"
#include "nt_reset.h"
#include "ckmalloc.h"
#include "trace.h"
#include "nt_event.h"
extern VOID (*pW32HungAppNotifyThread)(UINT);
int error_window_options = 0;
VOID SuspendTimerThread(VOID);
VOID ResumeTimerThread(VOID);
/*::::::::::::::::::::::::::::::::: Internally used variables and functions */
typedef struct _ErrorDialogBoxInfo{
DWORD dwOptions;
DWORD dwReply;
HWND hWndCon;
char *message;
char *pEdit;
char Title[MAX_PATH];
}ERRORDIALOGINFO, *PERRORDIALOGINFO;
char achPERIOD[]=". ";
/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: STDOUT macro */
#define ERRORMSG OutputDebugString
#define HIDEDLGITM(d,b) ShowWindow(GetDlgItem(d,b),SW_HIDE);
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
int ErrorDialogBox(char *message, char *Edit, DWORD dwOptions);
DWORD ErrorDialogBoxThread(VOID *pv);
int WowErrorDialogEvents(ERRORDIALOGINFO *pedgi);
LONG APIENTRY ErrorDialogEvents(HWND hDlg,WORD wMsg,LONG wParam,LONG lParam);
void SwpButtons(HWND hDlg, DWORD dwOptions);
void SwpDosDialogs(HWND hDlg, HWND hWndCon,HWND SwpInsert, UINT SwpFlags);
DWORD OemMessageToAnsiMessage(CHAR *, CHAR *);
DWORD AnsiMessageToOemMessage(CHAR *pBuff, CHAR *pMsg);
ULONG WOWpSysErrorBox(LPSTR,LPSTR,USHORT,USHORT,USHORT);
#ifndef MONITOR
/*
* Do things the old fashioned way for some of the cpu building tools
* which cannot be changed to match our host
*/
#ifdef host_error_ext
#undef host_error_ext
#endif
SHORT host_error_ext(int error_num, int options, ErrDataPtr data)
{
return host_error(error_num, options, NULL);
}
#ifdef host_error
#undef host_error
#endif
SHORT host_error(int error_num, int options, char *extra_char);
#ifdef host_error_conf
#undef host_error_conf
#endif
SHORT host_error_conf(int config_panel, int error_num, int options,
char *extra_char)
{
return host_error(error_num, options, extra_char);
}
ERRORFUNCS nt_error_funcs = { host_error_conf,host_error,host_error_ext};
ERRORFUNCS *working_error_funcs = &nt_error_funcs;
#endif
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
/*:::::::::::::::::::::: Display error, terminate ::::::::::::::::::::::::::*/
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
int DisplayErrorTerm(int ErrorNo, /* Softpc Error number */
DWORD OSErrno, /* OS Error number */
char *Filename, /* File name of file containing err */
int Lineno) /* LIne number of error */
{
char Msg[EHS_MSG_LEN];
DWORD errno, len;
UNUSED(ErrorNo); //Always internal error
#ifndef PROD
sprintf(Msg,"NTVDM:ErrNo %#x, %s:%d\n", OSErrno, Filename, Lineno);
OutputDebugString(Msg);
#endif
// assume NT error if either of top two bits set (err or warning).
// this means we'll confuse some of the lesser NT errors but we get a
// second chance if the mapping fails.
if (OSErrno & 0xc0000000)
errno = RtlNtStatusToDosError(OSErrno);
else
errno = OSErrno;
// Now get message from system
len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
errno,
0,
Msg,
EHS_MSG_LEN,
NULL
);
if (!len) {
sprintf(Msg, "%s %lxh", szSysErrMsg, OSErrno);
}
return(host_error(EHS_SYSTEM_ERROR, ERR_QUIT, Msg));
}
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
/*:::::::::::::::::::::::::::: Display host error ::::::::::::::::::::::::::*/
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
SHORT host_error(int error_num, int options, char *extra_char)
{
char message[EHS_MSG_LEN];
host_nls_get_msg(error_num, message, EHS_MSG_LEN);
if (extra_char && *extra_char) {
strcat(message,"\n");
strcat(message,extra_char);
}
#ifndef PROD
OutputDebugString(message);
if (extra_char) {
OutputDebugString("\n");
}
#endif
ErrorDialogBox(message, NULL, RMB_ICON_STOP | RMB_ABORT | RMB_IGNORE);
return ERR_CONT;
}
DWORD TlsDirectError;
//
// Called directly from C or via bop. Type checked against global 'DirectError'
// to see if called already in this app. 'DirectError' cleared on VDM resume.
//
// This function is expected to be called by 16 bit threads
// which is doing the unsupported service. For DosApps this is
// the CPU thread, For WOW this is one of the individual 16 bit tasks.
//
//
VOID host_direct_access_error(ULONG type)
{
CHAR message[EHS_MSG_LEN];
CHAR acctype[EHS_MSG_LEN];
CHAR dames[EHS_MSG_LEN];
DWORD dwDirectError;
/*
* Get the direct error record for the current thread
* if TlsGetValue returns NULL
* - could be invalid index (TlsAlloc failed)
* - actual value is 0, (no bits set)
* In both cases we will go ahead with the popup
*/
dwDirectError = (DWORD)TlsGetValue(TlsDirectError);
// don't annoy user with repeated popups
if ((dwDirectError & (1<<type)) != 0)
return;
TlsSetValue(TlsDirectError, (LPVOID)(dwDirectError | (1 << type)));
if (LoadString(GetModuleHandle(NULL), D_A_MESS,
dames, sizeof(dames)/sizeof(CHAR)) &&
LoadString(GetModuleHandle(NULL), D_A_MESS + type + 1,
acctype, sizeof(acctype)/sizeof(CHAR)) )
{
sprintf(message, dames, acctype);
}
else {
strcpy(message, szDoomMsg);
}
ErrorDialogBox(message, NULL, RMB_ICON_STOP | RMB_ABORT | RMB_IGNORE);
}
/*
* RcErrorDialogBox
*
* Displays standard dialog Box for errors and warnings
* Looks up the error message from ntvdm's reource string table
*
* entry: UINT wId - string table resource index
* CHAR *msg1 - Optional OEM strings which are displayed
* CHAR *msg2 before the main error message. Each string
* is limited to MAX_PATH inclusive of NULL,
* (auto-truncate).
*
* exit:
*
*/
void RcErrorDialogBox(UINT wId, CHAR *msg1, CHAR *msg2)
{
DWORD dw, dwTotal;
CHAR ErrMsg[MAX_PATH*4];
dwTotal = 0;
dw = OemMessageToAnsiMessage(ErrMsg, msg1);
if (dw) {
dwTotal += dw;
strcpy(&ErrMsg[dwTotal], achPERIOD);
dwTotal += sizeof(achPERIOD) - 1;
}
dw = OemMessageToAnsiMessage(&ErrMsg[dwTotal], msg2);
if (dw) {
dwTotal += dw;
strcpy(&ErrMsg[dwTotal], achPERIOD);
dwTotal += sizeof(achPERIOD) - 1;
}
if (!LoadString(GetModuleHandle(NULL), wId, &ErrMsg[dwTotal], MAX_PATH))
{
strcpy(ErrMsg, szDoomMsg);
}
ErrorDialogBox(ErrMsg, NULL, RMB_ICON_STOP | RMB_ABORT | RMB_IGNORE);
}
/*
* RcMessageBox
*
* Displays standard dialog Box for errors and warnings
* Looks up the error message from ntvdm's reource string table
*
* Optionally shows an edit dialog control. The edit control
* is placed just below the first line of the message text,
* leaving only enuf space to display a one line message.
*
* entry: UINT wId - string table resource index
* CHAR *msg1 - Optional OEM strings which are displayed
* CHAR *msg2 before the main error message. Each string
* is limited to MAX_PATH inclusive of NULL,
* (auto-truncate).
*
* If RMB_EDIT is specified msg2 is NOT used for messages
* to be displayed, rather is used for the default string for the
* edit control. The hiword of dwOPtions is used as max size of
* edit buffer, and must be less than MAX_PATH
*
* DWORD dwOptions - accepts
* RMB_ABORT
* RMB_RETRY
* RMB_IGNORE msg box equivalent
* RMB_ICON_INFO - IDI_ASTERICK
* RMB_ICON_BANG - IDI_EXCLAMATION
* RMB_ICON_STOP - IDI_HAND
* RMB_ICON_WHAT - IDI_QUESTION
* RMB_EDIT - edit dialog control
*
* exit: returns RMB_ABORT RMB_RETRY RMB_IGNORE RMB_EDIT
* If RMB_EDIT is specified msg2 is used to return
* the contents of the edit control
*
*/
int RcMessageBox(UINT wId, CHAR *msg1, CHAR *msg2, DWORD dwOptions)
{
DWORD dw, dwTotal;
char *pEdit;
CHAR ErrMsg[MAX_PATH*4];
CHAR Edit[MAX_PATH];
int i;
dwTotal = 0;
dw = OemMessageToAnsiMessage(ErrMsg, msg1);
if (dw) {
dwTotal += dw;
strcpy(&ErrMsg[dwTotal], achPERIOD);
dwTotal += sizeof(achPERIOD) - 1;
}
if (dwOptions & RMB_EDIT) {
dw = OemMessageToAnsiMessage(Edit, msg2);
pEdit = Edit;
}
else {
dw = OemMessageToAnsiMessage(&ErrMsg[dwTotal], msg2);
if (dw) {
dwTotal += dw;
strcpy(&ErrMsg[dwTotal], achPERIOD);
dwTotal += sizeof(achPERIOD) - 1;
}
pEdit = NULL;
}
if (!LoadString(GetModuleHandle(NULL), wId, &ErrMsg[dwTotal], MAX_PATH))
{
strcpy(ErrMsg, szDoomMsg);
}
i = ErrorDialogBox(ErrMsg, pEdit, dwOptions);
if (pEdit) {
AnsiMessageToOemMessage(msg2, pEdit);
}
return i;
}
/*
* AnsiMessageToOemMessage
*
* converts string messages from ansi to oem strings, for display output
*
* entry: CHAR *msg
* Each string is limited to MAX_PATH inclusive of NULL,
* (auto-truncate).
*
* CHAR *pBuff - destination buffer, must be at least MAX_PATH
*
* exit: returns string len
*/
DWORD AnsiMessageToOemMessage(CHAR *pBuff, CHAR *pMsg)
{
PUNICODE_STRING pUnicode;
ANSI_STRING AnsiString;
OEM_STRING OemString;
if (!pBuff)
return 0;
if (!pMsg || !*pMsg) {
*pBuff = '\0';
return 0;
}
RtlInitString(&AnsiString, pMsg);
if (AnsiString.Length > MAX_PATH) {
AnsiString.Length = MAX_PATH-1;
AnsiString.MaximumLength = MAX_PATH;
}
OemString.MaximumLength = AnsiString.MaximumLength;
OemString.Buffer = pBuff;
*(OemString.Buffer+AnsiString.Length) = '\0';
pUnicode = &NtCurrentTeb()->StaticUnicodeString;
if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(pUnicode,
&AnsiString,
FALSE)) ||
!NT_SUCCESS(RtlUnicodeStringToOemString((POEM_STRING)&OemString,
pUnicode,
FALSE)) )
{
OemString.Length = 0;
}
return OemString.Length;
}
/*
* OemMessageToAnsiMessage
*
* converts string messages from oem to ansi strings, for display output
*
* entry: CHAR *msg
* Each string is limited to MAX_PATH inclusive of NULL,
* (auto-truncate).
*
* CHAR *pBuff - destination buffer, must be at least MAX_PATH
*
* exit: returns string len
*/
DWORD OemMessageToAnsiMessage(CHAR *pBuff, CHAR *pMsg)
{
PUNICODE_STRING pUnicode;
ANSI_STRING AnsiString;
OEM_STRING OemString;
if (!pBuff)
return 0;
if (!pMsg || !*pMsg) {
*pBuff = '\0';
return 0;
}
RtlInitString(&OemString, pMsg);
if (OemString.Length > MAX_PATH) {
OemString.Length = MAX_PATH-1;
OemString.MaximumLength = MAX_PATH;
}
AnsiString.MaximumLength = OemString.MaximumLength;
AnsiString.Buffer = pBuff;
*(AnsiString.Buffer+OemString.Length) = '\0';
pUnicode = &NtCurrentTeb()->StaticUnicodeString;
if (!NT_SUCCESS(RtlOemStringToUnicodeString(pUnicode,
&OemString,
FALSE)) ||
!NT_SUCCESS(RtlUnicodeStringToAnsiString((POEM_STRING)&AnsiString,
pUnicode,
FALSE)) )
{
AnsiString.Length = 0;
}
return AnsiString.Length;
}
/*
* Thread call back function for EnumThreadWindows
* entry: HWND hWnd - window handle to verify
* LPARAM lParam - address of edgi->hWnd == ThreadID
*
* exit: TRUE - to continue enumeration
* FALSE - edgi->hWnd has window handle for TopLevelWindow of thread
*
*/
BOOL CALLBACK GetThreadTopLevelWindow(HWND hWnd, LPARAM lParam)
{
PDWORD pdw = (PDWORD)lParam;
if (GetWindowThreadProcessId(hWnd, NULL) == *pdw)
{
*pdw = (DWORD)hWnd;
return FALSE;
}
return TRUE;
}
/* ErrorDialogBox
*
* Displays standard dialog Box for errors and warnings
*
*/
int ErrorDialogBox(char *message, char *pEdit, DWORD dwOptions)
{
static BOOL bCalled=0;
HANDLE hThread = NULL;
HWND hWndApp;
DWORD dwThreadID, dw;
ERRORDIALOGINFO edgi;
if (bCalled) { // recursive call, so stop annoying the user
return RMB_IGNORE;
}
bCalled++;
/* Raid HotFix 3381 - alpha stress hang. All RISC implementations.
* If we leave the heartbeat generating timer hardware interrupts
* all of the time, we will continually add quick events which
* don't go off until the popup is dismissed. This will suck up
* local heap and CPU at a hipriority.
*/
SuspendTimerThread();
// init err dialog info
edgi.message = message;
edgi.dwReply = 0;
edgi.hWndCon = hWndConsole;
edgi.dwOptions = dwOptions;
edgi.pEdit = pEdit;
// get window handle for the offending app
if (VDMForWOW) {
hWndApp = (HWND)GetCurrentThreadId();
EnumWindows((WNDENUMPROC)GetThreadTopLevelWindow,(LPARAM)&hWndApp);
if (hWndApp == (HWND)GetCurrentThreadId()) {
hWndApp = HWND_DESKTOP;
}
}
else {
hWndApp = edgi.hWndCon;
}
//
// get title of app, using DefWindowProc in lieu of
// GetWindowText to avoid callbacks into threads window proc
//
if (hWndApp == HWND_DESKTOP ||
!DefWindowProc(hWndApp, WM_GETTEXT,
(WPARAM) (sizeof(edgi.Title)-1),
(LPARAM) edgi.Title) )
{
edgi.Title[0] = '\0';
}
//
// spin off a separate thread, why ?
// For DOS, to avoid suspended threads during full screen switching
// For Wow required for task termination if user chooses terminate.
//
dw = 5;
do {
hThread = CreateThread(NULL, // security
0, // stack size
ErrorDialogBoxThread, // start address
&edgi, // thread argument
0, // flags
&dwThreadID // gets thread ID
);
if (hThread)
break;
else
Sleep(2000);
} while (dw--);
if (hThread) {
do {
dw = WaitForSingleObject(hThread, 1000);
} while (dw == WAIT_TIMEOUT && !edgi.dwReply);
CloseHandle(hThread);
ResumeTimerThread();
if (edgi.dwReply == RMB_ABORT)
//
// The wow termination will occur via the ErrorDialogBoxThread
// as it calls the HungAppNotifyThread. Befotrewe return give
// wow a chance to set up for termination.
//
if (VDMForWOW) {
Sleep(10);
}
//
// If a dos app terminate now!
//
else {
TerminateVDM();
}
}
else {
#ifndef PROD
printf("CreateThread(ErrorDialogBoxThread) GLE=%d\n", GetLastError());
printf("NTVDM:<%s>\n<%s>\n", edgi.Title, edgi.message );
HostDebugBreak();
#endif
ResumeTimerThread();
//
// If we can't create a thread, we are in a pretty bad way
// wow: ignore error, since not alllowed to kill WOW ssystem
// dos: terminate the VDM
//
if (!VDMForWOW)
TerminateVDM();
}
bCalled--;
return (int) edgi.dwReply;
}
/* ErrorDialogBoxThread
*
* Worker routine for ErrorDialogBox. In WOW VDMs this function is
* run as its own thread. For other VDMs it is called directly.
*
* WOW: If the user chooses terminate, it will not return.
*
* exit: fills in pedgi.dwReply with ret code from DialogBoxParam
* IDB_QUIT, IDB_CONTINUE
*/
DWORD ErrorDialogBoxThread(VOID *pv)
{
int i;
ERRORDIALOGINFO *pedgi = pv;
char *pch;
char *pLast;
// skip leading white space
pch = pedgi->Title;
while (*pch && !isgraph(*pch)) {
pch++;
}
// move string to beg of buffer, strip trailing white space
i = 0;
pLast = pedgi->Title;
while (*pch) {
pedgi->Title[i++] = *pch;
if (isgraph(*pch)) {
pLast = &pedgi->Title[i];
}
pch++;
}
*pLast = '\0';
if (VDMForWOW) {
i = WowErrorDialogEvents(pedgi);
}
else {
if (pedgi->hWndCon != HWND_DESKTOP) {
SetForegroundWindow(pedgi->hWndCon);
}
i = DialogBoxParam(GetModuleHandle(NULL),
"ERRORPANEL",
GetDesktopWindow(),
(DLGPROC) ErrorDialogEvents,
(LPARAM) pedgi
);
}
if (i == RMB_ABORT || i == -1) {
pedgi->dwReply = RMB_ABORT;
if (VDMForWOW && pW32HungAppNotifyThread) {
(*pW32HungAppNotifyThread)(0); // we won't return from this
}
}
else {
pedgi->dwReply = i;
}
return 0;
}
LONG APIENTRY ErrorDialogEvents(HWND hDlg,WORD wMsg,LONG wParam,LONG lParam)
{
ERRORDIALOGINFO *pedgi;
CHAR szBuff[MAX_PATH];
int i;
LPSTR lpstr;
LONG l;
/*:::::::::::::::::::::::::::::::::::::::::::::::::::: Process messages */
switch(wMsg)
{
/*:::::::::::::::::::::::::::::::::::::: Initialise Dialog controls */
case WM_INITDIALOG:
pedgi = (PERRORDIALOGINFO) lParam;
// set the desired icon
switch (pedgi->dwOptions & (RMB_ICON_INFO | RMB_ICON_BANG |
RMB_ICON_STOP | RMB_ICON_WHAT))
{
case RMB_ICON_STOP: lpstr = NULL; break;
case RMB_ICON_INFO: lpstr = IDI_ASTERISK; break;
case RMB_ICON_BANG: lpstr = IDI_EXCLAMATION; break;
case RMB_ICON_WHAT: lpstr = IDI_QUESTION; break;
default: lpstr = IDI_APPLICATION; break;
}
if (lpstr) { // default is STOP sign
SendDlgItemMessage(hDlg, IDE_ICON, STM_SETICON,
(WPARAM)LoadIcon(NULL,lpstr), 0);
}
SwpButtons(hDlg, pedgi->dwOptions);
// set Edit control message if we have one
if (pedgi->dwOptions & RMB_EDIT) {
SetWindowText(GetDlgItem(hDlg,IDE_EDIT), pedgi->pEdit);
if (*pedgi->pEdit) {
SendDlgItemMessage(hDlg, IDE_EDIT,
EM_SETSEL,
(WPARAM)0,
(LPARAM)strlen(pedgi->pEdit));
}
SendDlgItemMessage(hDlg, IDE_EDIT,
EM_LIMITTEXT,
(WPARAM)HIWORD(pedgi->dwOptions),
(LPARAM)0);
}
else {
ShowWindow(GetDlgItem(hDlg,IDE_EDIT), SW_HIDE);
}
// set err message text
SetWindowText(GetDlgItem(hDlg,IDE_ERRORMSG), pedgi->message);
// set app title text
if (*pedgi->Title) {
sprintf(szBuff,
strlen(pedgi->Title) < 80 ? "\n%s" : "%s",
pedgi->Title);
SetWindowText(GetDlgItem(hDlg,IDE_APPTITLE), szBuff);
}
SwpDosDialogs(hDlg, pedgi->hWndCon, HWND_TOPMOST, 0);
SetWindowLong(hDlg, DWL_USER, (LONG)pedgi);
break;
/*:::::::::::::::::::::::::::::::: Trap and process button messages */
case WM_COMMAND:
pedgi = (PERRORDIALOGINFO)GetWindowLong(hDlg,DWL_USER);
i = (int) LOWORD(wParam);
switch (i) {
case IDB_QUIT:
if (pedgi->pEdit) {
*pedgi->pEdit = '\0';
}
EndDialog(hDlg,RMB_ABORT);
break;
case IDB_RETRY:
if (pedgi->pEdit) {
*pedgi->pEdit = '\0';
}
EndDialog(hDlg,RMB_RETRY);
break;
case IDCANCEL:
case IDB_CONTINUE:
if (pedgi->pEdit) {
*pedgi->pEdit = '\0';
}
EndDialog(hDlg,RMB_IGNORE);
break;
case IDB_OKEDIT:
if (pedgi->pEdit) {
l = SendDlgItemMessage(hDlg, IDE_EDIT,
WM_GETTEXT,
(WPARAM)HIWORD(pedgi->dwOptions),
(LPARAM)pedgi->pEdit);
if (!l)
*(pedgi->pEdit) = '\0';
}
EndDialog(hDlg, RMB_EDIT);
break;
default:
return(FALSE);
}
/*:::::::::::::::::::::::::::::::::::::::::: Not processing message */
default:
return(FALSE); /* Message not processed */
}
return TRUE;
}
/*
* SwpButtons - SetWindowPos\showstate for the vraious buttons
*
* entry: HWND hDlg, - DialogBox window handle
* DWORD dwOptions
*
*/
void SwpButtons(HWND hDlg, DWORD dwOptions)
{
RECT rect;
POINT point;
long DlgWidth, ButWidth, xOrg, xIncr, yClientPos;
WORD wButtons;
// count number of buttons being shown
wButtons = 0;
if (dwOptions & RMB_ABORT) {
wButtons++;
}
if (dwOptions & RMB_RETRY) {
wButtons++;
}
if (dwOptions & RMB_IGNORE) {
wButtons++;
}
if (dwOptions & RMB_EDIT) {
wButtons++;
}
// figure out where first button goes,
// and how much space between buttons
GetWindowRect(GetDlgItem(hDlg,IDB_QUIT), &rect);
point.x = rect.left;
point.y = rect.top;
ScreenToClient(hDlg, &point);
DlgWidth = point.x;
GetWindowRect(GetDlgItem(hDlg,IDB_OKEDIT), &rect);
point.x = rect.right;
point.y = rect.top;
ScreenToClient(hDlg, &point);
DlgWidth = point.x - DlgWidth;
yClientPos = point.y;
ButWidth = rect.right - rect.left;
xIncr = ButWidth + ButWidth/2;
if (wButtons & 1) { // odd number of buttons
xOrg = (DlgWidth - ButWidth)/2;
if (wButtons > 1)
xOrg -= xIncr;
}
else { // even number of buttons
xOrg = DlgWidth/2 - (ButWidth + ButWidth/4);
if (wButtons == 4)
xOrg -= xIncr;
}
// set each of the buttons in their correct place
if (dwOptions & RMB_ABORT) {
SetWindowPos(GetDlgItem(hDlg,IDB_QUIT), 0,
xOrg, yClientPos, 0,0,
SWP_NOSIZE | SWP_NOZORDER);
xOrg += xIncr;
}
else {
ShowWindow(GetDlgItem(hDlg,IDB_QUIT), SW_HIDE);
}
if (dwOptions & RMB_RETRY) {
SetWindowPos(GetDlgItem(hDlg,IDB_RETRY), 0,
xOrg, yClientPos, 0,0,
SWP_NOSIZE | SWP_NOZORDER);
xOrg += xIncr;
}
else {
ShowWindow(GetDlgItem(hDlg,IDB_RETRY), SW_HIDE);
}
if (dwOptions & RMB_IGNORE) {
SetWindowPos(GetDlgItem(hDlg,IDB_CONTINUE), 0,
xOrg, yClientPos, 0,0,
SWP_NOSIZE | SWP_NOZORDER);
xOrg += xIncr;
}
else {
ShowWindow(GetDlgItem(hDlg,IDB_CONTINUE), SW_HIDE);
}
if (dwOptions & RMB_EDIT) {
SetWindowPos(GetDlgItem(hDlg,IDB_OKEDIT), 0,
xOrg, yClientPos, 0,0,
SWP_NOSIZE | SWP_NOZORDER);
xOrg += xIncr;
// if we have edit control, its button is awlays
// the default button
SendMessage(hDlg, DM_SETDEFID,
(WPARAM)IDB_OKEDIT,
(LPARAM)0);
}
else {
ShowWindow(GetDlgItem(hDlg,IDB_OKEDIT), SW_HIDE);
}
}
/*
* SwpDosDialogs - SetWindowPos for Dos Dialogs
*
* used by Dos dialog procedures to position themselves
* relative to the current Dos session
*
* entry: HWND hDlg, - DialogBox window handle
* HWND hWndCon, - Window handle for dos session
* HWND SwpInsert, - SetWindowPos's placement order handle
* UINT SwpFlags - SetWindowPos's window positioning flags
*/
void SwpDosDialogs(HWND hDlg, HWND hWndCon,
HWND SwpInsert, UINT SwpFlags)
{
RECT rDeskTop, rDosSess;
long DlgWidth,DlgHeight;
GetWindowRect(GetDesktopWindow(), &rDeskTop);
GetWindowRect(hDlg, &rDosSess);
DlgWidth = rDosSess.right - rDosSess.left;
DlgHeight = rDosSess.bottom - rDosSess.top;
// center the dialog, if no hWnd for console
if (hWndCon == HWND_DESKTOP) {
rDosSess.left = (rDeskTop.right - DlgWidth)/2;
rDosSess.top = (rDeskTop.bottom - DlgHeight)/2;
}
// pos relative to console window, staying on screen
else {
GetWindowRect(hWndCon, &rDosSess);
rDosSess.left += (rDosSess.right - rDosSess.left - DlgWidth)/3;
if (rDosSess.left + DlgWidth > rDeskTop.right) {
rDosSess.left = rDeskTop.right - DlgWidth - GetSystemMetrics(SM_CXICONSPACING)/2;
}
if (rDosSess.left < rDeskTop.left) {
rDosSess.left = rDeskTop.left + GetSystemMetrics(SM_CXICONSPACING)/2;
}
rDosSess.top += DlgHeight/4;
if (rDosSess.top + DlgHeight > rDeskTop.bottom) {
rDosSess.top = rDeskTop.bottom - DlgHeight - GetSystemMetrics(SM_CYICONSPACING)/2;
}
if (rDosSess.top < rDeskTop.top) {
rDosSess.top = rDeskTop.top + GetSystemMetrics(SM_CYICONSPACING)/2;
}
}
SetWindowPos(hDlg, SwpInsert,
rDosSess.left, rDosSess.top,0,0,
SWP_NOSIZE | SwpFlags);
}
/*
* WowErrorDialogEvents
*
* Uses WOWpSysErrorBox, to safely create a message box on WOW
* Replaces the functionality of the User mode DialogBox
* "ErrorDialogEvents"
*/
int WowErrorDialogEvents(ERRORDIALOGINFO *pedgi)
{
CHAR szTitle[MAX_PATH];
CHAR szMsg[EHS_MSG_LEN];
USHORT wButt1, wButt2, wButt3;
if (*pedgi->Title) {
sprintf(szMsg, "%s\n", pedgi->Title);
}
else {
szMsg[0] = '\0';
}
strcat(szMsg, pedgi->message);
strcat(szMsg, " ");
if (!LoadString(GetModuleHandle(NULL), ED_WOWPROMPT,
szTitle, sizeof(szTitle) - 1))
{
szTitle[0] = '\0';
}
strcat(szMsg, szTitle);
if (!LoadString(GetModuleHandle(NULL), ED_WOWTITLE,
szTitle, sizeof(szTitle) - 1))
{
szTitle[0] = '\0';
}
wButt1 = pedgi->dwOptions & RMB_ABORT ? SEB_CLOSE : 0;
wButt2 = pedgi->dwOptions & RMB_RETRY ? SEB_RETRY : 0;
wButt3 = pedgi->dwOptions & RMB_IGNORE ? SEB_IGNORE : 0;
if (wButt1) {
wButt1 |= SEB_DEFBUTTON;
}
else if (wButt2) {
wButt1 |= SEB_DEFBUTTON;
}
else if (wButt3) {
wButt2 |= SEB_DEFBUTTON;
}
switch (WOWpSysErrorBox(szTitle,
szMsg,
wButt1,
wButt2,
wButt3) )
{
case 1:
return RMB_ABORT;
case 2:
return RMB_RETRY;
case 3:
return RMB_IGNORE;
}
return RMB_ABORT;
}
/*++
* WOWpSysErrorBox
*
* 32-bit Implementation of of SysErrorBox, which doesn't exist in Win32
* This is the only safe way to raise a message box for WOW, and is also
* safe to use for dos apps.
*
* History:
* 23-Mar-93 DaveHart Created
--*/
ULONG WOWpSysErrorBox(
LPSTR szTitle,
LPSTR szMessage,
USHORT wBtn1,
USHORT wBtn2,
USHORT wBtn3)
{
NTSTATUS Status;
ULONG dwParameters[4];
ULONG dwResponse;
ANSI_STRING AnsiString;
UNICODE_STRING UnicodeTitle;
UNICODE_STRING UnicodeMessage;
RtlInitAnsiString(&AnsiString, szTitle);
RtlAnsiStringToUnicodeString(&UnicodeTitle, &AnsiString, TRUE);
RtlInitAnsiString(&AnsiString, szMessage);
RtlAnsiStringToUnicodeString(&UnicodeMessage, &AnsiString, TRUE);
dwParameters[0] = ((ULONG)TRUE << 16) | (ULONG) wBtn1;
dwParameters[1] = ((ULONG)wBtn2 << 16) | (ULONG) wBtn3;
dwParameters[2] = (ULONG)&UnicodeTitle;
dwParameters[3] = (ULONG)&UnicodeMessage;
//
// OR in 0x10000000 to force the hard error through even if
// SetErrorMode has been called.
//
Status = NtRaiseHardError(
STATUS_VDM_HARD_ERROR | 0x10000000,
4,
1 << 2 | 1 << 3,
dwParameters,
0,
&dwResponse
);
RtlFreeUnicodeString(&UnicodeTitle);
RtlFreeUnicodeString(&UnicodeMessage);
return NT_SUCCESS(Status) ? dwResponse : 0;
}
/*
* Exported routine for wow32 to invoke a system error box
* Uses WowpSysErrorBox
*/
ULONG WOWSysErrorBox(
LPSTR szTitle,
LPSTR szMessage,
USHORT wBtn1,
USHORT wBtn2,
USHORT wBtn3)
{
ULONG ulRet;
SuspendTimerThread();
ulRet = WOWpSysErrorBox(szTitle,
szMessage,
wBtn1,
wBtn2,
wBtn3);
ResumeTimerThread();
return ulRet;
}
#ifndef PROD
/*
* HostDebugBreak
*
* Raises a breakpoint by creating an access violation
* to give us a chance to get into a user mode debugger
*
*/
void HostDebugBreak(void)
{
DbgBreakPoint();
}
#endif
VOID RcErrorBoxPrintf(UINT wId, CHAR *szMsg)
{
CHAR message[EHS_MSG_LEN];
CHAR acctype[EHS_MSG_LEN];
CHAR dames[EHS_MSG_LEN];
OemMessageToAnsiMessage(acctype, szMsg);
if (LoadString(GetModuleHandle(NULL),wId,
dames, sizeof(dames)/sizeof(CHAR)))
{
sprintf(message, dames, acctype);
}
else {
strcpy(message, szDoomMsg);
}
ErrorDialogBox(message, NULL, RMB_ICON_STOP | RMB_ABORT | RMB_IGNORE);
}