windows-nt/Source/XPSP1/NT/admin/wmi/wbem/adapters/oledb/errinf.cpp

1319 lines
45 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Microsoft WMI OLE DB Provider
// (C) Copyright 1999 Microsoft Corporation. All Rights Reserved.
//
// Error Routines
//
///////////////////////////////////////////////////////////////////////////////////////////////////////
#include "headers.h"
#define ERROR_GUID_ARRAYSIZE 5
// NTRaid : 111781
// 06/13/00
#define ERROR_DESCRIPTION_SIZE 512
static const ULONG INITIAL_ERROR_QUEUE_SIZE = 10;
CImpISupportErrorInfo::CImpISupportErrorInfo( IUnknown* pUnkOuter)
{
m_cRef = 0L;
m_pUnkOuter = pUnkOuter;
m_cpErrInt = 0;
m_rgpErrInt = NULL;
m_cAllocGuid = 0;
}
CImpISupportErrorInfo::~CImpISupportErrorInfo()
{
SAFE_DELETE_ARRAY(m_rgpErrInt);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////
STDMETHODIMP_(ULONG) CImpISupportErrorInfo::AddRef(void)
{
InterlockedIncrement((long*)&m_cRef);
return m_pUnkOuter->AddRef();
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
STDMETHODIMP_(ULONG) CImpISupportErrorInfo::Release(void)
{
InterlockedDecrement((long*)&m_cRef);
return m_pUnkOuter->Release();
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CImpISupportErrorInfo::QueryInterface( REFIID riid, LPVOID * ppv )
{
return m_pUnkOuter->QueryInterface(riid, ppv);
}
// Modifications done for
// NTRaid:111765
HRESULT CImpISupportErrorInfo::AddInterfaceID(REFIID riid)
{
HRESULT hr = S_OK;
if(m_rgpErrInt == NULL)
{
m_rgpErrInt = new GUID*[ERROR_GUID_ARRAYSIZE];
if(m_rgpErrInt)
{
m_cAllocGuid = ERROR_GUID_ARRAYSIZE;
}
else
{
hr = E_OUTOFMEMORY;
}
}
else
if(m_cpErrInt >= m_cAllocGuid)
{
GUID **pTemp = m_rgpErrInt;
m_rgpErrInt = NULL;
m_rgpErrInt = new GUID*[m_cAllocGuid + ERROR_GUID_ARRAYSIZE];
if(m_rgpErrInt)
{
memset(m_rgpErrInt ,0, (m_cAllocGuid + ERROR_GUID_ARRAYSIZE) * sizeof(GUID*));
memcpy(m_rgpErrInt ,pTemp, m_cAllocGuid * sizeof(GUID*));
m_cAllocGuid += ERROR_GUID_ARRAYSIZE;
SAFE_DELETE_ARRAY(pTemp);
}
else
{
m_rgpErrInt = pTemp;
hr = E_OUTOFMEMORY;
}
}
if(m_rgpErrInt && SUCCEEDED(hr))
{
m_rgpErrInt[m_cpErrInt++] = (GUID *)&riid;
hr = S_OK;
}
return hr;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Indicates whether a OLE DB Interface can return OLE DB error objects
//
///////////////////////////////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CImpISupportErrorInfo::InterfaceSupportsErrorInfo( REFIID riid )
{
ULONG ul;
HRESULT hr = S_FALSE;
//==========================================================================
// See if the interface asked about, actually creates an error object.
//==========================================================================
for(ul=0; ul<m_cpErrInt; ul++){
if ( (*(m_rgpErrInt[ul])) == riid )
{
hr = S_OK;
break;
}
}
return hr;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Constructor for this class
//
///////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma warning (disable:4355)
CErrorLookup::CErrorLookup( LPUNKNOWN pUnkOuter ) : m_IErrorLookup(this), CBaseObj(BOT_ERROR,pUnkOuter)
{
}
#pragma warning (default:4355)
///////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Returns a pointer to a specified interface. Callers use QueryInterface to determine which interfaces
// the called object supports.
//
///////////////////////////////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CErrorLookup::QueryInterface( REFIID riid, LPVOID * ppv)
{
if ( ppv == NULL )
return E_INVALIDARG;
//=========================================================
// This is the non-delegating IUnknown implementation
//=========================================================
if ( riid == IID_IUnknown )
*ppv = (LPVOID)this;
else if ( riid == IID_IErrorLookup )
*ppv = (LPVOID)&m_IErrorLookup;
else{
*ppv = NULL;
return E_NOINTERFACE;
}
((LPUNKNOWN)*ppv)->AddRef();
return S_OK;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Increments a persistence count for the object
//
///////////////////////////////////////////////////////////////////////////////////////////////////////
STDMETHODIMP_(ULONG) CErrorLookup::AddRef(void)
{
ULONG cRef = InterlockedIncrement( (long*) &m_cRef);
return cRef;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Decrements a persistence count for the object and if persistence count is 0, the object destroys
// itself.
//
///////////////////////////////////////////////////////////////////////////////////////////////////////
STDMETHODIMP_(ULONG) CErrorLookup::Release (void)
{
ULONG cRef = InterlockedDecrement( (long*) &m_cRef);
if ( !cRef ){
delete this;
return 0;
}
return cRef;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Increments a reference count for the object.
//
///////////////////////////////////////////////////////////////////////////////////////////////////////
STDMETHODIMP_(ULONG) CImpIErrorLookup::AddRef(void)
{
InterlockedIncrement((long*)&m_cRef);
return m_pCErrorLookup->AddRef();
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Decrement the object's reference count and deletes the object when the new reference count is zero.
//
///////////////////////////////////////////////////////////////////////////////////////////////////////
STDMETHODIMP_(ULONG) CImpIErrorLookup::Release(void)
{
InterlockedDecrement((long*)&m_cRef);
return m_pCErrorLookup->Release();
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Returns a pointer to a specified interface. Callers use QueryInterface to determine which interfaces
// the called object supports.
//
///////////////////////////////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CImpIErrorLookup::QueryInterface( REFIID riid, LPVOID * ppv)
{
return m_pCErrorLookup->QueryInterface(riid, ppv);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Retrieve the error message and source based on the HRESULT and the provider specific error number
//
///////////////////////////////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CImpIErrorLookup::GetErrorDescription( HRESULT hrError,
DWORD dwLookupId,
DISPPARAMS* pdispparams,
LCID lcid,
BSTR* ppwszSource,
BSTR* ppwszDescription )
{
HRESULT hr = NOERROR;
int cchBuffer;
// NTRaid : 111781
// 06/13/00
WCHAR wszBuffer[ERROR_DESCRIPTION_SIZE];
//=========================================================
// Check the Arguments
//=========================================================
if ( !ppwszSource || !ppwszDescription )
{
hr = E_INVALIDARG;
}
else
{
//=========================================================
// Initialize return values
//=========================================================
*ppwszSource = NULL;
*ppwszDescription = NULL;
// Check the Locale
// if ( lcid != GetSystemDefaultLCID() )
// return DB_E_NOLOCALE;
wcscpy(wszBuffer,L"");
WMIOledb_LoadStringW(IDS_WMIOLEDBDES,wszBuffer,ERROR_DESCRIPTION_SIZE);
//=========================================================
// Store source name
//=========================================================
*ppwszSource = Wmioledb_SysAllocString(wszBuffer);
if ( *ppwszSource == NULL )
{
hr = E_OUTOFMEMORY;
}
else
//=========================================================
// If the lookup id was to be looked up in the resource dll
// of the error collection, make sure we just return NULL
// for the error description.
//=========================================================
if ( (dwLookupId &= ~IDENTIFIER_SDK_MASK) == 0 )
{
hr = S_OK;
}
else
//=========================================================
// After this point make sure to exit to goto
// the FAILED(hr) code or drop through to the return hr,
// as to make sure memory is freed if need be.
// Determine if it is a static or dynamic string
//=========================================================
if ( dwLookupId & ERR_STATIC_STRING )
{
wcscpy(wszBuffer,L"");
// NTRaid : 111781
// 06/13/00
// cchBuffer = LoadStringW(g_hInstance, (UINT)(dwLookupId & ~(ERR_STATIC_STRING)), wszBuffer,ERROR_DESCRIPTION_SIZE);
cchBuffer = WMIOledb_LoadStringW( (UINT)(dwLookupId & ~(ERR_STATIC_STRING)), wszBuffer,ERROR_DESCRIPTION_SIZE);
//=====================================================
// Convert to a BSTR
//=====================================================
if (cchBuffer)
{
*ppwszDescription = Wmioledb_SysAllocString(wszBuffer);
if ( *ppwszDescription == NULL )
{
hr = E_OUTOFMEMORY;
}
}
}
else
{
hr = g_pCError->GetErrorDescription(dwLookupId, ppwszDescription);
}
if ( FAILED(hr) )
{
//=====================================================
// If allocation done, make sure that it is freed
//=====================================================
if ( ppwszSource )
{
SysFreeString(*ppwszSource);
*ppwszSource = NULL;
}
if ( ppwszDescription )
{
SysFreeString(*ppwszDescription);
*ppwszDescription = NULL;
}
}
} // else for if(check valid parameters)
return hr;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Retrieve the error message and source based on the HRESULT and the provider specific error number
//
///////////////////////////////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CImpIErrorLookup::GetHelpInfo( HRESULT hrError,DWORD dwLookupId, LCID lcid,
BSTR* ppwszHelpFile, DWORD* pdwHelpContext )
{
HRESULT hr = S_OK;
//=====================================================
// Check the Arguments
//=====================================================
if ( !ppwszHelpFile || !pdwHelpContext )
{
hr = E_INVALIDARG;
}
else
{
//=====================================================
// Initialize return values
//=====================================================
*ppwszHelpFile = NULL;
*pdwHelpContext = 0;
//=====================================================
// Check the Locale
//=====================================================
if ( lcid != GetSystemDefaultLCID() )
{
hr = DB_E_NOLOCALE;
}
}
//=====================================================
// We currently can't return any help file context or
// names. So, we will just return S_OK.
//=====================================================
return hr;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Method to be called to release non static error messages.
//
///////////////////////////////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CImpIErrorLookup::ReleaseErrors( const DWORD dwDynamicErrorID )
{
HRESULT hr = S_OK;
//=====================================================
// Check the Arguments
//=====================================================
if ( dwDynamicErrorID == 0 )
{
hr = E_INVALIDARG;
}
else
{
g_pCError->RemoveErrors(dwDynamicErrorID);
}
return hr;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Constructor for this class
//
///////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma warning (disable:4355)
CImpIWMIErrorInfo::CImpIWMIErrorInfo( PERRORSTUFF pErrStuff )
{
//=====================================================
// Initialize simple member vars
//=====================================================
m_cRef = 0L;
m_hObjCollection = ULONG(-1);
//=====================================================
// Store values
//=====================================================
m_pErrStuff = pErrStuff;
//=====================================================
// Since the memory is created and owned by WMIoledb,
// we need to make sure that this DLL is not unloaded,
// else we will clean up the handed out pointer
//=====================================================
InterlockedIncrement(&g_cObj);
}
#pragma warning (default:4355)
///////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Destructor for this class
//
///////////////////////////////////////////////////////////////////////////////////////////////////////
CImpIWMIErrorInfo::~CImpIWMIErrorInfo (void)
{
//=====================================================
// For Abnormal Termination,Remove self from Collection
//=====================================================
g_pCError->RemoveFromCollection(m_hObjCollection);
//=====================================================
// If this object has been released, we can now
// decrement our object count
//=====================================================
InterlockedDecrement(&g_cObj);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Returns a pointer to a specified interface. Callers use QueryInterface to determine which interfaces
// the called object supports.
//
///////////////////////////////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CImpIWMIErrorInfo::QueryInterface( REFIID riid, LPVOID * ppv)
{
HRESULT hr = E_NOINTERFACE;
if ( ppv == NULL ){
hr = E_INVALIDARG;
}
else
//=====================================================
// This is the non-delegating IUnknown implementation
//=====================================================
if ( (riid == IID_IUnknown) || (riid == IID_IErrorInfo) ){
*ppv = (LPVOID)this;
}
else{
*ppv = NULL;
}
//=====================================================
// If we're going to return an interface, AddRef first
//=====================================================
if (*ppv){
((LPUNKNOWN)*ppv)->AddRef();
hr = S_OK;
}
return hr;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Increments a persistence count for the object
//
///////////////////////////////////////////////////////////////////////////////////////////////////////
STDMETHODIMP_(ULONG) CImpIWMIErrorInfo::AddRef(void)
{
ULONG cRef = InterlockedIncrement( (long*) &m_cRef);
return cRef;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Decrements a persistence count for the object and if persistence count is 0,object destroys itself.
//
///////////////////////////////////////////////////////////////////////////////////////////////////////
STDMETHODIMP_(ULONG) CImpIWMIErrorInfo::Release (void)
{
ULONG cRef = InterlockedDecrement( (long*) &m_cRef);
if ( !cRef ){
delete this;
return 0;
}
return cRef;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Return the WMIstate associated with this custom error object.
//
///////////////////////////////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CImpIWMIErrorInfo::GetWMIInfo( BSTR* pbstrMsg, LONG* plNativeError )
{
HRESULT hr = S_OK;
//=====================================================
// Check arguments
//=====================================================
if ( !pbstrMsg || !plNativeError)
{
hr = E_INVALIDARG;
}
else
{
//=====================================================
// Initialize return values
//=====================================================
*pbstrMsg = Wmioledb_SysAllocString(NULL);
*plNativeError = 0;
//=====================================================
// Handle WMIState
//=====================================================
if ( wcslen(m_pErrStuff->pwszMessage) > 0 )
{
//=================================================
// If string is not NULL,then we can allocate it
//=================================================
*pbstrMsg = Wmioledb_SysAllocString(m_pErrStuff->pwszMessage);
if ( *pbstrMsg == NULL )
{
hr = E_OUTOFMEMORY;
}
}
//=====================================================
// Handle Native Error Code.
//=====================================================
*plNativeError = m_pErrStuff->lNative;
}
return hr;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
CError::CError( )
{
//=====================================================
// Note that this is NOT a first-class object: it is
// NOT given away outside this DLL. So we do not want
// to alter global object count.
//=====================================================
// Clear variables
m_pWMIErrorInfoCollection = NULL;
m_prgErrorDex = NULL;
m_cErrorsUsed = 0;
m_dwId = 0;
m_ulNext = 1;
//=====================================================
// Initialize ErrorInfo with constant information
//=====================================================
m_ErrorInfo.clsid = CLSID_WMIOLEDB;
m_ErrorInfo.dispid = NULL;
m_pcsErrors = new CCriticalSection(TRUE);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
CError::~CError()
{
ULONG iElems;
ULONG cElems;
ULONG ul;
PIMPIWMIERRORINFO pIWMIErrorInfo;
m_pcsErrors->Enter();
//=====================================================
// Release the general Object
//=====================================================
if ( m_pWMIErrorInfoCollection ){
cElems = m_pWMIErrorInfoCollection->Size();
//=================================================
// Loop through stored object handles and release.
//=================================================
for(iElems=0; iElems<cElems; iElems++){
pIWMIErrorInfo = (PIMPIWMIERRORINFO )m_pWMIErrorInfoCollection->GetAt(iElems);
if ( pIWMIErrorInfo != NULL )
{
delete pIWMIErrorInfo;
}
}
delete m_pWMIErrorInfoCollection;
}
//=====================================================
// Cleanup and error information hanging off the
// pointer array
//=====================================================
if ( m_prgErrorDex ){
for(ul=0; ul<m_cErrors; ul++){
if ( m_prgErrorDex[ul] ){
delete[] m_prgErrorDex[ul];
m_prgErrorDex[ul] = NULL;
}
}
delete[] m_prgErrorDex;
}
m_pcsErrors->Leave();
SAFE_DELETE_PTR(m_pcsErrors);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
//
// If this initialization routine fails, it is the callers responsibility to delete this object.
// The destructor will then clean up any allocated resources
//
///////////////////////////////////////////////////////////////////////////////////////////////////////
HRESULT CError::FInit()
{
HRESULT hr = S_OK;
//=============================================================
// Create array of pointers into the heap
//=============================================================
m_prgErrorDex = new PERRORSTUFF[INITIAL_SIZE_FOR_ERRORSTUFF];
if ( NULL == m_prgErrorDex )
{
hr = E_OUTOFMEMORY;
}
else
{
m_cErrors = INITIAL_SIZE_FOR_ERRORSTUFF;
memset(m_prgErrorDex, 0, INITIAL_SIZE_FOR_ERRORSTUFF * sizeof(PERRORSTUFF));
//=============================================================
// Create WMI Error Object Collection
//=============================================================
m_pWMIErrorInfoCollection = new CFlexArray;
if ( NULL == m_pWMIErrorInfoCollection )
{
hr = E_OUTOFMEMORY;
}
}
return hr;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Remove the Error Information for a particular DynamicId. This could be one or more elements of the
// ERRORSTUFF array and their associated pwszMessages on the Heap.
//
///////////////////////////////////////////////////////////////////////////////////////////////////////
void CError::RemoveErrors( DWORD dwDynamicId )
{
ULONG ul;
//=============================================================
// At the creation of the CAutoBlock object a critical section
// is entered. This is because the method manipulates shared
// structures access to which must be serialized .
// The criticalsection is left when this method terminate
// and the destructor for CAutoBlock is called.
//=============================================================
CAutoBlock Crit(m_pcsErrors);
for(ul=0; ul<m_cErrors; ul++){
if ( m_prgErrorDex[ul] && m_prgErrorDex[ul]->dwDynamicId == dwDynamicId ){
delete[] m_prgErrorDex[ul];
m_prgErrorDex[ul] = NULL;
m_cErrorsUsed--;
//=====================================================
// For each error description that we cache, we have
// up'd the object count to make sure that we stay
// alive while there is a possibility the error
// collection could call back into us for this desc.
// Here is where we decrement that count upon
// release of the error message.
//=====================================================
InterlockedDecrement(&g_cObj);
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////
//
// Retrieve the WMI Server Error Message from the cache
//
////////////////////////////////////////////////////////////////////////////////////////////
HRESULT CError::GetErrorDescription(ULONG ulDex, BSTR* ppwszDescription )
{
HRESULT hr = S_OK;
//======================================================
// Enter critical section
//======================================================
CAutoBlock Crit(m_pcsErrors);
//======================================================
//
//======================================================
if (ulDex < m_cErrors && m_prgErrorDex[ulDex]){
PERRORSTUFF pErrorStuff = m_prgErrorDex[ulDex];
if (wcslen(pErrorStuff->pwszMessage) > 0 ){
//======================================================
// return the message from WMI
//======================================================
*ppwszDescription = Wmioledb_SysAllocString(pErrorStuff->pwszMessage);
if (*ppwszDescription == NULL){
hr = E_OUTOFMEMORY;
}
}
else{
//======================================================
// return the standard error
//======================================================
WCHAR rgwchBuff[MAX_PATH+1];
WCHAR *pwsz = rgwchBuff;
int cwch = LoadStringW(g_hInstance, pErrorStuff->uStringId, rgwchBuff, NUMELEM(rgwchBuff));
*ppwszDescription = Wmioledb_SysAllocString(pwsz);
if (*ppwszDescription == NULL){
hr = E_OUTOFMEMORY;
}
}
}
else{
*ppwszDescription = NULL;
hr = DB_E_BADLOOKUPID;
}
return hr;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Retrieve the IErrorInfo and IErrorRecords pointers whether from automation or from creating a new
// instance
//
///////////////////////////////////////////////////////////////////////////////////////////////////////
HRESULT CError::GetErrorInterfaces( IErrorInfo** ppIErrorInfo, IErrorRecords** ppIErrorRecords )
{
HRESULT hr = S_OK;
*ppIErrorInfo = NULL;
*ppIErrorRecords = NULL;
//=============================================================
//Obtain the error object or create a new one if none exists
//=============================================================
// NTRaid:111806
// 06/07/00
hr = GetErrorInfo(0, ppIErrorInfo);
if (SUCCEEDED(hr) && !*ppIErrorInfo){
hr = g_pErrClassFact->CreateInstance(NULL, IID_IErrorInfo, (LPVOID*)ppIErrorInfo);
}
if(SUCCEEDED(hr))
{
//=============================================================
// Obtain the IErrorRecord Interface
//=============================================================
hr = (*ppIErrorInfo)->QueryInterface(IID_IErrorRecords, (LPVOID*)ppIErrorRecords);
//=============================================================
// On a failure retrieving IErrorRecords, we need to release
// the IErrorInfo interface
//=============================================================
if ( FAILED(hr) ){
(*ppIErrorInfo)->Release();
*ppIErrorInfo = NULL;
}
}
return hr;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Determine the next free index of the PERRORSTUFF array.
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////
HRESULT CError::FindFreeDex( ULONG* ulDex )
{
PERRORSTUFF* pNew = NULL;
HRESULT hr = S_OK;
//===========================================================================
// Check if we need to expand the buffer
// Since we do not use element 0, we need to reallocate when at m_cErrors - 1
//===========================================================================
if ( m_cErrorsUsed == (m_cErrors - 1))
{
try
{
pNew = new PERRORSTUFF[m_cErrors + INCREMENT_BY_FOR_ERRORSTUFF];
}
catch(...)
{
SAFE_DELETE_PTR(pNew);
throw;
}
if ( pNew )
{
//===================================================================
// Copy old pointers to new array
//===================================================================
memcpy(pNew, m_prgErrorDex, m_cErrors * sizeof(PERRORSTUFF));
memset((pNew + m_cErrors), 0, INCREMENT_BY_FOR_ERRORSTUFF * sizeof(PERRORSTUFF));
//===================================================================
// Set the new array size
//===================================================================
m_ulNext = m_cErrors;
m_cErrors += INCREMENT_BY_FOR_ERRORSTUFF;
delete[] m_prgErrorDex;
m_prgErrorDex = pNew;
}
else
{
*ulDex = 0;
hr = E_OUTOFMEMORY;
}
}
if(SUCCEEDED(hr))
{
//===========================================================================
// Loop through looking for unused index
//===========================================================================
while( 1 ){
//=======================================================================
// If we are at the top of our buffer rap back to the begining
//=======================================================================
if (m_ulNext == m_cErrors)
{
m_ulNext = 1;
}
else if (NULL == m_prgErrorDex[m_ulNext])
{
m_cErrorsUsed++;
*ulDex = m_ulNext++;
break;
}
else
{
m_ulNext++;
}
}
}
return hr;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Creates error records for the WMI errors encountered. The WMIState and Native error code are
// stored in a custom interface, where as the description is returned by the standard IErrorInfo
// interface.
//
////////////////////////////////////////////////////////////////////////////////////////////////////
HRESULT CError::PostWMIErrors( HRESULT hrErr, const IID* piid, CErrorData* pErrData )
{
HRESULT hr = S_OK;
IErrorInfo* pIErrorInfo = NULL;
IErrorRecords* pIErrorRecords = NULL;
PIMPIWMIERRORINFO pWMIError = NULL;
ULONG iElems;
ULONG cElems;
PERRORSTUFF pErrStuff;
DWORD dwDex;
//===========================================================================
// Enter critical section
//===========================================================================
CAutoBlock Crit(m_pcsErrors);
//===========================================================================
// We cannot Init the Datasource object without this pointer being set, so it
// should exist at this point
// Get the # errors
//===========================================================================
cElems = pErrData->Size();
if (0 == cElems){
if (FAILED(hrErr))
g_pCError->PostHResult(hrErr, piid);
hr = S_OK;
}
else{
//=======================================================================
// Obtain the error object or create a new one if none exists
//=======================================================================
if ( SUCCEEDED(hr = GetErrorInterfaces(&pIErrorInfo, &pIErrorRecords)) ){
//===================================================================
// Assign static information across each error record added
//===================================================================
m_ErrorInfo.hrError = hrErr;
m_ErrorInfo.iid = *piid;
m_ErrorInfo.dispid = NULL;
//===================================================================
// Increment Dynamic Id;
//===================================================================
m_dwId++;
//===================================================================
// Loop through an array of indexes into the error array
//===================================================================
for (iElems=0; iElems<cElems; iElems++){
//===============================================================
// Get the error stuff
//===============================================================
pErrData->SetAt(iElems,(void**)&pErrStuff);
//===============================================================
// Save the dynamic id
//===============================================================
pErrStuff->dwDynamicId = m_dwId;
//===============================================================
// Save WMI Server error code
//===============================================================
m_ErrorInfo.dwMinor = DWORD(pErrStuff->lNative);
//===============================================================
// Determine index to store heap pointer
//===============================================================
if ( SUCCEEDED(hr = FindFreeDex(&dwDex)) ){
try
{
//===========================================================
// Create the custom error object
//===========================================================
pWMIError = new CImpIWMIErrorInfo(pErrStuff);
}
catch(...)
{
SAFE_DELETE_PTR(pWMIError);
throw;
}
if ( pWMIError == NULL ){
hr = E_OUTOFMEMORY;
}
else{
pWMIError->AddRef();
if ( SUCCEEDED(hr = pWMIError->FInit()) ){
//===================================================
// Add the record to the Error Service Object
//===================================================
hr = pIErrorRecords->AddErrorRecord(&m_ErrorInfo, dwDex, NULL,(IUnknown*) pWMIError, m_dwId);
if ( SUCCEEDED(hr) ){
//===============================================
// Release the custom Error Object
//===============================================
pWMIError->Release();
pWMIError = NULL;
//===============================================
// Save the pointer to the error stuff
//===============================================
m_prgErrorDex[dwDex] = pErrStuff;
//===============================================
// For each error description that we cache, we
// have up'd the the object count to make sure
// that we stay alive while there is a
// possibility the errorcollection could call back
// into us for this description. Here is where we
// increment that count.
//===============================================
InterlockedIncrement(&g_cObj);
}
}
}
}
//================================================================
// Pass the error object to the Ole Automation DLL
//================================================================
hr = SetErrorInfo(0, pIErrorInfo);
}
}
}
//============================================================================
// Release the interfaces to transfer ownership to the Ole Automation DLL
//============================================================================
SAFE_RELEASE_PTR(pWMIError);
SAFE_RELEASE_PTR(pIErrorRecords);
SAFE_RELEASE_PTR(pIErrorInfo);
//============================================================================
// Free the error data
//============================================================================
pErrData->FreeErrors();
return hr;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// This method is used to post an HRESULT that is to be looked up in the resource fork of the error collection
// object.
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
HRESULT CError::PostHResult( HRESULT hrErr, const IID* piid )
{
HRESULT hr = S_OK;
IErrorInfo* pIErrorInfo = NULL;
IErrorRecords* pIErrorRecords = NULL;
//==================================================================
// Enter critical section
//==================================================================
CAutoBlock Crit(m_pcsErrors);
//==================================================================
// Obtain the error object or create a new one if none exists
//==================================================================
if ( SUCCEEDED(hr = GetErrorInterfaces(&pIErrorInfo, &pIErrorRecords)) )
{
//==================================================================
// Assign static information across each error record added
//==================================================================
m_ErrorInfo.hrError = hrErr;
m_ErrorInfo.iid = *piid;
m_ErrorInfo.dispid = NULL;
m_ErrorInfo.dwMinor = 0;
//==================================================================
// Add the record to the Error Service Object
//==================================================================
hr = pIErrorRecords->AddErrorRecord(&m_ErrorInfo,IDENTIFIER_SDK_ERROR,NULL,(IUnknown*)NULL,0);
if ( SUCCEEDED(hr) )
{
//==================================================================
// Pass the error object to the Ole Automation DLL
//==================================================================
hr = SetErrorInfo(0, pIErrorInfo);
}
}
//==================================================================
// Release the interfaces to transfer ownership to the Ole Automation DLL
//==================================================================
SAFE_RELEASE_PTR(pIErrorRecords);
SAFE_RELEASE_PTR(pIErrorInfo);
return hrErr;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// This method is used to post static strings to the error objects. The static strings are stored in the
// resource fork, and thus an id needs to be specified.
//
// @devnote If the error object is not our implementation of IID_IErrorInfo, we will not be able to load
// IErrorRecord and add our records.
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
HRESULT CError::PostError( HRESULT hrErr, const IID* piid, DWORD dwIds, DISPPARAMS* pdispparams )
{
HRESULT hr = S_OK;
IErrorInfo* pIErrorInfo = NULL;
IErrorRecords* pIErrorRecords = NULL;
//====================================================================
// Enter critical section
//====================================================================
CAutoBlock Crit(m_pcsErrors);
//====================================================================
// Obtain the error object or create a new one if none exists
//====================================================================
if ( SUCCEEDED(hr = GetErrorInterfaces(&pIErrorInfo, &pIErrorRecords)) )
{
//====================================================================
// Assign static information across each error record added
//====================================================================
m_ErrorInfo.hrError = hrErr;
m_ErrorInfo.iid = *piid;
m_ErrorInfo.dispid = NULL;
m_ErrorInfo.dwMinor = 0;
//====================================================================
// Add the record to the Error Service Object
//====================================================================
hr = pIErrorRecords->AddErrorRecord(&m_ErrorInfo, (dwIds | ERR_STATIC_STRING), pdispparams, NULL, 0);
if ( SUCCEEDED(hr) )
{
//====================================================================
// Pass the error object to the Ole Automation DLL
//====================================================================
hr = SetErrorInfo(0, pIErrorInfo);
}
}
//====================================================================
// Release the interfaces to transfer ownership to the Ole Automation DLL
//====================================================================
SAFE_RELEASE_PTR(pIErrorRecords);
SAFE_RELEASE_PTR(pIErrorInfo);
return hr;
}
////////////////////////////////////////////////////////////////////////////////////////////////
//
// This method is used to post static strings to the error objects.
//
////////////////////////////////////////////////////////////////////////////////////////////////
HRESULT CError::PostErrorMessage( HRESULT hrErr, const IID* piid, UINT uStringId, LPCWSTR pwszMessage )
{
PERRORSTUFF pErrStuff = NULL;
ULONG cwch = wcslen(pwszMessage);
HRESULT hr = S_OK;
IErrorInfo* pIErrorInfo = NULL;
IErrorRecords* pIErrorRecords = NULL;
PIMPIWMIERRORINFO pWMIError = NULL;
DWORD dwDex;
//==========================================================
// CS because the method manipulates shared structures
// access to which must be serialized .
//==========================================================
CAutoBlock Crit(m_pcsErrors);
try
{
pErrStuff = (PERRORSTUFF) new BYTE[sizeof(ERRORSTUFF)+(cwch+2)*sizeof(WCHAR)];
}
catch(...)
{
SAFE_DELETE_ARRAY(pErrStuff);
throw;
}
if (!pErrStuff) {
hr = E_OUTOFMEMORY;
}
else
{
//==========================================================
// Initialize error stuff
//==========================================================
pErrStuff->dwDynamicId = 0;
pErrStuff->uStringId = uStringId;
pErrStuff->hr = S_OK;
pErrStuff->lNative = 0;
pErrStuff->wLineNumber = 0;
AllocateAndCopy(pErrStuff->pwszMessage, (unsigned short*)pwszMessage);
//==========================================================
// We cannot Init the Datasource object without this pointer
// being set, so it should exist at this point
// Obtain the error object or create new one if none exists
//==========================================================
if ( SUCCEEDED(hr = GetErrorInterfaces(&pIErrorInfo, &pIErrorRecords)) )
{
//==========================================================
// Assign static information across each error record added
//==========================================================
m_ErrorInfo.hrError = hrErr;
m_ErrorInfo.iid = *piid;
m_ErrorInfo.dispid = NULL;
m_ErrorInfo.dwMinor = 0;
//==========================================================
// Increment Dynamic Id and save it
//==========================================================
pErrStuff->dwDynamicId = ++m_dwId;
//==========================================================
// Determine index to store heap pointer
//==========================================================
if ( SUCCEEDED(hr = FindFreeDex(&dwDex)) )
{
try
{
//==========================================================
// Create the custom error object
//==========================================================
pWMIError = new CImpIWMIErrorInfo(pErrStuff);
}
catch(...)
{
SAFE_DELETE_ARRAY(pErrStuff);
SAFE_DELETE_PTR(pErrStuff);
throw;
}
if ( pWMIError == NULL ){
hr = E_OUTOFMEMORY;
}
else
{
//==========================================================
// Give the object existence
//==========================================================
pWMIError->AddRef();
if ( SUCCEEDED(hr = pWMIError->FInit()) )
{
//==========================================================
// Add the record to the Error Service Object
//==========================================================
if(SUCCEEDED(hr = pIErrorRecords->AddErrorRecord(&m_ErrorInfo, dwDex, NULL, (IUnknown*)pWMIError, m_dwId)))
{
//==========================================================
// Release the custom Error Object
//==========================================================
pWMIError->Release();
pWMIError = NULL;
//==========================================================
// Save the pointer to the error stuff
//==========================================================
m_prgErrorDex[dwDex] = pErrStuff;
//==========================================================
// For each error description that we cache, we have up'd the
// the object count to make sure that we stay alive while there is
// a possibility the errorcollection could call back into us for
// this description. Here is where we increment that count.
//==========================================================
InterlockedIncrement(&g_cObj);
//==========================================================
// Pass the error object to the Ole Automation DLL
//==========================================================
hr = SetErrorInfo(0, pIErrorInfo);
} // if Succeeded(AddErrorRecord(())
} // if (succeeded(pWMIError->FInit))
} // if allocation of pWMIError is successful
} // if(succeeded(FindFreeDex))
} // if succeeded(GetErrorInterfaces)
} // if propert allocation
//==========================================================
// Release the interfaces to transfer ownership to
//==========================================================
SAFE_DELETE_ARRAY(pErrStuff);
SAFE_DELETE_PTR(pErrStuff);
SAFE_RELEASE_PTR(pWMIError);
SAFE_RELEASE_PTR(pIErrorRecords);
SAFE_RELEASE_PTR(pIErrorInfo);
return hr;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Frees error information and empties the array
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////
void CError::FreeErrors()
{
ULONG iElems;
ULONG cElems;
BYTE* pb;
cElems = Size();
for (iElems=0; iElems<cElems; iElems++){
pb = (BYTE*) m_pWMIErrorInfoCollection->GetAt(iElems);
if (pb){
delete[] pb;
}
}
m_pWMIErrorInfoCollection->Empty();
}
//**********************************************************************************************************
//
//**********************************************************************************************************
////////////////////////////////////////////////////////////////////////////////////////////////////////////
CErrorData::CErrorData()
{
//
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////
CErrorData::~CErrorData()
{
FreeErrors();
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////
void CErrorData::FreeErrors()
{
}