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.
374 lines
10 KiB
374 lines
10 KiB
/* Copyright (c) 1995, Microsoft Corporation, all rights reserved
|
|
**
|
|
** popupdlg.c
|
|
** UI helper library
|
|
** Popup dialog routines
|
|
** Listed alphabetically
|
|
**
|
|
** 08/25/95 Steve Cobb
|
|
*/
|
|
|
|
|
|
#include <nt.h> // NT declarations
|
|
#include <ntrtl.h> // NT general runtime-library
|
|
#include <nturtl.h> // NT user-mode runtime-library
|
|
#include <windows.h> // Win32 root
|
|
#include <lmerr.h> // LAN Manager errors
|
|
#include <lmcons.h> // LAN Manager constants
|
|
#include <stdarg.h> // To stop va_list argument warning only
|
|
#include <ras.h> // RAS API definitions
|
|
#include <raserror.h> // Win32 RAS error codes
|
|
#include <debug.h> // Trace/assert library
|
|
#include <nouiutil.h> // No-HWND utilities
|
|
#include <uiutil.h> // Our public header
|
|
|
|
|
|
/*----------------------------------------------------------------------------
|
|
** Error popup
|
|
**----------------------------------------------------------------------------
|
|
*/
|
|
|
|
int
|
|
ErrorDlgUtil(
|
|
IN HWND hwndOwner,
|
|
IN DWORD dwOperation,
|
|
IN DWORD dwError,
|
|
IN OUT ERRORARGS* pargs,
|
|
IN HINSTANCE hInstance,
|
|
IN DWORD dwTitle,
|
|
IN DWORD dwFormat )
|
|
|
|
/* Pops up a modal error dialog centered on 'hwndOwner'. 'DwOperation' is
|
|
** the string resource ID of the string describing the operation underway
|
|
** when the error occurred. 'DwError' is the code of the system or RAS
|
|
** error that occurred. 'Pargs' is a extended formatting arguments or
|
|
** NULL if none. 'hInstance' is the application/module handle where
|
|
** string resources are located. 'DwTitle' is the string ID of the dialog
|
|
** title. 'DwFormat' is the string ID of the error format title.
|
|
**
|
|
** Returns MessageBox-style code.
|
|
*/
|
|
{
|
|
TCHAR* pszUnformatted;
|
|
TCHAR* pszOp;
|
|
TCHAR szErrorNum[ 50 ];
|
|
TCHAR* pszError;
|
|
TCHAR* pszResult;
|
|
TCHAR* pszNotFound;
|
|
int nResult;
|
|
|
|
TRACE("ErrorDlgUtil");
|
|
|
|
/* A placeholder for missing strings components.
|
|
*/
|
|
pszNotFound = TEXT("");
|
|
|
|
/* Build the error number string.
|
|
*/
|
|
if (dwError > 0x7FFFFFFF)
|
|
wsprintf( szErrorNum, TEXT("0x%X"), dwError );
|
|
else
|
|
wsprintf( szErrorNum, TEXT("%u"), dwError );
|
|
|
|
/* Build the error text string.
|
|
*/
|
|
if (!GetErrorText( dwError, &pszError ))
|
|
pszError = pszNotFound;
|
|
|
|
/* Build the operation string.
|
|
*/
|
|
pszUnformatted = PszFromId( hInstance, dwOperation );
|
|
pszOp = pszNotFound;
|
|
|
|
if (pszUnformatted)
|
|
{
|
|
FormatMessage(
|
|
FORMAT_MESSAGE_FROM_STRING +
|
|
FORMAT_MESSAGE_ALLOCATE_BUFFER +
|
|
FORMAT_MESSAGE_ARGUMENT_ARRAY,
|
|
pszUnformatted, 0, 0, (LPTSTR )&pszOp, 1,
|
|
(va_list* )((pargs) ? pargs->apszOpArgs : NULL) );
|
|
|
|
Free( pszUnformatted );
|
|
}
|
|
|
|
/* Call MsgDlgUtil with the standard arguments plus any auxillary format
|
|
** arguments.
|
|
*/
|
|
pszUnformatted = PszFromId( hInstance, dwFormat );
|
|
pszResult = pszNotFound;
|
|
|
|
if (pszUnformatted)
|
|
{
|
|
MSGARGS msgargs;
|
|
|
|
ZeroMemory( &msgargs, sizeof(msgargs) );
|
|
msgargs.dwFlags = MB_ICONEXCLAMATION + MB_OK + MB_SETFOREGROUND;
|
|
msgargs.pszString = pszUnformatted;
|
|
msgargs.apszArgs[ 0 ] = pszOp;
|
|
msgargs.apszArgs[ 1 ] = szErrorNum;
|
|
msgargs.apszArgs[ 2 ] = pszError;
|
|
|
|
if (pargs)
|
|
{
|
|
msgargs.fStringOutput = pargs->fStringOutput;
|
|
|
|
CopyMemory( &msgargs.apszArgs[ 3 ], pargs->apszAuxFmtArgs,
|
|
3 * sizeof(TCHAR) );
|
|
}
|
|
|
|
nResult =
|
|
MsgDlgUtil(
|
|
hwndOwner, 0, &msgargs, hInstance, dwTitle );
|
|
|
|
Free( pszUnformatted );
|
|
|
|
if (pargs && pargs->fStringOutput)
|
|
pargs->pszOutput = msgargs.pszOutput;
|
|
}
|
|
|
|
if (pszOp != pszNotFound)
|
|
LocalFree( pszOp );
|
|
if (pszError != pszNotFound)
|
|
LocalFree( pszError );
|
|
|
|
return nResult;
|
|
}
|
|
|
|
|
|
BOOL
|
|
GetErrorText(
|
|
DWORD dwError,
|
|
TCHAR** ppszError )
|
|
|
|
/* Fill caller's '*ppszError' with the address of a LocalAlloc'ed heap
|
|
** block containing the error text associated with error 'dwError'. It is
|
|
** caller's responsibility to LocalFree the returned string.
|
|
**
|
|
** Returns true if successful, false otherwise.
|
|
*/
|
|
{
|
|
#define MAXRASERRORLEN 256
|
|
|
|
TCHAR szBuf[ MAXRASERRORLEN + 1 ];
|
|
DWORD dwFlags;
|
|
HANDLE hmodule;
|
|
DWORD cch;
|
|
|
|
/* Don't panic if the RAS API address is not loaded. Caller may be trying
|
|
** and get an error up during LoadRas.
|
|
*/
|
|
if ((Rasapi32DllLoaded() || RasRpcDllLoaded())
|
|
&& g_pRasGetErrorString
|
|
&& g_pRasGetErrorString(
|
|
(UINT )dwError, (LPTSTR )szBuf, MAXRASERRORLEN ) == 0)
|
|
{
|
|
/* It's a RAS error.
|
|
*/
|
|
*ppszError = LocalAlloc( LPTR, (lstrlen( szBuf ) + 1) * sizeof(TCHAR) );
|
|
if (!*ppszError)
|
|
return FALSE;
|
|
|
|
lstrcpy( *ppszError, szBuf );
|
|
return TRUE;
|
|
}
|
|
|
|
/* The rest adapted from BLT's LoadSystem routine.
|
|
*/
|
|
dwFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER + FORMAT_MESSAGE_IGNORE_INSERTS;
|
|
|
|
if (dwError >= MIN_LANMAN_MESSAGE_ID && dwError <= MAX_LANMAN_MESSAGE_ID)
|
|
{
|
|
/* It's a net error.
|
|
*/
|
|
dwFlags += FORMAT_MESSAGE_FROM_HMODULE;
|
|
hmodule = GetModuleHandle( TEXT("NETMSG.DLL") );
|
|
}
|
|
else
|
|
{
|
|
/* It must be a system error.
|
|
*/
|
|
dwFlags += FORMAT_MESSAGE_FROM_SYSTEM;
|
|
hmodule = NULL;
|
|
}
|
|
|
|
/* Whistler bug: 389111 VPN connection returns unacceptable error message
|
|
** when smart card is not available
|
|
*/
|
|
dwFlags |= FORMAT_MESSAGE_MAX_WIDTH_MASK;
|
|
|
|
/* This is an NTSTATUS error msg.
|
|
*/
|
|
if (NT_ERROR(dwError))
|
|
{
|
|
dwError = RtlNtStatusToDosError( dwError );
|
|
}
|
|
|
|
cch = FormatMessage(
|
|
dwFlags, hmodule, dwError, 0, (LPTSTR )ppszError, 1, NULL );
|
|
|
|
/* FormatMessage failed so we are going to get a generic one from RAS.
|
|
*/
|
|
if (!cch || !*ppszError)
|
|
{
|
|
Free0( *ppszError );
|
|
dwError = ERROR_UNKNOWN;
|
|
|
|
if ((Rasapi32DllLoaded() || RasRpcDllLoaded())
|
|
&& g_pRasGetErrorString
|
|
&& g_pRasGetErrorString(
|
|
(UINT )dwError, (LPTSTR )szBuf, MAXRASERRORLEN ) == 0)
|
|
{
|
|
*ppszError = LocalAlloc( LPTR, (lstrlen( szBuf ) + 1) *
|
|
sizeof(TCHAR) );
|
|
if (!*ppszError)
|
|
return FALSE;
|
|
|
|
lstrcpy( *ppszError, szBuf );
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return (cch > 0);
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------
|
|
** Message popup
|
|
**----------------------------------------------------------------------------
|
|
*/
|
|
|
|
int
|
|
MsgDlgUtil(
|
|
IN HWND hwndOwner,
|
|
IN DWORD dwMsg,
|
|
IN OUT MSGARGS* pargs,
|
|
IN HINSTANCE hInstance,
|
|
IN DWORD dwTitle )
|
|
|
|
/* Pops up a message dialog centered on 'hwndOwner'. 'DwMsg' is the
|
|
** string resource ID of the message text. 'Pargs' is a extended
|
|
** formatting arguments or NULL if none. 'hInstance' is the
|
|
** application/module handle where string resources are located.
|
|
** 'DwTitle' is the string ID of the dialog title.
|
|
**
|
|
** Returns MessageBox-style code.
|
|
*/
|
|
{
|
|
TCHAR* pszUnformatted;
|
|
TCHAR* pszResult;
|
|
TCHAR* pszNotFound;
|
|
int nResult;
|
|
|
|
TRACE("MsgDlgUtil");
|
|
|
|
/* A placeholder for missing strings components.
|
|
*/
|
|
pszNotFound = TEXT("");
|
|
|
|
/* Build the message string.
|
|
*/
|
|
pszResult = pszNotFound;
|
|
|
|
if (pargs && pargs->pszString)
|
|
{
|
|
FormatMessage(
|
|
FORMAT_MESSAGE_FROM_STRING +
|
|
FORMAT_MESSAGE_ALLOCATE_BUFFER +
|
|
FORMAT_MESSAGE_ARGUMENT_ARRAY,
|
|
pargs->pszString, 0, 0, (LPTSTR )&pszResult, 1,
|
|
(va_list* )pargs->apszArgs );
|
|
}
|
|
else
|
|
{
|
|
pszUnformatted = PszFromId( hInstance, dwMsg );
|
|
|
|
if (pszUnformatted)
|
|
{
|
|
FormatMessage(
|
|
FORMAT_MESSAGE_FROM_STRING +
|
|
FORMAT_MESSAGE_ALLOCATE_BUFFER +
|
|
FORMAT_MESSAGE_ARGUMENT_ARRAY,
|
|
pszUnformatted, 0, 0, (LPTSTR )&pszResult, 1,
|
|
(va_list* )((pargs) ? pargs->apszArgs : NULL) );
|
|
|
|
Free( pszUnformatted );
|
|
}
|
|
}
|
|
|
|
if (!pargs || !pargs->fStringOutput)
|
|
{
|
|
TCHAR* pszTitle;
|
|
DWORD dwFlags;
|
|
HHOOK hhook;
|
|
|
|
if (pargs && pargs->dwFlags != 0)
|
|
dwFlags = pargs->dwFlags;
|
|
else
|
|
dwFlags = MB_ICONINFORMATION + MB_OK + MB_SETFOREGROUND;
|
|
|
|
pszTitle = PszFromId( hInstance, dwTitle );
|
|
|
|
if (hwndOwner)
|
|
{
|
|
/* Install hook that will get the message box centered on the
|
|
** owner window.
|
|
*/
|
|
hhook = SetWindowsHookEx( WH_CALLWNDPROC,
|
|
CenterDlgOnOwnerCallWndProc,
|
|
hInstance, GetCurrentThreadId() );
|
|
}
|
|
else
|
|
hhook = NULL;
|
|
|
|
if (pszResult)
|
|
{
|
|
nResult = MessageBox( hwndOwner, pszResult, pszTitle, dwFlags );
|
|
}
|
|
|
|
if (hhook)
|
|
UnhookWindowsHookEx( hhook );
|
|
|
|
Free0( pszTitle );
|
|
if (pszResult != pszNotFound)
|
|
LocalFree( pszResult );
|
|
}
|
|
else
|
|
{
|
|
/* Caller wants the string without doing the popup.
|
|
*/
|
|
pargs->pszOutput = (pszResult != pszNotFound) ? pszResult : NULL;
|
|
nResult = IDOK;
|
|
}
|
|
|
|
return nResult;
|
|
}
|
|
|
|
|
|
LRESULT CALLBACK
|
|
CenterDlgOnOwnerCallWndProc(
|
|
int code,
|
|
WPARAM wparam,
|
|
LPARAM lparam )
|
|
|
|
/* Standard Win32 CallWndProc hook callback that looks for the next dialog
|
|
** started and centers it on it's owner window.
|
|
*/
|
|
{
|
|
/* Arrive here when any window procedure associated with our thread is
|
|
** called.
|
|
*/
|
|
if (!wparam)
|
|
{
|
|
CWPSTRUCT* p = (CWPSTRUCT* )lparam;
|
|
|
|
/* The message is from outside our process. Look for the MessageBox
|
|
** dialog initialization message and take that opportunity to center
|
|
** the dialog on it's owner's window.
|
|
*/
|
|
if (p->message == WM_INITDIALOG)
|
|
CenterWindow( p->hwnd, GetParent( p->hwnd ) );
|
|
}
|
|
|
|
return 0;
|
|
}
|