545 lines
14 KiB
C++
545 lines
14 KiB
C++
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Microsoft Windows
|
||
|
// Copyright (C) Microsoft Corporation, 1992 - 1999
|
||
|
//
|
||
|
// File: mmcerror.cpp
|
||
|
//
|
||
|
// Contents: Class definitions for mmc debug support code.
|
||
|
//
|
||
|
// History: 15-Jul-99 VivekJ Created
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
#include "stdafx.h"
|
||
|
#include "conuistr.h" // needed for IDR_MAINFRAME
|
||
|
#define cchMaxSmallLine 256
|
||
|
|
||
|
|
||
|
#ifdef DBG
|
||
|
CTraceTag tagSCConversion(TEXT("SC"), TEXT("Conversion"));
|
||
|
CTraceTag tagCallDump( TEXT("Function calls"), TEXT("ALL") );
|
||
|
#endif //DBG
|
||
|
|
||
|
|
||
|
|
||
|
//############################################################################
|
||
|
//############################################################################
|
||
|
//
|
||
|
// Definition of GetStringModule() - used by all binaries
|
||
|
//
|
||
|
//############################################################################
|
||
|
//############################################################################
|
||
|
HINSTANCE GetStringModule()
|
||
|
{
|
||
|
return SC::GetHinst();
|
||
|
}
|
||
|
|
||
|
//############################################################################
|
||
|
//############################################################################
|
||
|
//
|
||
|
// Implementation of class SC
|
||
|
//
|
||
|
//############################################################################
|
||
|
//############################################################################
|
||
|
|
||
|
// static variables
|
||
|
HINSTANCE SC::s_hInst = 0;
|
||
|
HWND SC::s_hWnd = NULL;
|
||
|
DWORD SC::s_dwMainThreadID = -1;
|
||
|
|
||
|
#ifdef DBG
|
||
|
UINT SC::s_CallDepth = 0;
|
||
|
#endif
|
||
|
|
||
|
// accessors for the static variables.
|
||
|
void
|
||
|
SC::SetHinst(HINSTANCE hInst)
|
||
|
{
|
||
|
s_hInst = hInst;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
SC::SetHWnd(HWND hWnd)
|
||
|
{
|
||
|
s_hWnd = hWnd;
|
||
|
}
|
||
|
|
||
|
|
||
|
void
|
||
|
SC::SetMainThreadID(DWORD dwThreadID)
|
||
|
{
|
||
|
ASSERT(-1 != dwThreadID);
|
||
|
s_dwMainThreadID = dwThreadID;
|
||
|
}
|
||
|
|
||
|
#ifdef DBG
|
||
|
|
||
|
SC&
|
||
|
SC::operator = (const SC& other)
|
||
|
{
|
||
|
m_facility = other.m_facility;
|
||
|
m_value = other.m_value;
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
SC::SC(const SC& other)
|
||
|
: m_szFunctionName(NULL),
|
||
|
m_szSnapinName(NULL)
|
||
|
{
|
||
|
*this = other;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*+-------------------------------------------------------------------------*
|
||
|
*
|
||
|
* SC::SetFunctionName
|
||
|
*
|
||
|
* PURPOSE: Sets the debug function name to the supplied string.
|
||
|
*
|
||
|
* PARAMETERS:
|
||
|
* LPCTSTR szFunctionName : the supplied string.
|
||
|
*
|
||
|
* RETURNS:
|
||
|
* inline void
|
||
|
*
|
||
|
*+-------------------------------------------------------------------------*/
|
||
|
inline void SC::SetFunctionName(LPCTSTR szFunctionName)
|
||
|
{
|
||
|
m_szFunctionName = szFunctionName;
|
||
|
|
||
|
INCREMENT_CALL_DEPTH();
|
||
|
|
||
|
// This computes the format string based on the call depth.
|
||
|
// eg if s_CallDepth is 4, the string is " %s" (four spaces)
|
||
|
// if s_CallDepth is 5, the string is " %s" (five spaces)
|
||
|
|
||
|
LPCTSTR szFormatString = TEXT(" %s");
|
||
|
UINT maxLen = _tcslen(szFormatString);
|
||
|
|
||
|
UINT formatLen = s_CallDepth + 2; // the -2 is for the "%s"
|
||
|
|
||
|
formatLen = (formatLen < maxLen ? formatLen : maxLen);
|
||
|
|
||
|
Trace(tagCallDump, szFormatString + (maxLen - formatLen), szFunctionName);
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
/*+-------------------------------------------------------------------------*
|
||
|
*
|
||
|
* SC::ToHr
|
||
|
*
|
||
|
* PURPOSE: Converts from a status code (SC) to an HRESULT. USE SPARINGLY.
|
||
|
*
|
||
|
* PARAMETERS: None
|
||
|
*
|
||
|
* RETURNS:
|
||
|
* HRESULT
|
||
|
*
|
||
|
*+-------------------------------------------------------------------------*/
|
||
|
HRESULT
|
||
|
SC::ToHr() const
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
switch(GetFacility())
|
||
|
{
|
||
|
default:
|
||
|
ASSERT(0 && "Should not come here.");
|
||
|
break;
|
||
|
|
||
|
case FACILITY_WIN:
|
||
|
hr = HRESULT_FROM_WIN32 (GetCode());
|
||
|
break;
|
||
|
|
||
|
case FACILITY_MMC:
|
||
|
Trace (tagSCConversion, _T("Converting from MMC error code to HRESULT, probable loss of fidelity"), *this);
|
||
|
hr = (GetCode() != 0) ? E_UNEXPECTED : S_OK;
|
||
|
break;
|
||
|
|
||
|
case FACILITY_HRESULT:
|
||
|
hr = (HRESULT) GetCode();
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
|
||
|
}
|
||
|
|
||
|
/*+-------------------------------------------------------------------------*
|
||
|
*
|
||
|
* SC::GetErrorMessage
|
||
|
*
|
||
|
* PURPOSE: Writes the error message corresponding to the error code to
|
||
|
* the buffer pointed to by szMessage.
|
||
|
*
|
||
|
* PARAMETERS:
|
||
|
* UINT maxLength : The maximum no of characters to output.
|
||
|
* LPTSTR szMessage : Pointer to the buffer to use. Must be non-null.
|
||
|
*
|
||
|
* RETURNS:
|
||
|
* void
|
||
|
*
|
||
|
*+-------------------------------------------------------------------------*/
|
||
|
void SC::GetErrorMessage(UINT maxLength, /*[OUT]*/ LPTSTR szMessage) const
|
||
|
{
|
||
|
ASSERT(szMessage != NULL && maxLength > 0);
|
||
|
if (szMessage == NULL || maxLength == 0)
|
||
|
return;
|
||
|
|
||
|
szMessage[0] = 0;
|
||
|
|
||
|
switch(GetFacility())
|
||
|
{
|
||
|
default:
|
||
|
ASSERT(0 && "SC::GetErrorMessage: Unknown SC facility.");
|
||
|
break;
|
||
|
|
||
|
case FACILITY_WIN:
|
||
|
case FACILITY_HRESULT:
|
||
|
{
|
||
|
int nChars = 0;
|
||
|
|
||
|
if ( GetCode() == E_UNEXPECTED )
|
||
|
{
|
||
|
nChars = ::LoadString(SC::GetHinst(), IDS_E_UNEXPECTED, szMessage, maxLength);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DWORD dwFlags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS;
|
||
|
void *lpSource = NULL;
|
||
|
|
||
|
// add XML module to be searched as well
|
||
|
HMODULE hmodXML = GetModuleHandle(_T("msxml.dll"));
|
||
|
if (hmodXML)
|
||
|
{
|
||
|
dwFlags |= FORMAT_MESSAGE_FROM_HMODULE;
|
||
|
lpSource = hmodXML;
|
||
|
}
|
||
|
|
||
|
DWORD dwMessageID = GetCode();
|
||
|
|
||
|
// reverse values made by HRESULT_FROM_WIN32
|
||
|
// Not sure why ::FormatMessage does not work with such values,
|
||
|
// but we need to convert them back, or else there won't be any messages
|
||
|
if ( (dwMessageID & 0xFFFF0000) == ((FACILITY_WIN32 << 16) | 0x80000000) )
|
||
|
dwMessageID &= 0x0000FFFF;
|
||
|
|
||
|
nChars = ::FormatMessage( dwFlags,
|
||
|
lpSource,
|
||
|
dwMessageID,
|
||
|
0, /*dwLangID*/
|
||
|
szMessage, /*lpBuffer*/
|
||
|
maxLength, /*nSize*/
|
||
|
0 /*Arguments*/
|
||
|
);
|
||
|
}
|
||
|
|
||
|
if (nChars)
|
||
|
break;
|
||
|
|
||
|
// if former failed - add a default error
|
||
|
nChars = ::LoadString(SC::GetHinst(), IDS_MESSAGE_NOT_FOUND_ERROR, szMessage, maxLength);
|
||
|
|
||
|
if (nChars == 0)
|
||
|
{
|
||
|
// too bad. we can only use hardcoded one
|
||
|
_tcsncpy(szMessage, _T("Unknown error"), maxLength);
|
||
|
szMessage[maxLength - 1] = 0;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case FACILITY_MMC:
|
||
|
{
|
||
|
int nChars = ::LoadString(GetHinst(), GetCode(), szMessage, maxLength);
|
||
|
if(nChars == 0) // did not exist
|
||
|
{
|
||
|
nChars = ::LoadString(GetHinst(), IDS_MESSAGE_NOT_FOUND_ERROR, szMessage, maxLength);
|
||
|
ASSERT(nChars > 0);
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/*+-------------------------------------------------------------------------*
|
||
|
*
|
||
|
* SC::GetHelpID
|
||
|
*
|
||
|
* PURPOSE: Returns the help ID associated with a status code
|
||
|
*
|
||
|
* RETURNS:
|
||
|
* DWORD
|
||
|
*
|
||
|
*+-------------------------------------------------------------------------*/
|
||
|
DWORD
|
||
|
SC::GetHelpID()
|
||
|
{
|
||
|
return 0; // TODO
|
||
|
}
|
||
|
|
||
|
LPCTSTR
|
||
|
SC::GetHelpFile()
|
||
|
{
|
||
|
static TCHAR szFilePath[MAX_PATH] = TEXT("\0");
|
||
|
|
||
|
// set the path if not already set
|
||
|
if(*szFilePath == TEXT('\0') )
|
||
|
{
|
||
|
DWORD dwCnt = ExpandEnvironmentStrings(_T("%WINDIR%\\help\\mmc.chm"), szFilePath, MAX_PATH);
|
||
|
ASSERT(dwCnt != 0);
|
||
|
}
|
||
|
|
||
|
return szFilePath;
|
||
|
}
|
||
|
|
||
|
void SC::Throw() throw(SC)
|
||
|
{
|
||
|
// make exact copy of itself and destroy it (forces all the output)
|
||
|
#ifdef DBG
|
||
|
{
|
||
|
SC sc(*this);
|
||
|
sc.SetFunctionName(m_szFunctionName);
|
||
|
// forget the debug info - it will not be usefull anyway
|
||
|
// This will turn off the Trace on destructor
|
||
|
SetFunctionName(NULL);
|
||
|
}
|
||
|
#endif // DBG
|
||
|
|
||
|
throw(*this);
|
||
|
}
|
||
|
|
||
|
void SC::Throw(HRESULT hr)
|
||
|
{
|
||
|
(*this) = hr;
|
||
|
Throw();
|
||
|
}
|
||
|
|
||
|
|
||
|
/*+-------------------------------------------------------------------------*
|
||
|
*
|
||
|
* SC::FatalError
|
||
|
*
|
||
|
* PURPOSE: Terminates the application.
|
||
|
*
|
||
|
* RETURNS:
|
||
|
* void
|
||
|
*
|
||
|
*+-------------------------------------------------------------------------*/
|
||
|
void
|
||
|
SC::FatalError() const
|
||
|
{
|
||
|
MMCErrorBox(*this);
|
||
|
exit(1);
|
||
|
}
|
||
|
|
||
|
/*+-------------------------------------------------------------------------*
|
||
|
*
|
||
|
* SC::FromLastError
|
||
|
*
|
||
|
* PURPOSE: Fill SC with value from GetLastError.
|
||
|
*
|
||
|
* The SC is guaranteed to contain a failure code (i.e. IsError()
|
||
|
* will return true) when this function returns.
|
||
|
*
|
||
|
* RETURNS: Reference to the current SC
|
||
|
*
|
||
|
*+-------------------------------------------------------------------------*/
|
||
|
SC& SC::FromLastError()
|
||
|
{
|
||
|
FromWin32 (::GetLastError());
|
||
|
|
||
|
/*
|
||
|
* Some APIs will fail without setting extended error information.
|
||
|
* Presumably this function was called in response to an error, so
|
||
|
* we always want this SC to indicate *some* sort of error. If the
|
||
|
* failing API neglected to set extended error information, give
|
||
|
* this SC a generic error code
|
||
|
*/
|
||
|
if (!IsError())
|
||
|
MakeSc (FACILITY_HRESULT, E_FAIL);
|
||
|
|
||
|
ASSERT (IsError());
|
||
|
return (*this);
|
||
|
}
|
||
|
|
||
|
//############################################################################
|
||
|
//############################################################################
|
||
|
//
|
||
|
// Error formatting
|
||
|
//
|
||
|
//############################################################################
|
||
|
//############################################################################
|
||
|
/*
|
||
|
* Purpose: Formats an error message
|
||
|
*
|
||
|
* Parameters:
|
||
|
* ids String describing the operation in progress
|
||
|
* sc Error code describing the problem encountered
|
||
|
* pstrMessage
|
||
|
* the resulting message.
|
||
|
*/
|
||
|
void FormatErrorIds(UINT ids, SC sc, UINT maxLength, /*[OUT]*/ LPTSTR szMessage)
|
||
|
{
|
||
|
TCHAR sz[cchMaxSmallLine];
|
||
|
LoadString(SC::GetHinst(), IDR_MAINFRAME, sz, cchMaxSmallLine);
|
||
|
FormatErrorString(sz, sc, maxLength, szMessage);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Returns a short version of an error message associated a given SC.
|
||
|
//
|
||
|
void FormatErrorShort(SC sc, UINT maxLength, /*[OUT]*/ LPTSTR szMessage)
|
||
|
{
|
||
|
FormatErrorString(NULL, sc, maxLength, szMessage, TRUE);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// FormatErrorString formats an error message from any SC
|
||
|
//
|
||
|
// Parameters:
|
||
|
// szOperation
|
||
|
// String describing the operation in progress
|
||
|
// May be NULL if sc is sufficient.
|
||
|
// szMessage
|
||
|
// the resulting message.
|
||
|
// fShort
|
||
|
// TRUE if you want the error message only (no header/footer)
|
||
|
//
|
||
|
void FormatErrorString(LPCTSTR szOperation, SC sc , UINT maxLength, /*[OUT]*/ LPTSTR szMessage, BOOL fShort)
|
||
|
{
|
||
|
sc.GetErrorMessage(maxLength, szMessage);
|
||
|
// TODO: add p
|
||
|
}
|
||
|
|
||
|
//############################################################################
|
||
|
//############################################################################
|
||
|
//
|
||
|
// MMCErrorBox
|
||
|
//
|
||
|
//############################################################################
|
||
|
//############################################################################
|
||
|
|
||
|
/*
|
||
|
* MMCErrorBox
|
||
|
*
|
||
|
* Purpose: Displays an Error Box for the given SZ.
|
||
|
* NOTE: This is the one that actually puts-up the dialog.
|
||
|
*
|
||
|
* Parameters:
|
||
|
* sz Pointer to the message to display
|
||
|
* fuStyle As per windows MessageBox
|
||
|
*
|
||
|
* Return value:
|
||
|
* int Button Pressed to dismiss the ErrorBox
|
||
|
*/
|
||
|
int MMCErrorBox(LPCTSTR szMessage, UINT fuStyle )
|
||
|
{
|
||
|
INT id;
|
||
|
|
||
|
// If not system modal (background thread), force task modal.
|
||
|
if (!(fuStyle & MB_SYSTEMMODAL))
|
||
|
fuStyle |= MB_TASKMODAL;
|
||
|
|
||
|
TCHAR szCaption[cchMaxSmallLine];
|
||
|
LoadString(SC::GetHinst(), IDR_MAINFRAME, szCaption, cchMaxSmallLine);
|
||
|
|
||
|
// get window to parent the message box
|
||
|
HWND hWndActive = SC::GetHWnd();
|
||
|
|
||
|
// cannot parent on hidden window!
|
||
|
if ( !IsWindowVisible(hWndActive) )
|
||
|
hWndActive = NULL;
|
||
|
|
||
|
id = ::MessageBox(hWndActive, szMessage, szCaption, fuStyle);
|
||
|
|
||
|
return id;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*+-------------------------------------------------------------------------*
|
||
|
*
|
||
|
* MMCErrorBox
|
||
|
*
|
||
|
* PURPOSE: Displays an error box with the specified message and style
|
||
|
*
|
||
|
* PARAMETERS:
|
||
|
* UINT idsOperation :
|
||
|
* UINT fuStyle :
|
||
|
*
|
||
|
* RETURNS:
|
||
|
* int: Button pressed
|
||
|
*
|
||
|
*+-------------------------------------------------------------------------*/
|
||
|
int
|
||
|
MMCErrorBox(UINT idsOperation, UINT fuStyle)
|
||
|
{
|
||
|
TCHAR sz[cchMaxSmallLine];
|
||
|
LoadString(SC::GetHinst(), idsOperation, sz, cchMaxSmallLine);
|
||
|
return MMCErrorBox(sz, fuStyle);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* MMCErrorBox
|
||
|
*
|
||
|
* Purpose: Displays a complex Error Box, given the operation
|
||
|
* and the status code
|
||
|
*
|
||
|
* Parameters:
|
||
|
* ids description of the operation that failed.
|
||
|
* SC Status Code to report
|
||
|
* fuStyle As per windows MessageBox
|
||
|
*
|
||
|
* Return value:
|
||
|
* int Button Pressed to dismiss the ErrorBox
|
||
|
*/
|
||
|
int MMCErrorBox(UINT ids, SC sc, UINT fuStyle)
|
||
|
{
|
||
|
TCHAR sz[cchMaxSmallLine];
|
||
|
LoadString(SC::GetHinst(), ids, sz, cchMaxSmallLine);
|
||
|
return MMCErrorBox(sz, sc, fuStyle);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* MMCErrorBox
|
||
|
*
|
||
|
* Purpose: Displays a complex Error Box, given the operation
|
||
|
* and the status code
|
||
|
*
|
||
|
* Parameters:
|
||
|
* szOperation Description of the operation that failed.
|
||
|
* sz Status Code to report
|
||
|
* fuStyle As per windows MessageBox
|
||
|
*
|
||
|
* Return value:
|
||
|
* int Button Pressed to dismiss the ErrorBox
|
||
|
*/
|
||
|
int MMCErrorBox(LPCTSTR szOperation, SC sc, UINT fuStyle)
|
||
|
{
|
||
|
TCHAR sz[cchMaxSmallLine];
|
||
|
FormatErrorString(szOperation, sc, cchMaxSmallLine, sz);
|
||
|
return MMCErrorBox(sz, fuStyle);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* MMCErrorBox
|
||
|
*
|
||
|
* Purpose: Displays an Error Box for the given Status Code.
|
||
|
*
|
||
|
* Parameters:
|
||
|
* SC Status Code to report
|
||
|
* fuStyle As per windows MessageBox
|
||
|
*
|
||
|
* Return value:
|
||
|
* int Button Pressed to dismiss the ErrorBox
|
||
|
*/
|
||
|
int MMCErrorBox(SC sc, UINT fuStyle)
|
||
|
{
|
||
|
TCHAR sz[cchMaxSmallLine];
|
||
|
FormatErrorString(NULL, sc, cchMaxSmallLine, sz);
|
||
|
return MMCErrorBox(sz, fuStyle);
|
||
|
}
|
||
|
|