|
|
//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1997 - 1999
//
// File: errutil.cpp
//
//--------------------------------------------------------------------------
#include "stdafx.h"
#include "errutil.h"
#include "mprapi.h"
#include "mprerror.h"
#include "raserror.h"
#define IS_WIN32_HRESULT(x) (((x) & 0xFFFF0000) == 0x80070000)
#define WIN32_FROM_HRESULT(hr) (0x0000FFFF & (hr))
/*!--------------------------------------------------------------------------
FormatError - Author: KennT ---------------------------------------------------------------------------*/ TFSCORE_API(HRESULT) FormatError(HRESULT hr, TCHAR *pszBuffer, UINT cchBuffer) { DWORD dwErr; // Copy over default message into szBuffer
_tcscpy(pszBuffer, _T("Error"));
// Ok, we can't get the error info, so try to format it
// using the FormatMessage
// Ignore the return message, if this call fails then I don't
// know what to do.
dwErr = FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, NULL, hr, 0, pszBuffer, cchBuffer, NULL); pszBuffer[cchBuffer-1] = 0; return HResultFromWin32(dwErr); }
/*---------------------------------------------------------------------------
TFS Error handling code. ---------------------------------------------------------------------------*/
struct TFSInternalErrorInfo { DWORD m_dwSize; // size of the structure, used for versioning
DWORD m_dwThreadId; // thread id of this error structure
LONG_PTR m_uReserved1; // = 0, reserved for object id
LONG_PTR m_uReserved2; // = 0 for now, reserved for HRESULT component type
DWORD m_hrLow; // HRESULT of the low level error
CString m_stLow; // allocate using HeapAlloc() and GetErrorHeap()
CString m_stHigh; // allocate using HeapAlloc() and GetErrorHeap()
CString m_stGeek; // allocate using HeapAlloc() and GetErrorHeap()
LONG_PTR m_uReserved3; // =0, reserved for error dialog information(?)
LONG_PTR m_uReserved4; // =0, reserved for error dialog information(?)
LONG_PTR m_uReserved5; // =0, reserved for future use
DWORD m_dwFlags; // used to pass info between our objects
// Allocates and serializes a TFSErrorInfo. Used by GetErrorInfo();
TFSErrorInfo * SaveToBlock(); void LoadFromBlock(const TFSErrorInfo *pErr); };
/*!--------------------------------------------------------------------------
TFSInternalErrorInfo::SaveToBlock This function converts the internal structure into a TFSErrorInfo structure (that is allocated on the error heap). It will allocate all of the data at once. Author: KennT ---------------------------------------------------------------------------*/ TFSErrorInfo * TFSInternalErrorInfo::SaveToBlock() { DWORD dwSize = 0; TFSErrorInfo *pError = NULL; WCHAR * pswz = NULL; // Determine how large of an allocation we will need
// Need the size of the structure itself
dwSize += sizeof(TFSErrorInfo);
// Need the size of the low-level error string
dwSize += (m_stLow.GetLength() + 1) * sizeof(WCHAR); dwSize += (m_stHigh.GetLength() + 1) * sizeof(WCHAR); dwSize += (m_stGeek.GetLength() + 1) * sizeof(WCHAR);
// Allocate a chunk of memory for this
HANDLE hHeap = GetTFSErrorHeap(); if (hHeap) { pError = (TFSErrorInfo *) ::HeapAlloc(hHeap, HEAP_ZERO_MEMORY, dwSize); if (pError) { pError->m_dwSize = sizeof(TFSErrorInfo); // pError->m_dwThreadId = m_dwThreadId;
pError->m_hrLow = m_hrLow; // pError->m_uReserved1 = m_uReserved1;
pError->m_uReserved2 = m_uReserved2; pError->m_uReserved3 = m_uReserved3; pError->m_uReserved4 = m_uReserved4; pError->m_uReserved5 = m_uReserved5;
// Add the strings to the end of this structure
pswz = (LPWSTR) (pError+1); StrCpy(pswz, (LPCWSTR) T2CW(m_stLow)); pError->m_pszLow = pswz; pswz += (StrLenW(pswz) + 1); StrCpy(pswz, (LPCWSTR) T2CW(m_stHigh)); pError->m_pszHigh = pswz; pswz += (StrLenW(pswz) + 1); StrCpy(pswz, (LPCWSTR) T2CW(m_stGeek)); pError->m_pszGeek = pswz;
// Check to see that the size is what we think it is
Assert( (sizeof(TFSErrorInfo) + (pswz - (LPWSTR)(pError+1)) + StrLenW(pswz) + 1) <= dwSize );
} }
return pError; }
/*!--------------------------------------------------------------------------
TFSInternalErrorInfo::LoadFromBlock Fills a TFSInternalErrorInfo struct with the information from a TFSErrorInfo. If pErr is NULL, then we clear this struct (i.e. fill it in with NULL data). Author: KennT ---------------------------------------------------------------------------*/ void TFSInternalErrorInfo::LoadFromBlock(const TFSErrorInfo *pErr) { USES_CONVERSION;
if (pErr) { m_dwSize = pErr->m_dwSize; // m_dwThreadId = pErr->m_dwThreadId;
// m_uReserved1 = pErr->m_uReserved1;
m_uReserved2 = pErr->m_uReserved2; m_uReserved3 = pErr->m_uReserved3; m_uReserved4 = pErr->m_uReserved4; m_uReserved5 = pErr->m_uReserved5;
if (pErr->m_hrLow) m_hrLow = pErr->m_hrLow;
// Overwrite the low-level string if one is provided
if (pErr->m_pszLow) m_stLow = OLE2CT(pErr->m_pszLow);
// Overwrite the high-level error
if (pErr->m_pszHigh && ((pErr->m_dwFlags & FILLTFSERR_NOCLOBBER) == 0)) m_stHigh = OLE2CT(pErr->m_pszHigh);
// Overwrite the geek-level string if one is provided
if (pErr->m_pszGeek) m_stGeek = OLE2CT(pErr->m_pszGeek); } else { // if pErr==NULL, clear out the structure
m_dwSize = 0; // m_dwThreadId = 0;
// m_uReserved1 = 0;
m_uReserved2 = 0; m_uReserved3 = 0; m_uReserved4 = 0; m_uReserved5 = 0; m_hrLow = 0;
m_stLow.Empty(); m_stHigh.Empty(); m_stGeek.Empty(); } }
/*---------------------------------------------------------------------------
Type: TFSInternalErrorList ---------------------------------------------------------------------------*/ typedef CList<TFSInternalErrorInfo *, TFSInternalErrorInfo *> TFSInternalErrorInfoList;
/*---------------------------------------------------------------------------
Class: TFSErrorObject
This is the central class that manages the error information structures for the various threads and objects.
This class is thread-safe. ---------------------------------------------------------------------------*/
class TFSErrorObject : public ITFSError { public: DeclareIUnknownMembers(IMPL); DeclareITFSErrorMembers(IMPL);
TFSErrorObject(); ~TFSErrorObject();
void Lock(); void Unlock();
HRESULT Init(); HRESULT Cleanup();
HANDLE GetHeap();
HRESULT CreateErrorInfo(DWORD dwThreadId, LONG_PTR uReserved); HRESULT DestroyErrorInfo(DWORD dwThreadId, LONG_PTR uReserved);
// Looks for the error info that matches up with the dwThreadId
// and uReserved.
TFSInternalErrorInfo * FindErrorInfo(DWORD dwThreadId, LONG_PTR uReserved);
protected: long m_cRef;
BOOL m_fInitialized; // TRUE if initialized, FALSE otherwise
CRITICAL_SECTION m_critsec;
TFSInternalErrorInfoList m_tfserrList; HANDLE m_hHeap; // Handle of the heap for this error object
};
TFSErrorObject::TFSErrorObject() : m_cRef(1), m_fInitialized(FALSE), m_hHeap(NULL) { InitializeCriticalSection(&m_critsec); }
TFSErrorObject::~TFSErrorObject() { Cleanup(); DeleteCriticalSection(&m_critsec); }
IMPLEMENT_SIMPLE_QUERYINTERFACE(TFSErrorObject, ITFSError)
STDMETHODIMP_(ULONG) TFSErrorObject::AddRef() { return InterlockedIncrement(&m_cRef); }
STDMETHODIMP_(ULONG) TFSErrorObject::Release() { Assert(m_cRef > 0); if (0 == InterlockedDecrement(&m_cRef)) { // No need to free this object up since it's static
return 0; } return m_cRef; }
/*!--------------------------------------------------------------------------
TFSErrorObject::Lock - Author: KennT ---------------------------------------------------------------------------*/ void TFSErrorObject::Lock() { EnterCriticalSection(&m_critsec); }
/*!--------------------------------------------------------------------------
TFSErrorObject::Unlock - Author: KennT ---------------------------------------------------------------------------*/ void TFSErrorObject::Unlock() { LeaveCriticalSection(&m_critsec); }
/*!--------------------------------------------------------------------------
TFSErrorObject::Init - Author: KennT ---------------------------------------------------------------------------*/ HRESULT TFSErrorObject::Init() { HRESULT hr = hrOK;
Lock();
if (!m_fInitialized) { Assert(m_tfserrList.GetCount() == 0); // Create the heap
m_hHeap = HeapCreate(0, 4096, 0); if (m_hHeap == NULL) hr = HRESULT_FROM_WIN32(GetLastError());
if (FHrSucceeded(hr)) m_fInitialized = TRUE; } Unlock();
return hr; }
/*!--------------------------------------------------------------------------
TFSErrorObject::Cleanup - Author: KennT ---------------------------------------------------------------------------*/ HRESULT TFSErrorObject::Cleanup() { HRESULT hr = hrOK; POSITION pos; TFSInternalErrorInfo * pErr;
Lock();
if (m_fInitialized) { while (!m_tfserrList.IsEmpty()) { delete m_tfserrList.RemoveHead(); }
if (m_hHeap) { HeapDestroy(m_hHeap); m_hHeap = NULL; } } Unlock();
return hr; }
/*!--------------------------------------------------------------------------
TFSErrorObject::GetHeap - Author: KennT ---------------------------------------------------------------------------*/ HANDLE TFSErrorObject::GetHeap() { HANDLE hHeap = NULL;
Lock();
if (m_fInitialized) hHeap = m_hHeap; Unlock();
return hHeap; }
HRESULT TFSErrorObject::CreateErrorInfo(DWORD dwThreadId, LONG_PTR uReserved) { HRESULT hr = hrOK; TFSInternalErrorInfo * pErr = NULL;
COM_PROTECT_TRY { if (FindErrorInfo(dwThreadId, uReserved) == NULL) { pErr = new TFSInternalErrorInfo;
pErr->LoadFromBlock(NULL);
// Fill in the data with the appropriate fields
pErr->m_dwThreadId = dwThreadId; pErr->m_uReserved1 = uReserved;
m_tfserrList.AddTail(pErr); } } COM_PROTECT_CATCH;
if (!FHrSucceeded(hr)) delete pErr; return hr; }
HRESULT TFSErrorObject::DestroyErrorInfo(DWORD dwThreadId, LONG_PTR uReserved) { HRESULT hr = hrOK; POSITION pos, posTemp; TFSInternalErrorInfo * pErr; BOOL bFound = FALSE;
COM_PROTECT_TRY { pos = m_tfserrList.GetHeadPosition(); while (pos) { posTemp = pos; pErr = m_tfserrList.GetNext(pos); if ((pErr->m_dwThreadId == dwThreadId) && (pErr->m_uReserved1 == uReserved)) { m_tfserrList.RemoveAt(posTemp); delete pErr; bFound = TRUE; break; } }
if (!bFound) hr = E_INVALIDARG; } COM_PROTECT_CATCH; return hr; }
TFSInternalErrorInfo * TFSErrorObject::FindErrorInfo(DWORD dwThreadId, LONG_PTR uReserved) { POSITION pos; POSITION posTemp; TFSInternalErrorInfo * pErr = NULL; BOOL bFound = FALSE; HRESULT hr = hrOK;
COM_PROTECT_TRY { pos = m_tfserrList.GetHeadPosition(); while (pos) { posTemp = pos; pErr = m_tfserrList.GetNext(pos); if ((pErr->m_dwThreadId == dwThreadId) && (pErr->m_uReserved1 == uReserved)) { bFound = TRUE; break; } } } COM_PROTECT_CATCH; return bFound ? pErr : NULL; } /*!--------------------------------------------------------------------------
TFSErrorObject::GetErrorInfo Implementation of ITFSError::GetErrorInfo Author: KennT ---------------------------------------------------------------------------*/ STDMETHODIMP TFSErrorObject::GetErrorInfo(LONG_PTR uReserved, TFSErrorInfo **ppErr) { HRESULT hr = hrOK;
Lock(); COM_PROTECT_TRY { hr = GetErrorInfoForThread(GetCurrentThreadId(), uReserved, ppErr); } COM_PROTECT_CATCH;
Unlock();
return hr; }
/*!--------------------------------------------------------------------------
TFSErrorObject::GetErrorInfoForThread Implementation of ITFSError::GetErrorInfoForThread Author: KennT ---------------------------------------------------------------------------*/ STDMETHODIMP TFSErrorObject::GetErrorInfoForThread(DWORD dwThreadId, LONG_PTR uReserved, TFSErrorInfo **ppErr) { HRESULT hr = hrOK; TFSInternalErrorInfo * pInternalError; TFSErrorInfo * pErr = NULL;
if (ppErr == NULL) return E_INVALIDARG; *ppErr = NULL;
Lock(); COM_PROTECT_TRY { if (!m_fInitialized) hr = E_FAIL; else { // Can we find the right error object?
pInternalError = FindErrorInfo(dwThreadId, uReserved); if (pInternalError) pErr = pInternalError->SaveToBlock(); else hr = E_INVALIDARG;
*ppErr = pErr; } } COM_PROTECT_CATCH;
Unlock();
return hr; }
/*!--------------------------------------------------------------------------
TFSErrorObject::SetErrorInfo Implementation of ITFSError::SetErrorInfo Author: KennT ---------------------------------------------------------------------------*/ STDMETHODIMP TFSErrorObject::SetErrorInfo(LONG_PTR uReserved, const TFSErrorInfo *pErr) { HRESULT hr = hrOK;
Lock(); COM_PROTECT_TRY { hr = SetErrorInfoForThread(GetCurrentThreadId(), uReserved, pErr); } COM_PROTECT_CATCH;
Unlock();
return hr; }
/*!--------------------------------------------------------------------------
TFSErrorObject::SetErrorInfoForThread Implementation of ITFSError::SetErrorInfoForThread Author: KennT ---------------------------------------------------------------------------*/ STDMETHODIMP TFSErrorObject::SetErrorInfoForThread(DWORD dwThreadId, LONG_PTR uReserved, const TFSErrorInfo *pErr) { HRESULT hr = hrOK; TFSInternalErrorInfo * pInternalError;
Lock(); COM_PROTECT_TRY { if (!m_fInitialized) hr = E_FAIL; else { // Can we find the right error object?
pInternalError = FindErrorInfo(dwThreadId, uReserved); if (pInternalError) { pInternalError->LoadFromBlock(pErr); } else hr = E_INVALIDARG; } } COM_PROTECT_CATCH;
Unlock();
return hr; }
/*!--------------------------------------------------------------------------
TFSErrorObject::ClearErrorInfo Implementation of ITFSError::ClearErrorInfo Author: KennT ---------------------------------------------------------------------------*/ STDMETHODIMP TFSErrorObject::ClearErrorInfo(LONG_PTR uReserved) { HRESULT hr = hrOK;
Lock(); COM_PROTECT_TRY { hr = ClearErrorInfoForThread(GetCurrentThreadId(), uReserved); } COM_PROTECT_CATCH;
Unlock();
return hr; }
/*!--------------------------------------------------------------------------
TFSErrorObject::ClearErrorInfoForThread Implementation of ITFSError::ClearErrorInfoForThread Author: KennT ---------------------------------------------------------------------------*/ STDMETHODIMP TFSErrorObject::ClearErrorInfoForThread(DWORD dwThreadId, LONG_PTR uReserved) { HRESULT hr = hrOK; TFSInternalErrorInfo * pInternalError;
Lock(); COM_PROTECT_TRY { if (!m_fInitialized) hr = E_FAIL; else { // Can we find the right error object?
pInternalError = FindErrorInfo(dwThreadId, uReserved); if (pInternalError) { // Clear the information out of the internal block
pInternalError->LoadFromBlock(NULL); } else hr = E_INVALIDARG; } } COM_PROTECT_CATCH;
Unlock();
return hr; }
/*---------------------------------------------------------------------------
This is a static object that lives in the process space. It does not get dynamically created or destroyed. ---------------------------------------------------------------------------*/ static TFSErrorObject s_tfsErrorObject;
/*---------------------------------------------------------------------------
Global API functions ---------------------------------------------------------------------------*/
/*!--------------------------------------------------------------------------
InitializeTFSError - Author: KennT ---------------------------------------------------------------------------*/ TFSCORE_API(HRESULT) InitializeTFSError() { return s_tfsErrorObject.Init(); }
/*!--------------------------------------------------------------------------
CleanupTFSError - Author: KennT ---------------------------------------------------------------------------*/ TFSCORE_API(HRESULT) CleanupTFSError() { return s_tfsErrorObject.Cleanup(); }
/*!--------------------------------------------------------------------------
GetTFSErrorObject - Author: KennT ---------------------------------------------------------------------------*/ TFSCORE_API(ITFSError *) GetTFSErrorObject() { return &s_tfsErrorObject; }
/*!--------------------------------------------------------------------------
GetTFSErrorHeap - Author: KennT ---------------------------------------------------------------------------*/ TFSCORE_API(HANDLE) GetTFSErrorHeap() { return s_tfsErrorObject.GetHeap(); }
/*!--------------------------------------------------------------------------
CreateTFSErrorInfo - Author: KennT ---------------------------------------------------------------------------*/ TFSCORE_API(HRESULT) CreateTFSErrorInfo(LONG_PTR uReserved) { return CreateTFSErrorInfoForThread(GetCurrentThreadId(), uReserved); }
/*!--------------------------------------------------------------------------
CreateTFSErrorInfoForThread - Author: KennT ---------------------------------------------------------------------------*/ TFSCORE_API(HRESULT) CreateTFSErrorInfoForThread(DWORD dwThreadId, LONG_PTR uReserved) { return s_tfsErrorObject.CreateErrorInfo(dwThreadId, uReserved); }
/*!--------------------------------------------------------------------------
DestroyTFSErrorInfo - Author: KennT ---------------------------------------------------------------------------*/ TFSCORE_API(HRESULT) DestroyTFSErrorInfo(LONG_PTR uReserved) { return DestroyTFSErrorInfoForThread(GetCurrentThreadId(), uReserved); }
/*!--------------------------------------------------------------------------
DestroyTFSErrorInfoForThread - Author: KennT ---------------------------------------------------------------------------*/ TFSCORE_API(HRESULT) DestroyTFSErrorInfoForThread(DWORD dwThreadId, LONG_PTR uReserved) { return s_tfsErrorObject.DestroyErrorInfo(dwThreadId, uReserved); }
TFSCORE_API(HRESULT) ClearTFSErrorInfo(LONG_PTR uReserved) { return ClearTFSErrorInfoForThread(GetCurrentThreadId(), uReserved); }
TFSCORE_API(HRESULT) ClearTFSErrorInfoForThread(DWORD dwThreadId, LONG_PTR uReserved) { return s_tfsErrorObject.ClearErrorInfoForThread(dwThreadId, uReserved); }
/*!--------------------------------------------------------------------------
DisplayTFSErrorMessage - Author: KennT ---------------------------------------------------------------------------*/ TFSCORE_API(HRESULT) DisplayTFSErrorMessage(HWND hWndParent) { CString stTitle; stTitle.LoadString(AFX_IDS_APP_TITLE);
HRESULT hr = hrOK; CString st; TFSErrorInfo * pErr = NULL; BOOL fQuit; MSG msgT;
// Format the string with the text for the current error message
GetTFSErrorObject()->GetErrorInfo(0, &pErr); if (pErr && !FHrSucceeded(pErr->m_hrLow)) { if (pErr->m_pszHigh && pErr->m_pszLow) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); AfxFormatString2(st, IDS_ERROR_FORMAT2, pErr->m_pszHigh, pErr->m_pszLow); } else if (pErr->m_pszHigh || pErr->m_pszLow) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); AfxFormatString1(st, IDS_ERROR_FORMAT1, pErr->m_pszHigh ? pErr->m_pszHigh : pErr->m_pszLow); } // Is there a WM_QUIT message in the queue, if so remove it.
fQuit = ::PeekMessage(&msgT, NULL, WM_QUIT, WM_QUIT, PM_REMOVE); ::MessageBox(hWndParent, (LPCTSTR) st, (LPCTSTR) stTitle, MB_OK | MB_ICONERROR | /*MB_DEFAULT_DESKTOP_ONLY | --ft:removed as per bug #233282*/ MB_SETFOREGROUND); // If there was a quit message, add it back into the queue
if (fQuit) ::PostQuitMessage((int)msgT.wParam);
if ((GetAsyncKeyState(VK_CONTROL) & 0x8000) != 0) { CString stHresult; // Bring up another message box with the geek message
// if there is one
if (pErr->m_pszGeek) { { AFX_MANAGE_STATE(AfxGetStaticModuleState()); stHresult.Format(_T("%08lx"), pErr->m_hrLow); AfxFormatString2(st, IDS_ERROR_MORE_INFORMATION, stHresult, pErr->m_pszGeek); } // Is there a WM_QUIT message in the queue, if so remove it.
fQuit = ::PeekMessage(&msgT, NULL, WM_QUIT, WM_QUIT, PM_REMOVE); ::MessageBox(hWndParent, (LPCTSTR) st, (LPCTSTR) stTitle, MB_OK | MB_ICONERROR | /*MB_DEFAULT_DESKTOP_ONLY | --ft:removed as per bug #233282*/ MB_SETFOREGROUND); // If there was a quit message, add it back into the queue
if (fQuit) ::PostQuitMessage((int)msgT.wParam); } }
TFSErrorInfoFree(pErr); pErr = NULL; } else hr = E_FAIL; return hr; }
TFSCORE_API(HRESULT) FillTFSError(LONG_PTR uReserved, HRESULT hrLow, DWORD dwFlags, LPCTSTR pszHigh, LPCTSTR pszLow, LPCTSTR pszGeek) { TFSErrorInfo es; HRESULT hr = hrOK; USES_CONVERSION;
::ZeroMemory(&es, sizeof(es)); es.m_dwSize = sizeof(TFSErrorInfo); es.m_uReserved2 = 0; es.m_hrLow = hrLow; if (dwFlags & FILLTFSERR_LOW) es.m_pszLow = T2COLE(pszLow); if (dwFlags & FILLTFSERR_HIGH) es.m_pszHigh = T2COLE(pszHigh); if (dwFlags & FILLTFSERR_GEEK) es.m_pszGeek = T2COLE(pszGeek); es.m_uReserved3 = 0; es.m_uReserved4 = 0; es.m_uReserved5 = 0; es.m_dwFlags = dwFlags; GetTFSErrorObject()->SetErrorInfo(uReserved, &es); return hr; }
TFSCORE_API(HRESULT) FillTFSErrorId(LONG_PTR uReserved, HRESULT hrLow, DWORD dwFlags, UINT nHigh, UINT nLow, UINT nGeek) { CString stHigh, stLow, stGeek;
if ((dwFlags & FILLTFSERR_HIGH) && nHigh) stHigh.LoadString(nHigh); if ((dwFlags & FILLTFSERR_LOW) && nLow) stLow.LoadString(nLow); if ((dwFlags & FILLTFSERR_GEEK) && nGeek) stGeek.LoadString(nGeek);
return FillTFSError(uReserved, hrLow, dwFlags, (LPCTSTR) stHigh, (LPCTSTR) stLow, (LPCTSTR) stGeek); }
TFSCORE_API(void) AddSystemErrorMessage(HRESULT hr) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); if (!FHrSucceeded(hr)) { TCHAR szBuffer[4096]; CString st, stHr;
FormatError(hr, szBuffer, DimensionOf(szBuffer)); stHr.Format(_T("%08lx"), hr);
AfxFormatString2(st, IDS_ERROR_SYSTEM_ERROR_FORMAT, szBuffer, (LPCTSTR) stHr);
FillTFSError(0, hr, FILLTFSERR_LOW, NULL, (LPCTSTR) st, NULL); } }
TFSCORE_API(void) AddWin32ErrorMessage(DWORD dwErr) { AFX_MANAGE_STATE(AfxGetStaticModuleState());
if (dwErr != ERROR_SUCCESS) { TCHAR szBuffer[4096]; CString st, stHr;
FormatError(dwErr, szBuffer, DimensionOf(szBuffer)); stHr.Format(_T("%08lx"), dwErr);
AfxFormatString2(st, IDS_ERROR_SYSTEM_ERROR_FORMAT, szBuffer, (LPCTSTR) stHr);
FillTFSError(0, HResultFromWin32(dwErr), FILLTFSERR_LOW, NULL, (LPCTSTR) st, NULL); } }
TFSCORE_API(HRESULT) GetTFSErrorInfo(TFSErrorInfo **ppErrInfo) { return GetTFSErrorInfoForThread(GetCurrentThreadId(), ppErrInfo); }
TFSCORE_API(HRESULT) SetTFSErrorInfo(const TFSErrorInfo *pErrInfo) { return SetTFSErrorInfoForThread(GetCurrentThreadId(), pErrInfo); }
TFSCORE_API(HRESULT) GetTFSErrorInfoForThread(DWORD dwThreadId, TFSErrorInfo **ppErrInfo) { return GetTFSErrorObject()->GetErrorInfoForThread(dwThreadId, 0, ppErrInfo); }
TFSCORE_API(HRESULT) SetTFSErrorInfoForThread(DWORD dwThreadId, const TFSErrorInfo *pErrInfo) { return GetTFSErrorObject()->SetErrorInfoForThread(dwThreadId, 0, pErrInfo); }
TFSCORE_API(HRESULT) TFSErrorInfoFree(TFSErrorInfo *pErrInfo) { HANDLE hHeap = GetTFSErrorHeap(); if (hHeap) { ::HeapFree(hHeap, 0, pErrInfo); }
return hrOK; }
|