Dryad/DryadVertex/VertexHost/system/classlib/src/DrError.cpp

504 lines
14 KiB
C++

/*
Copyright (c) Microsoft Corporation
All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License
at http://www.apache.org/licenses/LICENSE-2.0
THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER
EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF
TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT.
See the Apache Version 2.0 License for specific language governing permissions and
limitations under the License.
*/
#include "DrCommon.h"
#include <lmerr.h>
#include <winhttp.h>
#pragma unmanaged
typedef struct {
DrError value;
const char *pszDescription;
} ErrEntry;
typedef struct _ErrHashEntry {
DrError value;
const char *pszDescription;
struct _ErrHashEntry *pNext;
} ErrHashEntry;
#define FACILITY_DRYAD 778
#define DRYAD_ERROR(n) ((HRESULT)(0x80000000 + (FACILITY_DRYAD << 16) + n))
#ifdef DEFINE_DRYAD_ERROR
#undef DEFINE_DRYAD_ERROR
#endif
#define DEFINE_DRYAD_ERROR(name, number, description) const DrError name = number;
#include "..\..\common\include\dryaderror.h"
#undef DEFINE_DRYAD_ERROR
static ErrEntry g_DryadErrorMap[] = {
#undef DEFINE_DR_ERROR
#undef COMMON_DR_ERRORS_DEFINED
#define DEFINE_DR_ERROR(name, number, description) {name, description},
#include "DrError.h"
#undef DEFINE_DR_ERROR
#ifdef DEFINE_DRYAD_ERROR
#undef DEFINE_DRYAD_ERROR
#endif
#define DEFINE_DRYAD_ERROR(name, number, description) {name, description},
#include "..\..\common\include\dryaderror.h"
#undef DEFINE_DRYAD_ERROR
};
class DrErrorTable : public DrTempStringPool
{
public:
static const DWORD k_hashTableSize = 111;
public:
DrErrorTable()
{
m_fInitialized = false;
for (int i = 0; i < k_hashTableSize; i++) {
m_pBucket[i] = NULL;
}
m_hModuleNetMsg = NULL;
m_hModuleWinHttp = NULL;
}
~DrErrorTable()
{
ErrHashEntry *p;
for (int i = 0; i < k_hashTableSize; i++) {
while ((p = m_pBucket[i]) != NULL) {
m_pBucket[i] = p->pNext;
delete p;
}
}
if (m_hModuleNetMsg != NULL) {
FreeLibrary(m_hModuleNetMsg);
}
if (m_hModuleWinHttp != NULL) {
FreeLibrary(m_hModuleWinHttp);
}
}
void Lock()
{
m_lock.Enter();
}
void Unlock()
{
m_lock.Leave();
}
// The returned error string should be freed with free();
//
// If the error code is unknown, a generic error description is returned.
char *GetSystemErrorText(DWORD dwError)
{
LPSTR MessageBuffer;
DWORD dwBufferLength;
HANDLE hModule = NULL;
DWORD dwUse = dwError;
DWORD dwNormalized = dwError;
if ((dwNormalized & 0xFFFF0000) == ((FACILITY_WIN32 << 16) | 0x80000000)) {
dwNormalized = dwNormalized & 0xFFFF;
}
DWORD dwFormatFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_IGNORE_INSERTS |
FORMAT_MESSAGE_FROM_SYSTEM ;
//
// If dwLastError is in the network range,
// load the message source.
//
if (dwNormalized >= NERR_BASE && dwNormalized <= MAX_NERR) {
Lock();
if (m_hModuleNetMsg == NULL) {
m_hModuleNetMsg = LoadLibraryEx(
TEXT("netmsg.dll"),
NULL,
LOAD_LIBRARY_AS_DATAFILE
);
}
Unlock();
if(m_hModuleNetMsg != NULL) {
dwFormatFlags |= FORMAT_MESSAGE_FROM_HMODULE;
hModule = m_hModuleNetMsg;
}
} else if (dwNormalized >= WINHTTP_ERROR_BASE && dwNormalized <= WINHTTP_ERROR_LAST) {
Lock();
if (m_hModuleWinHttp == NULL) {
m_hModuleWinHttp = LoadLibraryEx(
TEXT("winhttp.dll"),
NULL,
LOAD_LIBRARY_AS_DATAFILE
);
}
Unlock();
if(m_hModuleWinHttp != NULL) {
dwFormatFlags |= FORMAT_MESSAGE_FROM_HMODULE;
hModule = m_hModuleWinHttp;
dwUse = dwNormalized;
}
}
//
// Call FormatMessage() to allow for message
// text to be acquired from the system
// or from the supplied module handle.
//
// For perf, we assume here that all ANSI error messages are also valid UTF-8. If
// this turns out not to be true, we'll have to get the unicode message and convert to UTF-8
if ((dwBufferLength = FormatMessageA(
dwFormatFlags,
hModule,
dwUse,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // default language
(LPSTR) &MessageBuffer,
0,
NULL
)) != 0) {
char *pszBuffer = (char *)malloc(dwBufferLength + 1);
LogAssert(pszBuffer != NULL);
memcpy(pszBuffer, MessageBuffer, dwBufferLength+1);
LocalFree(MessageBuffer);
DWORD i;
for (i = 0; i < dwBufferLength; ++i)
if (pszBuffer[i] == '\r' || pszBuffer[i] == '\n')
pszBuffer[i] = ' ';
return pszBuffer;
}
char *pszBuffer = (char *)malloc(64);
LogAssert(pszBuffer != NULL);
_snprintf(pszBuffer, 64, "Error code %u (0x%08x)", dwError, dwError);
return pszBuffer;
}
// The returned error string should be freed with free();
//
// If the error code is unknown, a generic error description is returned.
/*JC
WCHAR *GetSystemErrorTextW(DWORD dwError)
{
LPWSTR MessageBuffer;
DWORD dwBufferLength;
DWORD dwFormatFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_IGNORE_INSERTS |
FORMAT_MESSAGE_FROM_SYSTEM ;
//
// If dwLastError is in the network range,
// load the message source.
//
if (dwError >= NERR_BASE && dwError <= MAX_NERR) {
Lock();
if (m_hModuleNetMsg == NULL) {
m_hModuleNetMsg = LoadLibraryEx(
TEXT("netmsg.dll"),
NULL,
LOAD_LIBRARY_AS_DATAFILE
);
}
Unlock();
if(m_hModuleNetMsg != NULL) {
dwFormatFlags |= FORMAT_MESSAGE_FROM_HMODULE;
}
}
//
// Call FormatMessage() to allow for message
// text to be acquired from the system
// or from the supplied module handle.
//
if ((dwBufferLength = FormatMessageW(
dwFormatFlags,
m_hModuleNetMsg,
dwError,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // default language
(LPWSTR) &MessageBuffer,
0,
NULL
)) != 0) {
WCHAR *pszBuffer = (WCHAR *)malloc((dwBufferLength + 1) * sizeof(WCHAR));
LogAssert(pszBuffer != NULL);
memcpy(pszBuffer, MessageBuffer, (dwBufferLength+1) * sizeof(WCHAR));
LocalFree(MessageBuffer);
return pszBuffer;
}
WCHAR*pszBuffer = (WCHAR *)malloc(64 * sizeof(WCHAR));
LogAssert(pszBuffer != NULL);
_snwprintf(pszBuffer, 64, L"Error code %u (0x%08x)", dwError, dwError);
return pszBuffer;
}
*/
static DWORD IndexOf(DrError err) {
return ((DWORD)err % k_hashTableSize);
}
// Returns NULL if not found
// Must be called under lock
ErrHashEntry *FindEntry(DrError err)
{
DWORD dw = IndexOf(err);
ErrHashEntry *p = m_pBucket[dw];
while (p != NULL) {
if (p->value == err) {
return p;
}
p = p->pNext;
}
return NULL;
}
// returns ERROR_ALREADY_ASSIGNED if the error has already been defined
DrError AddEntry(DrError code, const char *pszDescription)
{
DrError err = DrError_Fail;
Lock();
if (FindEntry(code) != NULL) {
err = HRESULT_FROM_WIN32( ERROR_ALREADY_ASSIGNED );
goto done;
}
DWORD dw = IndexOf(code);
ErrHashEntry *p = new ErrHashEntry;
LogAssert(p != NULL);
p->value = code;
p->pszDescription = dupStr(pszDescription);
p->pNext = m_pBucket[dw];
m_pBucket[dw] = p;
err = DrError_OK;
done:
Unlock();
return err;
}
// The returned error string should be freed with free();
//
// If the error code is unknown, a generic error description is returned.
char *GetErrorText(DrError err)
{
char *pszText = NULL;
Lock();
Initialize();
ErrHashEntry *p = FindEntry(err);
if (p != NULL) {
const char *pszOrig = p->pszDescription;
if (pszOrig != NULL) {
Size_t len = strlen(pszOrig)+1;
pszText = (char *)malloc(len);
memcpy(pszText, pszOrig, len);
}
}
Unlock();
if (pszText == NULL) {
pszText = GetSystemErrorText((DWORD) err);
}
LogAssert(pszText != NULL);
return pszText;
}
/*JC
WCHAR *GetErrorTextW(DrError err)
{
WCHAR *pszText = NULL;
Lock();
Initialize();
ErrHashEntry *p = FindEntry(err);
if (p != NULL) {
const char *pszOrig = p->pszDescription;
if (pszOrig != NULL) {
DrWStr128 wstrText(pszOrig);
Size_t len = wstrText.GetLength()+1;
pszText = (WCHAR *)malloc(len * sizeof(WCHAR));
memcpy(pszText, wstrText.GetString(), len * sizeof(WCHAR));
}
}
Unlock();
if (pszText == NULL) {
pszText = GetSystemErrorTextW((DWORD) err);
}
LogAssert(pszText != NULL);
return pszText;
}
*/
inline void Initialize()
{
if (!m_fInitialized) {
Lock();
AddStaticCodes();
m_fInitialized = true;
Unlock();
}
}
void AddStaticCodes()
{
int n = sizeof(g_DryadErrorMap) / sizeof(g_DryadErrorMap[0]);
for (int i = 0; i < n; i++) {
DrError err = AddEntry(g_DryadErrorMap[i].value, g_DryadErrorMap[i].pszDescription);
if (err != DrError_OK) {
DrLogE( "DrErrorTable::AddStaticCodes - Could not add error code 0x%08x: [%s] to table, error: 0x%08x", g_DryadErrorMap[i].value, g_DryadErrorMap[i].pszDescription, err);
}
LogAssert(err == DrError_OK);
}
}
private:
ErrHashEntry *m_pBucket[k_hashTableSize];
HMODULE m_hModuleNetMsg;
HMODULE m_hModuleWinHttp;
DrCriticalSection m_lock;
bool m_fInitialized;
};
DrErrorTable g_csErrorTable;
// The returned error string should be freed with free();
//
// If the error code is unknown, a generic error description is returned.
char *DrGetErrorText(DrError err)
{
return g_csErrorTable.GetErrorText(err);
}
// The returned error string should be freed with free();
//
// If the error code is unknown, a generic error description is returned.
/*JC
WCHAR *DrGetErrorTextW(DrError err)
{
return g_csErrorTable.GetErrorTextW(err);
}
*/
void DrInitErrorTable(void)
{
g_csErrorTable.Initialize();
}
extern DrError DrAddErrorDescription(DrError code, const char *pszDescription)
{
return g_csErrorTable.AddEntry(code, pszDescription);
}
// The buffer must be at least 64 bytes long to guarantee a result. If the result won't fit in the buffer, a generic
// error message is generated.
const char *DrGetErrorDescription(DrError err, char *pBuffer, int buffLen)
{
if (buffLen < 64) {
return "Error Description Buffer too short!";
}
char *pszText = DrGetErrorText(err);
LogAssert(pszText != NULL);
Size_t len = strlen(pszText)+1;
if ((int) len <= buffLen) { // AKadatch: don't use "int". // TODO: fix this hack.
memcpy(pBuffer, pszText, len);
} else {
_snprintf(pBuffer, (size_t) (buffLen-1), "Error code %u (0x%08x)", err, err);
}
free(pszText);
return pBuffer;
}
// The buffer must be at least 64 chars long to guarantee a result. If the result won't fit in the buffer, a generic
// error message is generated.
/* JC
const WCHAR *DrGetErrorDescription(DrError err, WCHAR *pBuffer, int buffLen)
{
if (buffLen < 64) {
return L"Error Description Buffer too short!";
}
WCHAR *pszText = DrGetErrorTextW(err);
LogAssert(pszText != NULL);
Size_t len = wcslen(pszText)+1;
if ((int) len <= buffLen) { // AKadatch: don't use "int". // TODO: fix this hack.
memcpy(pBuffer, pszText, len * sizeof(WCHAR));
} else {
_snwprintf(pBuffer, (size_t) (buffLen-1), L"Error code %u (0x%08x)", err, err);
}
free(pszText);
return pBuffer;
}
*/
// The buffer must be at least 64 bytes long to guarantee a result. If the result won't fit in the buffer, a generic
// error message is generated.
DrStr& DrAppendErrorDescription(DrStr& strOut, DrError err)
{
char *pszText = DrGetErrorText(err);
LogAssert(pszText != NULL);
strOut.Append(pszText);
free(pszText);
return strOut;
}
// The buffer must be at least 64 chars long to guarantee a result. If the result won't fit in the buffer, a generic
// error message is generated.
/* JC
DrWStr& DrAppendErrorDescription(DrWStr& strOut, DrError err)
{
WCHAR *pszText = DrGetErrorTextW(err);
LogAssert(pszText != NULL);
strOut.Append(pszText);
free(pszText);
return strOut;
}
*/