Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

583 lines
19 KiB

//+-------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1999
//
// File: mmcerror.cpp
//
// Contents: Class definitions for mmc error support code.
//
// History: 15-Jul-99 VivekJ Created
//
//--------------------------------------------------------------------------
#pragma once
#ifndef _MMCERROR_H
#define _MMCERROR_H
#include "baseapi.h" // for MMCBASE_API
#include "stddbg.h" // for ASSERT, COMPILETIME_ASSERT
/*+-------------------------------------------------------------------------*
* WHY NAMESPACES ?
* We had problems trying to use "modified" SC when implementing
* com classes supporting ISupportErrorInfo.
* we had:
* [global version] - class CS
* [local version ] - a template class _SC, derived from SC and typedef'ed to SC.
* That was not only confusing to us - IDE debugger was also confused and crashing.
*
* The solution for that was to separate real types used for implementing.
* Thus to have typedef'ed definitions both in global and local scope.
* Plus (to avoid dealing with _SC and __SC and have better IDE support)
* we have used namespaces mmcerror and comerror, so we endup with this:
* - mmcerror::SC defining main functionality
* - comerror::SC (derived from mmcerror::SC) defining modified functionality
* - global SC - typedef of mmcerror::SC
* - local SC - typedef of comerror::SC
*+-------------------------------------------------------------------------*/
namespace mmcerror {
/*+-------------------------------------------------------------------------*
* class SC
*
* PURPOSE: The definition of a status code. Contains two members, a facility
* and an error code. This is a class rather
* than a typedef to avoid accidental casts to and from HRESULTS.
*
* SC's hold information about an error: The source of the error,
* and the error code itself. These are stored in
* different bit fields within the SC.
*
* NOTE: Do not add any virtual functions or member variables to this class.
* This could potentially wreak havoc on MMC performance.
*
*+-------------------------------------------------------------------------*/
class MMCBASE_API SC
{
public:
typedef long value_type;
private:
enum facility_type
{
FACILITY_WIN = 1, // Defined by the system
FACILITY_MMC = 2, // these map directly to an UINT.
FACILITY_HRESULT = 3, // these map directly to an HRESULT
};
public:
/*
* Constructor. Default copy construction and assignment are sufficient.
* If they are ever insufficient, that is a clear indication that this
* class has become heavier than is acceptable for its pervasive pass-by-
* value usage.
*/
SC (HRESULT hr = S_OK);
// equality operators
bool operator==(const SC &rhs) const;
bool operator==(HRESULT hr) const;
bool operator!=(const SC &rhs) const;
bool operator!=(HRESULT hr) const;
SC& operator= (HRESULT hr) {MakeSc(FACILITY_HRESULT, hr); return (*this);}
SC& FromWin32(value_type value) {MakeSc(FACILITY_WIN, value); return (*this);}
SC& FromMMC(value_type value) {MakeSc(FACILITY_MMC, value); return (*this);}
void Clear() {MakeSc(FACILITY_HRESULT, S_OK); }
HRESULT ToHr() const;
value_type GetCode() const {return m_value;}
// get the error message in a preallocated buffer
void GetErrorMessage(UINT maxLength, /*[OUT]*/ LPTSTR szMessage) const;
static void SetHinst(HINSTANCE hInst);
static void SetHWnd(HWND hWnd);
static DWORD GetMainThreadID() {return s_dwMainThreadID;}
static void SetMainThreadID(DWORD dwThreadID);
operator bool() const;
operator ! () const;
bool IsError() const {return operator bool();}
static HINSTANCE GetHinst() {ASSERT(s_hInst); return s_hInst;}
static HWND GetHWnd() {return s_hWnd;}
DWORD GetHelpID();
static LPCTSTR GetHelpFile();
void Throw() throw(SC);
void Throw(HRESULT hr) throw();
void FatalError() const; // ends the application.
SC& FromLastError();
// does the same trace like in ~SC(); does not change contents.
void Trace_() const;
void TraceAndClear() { Trace_(); Clear(); }
private:
void MakeSc(facility_type facility, value_type value){m_facility = facility, m_value = value;}
// accessor functions
facility_type GetFacility() const {return m_facility;}
private:
operator HRESULT() const; // this is to prevent automatic conversions to HRESULTs by way of bool's.
private:
facility_type m_facility;
value_type m_value; // the error code.
static HINSTANCE s_hInst; // the module that contains all error messages.
static HWND s_hWnd; // the parent HWnd for the error boxes.
static DWORD s_dwMainThreadID; // The main thread ID of MMC.
// debug specific behavior
#ifdef DBG // Debug SC's hold a pointer to the name of the function they are declared in.
public:
void SetFunctionName(LPCTSTR szFunctionName);
LPCTSTR GetFunctionName() const;
void SetSnapinName (LPCTSTR szSnapinName) { m_szSnapinName = szSnapinName;}
LPCTSTR GetSnapinName() const { return m_szSnapinName;}
void CheckCallingThreadID();
~SC();
// SC shouldn't pass the function name around - it's something personal.
// These will prevent doing so:
SC& operator = (const SC& other);
SC(const SC& other);
private:
LPCTSTR m_szFunctionName;
LPCTSTR m_szSnapinName;
static UINT s_CallDepth;
#endif // DBG
};
} // namespace mmcerror
// see "WHY NAMESPACES ?" comment at the top of file
typedef mmcerror::SC SC;
//############################################################################
//############################################################################
//
// the module that contains all the localized strings
//
//############################################################################
//############################################################################
MMCBASE_API HINSTANCE GetStringModule();
//############################################################################
//############################################################################
//
// Functions to format and display an error
//
//############################################################################
//############################################################################
//
// Functions to get an error string from a given SC
//
void MMCBASE_API FormatErrorIds( UINT idsOperation, SC sc, UINT maxLength, /*[OUT]*/ LPTSTR szMessage);
void MMCBASE_API FormatErrorString(LPCTSTR szOperation, SC sc, UINT maxLength, /*[OUT]*/ LPTSTR szMessage, BOOL fShort = FALSE);
void MMCBASE_API FormatErrorShort(SC sc, UINT maxLength, /*[OUT]*/ LPTSTR szMessage);
//
// Error Boxes - These will eventually allow to user to suppress more error messages
//
int MMCBASE_API MMCErrorBox(UINT idsOperation, UINT fuStyle = MB_ICONSTOP | MB_OK);
int MMCBASE_API MMCErrorBox(UINT idsOperation, SC sc, UINT fuStyle = MB_ICONSTOP | MB_OK);
int MMCBASE_API MMCErrorBox(LPCTSTR szOperation, SC sc, UINT fuStyle = MB_ICONSTOP | MB_OK);
int MMCBASE_API MMCErrorBox( SC sc, UINT fuStyle = MB_ICONSTOP | MB_OK);
int MMCBASE_API MMCErrorBox(LPCTSTR szMessage, UINT fuStyle = MB_ICONSTOP | MB_OK);
//
// Message Boxes - These cannot be suppressed
//
// This #define eventually will change so that MessageBox's are different and cannot be suppressed
#define MMCMessageBox MMCErrorBox
//############################################################################
//############################################################################
//
// Debug macros
//
//############################################################################
//############################################################################
#ifdef DBG
MMCBASE_API void TraceError(LPCTSTR sz, const SC& sc);
MMCBASE_API void TraceErrorMsg(LPCTSTR szFormat, ...);
MMCBASE_API void TraceSnapinError(LPCTSTR szError, const SC& sc);
#define DECLARE_SC(_sc, _func) SC _sc; sc.SetFunctionName(_func);
// This define is used only within the SC class
#define INCREMENT_CALL_DEPTH() ++s_CallDepth
#define DECREMENT_CALL_DEPTH() --s_CallDepth
///////////////////////////////////////////////////////////////////////
// MMC public interfaces (for snapins) should use this macro as this //
// does some initial error checks and more can be added later. //
///////////////////////////////////////////////////////////////////////
#define DECLARE_SC_FOR_PUBLIC_INTERFACE(_sc, _func) SC _sc;\
sc.SetFunctionName(_func);\
sc.SetSnapinName(GetSnapinName());\
sc.CheckCallingThreadID();
#define IMPLEMENTS_SNAPIN_NAME_FOR_DEBUG() tstring _szSnapinNameForDebug;\
LPCTSTR GetSnapinName()\
{\
return _szSnapinNameForDebug.data();\
};\
void SetSnapinName(LPCTSTR sz)\
{\
_szSnapinNameForDebug = sz;\
};
#else
#define TraceError ;/##/
#define TraceSnapinError ;/##/
#define DECLARE_SC(_sc, _func) SC _sc;
// This define is used only within the SC class
#define INCREMENT_CALL_DEPTH()
#define DECREMENT_CALL_DEPTH()
#define DECLARE_SC_FOR_PUBLIC_INTERFACE(_sc, _func) SC _sc;
#define IMPLEMENTS_SNAPIN_NAME_FOR_DEBUG()
#endif
//############################################################################
//############################################################################
//
// Parameter validation
//
//############################################################################
//############################################################################
/*+-------------------------------------------------------------------------*
*
* ScCheckPointers
*
* PURPOSE: Checks to make sure that all specified parameters are non-NULL
*
* PARAMETERS:
* const void * pv1 :
*
* RETURNS:
* inline SC: S_OK if no error, E_INVALIDARG if any of the pointers are NULL
*
*
* NOTE: Do not replace with a single function and optional parameters; that
* is inefficient.
*+-------------------------------------------------------------------------*/
inline SC ScCheckPointers(const void * pv1, HRESULT err = E_INVALIDARG)
{
return (NULL == pv1) ? err : S_OK;
}
inline SC ScCheckPointers(const void * pv1, const void *pv2, HRESULT err = E_INVALIDARG)
{
return ( (NULL == pv1) || (NULL == pv2) ) ? err : S_OK;
}
inline SC ScCheckPointers(const void * pv1, const void * pv2, const void * pv3, HRESULT err = E_INVALIDARG)
{
return ( (NULL == pv1) || (NULL == pv2) || (NULL == pv3) ) ? err : S_OK;
}
inline SC ScCheckPointers(const void * pv1, const void * pv2, const void * pv3, const void * pv4, HRESULT err = E_INVALIDARG)
{
return ( (NULL == pv1) || (NULL == pv2) || (NULL == pv3) || (NULL == pv4) ) ? err : S_OK;
}
inline SC ScCheckPointers(const void * pv1, const void * pv2, const void * pv3, const void * pv4, const void * pv5, HRESULT err = E_INVALIDARG)
{
return ( (NULL == pv1) || (NULL == pv2) || (NULL == pv3) || (NULL == pv4) || (NULL == pv5) ) ? err : S_OK;
}
inline SC ScCheckPointers(const void * pv1, const void * pv2, const void * pv3, const void * pv4, const void * pv5, const void* pv6, HRESULT err = E_INVALIDARG)
{
return ( (NULL == pv1) || (NULL == pv2) || (NULL == pv3) || (NULL == pv4) || (NULL == pv5) || (NULL == pv6)) ? err : S_OK;
}
// see "WHY NAMESPACES ?" comment at the top of file
namespace mmcerror {
/*+-------------------------------------------------------------------------*
* SC::SC
*
* Constructor for SC.
*
* Default copy construction and assignment are sufficient. If they are
* ever insufficient, that is a clear indication that this class has become
* heavier than is acceptable for its pervasive pass-by-value usage.
*--------------------------------------------------------------------------*/
inline SC::SC (HRESULT hr /* =S_OK */)
#ifdef DBG
: m_szFunctionName(NULL), m_szSnapinName(NULL)
#endif // DBG
{
/*
* This assert will fail if SC's ever derive from a non-trivial base
* class (i.e. one that has members or virtual functions), or defines
* virtual functions of its own. Don't do that! SC's must remain
* extremely lightweight.
*/
COMPILETIME_ASSERT (offsetof (SC, m_facility) == 0);
INCREMENT_CALL_DEPTH();
MakeSc (FACILITY_HRESULT, hr);
}
/*+-------------------------------------------------------------------------*
* SC::operator==
*
*
* PURPOSE: Determines whether two SC's are equivalent.
*
*+-------------------------------------------------------------------------*/
inline bool
SC::operator==(const SC &rhs) const
{
return ( (m_facility == rhs.m_facility) &&
(m_value == rhs.m_value) );
}
inline bool
SC::operator==(HRESULT hr) const
{
return ( (m_facility == FACILITY_HRESULT) &&
(m_value == hr) );
}
inline bool
SC::operator!=(const SC &rhs) const
{
return !operator==( rhs );
}
inline bool
SC::operator!=(HRESULT hr) const
{
return !operator==( hr );
}
// this version compares an hr to an SC.
inline
operator == (HRESULT hr, const SC & sc)
{
return (sc == hr);
}
#ifdef DBG
/*+-------------------------------------------------------------------------*
*
* SC::GetFunctionName
*
* PURPOSE: Sets the debug function name to the supplied string.
*
* PARAMETERS:
*
* RETURNS:
* LPCTSTR The function name.
*
*+-------------------------------------------------------------------------*/
inline LPCTSTR SC::GetFunctionName() const
{
return m_szFunctionName;
}
/*+-------------------------------------------------------------------------*
*
* SC::CheckCallingThreadID
*
* PURPOSE: Check if the method was called on main thread.
*
* PARAMETERS:
*
* RETURNS:
* inline void
*
*+-------------------------------------------------------------------------*/
inline void SC::CheckCallingThreadID()
{
ASSERT(-1 != GetMainThreadID());
if (GetMainThreadID() == ::GetCurrentThreadId())
return;
TraceSnapinError(_T(", method called from wrong thread"), (*this));
return;
}
/*+-------------------------------------------------------------------------*
*
* SC::~SC
*
* PURPOSE: Destructor - Debug mode only. Does a trace if an error occurred.
*
*+-------------------------------------------------------------------------*/
inline SC::~SC()
{
DECREMENT_CALL_DEPTH();
Trace_();
}
#endif // DBG
/*+-------------------------------------------------------------------------*
*
* SC::Trace_()
*
* PURPOSE: Does a trace if an error occurred. Does nothing in release mode
* It is very convenient when we want to register, but ignore the error -
* Simply doing sc.Trace_(); sc.Clear(); does all we need.
*
*+-------------------------------------------------------------------------*/
inline void SC::Trace_() const
{
#ifdef DBG
if (IsError())
{
// Distinguish between snapin error & MMC error using the
// snapin name variable.
if (m_szSnapinName != NULL)
{
TraceSnapinError(_T(""), *this);
}
else if (m_szFunctionName != NULL)
{
TraceError(m_szFunctionName, *this);
}
}
#endif // DBG
}
/*+-------------------------------------------------------------------------*
*
* SC::operator bool
*
* PURPOSE: Returns a value indicating whether the SC holds an error code
*
* PARAMETERS: None
*
* RETURNS:
* bool : true if error, else false
*
*+-------------------------------------------------------------------------*/
inline SC::operator bool() const
{
if(GetCode()==0)
return false; // quick exit if no error
return (GetFacility()==FACILITY_HRESULT) ? FAILED(GetCode()) : true;
}
inline SC::operator !() const
{
return (!operator bool());
}
} // namespace mmcerror
/*+-------------------------------------------------------------------------*
*
* ScFromWin32
*
* PURPOSE: Creates an SC with the facility set to Win32.
*
* PARAMETERS:
* SC::value_type code :
*
* RETURNS:
* inline SC
*
*+-------------------------------------------------------------------------*/
inline SC ScFromWin32(SC::value_type code)
{
SC sc;
sc.FromWin32(code);
return sc;
}
/*+-------------------------------------------------------------------------*
*
* ScFromMMC
*
* PURPOSE: Creates an SC with the facility set to MMC.
*
* PARAMETERS:
* SC::value_type code :
*
* RETURNS:
* inline SC
*
*+-------------------------------------------------------------------------*/
MMCBASE_API inline SC ScFromMMC(SC::value_type code)
{
SC sc;
sc.FromMMC(code);
return sc;
}
/*+-------------------------------------------------------------------------*
*
* HrFromSc
*
* PURPOSE: Converts a status code (SC) to an HRESULT. Use sparingly, as this
* loses information in the conversion.
*
* PARAMETERS:
* SC &sc: The SC to convert
*
* RETURNS:
* inline HRESULT: The converted value.
*
*+-------------------------------------------------------------------------*/
MMCBASE_API inline HRESULT HrFromSc(const SC &sc)
{
return sc.ToHr();
}
/*+-------------------------------------------------------------------------*
*
* SCODEFromSc
*
* PURPOSE: Converts a status code (SC) to an SCODE. Use sparingly, as this
* loses information in the conversion.
* On 32bit machine SCODE is same as HRESULT.
*
* PARAMETERS:
* SC &sc: The SC to convert
*
* RETURNS:
* inline SCODE: The converted value.
*
*+-------------------------------------------------------------------------*/
MMCBASE_API inline SCODE SCODEFromSc(const SC &sc)
{
return (SCODE)sc.ToHr();
}
#endif //_MMCERROR_H