2025-11-28 00:35:46 +09:00

251 lines
6.7 KiB
C++

// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (c) Microsoft Corporation. All rights reserved
#include "DebugHelper.h"
#include <strsafe.h>
// Print a debug string: global-scope method, which simplifies calls into
// this class.
void DebugPrintfW(_In_z_ LPCWSTR pFormat, ...)
{
static DebugHelper debugHelper;
va_list vl;
va_start(vl,pFormat);
// Call the class's public method.
debugHelper.DebugVPrintfW(pFormat,vl);
va_end(vl);
}
// Print a debug string: one external interface.
void DebugHelper::DebugPrintfW(_In_z_ LPCWSTR pFormat, ...)
{
va_list vl;
va_start(vl, pFormat);
// Call the class's public method.
DebugVPrintfW(pFormat, vl);
va_end(vl);
}
// Print a debug string: helper method, called by wrapper methods.
void DebugHelper::DebugVPrintfW(_In_z_ LPCWSTR pFormat, _In_opt_ va_list vl)
{
HRESULT hr = S_OK;
SYSTEMTIME st = {0};
if (debugOutputBuffer &&
debugOutputBufferTemp)
{
GetLocalTime(&st);
// Print the line's prefix.
hr = StringCbPrintfW(debugOutputBufferTemp,
debugOutputBufferLen,
L"[T%lu: %02u/%02u/%02u @ %02u:%02u:%02u.%03u] %s\n",
GetCurrentThreadId(),
st.wYear,
st.wMonth,
st.wDay,
st.wHour,
st.wMinute,
st.wSecond,
st.wMilliseconds,
pFormat);
if (FAILED(hr))
{
OutputDebugStringW(L"DebugHelper: Caller attempted to use a debug output format string that was too long!\n");
goto Cleanup;
}
if (vl != NULL)
{
// Print the given arguments as per the resultant format.
hr = StringCbVPrintfW(debugOutputBuffer,
debugOutputBufferLen,
debugOutputBufferTemp,
vl);
}
else
{
// If there is no argument return only the timestamp
hr = StringCbCopy(debugOutputBuffer,
debugOutputBufferLen,
debugOutputBufferTemp);
}
if (FAILED(hr))
{
OutputDebugStringW(L"DebugHelper: Caller attempted to print a debug string that was too long!\n");
goto Cleanup;
}
// Print the string to the debugger.
OutputDebugStringW(debugOutputBuffer);
}
else
{
hr = E_POINTER;
OutputDebugStringW(L"DebugHelper: Bad temporary buffer pointers\n");
goto Cleanup;
}
Cleanup:
if (FAILED(hr))
{
// Fail in a useful manner -- just display the caller's literal
// format string in the debugger, without expanding any format
// fields. (The output strings may still be useful to help diagnose
// problems, whether or not any actual runtime values are shown.)
OutputDebugStringW(pFormat);
OutputDebugStringW(L"\n");
}
return;
}
// Constructor.
DebugHelper::DebugHelper()
{
heapHandle = NULL;
debugOutputBuffer = NULL;
debugOutputBufferTemp = NULL;
Initialize();
}
// Destructor.
DebugHelper::~DebugHelper()
{
Finalize();
}
// The code behind the constructor.
void DebugHelper::Initialize()
{
// Create a heap to contain our memory allocations.
heapHandle = HeapCreate( 0, 1, 0 );
if ( heapHandle == NULL )
{
OutputDebugStringW(L"DebugHelper::Initialize(): Failed to create heap! Unable to create data buffers for formatted output strings.\n");
goto Cleanup;
}
//
// Allocate space for the two buffers.
//
// Buffer #1: final output string.
debugOutputBuffer = static_cast<PWCHAR>(HeapAlloc(heapHandle, HEAP_ZERO_MEMORY, debugOutputBufferLen));
// Buffer #2: intermediate output string; contains data prepended to every
// debug output string, such as a timestamp.
debugOutputBufferTemp = static_cast<PWCHAR>(HeapAlloc(heapHandle, HEAP_ZERO_MEMORY, debugOutputBufferLen));
// Make sure we either have both buffers, or neither buffer.
if (debugOutputBuffer == NULL ||
debugOutputBufferTemp == NULL)
{
OutputDebugStringW(L"\n"
L"DebugHelper::Initialize(): Failed to create formatted output string buffers!\n"
L" Debug output strings will be displayed _without_ expanding format fields (i.e., \"%d\").\n\n");
// Free any partial memory already allocated.
CleanupMem();
goto Cleanup;
}
// Report that the class is completely initialized.
OutputDebugStringW(L"DebugHelper::Initialize(): Initialization completed successfully.\n");
Cleanup:
return;
}
// The code behind the destructor.
void DebugHelper::Finalize()
{
OutputDebugStringW(L"DebugHelper::Finalize(): Finalize called, cleaning up object.\n");
CleanupMem();
}
// Cleanup dynamic resources used by this class.
// Called either at destruction time, or when Initialization encounters problems allocating.
void DebugHelper::CleanupMem()
{
BOOL fOk = FALSE;
if (heapHandle)
{
// Report that the class is being cleaned up, if we can.
if (debugOutputBuffer || debugOutputBufferTemp)
{
OutputDebugStringW(L"DebugHelper::Cleanup(): Freeing all allocated memory, and cleaning up this object.\n");
}
// Release the memory used by the two buffers.
if (debugOutputBufferTemp)
{
fOk = HeapFree(heapHandle, 0, debugOutputBufferTemp);
if ( fOk == FALSE )
{
OutputDebugStringW(L"DebugHelper::Cleanup(): Failed to free temp buffer!Heap memory LEAKED!!!\n");
}
}
if (debugOutputBuffer)
{
fOk = HeapFree(heapHandle, 0, debugOutputBuffer);
if ( fOk == FALSE )
{
OutputDebugStringW(L"DebugHelper::Cleanup(): Failed to free buffer!Heap memory LEAKED!!!\n");
}
}
// Release the containing heap.
fOk = HeapDestroy( heapHandle );
if ( fOk == FALSE )
{
OutputDebugStringW(L"DebugHelper::Cleanup(): Failed to destroy heap!Heap object LEAKED!!!\n");
}
else
{
OutputDebugStringW(L"DebugHelper::Cleanup(): Heap successfully destroyed.\n");
}
}
else
{
OutputDebugStringW(L"DebugHelper::Cleanup(): .\n");
}
debugOutputBufferTemp = NULL;
debugOutputBuffer = NULL;
heapHandle = NULL;
}