//+------------------------------------------------------------------------- // // 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); }