mirror of https://github.com/tongzx/nt5src
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.
1536 lines
39 KiB
1536 lines
39 KiB
//+---------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1993 - 1993.
|
|
//
|
|
// File: debug.cxx
|
|
//
|
|
// Contents: Shell debugging functionality
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
|
/*
|
|
* DEBUG.CXX
|
|
*
|
|
* Developer's API to the Debug Module
|
|
*/
|
|
|
|
#include <headers.h>
|
|
#include "debug.h"
|
|
#include "dalibc.h"
|
|
|
|
#ifdef _DEBUG
|
|
// Globals
|
|
|
|
HINSTANCE g_hinstMain = NULL;
|
|
HWND g_hwndMain = NULL;
|
|
|
|
ULONG g_cInitCount = 0;
|
|
BOOL g_fInit = FALSE;
|
|
BOOL g_fOutputToConsole = FALSE;
|
|
|
|
CRITICAL_SECTION g_csTrace;
|
|
CRITICAL_SECTION g_csResDlg;
|
|
|
|
// TAGS and stuff
|
|
|
|
/*
|
|
* Number of TAG's registered so far.
|
|
*
|
|
*/
|
|
TAG tagMac;
|
|
|
|
|
|
/*
|
|
* Mapping from TAG's to information about them. Entries
|
|
* 0...tagMac-1 are valid.
|
|
*/
|
|
TGRC mptagtgrc[tagMax];
|
|
|
|
|
|
TAG tagCom1 = tagNull;
|
|
TAG tagError = tagNull;
|
|
TAG tagWarn = tagNull;
|
|
TAG tagAssertPop = tagNull;
|
|
TAG tagTestFailures = tagNull;
|
|
TAG tagRRETURN = tagNull;
|
|
TAG tagLeaks = tagNull;
|
|
TAG tagMagic = tagNull;
|
|
TAG tagIWatch = tagNull;
|
|
TAG tagIWatch2 = tagNull;
|
|
TAG tagReadMapFile = tagNull;
|
|
TAG tagLeakFilter = tagNull;
|
|
TAG tagHookMemory = tagNull;
|
|
TAG tagHookBreak = tagNull;
|
|
TAG tagCheckAlways = tagNull;
|
|
TAG tagCheckCRT = tagNull;
|
|
TAG tagDelayFree = tagNull;
|
|
|
|
/*
|
|
* Handle for debug output file. This file is opened during init,
|
|
* and output is sent to it when enabled.
|
|
*/
|
|
HANDLE hfileDebugOutput = NULL;
|
|
|
|
|
|
/*
|
|
* static variables to prevent infinite recursion when calling
|
|
* SpitPchToDisk
|
|
*/
|
|
static BOOL fInSpitPchToDisk = FALSE;
|
|
|
|
static CHAR szNewline[] = "\r\n";
|
|
static CHAR szBackslash[] = "\\";
|
|
|
|
static CHAR szStateFileExt[] = ".tag";
|
|
static CHAR szDbgOutFileExt[] = ".log";
|
|
static CHAR szStateFileName[] = "capone.dbg";
|
|
static CHAR szDbgOutFileName[] = "capone.log";
|
|
|
|
/*
|
|
* Global temporary buffer for handling TraceTag output. Since
|
|
* this code is non-reentrant and not recursive, a single buffer
|
|
* for all Demilayr callers will work ok.
|
|
*/
|
|
CHAR rgchTraceTagBuffer[1024] = { 0 };
|
|
|
|
void DeinitDebug(void);
|
|
const LPTSTR GetHResultName(HRESULT r);
|
|
void DebugOutput( CHAR * sz );
|
|
VOID SpitPchToDisk(CHAR * pch, UINT cch, HANDLE hfile);
|
|
VOID SpitSzToDisk( CHAR * sz, HANDLE hfile);
|
|
TAG TagRegisterSomething(
|
|
TGTY tgty, CHAR * szOwner, CHAR * szDescrip, BOOL fEnabled = FALSE);
|
|
BOOL EnableTag(TAG tag, BOOL fEnable);
|
|
|
|
// F u n c t i o n s
|
|
|
|
// for some reason GetModuleFileNameA(NULL, rgch, sizeof(rgch));
|
|
// seems to return a different length (one including the terminating null?)
|
|
// when run under NT and Purify. So I made the dot detector non-fixed!
|
|
int findDot(char *string)
|
|
{
|
|
int value = -1; // default to return err
|
|
int index = 0; // start at the beggining
|
|
|
|
while(string[++index])
|
|
if(string[index]=='.') {
|
|
value = index;
|
|
break;
|
|
}
|
|
|
|
return(value);
|
|
}
|
|
|
|
|
|
/*
|
|
* InitDebug
|
|
*
|
|
* Purpose:
|
|
* Called to initialize the Debug Module. Sets up any debug
|
|
* structures. This routine DOES NOT restore the state of the
|
|
* Debug Module, since TAGs can't be registered until after
|
|
* this routine exit. The routine RestoreDefaultDebugState()
|
|
* should be called to restore the state of all TAGs after
|
|
* all TAGs have been registered.
|
|
*
|
|
* Parameters:
|
|
* hinstance Pointer to application instance
|
|
* phwnd Pointer to main application window
|
|
*
|
|
* Returns:
|
|
* error code
|
|
*/
|
|
void
|
|
InitDebug(HINSTANCE hinst, HWND hwnd)
|
|
{
|
|
static struct
|
|
{
|
|
TAG * ptag;
|
|
TGTY tgty;
|
|
LPSTR pszClass;
|
|
LPSTR pszDescr;
|
|
BOOL fEnabled;
|
|
}
|
|
g_ataginfo[] =
|
|
{
|
|
&tagCom1, tgtyOther, "!Debug", "Enable Disk for debug output", TRUE,
|
|
&tagAssertPop, tgtyOther, "!Debug", "Popups on asserts", TRUE,
|
|
&tagReadMapFile, tgtyOther, "!Debug", "Read MAP file for stack traces", TRUE,
|
|
&tagLeaks, tgtyOther, "!Memory", "Memory Leaks", FALSE,
|
|
&tagMagic, tgtyOther, "!Memory", "Module/MAP file parsing", FALSE,
|
|
&tagError, tgtyTrace, "!Trace", "Errors", TRUE,
|
|
&tagWarn, tgtyTrace, "!Trace", "Warnings", FALSE,
|
|
&tagTestFailures, tgtyTrace, "!Trace", "THR, IGNORE_HR", TRUE,
|
|
&tagRRETURN, tgtyTrace, "!Trace", "RRETURN", FALSE,
|
|
&tagIWatch, tgtyTrace, "!Watch", "Interface watch", FALSE,
|
|
&tagIWatch2, tgtyOther, "!Watch", "Interface watch (create wrap, no trace)", FALSE,
|
|
&tagLeakFilter, tgtyOther, "!Memory", "Filter out known leaks", FALSE,
|
|
&tagHookMemory, tgtyOther, "!Memory", "Watch unexp sysmem allocs", FALSE,
|
|
&tagHookBreak, tgtyOther, "!Memory", "Break on simulated failure", FALSE,
|
|
&tagCheckAlways, tgtyOther, "!Memory", "Check Mem on every alloc/free", FALSE,
|
|
&tagCheckCRT, tgtyOther, "!Memory", "Include CRT types in leak detection", FALSE,
|
|
&tagDelayFree, tgtyOther, "!Memory", "Keep freed blocks in heap list", FALSE,
|
|
};
|
|
|
|
TGRC * ptgrc;
|
|
CHAR rgch[MAX_PATH];
|
|
int i;
|
|
|
|
g_cInitCount++;
|
|
|
|
if (g_fInit)
|
|
return;
|
|
|
|
g_fInit = TRUE;
|
|
|
|
g_hinstMain = hinst;
|
|
g_hwndMain = hwnd;
|
|
|
|
// don't want windows to put up message box on INT 24H errors.
|
|
SetErrorMode(0x0001);
|
|
|
|
InitializeCriticalSection(&g_csTrace);
|
|
InitializeCriticalSection(&g_csResDlg);
|
|
|
|
// Initialize simulated failures
|
|
SetSimFailCounts(0, 1);
|
|
|
|
// Initialize TAG array
|
|
|
|
tagMac = tagMin;
|
|
|
|
// enable tagNull at end of RestoreDefaultDebugState
|
|
ptgrc = mptagtgrc + tagNull;
|
|
ptgrc->tgty = tgtyNull;
|
|
ptgrc->fEnabled = FALSE;
|
|
ptgrc->ulBitFlags = TGRC_DEFAULT_FLAGS;
|
|
ptgrc->szOwner = "dgreene";
|
|
ptgrc->szDescrip = "NULL";
|
|
|
|
// Open debug output file
|
|
if (g_hinstMain)
|
|
{
|
|
#ifndef _MAC
|
|
UINT cch = (UINT) GetModuleFileNameA(g_hinstMain, rgch, sizeof(rgch));
|
|
int dotLoc = findDot(rgch);
|
|
Assert(dotLoc!=-1);
|
|
strcpy(&rgch[dotLoc], szDbgOutFileExt);
|
|
#else
|
|
TCHAR achAppLoc[MAX_PATH];
|
|
DWORD dwRet;
|
|
short iRet;
|
|
|
|
dwRet = GetModuleFileName(g_hinstMain, achAppLoc, ARRAY_SIZE(achAppLoc));
|
|
Assert (dwRet != 0);
|
|
|
|
iRet = GetFileTitle(achAppLoc,rgch,sizeof(rgch));
|
|
Assert(iRet == 0);
|
|
|
|
strcat (rgch, szDbgOutFileExt);
|
|
#endif
|
|
|
|
}
|
|
else
|
|
strcpy(rgch, szDbgOutFileName);
|
|
|
|
hfileDebugOutput = CreateFileA(rgch,
|
|
GENERIC_WRITE,
|
|
FILE_SHARE_WRITE,
|
|
NULL,
|
|
CREATE_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
(HANDLE) NULL);
|
|
if (hfileDebugOutput != INVALID_HANDLE_VALUE)
|
|
{
|
|
char rgch2[100];
|
|
|
|
rgch2[(sizeof(rgch2)/sizeof(rgch2[0])) - 1] = 0;
|
|
_snprintf(rgch2, (sizeof(rgch2)/sizeof(rgch2[0])) - 1, "logging hinst %p to %s\r\n", g_hinstMain, rgch);
|
|
SpitSzToDisk(rgch2, hfileDebugOutput);
|
|
Assert(hfileDebugOutput);
|
|
}
|
|
|
|
for (i = 0; i < ARRAY_SIZE(g_ataginfo); i++)
|
|
{
|
|
*g_ataginfo[i].ptag = TagRegisterSomething(
|
|
g_ataginfo[i].tgty,
|
|
g_ataginfo[i].pszClass,
|
|
g_ataginfo[i].pszDescr,
|
|
g_ataginfo[i].fEnabled);
|
|
}
|
|
|
|
fInSpitPchToDisk = FALSE;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* DeinitDebug
|
|
*
|
|
* Undoes InitDebug().
|
|
*/
|
|
void
|
|
DeinitDebug(void)
|
|
{
|
|
TAG tag;
|
|
TGRC * ptgrc;
|
|
|
|
g_cInitCount--;
|
|
|
|
if (g_cInitCount)
|
|
return;
|
|
|
|
// Close the debug output file
|
|
if (hfileDebugOutput)
|
|
{
|
|
CHAR rgch[100];
|
|
|
|
rgch[(sizeof(rgch)/sizeof(rgch[0])) - 1] = 0;
|
|
_snprintf(rgch, (sizeof(rgch)/sizeof(rgch[0])) - 1, "Done logging for hinst %d\r\n", (ULONG_PTR)g_hinstMain);
|
|
SpitSzToDisk(rgch, hfileDebugOutput);
|
|
CloseHandle(hfileDebugOutput);
|
|
hfileDebugOutput = NULL;
|
|
}
|
|
|
|
// Free the tag strings if not already done
|
|
for (tag = tagMin, ptgrc = mptagtgrc + tag;
|
|
tag < tagMac; tag++, ptgrc++)
|
|
{
|
|
if (ptgrc->TestFlag(TGRC_FLAG_VALID))
|
|
{
|
|
LocalFree(ptgrc->szOwner);
|
|
ptgrc->szOwner = NULL;
|
|
LocalFree(ptgrc->szDescrip);
|
|
ptgrc->szDescrip = NULL;
|
|
}
|
|
}
|
|
|
|
// Set flags to FALSE. Need to separate from loop above so that
|
|
// final memory leak trace tag can work.
|
|
|
|
for (tag=tagMin, ptgrc = mptagtgrc + tag;
|
|
tag < tagMac; tag++, ptgrc++)
|
|
{
|
|
if (ptgrc->TestFlag(TGRC_FLAG_VALID))
|
|
{
|
|
ptgrc->fEnabled = FALSE;
|
|
ptgrc->ClearFlag(TGRC_FLAG_VALID);
|
|
}
|
|
}
|
|
|
|
DeleteCriticalSection(&g_csTrace);
|
|
DeleteCriticalSection(&g_csResDlg);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: SendDebugOutputToConsole
|
|
//
|
|
// Synopsis: If called, causes all debug output to go the the console as
|
|
// well as the debugger.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void
|
|
SendDebugOutputToConsole(void)
|
|
{
|
|
g_fOutputToConsole = TRUE;
|
|
}
|
|
|
|
|
|
/*
|
|
* FReadDebugState
|
|
*
|
|
* Purpose:
|
|
* Read the debug state information file whose name is given by the
|
|
* string szDebugFile. Set up the tag records accordingly.
|
|
*
|
|
* Parameters:
|
|
* szDebugFile Name of debug file to read
|
|
*
|
|
* Returns:
|
|
* TRUE if file was successfully read; FALSE otherwise.
|
|
*
|
|
*/
|
|
|
|
BOOL
|
|
FReadDebugState( CHAR * szDebugFile )
|
|
{
|
|
HANDLE hfile = NULL;
|
|
TGRC tgrc;
|
|
TGRC * ptgrc;
|
|
TAG tag;
|
|
INT cchOwner;
|
|
CHAR rgchOwner[MAX_PATH];
|
|
INT cchDescrip;
|
|
CHAR rgchDescrip[MAX_PATH];
|
|
BOOL fReturn = FALSE;
|
|
DWORD cRead;
|
|
|
|
hfile = CreateFileA(szDebugFile,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
(HANDLE) NULL);
|
|
if (hfile != INVALID_HANDLE_VALUE)
|
|
{
|
|
for (;;)
|
|
{
|
|
if (!ReadFile(hfile, &tgrc, sizeof(TGRC), &cRead, NULL))
|
|
break;
|
|
|
|
if (cRead == 0)
|
|
break;
|
|
|
|
if (!ReadFile(hfile, &cchOwner, sizeof(UINT), &cRead, NULL))
|
|
goto ErrorReturn;
|
|
Assert(cchOwner <= sizeof(rgchOwner));
|
|
if (!ReadFile(hfile, rgchOwner, cchOwner, &cRead, NULL))
|
|
goto ErrorReturn;
|
|
|
|
if (!ReadFile(hfile, &cchDescrip, sizeof(UINT), &cRead, NULL))
|
|
goto ErrorReturn;
|
|
Assert(cchDescrip <= sizeof(rgchDescrip));
|
|
if (!ReadFile(hfile, rgchDescrip, cchDescrip, &cRead, NULL))
|
|
goto ErrorReturn;
|
|
|
|
ptgrc = mptagtgrc + tagMin;
|
|
for (tag = tagMin; tag < tagMac; tag++)
|
|
{
|
|
if (ptgrc->TestFlag(TGRC_FLAG_VALID) &&
|
|
!strcmp(rgchOwner, ptgrc->szOwner) &&
|
|
!strcmp(rgchDescrip, ptgrc->szDescrip))
|
|
{
|
|
ptgrc->fEnabled = tgrc.fEnabled;
|
|
Assert(tgrc.TestFlag(TGRC_FLAG_VALID));
|
|
ptgrc->ulBitFlags = tgrc.ulBitFlags;
|
|
break;
|
|
}
|
|
|
|
ptgrc++;
|
|
}
|
|
}
|
|
|
|
CloseHandle(hfile);
|
|
fReturn = TRUE;
|
|
}
|
|
|
|
goto Exit;
|
|
|
|
ErrorReturn:
|
|
if (hfile)
|
|
CloseHandle(hfile);
|
|
|
|
Exit:
|
|
return fReturn;
|
|
}
|
|
|
|
/*
|
|
* FWriteDebugState
|
|
*
|
|
* Purpose:
|
|
* Writes the current state of the Debug Module to the file
|
|
* name given. The saved state can be restored later by calling
|
|
* FReadDebugState.
|
|
*
|
|
* Parameters:
|
|
* szDebugFile Name of the file to create and write the debug
|
|
* state to.
|
|
*
|
|
* Returns:
|
|
* TRUE if file was successfully written; FALSE otherwise.
|
|
*/
|
|
BOOL
|
|
FWriteDebugState( CHAR * szDebugFile )
|
|
{
|
|
HANDLE hfile = NULL;
|
|
TAG tag;
|
|
UINT cch;
|
|
TGRC * ptgrc;
|
|
BOOL fReturn = FALSE;
|
|
DWORD cWrite;
|
|
|
|
hfile = CreateFileA(szDebugFile,
|
|
GENERIC_WRITE,
|
|
FILE_SHARE_WRITE,
|
|
NULL,
|
|
CREATE_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
(HANDLE) NULL);
|
|
if (hfile != INVALID_HANDLE_VALUE)
|
|
{
|
|
for (tag = tagMin; tag < tagMac; tag++)
|
|
{
|
|
ptgrc = mptagtgrc + tag;
|
|
|
|
if (!ptgrc->TestFlag(TGRC_FLAG_VALID))
|
|
continue;
|
|
|
|
Assert(ptgrc->szOwner);
|
|
Assert(ptgrc->szDescrip);
|
|
|
|
if (!WriteFile(hfile, ptgrc, sizeof(TGRC), &cWrite, NULL))
|
|
goto ErrorReturn;
|
|
|
|
// SZ fields will be overwritten when read back
|
|
|
|
cch = strlen(ptgrc->szOwner) + 1;
|
|
if (!WriteFile(hfile, &cch, sizeof(UINT), &cWrite, NULL))
|
|
goto ErrorReturn;
|
|
if (!WriteFile(hfile, ptgrc->szOwner, cch, &cWrite, NULL))
|
|
goto ErrorReturn;
|
|
|
|
cch = strlen(ptgrc->szDescrip) + 1;
|
|
if (!WriteFile(hfile, &cch, sizeof(UINT), &cWrite, NULL))
|
|
goto ErrorReturn;
|
|
if (!WriteFile(hfile, ptgrc->szDescrip, cch, &cWrite, NULL))
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
CloseHandle(hfile);
|
|
fReturn = TRUE;
|
|
}
|
|
|
|
goto Exit;
|
|
|
|
ErrorReturn:
|
|
if (hfile)
|
|
CloseHandle(hfile);
|
|
DeleteFileA(szDebugFile);
|
|
|
|
Exit:
|
|
return fReturn;
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------------
|
|
//
|
|
// Function: SaveDefaultDebugState
|
|
//
|
|
// Synopsis: Saves the debug state of the executing program to a file
|
|
// of the same name, substituting the ".tag" suffix.
|
|
//
|
|
// Arguments: [void]
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
|
|
void
|
|
SaveDefaultDebugState( void )
|
|
{
|
|
CHAR rgch[MAX_PATH] = "";
|
|
|
|
if (g_hinstMain)
|
|
{
|
|
#ifndef _MAC
|
|
UINT cch = (UINT) GetModuleFileNameA(g_hinstMain, rgch, sizeof(rgch));
|
|
int dotLoc = findDot(rgch);
|
|
Assert(dotLoc!=-1);
|
|
strcpy(&rgch[dotLoc], szStateFileExt);
|
|
#else
|
|
TCHAR achAppLoc[MAX_PATH];
|
|
DWORD dwRet;
|
|
short iRet;
|
|
|
|
dwRet = GetModuleFileNameA(g_hinstMain, achAppLoc, ARRAY_SIZE(achAppLoc));
|
|
Assert (dwRet != 0);
|
|
|
|
iRet = GetFileTitle(achAppLoc,rgch,sizeof(rgch));
|
|
Assert(iRet == 0);
|
|
|
|
strcat (rgch, szStateFileExt);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
strcat(rgch, szStateFileName);
|
|
}
|
|
FWriteDebugState(rgch);
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------------
|
|
//
|
|
// Function: RestoreDefaultDebugState
|
|
//
|
|
// Synopsis: Restores the debug state for the executing program from
|
|
// the state file of the same name, substituting the ".tag"
|
|
// suffix.
|
|
//
|
|
// Arguments: [void]
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
|
|
void
|
|
RestoreDefaultDebugState( void )
|
|
{
|
|
CHAR rgch[MAX_PATH] = "";
|
|
|
|
if (!g_fInit)
|
|
{
|
|
DebugOutput("RestoreDefaultDebugState: Debug library not initialized\n");
|
|
return;
|
|
}
|
|
|
|
if (g_hinstMain)
|
|
{
|
|
#ifndef _MAC
|
|
UINT cch = (UINT) GetModuleFileNameA(g_hinstMain, rgch, sizeof(rgch));
|
|
int dotLoc = findDot(rgch);
|
|
Assert(dotLoc!=-1);
|
|
strcpy(&rgch[dotLoc], szStateFileExt);
|
|
#else
|
|
TCHAR achAppLoc[MAX_PATH];
|
|
DWORD dwRet;
|
|
short iRet;
|
|
|
|
dwRet = GetModuleFileName(g_hinstMain, achAppLoc, ARRAY_SIZE(achAppLoc));
|
|
Assert (dwRet != 0);
|
|
|
|
iRet = GetFileTitle(achAppLoc,rgch,sizeof(rgch));
|
|
Assert(iRet == 0);
|
|
|
|
strcat (rgch, szStateFileExt);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
strcat(rgch, szStateFileName);
|
|
}
|
|
FReadDebugState(rgch);
|
|
|
|
mptagtgrc[tagNull].fEnabled = TRUE;
|
|
}
|
|
|
|
/*
|
|
* IsTagEnabled
|
|
*
|
|
* Purpose:
|
|
* Returns a boolean value indicating whether the given TAG
|
|
* has been enabled or disabled by the user.
|
|
*
|
|
* Parameters:
|
|
* tag The TAG to check
|
|
*
|
|
* Returns:
|
|
* TRUE if the TAG has been enabled.
|
|
* FALSE if the TAG has been disabled.
|
|
*/
|
|
|
|
BOOL
|
|
IsTagEnabled(TAG tag)
|
|
{
|
|
return mptagtgrc[tag].TestFlag(TGRC_FLAG_VALID) &&
|
|
mptagtgrc[tag].fEnabled;
|
|
}
|
|
|
|
/*
|
|
* EnableTag
|
|
*
|
|
* Purpose:
|
|
* Sets or resets the TAG value given. Allows code to enable or
|
|
* disable TAG'd assertions and trace switches.
|
|
*
|
|
* Parameters:
|
|
* tag The TAG to enable or disable
|
|
* fEnable TRUE if TAG should be enabled, FALSE if it should
|
|
* be disabled.
|
|
* Returns:
|
|
* old state of tag (TRUE if tag was enabled, otherwise FALSE)
|
|
*
|
|
*/
|
|
|
|
BOOL EnableTag( TAG tag, BOOL fEnable )
|
|
{
|
|
BOOL fOld;
|
|
|
|
Assert(mptagtgrc[tag].TestFlag(TGRC_FLAG_VALID));
|
|
fOld = mptagtgrc[tag].fEnabled;
|
|
mptagtgrc[tag].fEnabled = fEnable;
|
|
return fOld;
|
|
}
|
|
|
|
|
|
/*
|
|
* SpitPchToDisk
|
|
*
|
|
* Purpose:
|
|
* Writes the given string to the (previously opened) debug module
|
|
* disk file. Does NOT write newline-return; caller should embed it
|
|
* in string.
|
|
*
|
|
* Parameters:
|
|
* pch Pointer to an array of characters.
|
|
* cch Number of characters to spit.
|
|
* pfile file to which to write, or NULL to use
|
|
* debug output file.
|
|
*/
|
|
|
|
void
|
|
SpitPchToDisk( CHAR * pch, UINT cch, HANDLE hfile )
|
|
{
|
|
DWORD cWrite;
|
|
|
|
if (fInSpitPchToDisk) // already inside this function
|
|
return; // aVOID recursion
|
|
|
|
if (hfile && pch && cch)
|
|
{
|
|
|
|
fInSpitPchToDisk = TRUE;
|
|
|
|
WriteFile(hfile, pch, cch, &cWrite, NULL);
|
|
|
|
fInSpitPchToDisk = FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* SpitSzToDisk
|
|
*
|
|
* Purpose:
|
|
* Writes the given string to the (previously opened) debug module
|
|
* disk file. Does NOT write newline-return; caller should embed it
|
|
* in string.
|
|
*
|
|
* Parameters:
|
|
* sz String to spit.
|
|
* pfile file to which to write, or NULL to use
|
|
* debug output file.
|
|
*
|
|
* Because this function calls fflush(), we're assuming for the
|
|
* sake of reasonable performance that only debug functions making
|
|
* output to disk are calling this function. We can't put this in
|
|
* SpitPchToDisk because calls that function, and any
|
|
* enabled trace tag would degrade performance.
|
|
*/
|
|
|
|
VOID
|
|
SpitSzToDisk( CHAR * sz, HANDLE hfile )
|
|
{
|
|
if (hfile && sz)
|
|
{
|
|
SpitPchToDisk(sz, strlen(sz), hfile);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* TagRegisterSomething
|
|
*
|
|
* Purpose:
|
|
* Does actual work of allocating TAG, and initializing TGRC.
|
|
* The owner and description strings are duplicated from the
|
|
* arguments passed in.
|
|
*
|
|
* Parameters:
|
|
* tgty Tag type to register.
|
|
* szOwner Owner.
|
|
* szDescrip Description.
|
|
*
|
|
* Returns:
|
|
* New TAG, or tagNull if none is available.
|
|
*/
|
|
|
|
TAG
|
|
TagRegisterSomething(
|
|
TGTY tgty,
|
|
CHAR * szOwner,
|
|
CHAR * szDescrip,
|
|
BOOL fEnabled)
|
|
{
|
|
TAG tag;
|
|
TAG tagNew = tagNull;
|
|
TGRC * ptgrc;
|
|
CHAR * szOwnerDup = NULL;
|
|
CHAR * szDescripDup = NULL;
|
|
UINT cb;
|
|
|
|
for (tag = tagMin, ptgrc = mptagtgrc + tag; tag < tagMac;
|
|
tag++, ptgrc++)
|
|
{
|
|
if (ptgrc->TestFlag(TGRC_FLAG_VALID))
|
|
{
|
|
if(!(strcmp(szOwner, ptgrc->szOwner) ||
|
|
strcmp(szDescrip, ptgrc->szDescrip)))
|
|
{
|
|
return tag;
|
|
}
|
|
}
|
|
else if (tagNew == tagNull)
|
|
tagNew= tag;
|
|
}
|
|
|
|
// Make duplicate copies.
|
|
|
|
Assert(szOwner);
|
|
Assert(szDescrip);
|
|
cb = strlen(szOwner) + 1;
|
|
|
|
// we use LocalAlloc here instead of new so
|
|
// we don't interfere with leak reporting because of the
|
|
// dependency between the debug library and the
|
|
// leak reporting code (i.e., don't touch this --Erik)
|
|
|
|
szOwnerDup = (LPSTR) LocalAlloc(LMEM_FIXED, cb);
|
|
if (szOwnerDup == NULL)
|
|
{
|
|
goto Error;
|
|
}
|
|
|
|
strcpy(szOwnerDup, szOwner);
|
|
|
|
cb = strlen(szDescrip) + 1;
|
|
szDescripDup = (LPSTR) LocalAlloc(LMEM_FIXED, cb);
|
|
if (szDescripDup == NULL)
|
|
{
|
|
goto Error;
|
|
}
|
|
|
|
strcpy(szDescripDup, szDescrip);
|
|
|
|
if (tagNew == tagNull)
|
|
{
|
|
if (tagMac >= tagMax)
|
|
{
|
|
#ifdef NEVER
|
|
AssertSz(FALSE, "Too many tags registered already!");
|
|
#endif
|
|
Assert(FALSE);
|
|
return tagNull;
|
|
}
|
|
|
|
tag = tagMac++;
|
|
}
|
|
else
|
|
tag = tagNew;
|
|
|
|
ptgrc = mptagtgrc + tag;
|
|
|
|
ptgrc->fEnabled = fEnabled;
|
|
ptgrc->ulBitFlags = TGRC_DEFAULT_FLAGS;
|
|
ptgrc->tgty = tgty;
|
|
ptgrc->szOwner = szOwnerDup;
|
|
ptgrc->szDescrip = szDescripDup;
|
|
|
|
return tag;
|
|
|
|
Error:
|
|
LocalFree(szOwnerDup);
|
|
LocalFree(szDescripDup);
|
|
return tagNull;
|
|
}
|
|
|
|
|
|
/*
|
|
* DeregisterTag
|
|
*
|
|
* Purpose:
|
|
* Deregisters tag, removing it from tag table.
|
|
*
|
|
* Parameters:
|
|
* tag Tag to deregister.
|
|
*/
|
|
|
|
void
|
|
DeregisterTag(TAG tag)
|
|
{
|
|
// don't allow deregistering the tagNull entry
|
|
// but exit gracefully
|
|
if (!tag)
|
|
return;
|
|
|
|
Assert(tag < tagMac);
|
|
Assert(mptagtgrc[tag].TestFlag(TGRC_FLAG_VALID));
|
|
|
|
mptagtgrc[tag].fEnabled = FALSE;
|
|
mptagtgrc[tag].ClearFlag(TGRC_FLAG_VALID);
|
|
LocalFree(mptagtgrc[tag].szOwner);
|
|
mptagtgrc[tag].szOwner = NULL;
|
|
LocalFree(mptagtgrc[tag].szDescrip);
|
|
mptagtgrc[tag].szDescrip = NULL;
|
|
}
|
|
|
|
|
|
/*
|
|
* TagRegisterTrace
|
|
*
|
|
* Purpose:
|
|
* Registers a class of trace points, and returns an identifying
|
|
* TAG for that class.
|
|
*
|
|
* Parameters:
|
|
* szOwner The email name of the developer writing the code
|
|
* that registers the class.
|
|
* szDescrip A short description of the class of trace points.
|
|
* For instance: "All calls to PvAlloc() and HvFree()"
|
|
*
|
|
* Returns:
|
|
* TAG identifying class of trace points, to be used in calls to
|
|
* the trace routines.
|
|
*/
|
|
|
|
TAG
|
|
TagRegisterTrace( CHAR * szOwner, CHAR * szDescrip, BOOL fEnabled )
|
|
{
|
|
if (!g_fInit)
|
|
{
|
|
DebugOutput("TagRegisterTrace: Debug library not initialized\n");
|
|
return tagNull;
|
|
}
|
|
|
|
return TagRegisterSomething(tgtyTrace, szOwner, szDescrip, fEnabled);
|
|
}
|
|
|
|
|
|
|
|
TAG
|
|
TagRegisterOther( CHAR * szOwner, CHAR * szDescrip, BOOL fEnabled )
|
|
{
|
|
if (!g_fInit)
|
|
{
|
|
OutputDebugStringA("TagRegisterOther: Debug library not initialized");
|
|
return tagNull;
|
|
}
|
|
|
|
return TagRegisterSomething(tgtyOther, szOwner, szDescrip, fEnabled);
|
|
}
|
|
|
|
|
|
|
|
TAG
|
|
TagError( void )
|
|
{
|
|
return tagError;
|
|
}
|
|
|
|
|
|
TAG
|
|
TagWarning( void )
|
|
{
|
|
return tagWarn;
|
|
}
|
|
|
|
|
|
TAG
|
|
TagLeakFilter( void )
|
|
{
|
|
return tagLeakFilter;
|
|
}
|
|
|
|
|
|
TAG
|
|
TagHookMemory(void)
|
|
{
|
|
return tagHookMemory;
|
|
}
|
|
|
|
|
|
TAG
|
|
TagHookBreak(void)
|
|
{
|
|
return tagHookBreak;
|
|
}
|
|
|
|
|
|
TAG
|
|
TagLeaks(void)
|
|
{
|
|
return tagLeaks;
|
|
}
|
|
|
|
|
|
TAG
|
|
TagCheckAlways(void)
|
|
{
|
|
return tagCheckAlways;
|
|
}
|
|
|
|
|
|
TAG
|
|
TagCheckCRT(void)
|
|
{
|
|
return tagCheckCRT;
|
|
}
|
|
|
|
|
|
TAG
|
|
TagDelayFree(void)
|
|
{
|
|
return tagDelayFree;
|
|
}
|
|
|
|
|
|
/*
|
|
* Purpose:
|
|
* Clears the debug screen
|
|
*/
|
|
|
|
void
|
|
ClearDebugScreen( void )
|
|
{
|
|
#ifndef _MAC
|
|
TraceTag((tagNull, "\x1B[2J"));
|
|
#endif
|
|
}
|
|
|
|
|
|
/*
|
|
* DebugOutput
|
|
*
|
|
* Purpose:
|
|
* Writes the given string out the debug port.
|
|
* Does NOT write newline-return; caller should embed it in string.
|
|
*
|
|
* Parameters:
|
|
* sz String to spit.
|
|
*/
|
|
|
|
void DebugOutput( CHAR * sz )
|
|
{
|
|
#ifdef NEVER
|
|
HANDLE hfile;
|
|
|
|
hfile = CreateFileA("COM1", GENERIC_READ | GENERIC_WRITE,
|
|
0, NULL, OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL, NULL);
|
|
|
|
if (hfile != INVALID_HANDLE_VALUE)
|
|
{
|
|
DWORD lcbWritten;
|
|
WriteFile(hfile, sz, (DWORD) strlen(sz), &lcbWritten, NULL);
|
|
CloseHandle(hfile);
|
|
}
|
|
#endif // NEVER
|
|
OutputDebugStringA(sz);
|
|
}
|
|
|
|
|
|
/*
|
|
* TaggedTrace
|
|
*
|
|
* Purpose:
|
|
* Uses the given format string and parameters to render a
|
|
* string into a buffer. The rendered string is sent to the
|
|
* destination indicated by the given tag, or sent to the bit
|
|
* bucket if the tag is disabled.
|
|
*
|
|
* Arguments:
|
|
* tag Identifies the tag group
|
|
* szFmt Format string for _snprintf (qqv)
|
|
*/
|
|
|
|
BOOL __cdecl
|
|
TaggedTrace(TAG tag, CHAR * szFmt, ...)
|
|
{
|
|
BOOL f;
|
|
|
|
va_list valMarker;
|
|
|
|
va_start(valMarker, szFmt);
|
|
f = TaggedTraceListEx(tag, 0, szFmt, valMarker);
|
|
va_end(valMarker);
|
|
|
|
return f;
|
|
}
|
|
|
|
BOOL __cdecl
|
|
TaggedTraceEx(TAG tag, USHORT usFlags, CHAR * szFmt, ...)
|
|
{
|
|
BOOL f;
|
|
|
|
va_list valMarker;
|
|
|
|
va_start(valMarker, szFmt);
|
|
f = TaggedTraceListEx(tag, usFlags, szFmt, valMarker);
|
|
va_end(valMarker);
|
|
|
|
return f;
|
|
}
|
|
|
|
BOOL __cdecl
|
|
TaggedTraceListEx(TAG tag, USHORT usFlags, CHAR * szFmt, va_list valMarker)
|
|
{
|
|
static CHAR szFmtOwner[] = "DA %s (%lx): ";
|
|
static CHAR szFmtHR[] = "<%ls (0x%lx)>";
|
|
static CHAR szHRID[] = "%hr";
|
|
TGRC * ptgrc;
|
|
int cch;
|
|
|
|
if (!g_fInit)
|
|
{
|
|
DebugOutput("TaggedTrace: Debug library not initialized\n");
|
|
return FALSE;
|
|
}
|
|
|
|
if (tag == tagNull)
|
|
ptgrc = mptagtgrc + tagCom1;
|
|
else
|
|
ptgrc = mptagtgrc + tag;
|
|
|
|
if (!ptgrc->fEnabled)
|
|
return FALSE;
|
|
|
|
EnterCriticalSection(&g_csTrace);
|
|
|
|
Assert(ptgrc->TestFlag(TGRC_FLAG_VALID));
|
|
|
|
if (!(usFlags & TAG_NONAME))
|
|
{
|
|
cch = _snprintf(
|
|
rgchTraceTagBuffer,
|
|
ARRAY_SIZE(rgchTraceTagBuffer),
|
|
szFmtOwner,
|
|
ptgrc->szOwner,
|
|
GetCurrentThreadId());
|
|
}
|
|
else
|
|
{
|
|
cch = 0;
|
|
}
|
|
|
|
hrvsnprintf(
|
|
rgchTraceTagBuffer + cch,
|
|
ARRAY_SIZE(rgchTraceTagBuffer) - cch,
|
|
szFmt,
|
|
valMarker);
|
|
|
|
if (ptgrc->TestFlag(TGRC_FLAG_DISK))
|
|
{
|
|
SpitSzToDisk(rgchTraceTagBuffer, hfileDebugOutput);
|
|
SpitSzToDisk(szNewline, hfileDebugOutput);
|
|
}
|
|
|
|
if ((usFlags & TAG_USECONSOLE) || g_fOutputToConsole)
|
|
printf(rgchTraceTagBuffer);
|
|
|
|
if (!(usFlags & TAG_USECONSOLE))
|
|
DebugOutput(rgchTraceTagBuffer);
|
|
|
|
if (!(usFlags & TAG_NONEWLINE))
|
|
{
|
|
if ((usFlags & TAG_USECONSOLE) || g_fOutputToConsole)
|
|
printf(szNewline);
|
|
if (!(usFlags & TAG_USECONSOLE))
|
|
DebugOutput(szNewline);
|
|
}
|
|
|
|
LeaveCriticalSection(&g_csTrace);
|
|
|
|
if (ptgrc->TestFlag(TGRC_FLAG_BREAK))
|
|
{
|
|
return MessageBoxA(
|
|
NULL,
|
|
ptgrc->szDescrip,
|
|
"Trace Tag Break, OK=Ignore, Cancel=Int3",
|
|
MB_SETFOREGROUND | MB_TASKMODAL
|
|
| MB_ICONEXCLAMATION | MB_OKCANCEL) == IDCANCEL;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
#ifdef NEVER
|
|
void TaggedTraceCallers(TAG tag, int iStart, int cTotal)
|
|
{
|
|
DWORD adwEip[32];
|
|
int i;
|
|
int c;
|
|
int ib;
|
|
LPSTR pstr;
|
|
|
|
if (!IsTagEnabled(tag))
|
|
return;
|
|
|
|
if (cTotal > ARRAY_SIZE(adwEip))
|
|
cTotal = ARRAY_SIZE(adwEip);
|
|
|
|
c = GetStackBacktrace(iStart + 1, cTotal, adwEip);
|
|
for (i = 0; i < c; i++)
|
|
{
|
|
MapAddressToFunctionOffset((LPBYTE) adwEip[i], &pstr, &ib);
|
|
TaggedTraceEx(tag, TAG_NONAME, " %08x %s + 0x%x",
|
|
adwEip[i], pstr, ib);
|
|
}
|
|
}
|
|
#endif // NEVER
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------
|
|
//
|
|
// Function: GetHResultName
|
|
//
|
|
// Synopsis: Returns a printable string for the given hresult
|
|
//
|
|
// Arguments: [scode] -- The status code to report.
|
|
//
|
|
// Notes: This function disappears in retail builds.
|
|
//
|
|
//----------------------------------------------------------------
|
|
|
|
const LPTSTR
|
|
GetHResultName(HRESULT r)
|
|
{
|
|
LPTSTR lpstr;
|
|
|
|
#define CASE_SCODE(sc) \
|
|
case sc: lpstr = _T(#sc); break;
|
|
|
|
switch (r) {
|
|
/* SCODE's defined in SCODE.H */
|
|
CASE_SCODE(S_OK)
|
|
CASE_SCODE(S_FALSE)
|
|
CASE_SCODE(OLE_S_USEREG)
|
|
CASE_SCODE(OLE_S_STATIC)
|
|
CASE_SCODE(OLE_S_MAC_CLIPFORMAT)
|
|
CASE_SCODE(DRAGDROP_S_DROP)
|
|
CASE_SCODE(DRAGDROP_S_USEDEFAULTCURSORS)
|
|
CASE_SCODE(DRAGDROP_S_CANCEL)
|
|
CASE_SCODE(DATA_S_SAMEFORMATETC)
|
|
CASE_SCODE(VIEW_S_ALREADY_FROZEN)
|
|
CASE_SCODE(CACHE_S_FORMATETC_NOTSUPPORTED)
|
|
CASE_SCODE(CACHE_S_SAMECACHE)
|
|
CASE_SCODE(CACHE_S_SOMECACHES_NOTUPDATED)
|
|
CASE_SCODE(OLEOBJ_S_INVALIDVERB)
|
|
CASE_SCODE(OLEOBJ_S_CANNOT_DOVERB_NOW)
|
|
CASE_SCODE(OLEOBJ_S_INVALIDHWND)
|
|
CASE_SCODE(INPLACE_S_TRUNCATED)
|
|
CASE_SCODE(CONVERT10_S_NO_PRESENTATION)
|
|
CASE_SCODE(MK_S_REDUCED_TO_SELF)
|
|
CASE_SCODE(MK_S_ME)
|
|
CASE_SCODE(MK_S_HIM)
|
|
CASE_SCODE(MK_S_US)
|
|
CASE_SCODE(MK_S_MONIKERALREADYREGISTERED)
|
|
CASE_SCODE(STG_S_CONVERTED)
|
|
|
|
CASE_SCODE(E_UNEXPECTED)
|
|
CASE_SCODE(E_NOTIMPL)
|
|
CASE_SCODE(E_OUTOFMEMORY)
|
|
CASE_SCODE(E_INVALIDARG)
|
|
CASE_SCODE(E_NOINTERFACE)
|
|
CASE_SCODE(E_POINTER)
|
|
CASE_SCODE(E_HANDLE)
|
|
CASE_SCODE(E_ABORT)
|
|
CASE_SCODE(E_FAIL)
|
|
CASE_SCODE(E_ACCESSDENIED)
|
|
|
|
/* SCODE's defined in DVOBJ.H */
|
|
CASE_SCODE(DATA_E_FORMATETC)
|
|
// same as DATA_E_FORMATETC CASE_SCODE(DV_E_FORMATETC)
|
|
CASE_SCODE(VIEW_E_DRAW)
|
|
// same as VIEW_E_DRAW CASE_SCODE(E_DRAW)
|
|
CASE_SCODE(CACHE_E_NOCACHE_UPDATED)
|
|
|
|
/* SCODE's defined in OLE2.H */
|
|
CASE_SCODE(OLE_E_OLEVERB)
|
|
CASE_SCODE(OLE_E_ADVF)
|
|
CASE_SCODE(OLE_E_ENUM_NOMORE)
|
|
CASE_SCODE(OLE_E_ADVISENOTSUPPORTED)
|
|
CASE_SCODE(OLE_E_NOCONNECTION)
|
|
CASE_SCODE(OLE_E_NOTRUNNING)
|
|
CASE_SCODE(OLE_E_NOCACHE)
|
|
CASE_SCODE(OLE_E_BLANK)
|
|
CASE_SCODE(OLE_E_CLASSDIFF)
|
|
CASE_SCODE(OLE_E_CANT_GETMONIKER)
|
|
CASE_SCODE(OLE_E_CANT_BINDTOSOURCE)
|
|
CASE_SCODE(OLE_E_STATIC)
|
|
CASE_SCODE(OLE_E_PROMPTSAVECANCELLED)
|
|
CASE_SCODE(OLE_E_INVALIDRECT)
|
|
CASE_SCODE(OLE_E_WRONGCOMPOBJ)
|
|
CASE_SCODE(OLE_E_INVALIDHWND)
|
|
CASE_SCODE(DV_E_DVTARGETDEVICE)
|
|
CASE_SCODE(DV_E_STGMEDIUM)
|
|
CASE_SCODE(DV_E_STATDATA)
|
|
CASE_SCODE(DV_E_LINDEX)
|
|
CASE_SCODE(DV_E_TYMED)
|
|
CASE_SCODE(DV_E_CLIPFORMAT)
|
|
CASE_SCODE(DV_E_DVASPECT)
|
|
CASE_SCODE(DV_E_DVTARGETDEVICE_SIZE)
|
|
CASE_SCODE(DV_E_NOIVIEWOBJECT)
|
|
CASE_SCODE(CONVERT10_E_OLESTREAM_GET)
|
|
CASE_SCODE(CONVERT10_E_OLESTREAM_PUT)
|
|
CASE_SCODE(CONVERT10_E_OLESTREAM_FMT)
|
|
CASE_SCODE(CONVERT10_E_OLESTREAM_BITMAP_TO_DIB)
|
|
CASE_SCODE(CONVERT10_E_STG_FMT)
|
|
CASE_SCODE(CONVERT10_E_STG_NO_STD_STREAM)
|
|
CASE_SCODE(CONVERT10_E_STG_DIB_TO_BITMAP)
|
|
CASE_SCODE(CLIPBRD_E_CANT_OPEN)
|
|
CASE_SCODE(CLIPBRD_E_CANT_EMPTY)
|
|
CASE_SCODE(CLIPBRD_E_CANT_SET)
|
|
CASE_SCODE(CLIPBRD_E_BAD_DATA)
|
|
CASE_SCODE(CLIPBRD_E_CANT_CLOSE)
|
|
CASE_SCODE(DRAGDROP_E_NOTREGISTERED)
|
|
CASE_SCODE(DRAGDROP_E_ALREADYREGISTERED)
|
|
CASE_SCODE(DRAGDROP_E_INVALIDHWND)
|
|
CASE_SCODE(OLEOBJ_E_NOVERBS)
|
|
CASE_SCODE(INPLACE_E_NOTUNDOABLE)
|
|
CASE_SCODE(INPLACE_E_NOTOOLSPACE)
|
|
|
|
/* SCODE's defined in STORAGE.H */
|
|
CASE_SCODE(STG_E_INVALIDFUNCTION)
|
|
CASE_SCODE(STG_E_FILENOTFOUND)
|
|
CASE_SCODE(STG_E_PATHNOTFOUND)
|
|
CASE_SCODE(STG_E_TOOMANYOPENFILES)
|
|
CASE_SCODE(STG_E_ACCESSDENIED)
|
|
CASE_SCODE(STG_E_INVALIDHANDLE)
|
|
CASE_SCODE(STG_E_INSUFFICIENTMEMORY)
|
|
CASE_SCODE(STG_E_INVALIDPOINTER)
|
|
CASE_SCODE(STG_E_NOMOREFILES)
|
|
CASE_SCODE(STG_E_DISKISWRITEPROTECTED)
|
|
CASE_SCODE(STG_E_SEEKERROR)
|
|
CASE_SCODE(STG_E_WRITEFAULT)
|
|
CASE_SCODE(STG_E_READFAULT)
|
|
CASE_SCODE(STG_E_LOCKVIOLATION)
|
|
CASE_SCODE(STG_E_FILEALREADYEXISTS)
|
|
CASE_SCODE(STG_E_INVALIDPARAMETER)
|
|
CASE_SCODE(STG_E_MEDIUMFULL)
|
|
CASE_SCODE(STG_E_ABNORMALAPIEXIT)
|
|
CASE_SCODE(STG_E_INVALIDHEADER)
|
|
CASE_SCODE(STG_E_INVALIDNAME)
|
|
CASE_SCODE(STG_E_UNKNOWN)
|
|
CASE_SCODE(STG_E_UNIMPLEMENTEDFUNCTION)
|
|
CASE_SCODE(STG_E_INVALIDFLAG)
|
|
CASE_SCODE(STG_E_INUSE)
|
|
CASE_SCODE(STG_E_NOTCURRENT)
|
|
CASE_SCODE(STG_E_REVERTED)
|
|
CASE_SCODE(STG_E_CANTSAVE)
|
|
CASE_SCODE(STG_E_OLDFORMAT)
|
|
CASE_SCODE(STG_E_OLDDLL)
|
|
CASE_SCODE(STG_E_SHAREREQUIRED)
|
|
|
|
/* SCODE's defined in COMPOBJ.H */
|
|
CASE_SCODE(CO_E_NOTINITIALIZED)
|
|
CASE_SCODE(CO_E_ALREADYINITIALIZED)
|
|
CASE_SCODE(CO_E_CANTDETERMINECLASS)
|
|
CASE_SCODE(CO_E_CLASSSTRING)
|
|
CASE_SCODE(CO_E_IIDSTRING)
|
|
CASE_SCODE(CO_E_APPNOTFOUND)
|
|
CASE_SCODE(CO_E_APPSINGLEUSE)
|
|
CASE_SCODE(CO_E_ERRORINAPP)
|
|
CASE_SCODE(CO_E_DLLNOTFOUND)
|
|
CASE_SCODE(CO_E_ERRORINDLL)
|
|
CASE_SCODE(CO_E_WRONGOSFORAPP)
|
|
CASE_SCODE(CO_E_OBJNOTREG)
|
|
CASE_SCODE(CO_E_OBJISREG)
|
|
CASE_SCODE(CO_E_OBJNOTCONNECTED)
|
|
CASE_SCODE(CO_E_APPDIDNTREG)
|
|
CASE_SCODE(CLASS_E_NOAGGREGATION)
|
|
CASE_SCODE(CLASS_E_CLASSNOTAVAILABLE)
|
|
CASE_SCODE(REGDB_E_READREGDB)
|
|
CASE_SCODE(REGDB_E_WRITEREGDB)
|
|
CASE_SCODE(REGDB_E_KEYMISSING)
|
|
CASE_SCODE(REGDB_E_INVALIDVALUE)
|
|
CASE_SCODE(REGDB_E_CLASSNOTREG)
|
|
CASE_SCODE(REGDB_E_IIDNOTREG)
|
|
CASE_SCODE(RPC_E_CALL_REJECTED)
|
|
CASE_SCODE(RPC_E_CALL_CANCELED)
|
|
CASE_SCODE(RPC_E_CANTPOST_INSENDCALL)
|
|
CASE_SCODE(RPC_E_CANTCALLOUT_INASYNCCALL)
|
|
CASE_SCODE(RPC_E_CANTCALLOUT_INEXTERNALCALL)
|
|
CASE_SCODE(RPC_E_CONNECTION_TERMINATED)
|
|
#if defined(NO_NTOLEBUGS)
|
|
CASE_SCODE(RPC_E_SERVER_DIED)
|
|
#endif // NO_NTOLEBUGS
|
|
CASE_SCODE(RPC_E_CLIENT_DIED)
|
|
CASE_SCODE(RPC_E_INVALID_DATAPACKET)
|
|
CASE_SCODE(RPC_E_CANTTRANSMIT_CALL)
|
|
CASE_SCODE(RPC_E_CLIENT_CANTMARSHAL_DATA)
|
|
CASE_SCODE(RPC_E_CLIENT_CANTUNMARSHAL_DATA)
|
|
CASE_SCODE(RPC_E_SERVER_CANTMARSHAL_DATA)
|
|
CASE_SCODE(RPC_E_SERVER_CANTUNMARSHAL_DATA)
|
|
CASE_SCODE(RPC_E_INVALID_DATA)
|
|
CASE_SCODE(RPC_E_INVALID_PARAMETER)
|
|
CASE_SCODE(RPC_E_UNEXPECTED)
|
|
|
|
/* SCODE's defined in MONIKER.H */
|
|
CASE_SCODE(MK_E_CONNECTMANUALLY)
|
|
CASE_SCODE(MK_E_EXCEEDEDDEADLINE)
|
|
CASE_SCODE(MK_E_NEEDGENERIC)
|
|
CASE_SCODE(MK_E_UNAVAILABLE)
|
|
CASE_SCODE(MK_E_SYNTAX)
|
|
CASE_SCODE(MK_E_NOOBJECT)
|
|
CASE_SCODE(MK_E_INVALIDEXTENSION)
|
|
CASE_SCODE(MK_E_INTERMEDIATEINTERFACENOTSUPPORTED)
|
|
CASE_SCODE(MK_E_NOTBINDABLE)
|
|
CASE_SCODE(MK_E_NOTBOUND)
|
|
CASE_SCODE(MK_E_CANTOPENFILE)
|
|
CASE_SCODE(MK_E_MUSTBOTHERUSER)
|
|
CASE_SCODE(MK_E_NOINVERSE)
|
|
CASE_SCODE(MK_E_NOSTORAGE)
|
|
#if defined(NO_NTOLEBUGS)
|
|
CASE_SCODE(MK_S_MONIKERALREADYREGISTERED)
|
|
#endif //NO_NTOLEBUGS
|
|
|
|
// Forms error codes
|
|
// CASE_SCODE(FORMS_E_NOPAGESSPECIFIED)
|
|
// CASE_SCODE(FORMS_E_NOPAGESINTERSECT)
|
|
|
|
// Dispatch error codes
|
|
CASE_SCODE(DISP_E_MEMBERNOTFOUND)
|
|
CASE_SCODE(DISP_E_PARAMNOTFOUND)
|
|
CASE_SCODE(DISP_E_BADPARAMCOUNT)
|
|
CASE_SCODE(DISP_E_BADINDEX)
|
|
CASE_SCODE(DISP_E_UNKNOWNINTERFACE)
|
|
CASE_SCODE(DISP_E_NONAMEDARGS)
|
|
CASE_SCODE(DISP_E_EXCEPTION)
|
|
CASE_SCODE(DISP_E_TYPEMISMATCH)
|
|
CASE_SCODE(DISP_E_UNKNOWNNAME)
|
|
|
|
// Typinfo error codes
|
|
CASE_SCODE(TYPE_E_REGISTRYACCESS)
|
|
CASE_SCODE(TYPE_E_LIBNOTREGISTERED)
|
|
CASE_SCODE(TYPE_E_UNDEFINEDTYPE)
|
|
CASE_SCODE(TYPE_E_WRONGTYPEKIND)
|
|
CASE_SCODE(TYPE_E_ELEMENTNOTFOUND)
|
|
CASE_SCODE(TYPE_E_INVALIDID)
|
|
CASE_SCODE(TYPE_E_CANTLOADLIBRARY)
|
|
|
|
default:
|
|
lpstr = _T("UNKNOWN SCODE");
|
|
}
|
|
|
|
#undef CASE_SCODE
|
|
|
|
return lpstr;
|
|
}
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: hrvsnprintf
|
|
//
|
|
// Synopsis: Prints a string to a buffer, interpreting %hr as a
|
|
// format string for an HRESULT.
|
|
//
|
|
// Arguments: [achBuf] -- The buffer to print into.
|
|
// [cchBuf] -- The size of the buffer.
|
|
// [pstrFmt] -- The format string.
|
|
// [valMarker] -- List of arguments to format string.
|
|
//
|
|
// Returns: Number of characters printed to the buffer not including
|
|
// the terminating NULL. In case of buffer overflow, returns
|
|
// -1.
|
|
//
|
|
// Modifies: [achBuf]
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
int
|
|
hrvsnprintf(char * achBuf, int cchBuf, const char * pstrFmt, va_list valMarker)
|
|
{
|
|
static char achFmtHR[] = "<%ls (0x%lx)>";
|
|
static char achHRID[] = "%hr";
|
|
char * buf = NULL;
|
|
|
|
int cch;
|
|
int cchTotal;
|
|
const char * lpstr;
|
|
const char * lpstrLast;
|
|
int cFormat;
|
|
HRESULT hrVA;
|
|
|
|
//
|
|
// Scan for %hr tokens. If found, print the corresponding
|
|
// hresult into the buffer.
|
|
//
|
|
|
|
// Need to copy a const string since we plan to modify it below
|
|
|
|
buf = (char *) malloc ((lstrlen(pstrFmt) + 1) * sizeof(char));
|
|
lstrcpy(buf,pstrFmt);
|
|
|
|
cch = 0;
|
|
cchTotal = 0;
|
|
cFormat = 0;
|
|
lpstrLast = buf;
|
|
lpstr = buf;
|
|
while (*lpstr)
|
|
{
|
|
if (*lpstr != '%')
|
|
{
|
|
lpstr++;
|
|
}
|
|
else if (lpstr[1] == '%')
|
|
{
|
|
lpstr += 2;
|
|
}
|
|
else if (StrCmpNA(lpstr, achHRID, ARRAY_SIZE(achHRID) - 1))
|
|
{
|
|
cFormat++;
|
|
lpstr++;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Print format string up to the hresult.
|
|
//
|
|
|
|
* (char *) lpstr = 0;
|
|
cch = _vsnprintf(
|
|
achBuf + cchTotal,
|
|
cchBuf - cchTotal,
|
|
lpstrLast,
|
|
valMarker);
|
|
* (char *) lpstr = '%';
|
|
if (cch == -1)
|
|
break;
|
|
|
|
cchTotal += cch;
|
|
|
|
//
|
|
// Advance valMarker for each printed format.
|
|
//
|
|
|
|
while (cFormat-- > 0)
|
|
{
|
|
//
|
|
// BUGBUG (adams): Won't work for floats, as their stack size
|
|
// is not four bytes.
|
|
//
|
|
|
|
va_arg(valMarker, void *);
|
|
}
|
|
|
|
//
|
|
// Print hresult into buffer.
|
|
//
|
|
|
|
hrVA = va_arg(valMarker, HRESULT);
|
|
cch = _snprintf(
|
|
achBuf + cchTotal,
|
|
cchBuf - cchTotal,
|
|
achFmtHR,
|
|
GetHResultName(hrVA),
|
|
hrVA);
|
|
if (cch == -1)
|
|
break;
|
|
|
|
cchTotal += cch;
|
|
lpstr += ARRAY_SIZE(achHRID) - 1;
|
|
lpstrLast = lpstr;
|
|
}
|
|
}
|
|
|
|
if (cch != -1)
|
|
{
|
|
cch = _vsnprintf(
|
|
achBuf + cchTotal,
|
|
cchBuf - cchTotal,
|
|
lpstrLast,
|
|
valMarker);
|
|
}
|
|
|
|
free (buf);
|
|
|
|
return (cch == -1) ? -1 : cchTotal + cch;
|
|
}
|
|
|
|
#endif
|