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.
629 lines
21 KiB
629 lines
21 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();
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// BufferCbValidate, BufferCchValidate, BufferCchValidateW, BufferCchValidateA
|
|
//
|
|
// PURPOSE: Validates that a buffer has the specified number of bytes by
|
|
// simulating a hack attack on it. This is done by setting all the
|
|
// bytes in the buffer to some value. In retail builds, this does
|
|
// nothing.
|
|
//
|
|
// NOTE: This functions destroys the contents of the buffer, DO NOT
|
|
// use it on [in] data.
|
|
//
|
|
// RETURNS:
|
|
// void
|
|
//
|
|
//****************************************************************************
|
|
#ifdef DBG
|
|
inline void BufferCbValidate(void *dest, size_t count)
|
|
{
|
|
memset(dest, 0xcc, count);
|
|
}
|
|
|
|
inline void BufferCchValidateW(WCHAR *sz, size_t cch)
|
|
{
|
|
memset(sz, 0xcc, cch*sizeof(WCHAR));
|
|
}
|
|
|
|
inline void BufferCchValidateA(char *sz, size_t cch)
|
|
{
|
|
memset(sz, 0xcc, cch*sizeof(char));
|
|
}
|
|
|
|
// The TCHAR version
|
|
#ifdef UNICODE
|
|
#define BufferCchValidate BufferCchValidateW
|
|
#else // UNICODE
|
|
#define BufferCchValidate BufferCchValidateA
|
|
#endif //UNICODE
|
|
|
|
#else // DBG
|
|
#define BufferCbValidate ;/##/
|
|
#define BufferCchValidateW ;/##/
|
|
#define BufferCchValidateA ;/##/
|
|
#define BufferCchValidate ;/##/
|
|
#endif // DBG
|
|
|
|
|
|
#endif //_MMCERROR_H
|