]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.databoard/cpp/DataBoardTest/DataBoardTest/Stackwalker.cpp
Fixed all line endings of the repository
[simantics/platform.git] / bundles / org.simantics.databoard / cpp / DataBoardTest / DataBoardTest / Stackwalker.cpp
index 10afabe1e28049ba705c7fe2eeef08f1b3e59e09..254b1f0cfb18d33056bde19a9f3477102d2d9400 100644 (file)
-/*////////////////////////////////////////////////////////////////////////////\r
- *  Project:\r
- *    Memory_and_Exception_Trace\r
- *\r
- * ///////////////////////////////////////////////////////////////////////////\r
- *     File:\r
- *             Stackwalker.cpp\r
- *\r
- *     Remarks:\r
- *    Dumps memory leaks (unreleased allocations) for CRT-Allocs and COM-Allocs\r
- *    Dumps the stack of an thread if an exepction occurs\r
- *\r
- *  Known bugs:\r
- *    - If the allocation-RequestID wrap, then allocations will get lost...\r
- *\r
- *     Author:\r
- *             Jochen Kalmbach, Germany\r
- *    (c) 2002-2005 (Freeware)\r
- *    http://www.codeproject.com/tools/leakfinder.asp\r
- * \r
- * License (The zlib/libpng License, http://www.opensource.org/licenses/zlib-license.php):\r
- *\r
- * Copyright (c) 2005 Jochen Kalmbach\r
- *\r
- * This software is provided 'as-is', without any express or implied warranty. \r
- * In no event will the authors be held liable for any damages arising from the \r
- * use of this software.\r
- *\r
- * Permission is granted to anyone to use this software for any purpose, including \r
- * commercial applications, and to alter it and redistribute it freely, subject to \r
- * the following restrictions:\r
- * \r
- * 1. The origin of this software must not be misrepresented; you must not claim \r
- *    that you wrote the original software. If you use this software in a product, \r
- *    an acknowledgment in the product documentation would be appreciated but is \r
- *    not required.\r
- *\r
- * 2. Altered source versions must be plainly marked as such, and must not be \r
- *    misrepresented as being the original software.\r
- *\r
- * 3. This notice may not be removed or altered from any source distribution.\r
- *\r
- *//////////////////////////////////////////////////////////////////////////////\r
-\r
-//#include "stdafx.h"  // should be uncommented for precompiled headers\r
-\r
-#include <windows.h>\r
-#include <string>\r
-#include <vector>\r
-#include <stdio.h>\r
-#include <stdlib.h>\r
-#include <time.h>\r
-#include <crtdbg.h>\r
-#include <tchar.h>\r
-\r
-#include "Stackwalker.h"\r
-\r
-#pragma warning(push)\r
-#pragma warning(disable : 4100)\r
-#pragma warning(disable : 4996)\r
-#pragma warning(disable : 4189)\r
-#pragma warning(disable : 4245)\r
-#pragma warning(disable : 4701)\r
-\r
-// If the following is defined, only the used memories are stored in the hash-table. \r
-// If the memory is freed, it will be removed from the hash-table (to reduce memory)\r
-// Consequences: At DeInitAllocHook, only Leaks will be reported\r
-#define HASH_ENTRY_REMOVE_AT_FREE\r
-\r
-\r
-// 0 = Do not write any output during runtime-alloc-call\r
-// 1 = Write only the alloc action (malloc, realloc, free)\r
-// 2 = Write alloc action and callstack only for malloc/realloc\r
-// 3 = Write alloc action and callstack for all actions\r
-static ULONG g_ulShowStackAtAlloc = 0;\r
-\r
-// the form of the output file\r
-static eAllocCheckOutput g_CallstackOutputType = ACOutput_Simple;\r
-\r
-\r
-// Size of Hash-Table (this should be a prime number to avoid collisions)\r
-#define ALLOC_HASH_ENTRIES 1023\r
-\r
-\r
-// Size of Callstack-trace in bytes (0x500 => appr. 5-9 functions, depending on parameter count for each function)\r
-#define MAX_ESP_LEN_BUF 0x500\r
-\r
-\r
-// Normally we can ignore allocations from the Runtime-System\r
-#define IGNORE_CRT_ALLOC\r
-\r
-// MaxSize: 1 MByte (only for StackwalkFilter)\r
-#define LOG_FILE_MAX_SIZE 1024*1024\r
-\r
-// If the following is defined, then COM-Leaks will also be tracked\r
-#define WITH_IMALLOC_SPY\r
-\r
-\r
-// #############################################################################################\r
-#ifdef WITH_IMALLOC_SPY\r
-//forwards:\r
-void IMallocHashInsert(void *pData, CONTEXT &Context, size_t nDataSize);\r
-BOOL IMallocHashRemove(void *pData);\r
-\r
-// IMallocSpy-Interface\r
-class CMallocSpy : public IMallocSpy\r
-{\r
-public:\r
-  CMallocSpy(void) {\r
-    m_cbRequest = 0;\r
-  }\r
-  ~CMallocSpy(void) {\r
-  }\r
-  // IUnknown methods\r
-  STDMETHOD(QueryInterface) (REFIID riid, LPVOID *ppUnk) {\r
-    HRESULT hr = S_OK;\r
-    if (IsEqualIID(riid, IID_IUnknown)) {\r
-        *ppUnk = (IUnknown *) this;\r
-    }\r
-    else if (IsEqualIID(riid, IID_IMallocSpy)) {\r
-        *ppUnk =  (IMalloc *) this;\r
-    }\r
-    else {\r
-        *ppUnk = NULL;\r
-        hr =  E_NOINTERFACE;\r
-    }\r
-    AddRef();\r
-    return hr;\r
-  }\r
-  STDMETHOD_(ULONG, AddRef) (void) {\r
-    return InterlockedIncrement(&m_cRef);\r
-  }\r
-  STDMETHOD_(ULONG, Release) (void) {\r
-    LONG cRef;\r
-    cRef = InterlockedDecrement(&m_cRef);\r
-    if (cRef == 0)\r
-    {\r
-      delete this;\r
-    }\r
-    return cRef;\r
-  }\r
-  // IMallocSpy methods\r
-  STDMETHOD_(ULONG, PreAlloc) (ULONG cbRequest) {\r
-    m_cbRequest = cbRequest;\r
-    return cbRequest;\r
-  }\r
-  STDMETHOD_(void *, PostAlloc) (void *pActual) {\r
-    HANDLE hThread;\r
-    if (DuplicateHandle( GetCurrentProcess(), GetCurrentThread(),\r
-      GetCurrentProcess(), &hThread, 0, false, DUPLICATE_SAME_ACCESS ) != 0) {\r
-      // Ok\r
-      CONTEXT c;\r
-      memset( &c, '\0', sizeof c );\r
-      c.ContextFlags = CONTEXT_FULL;\r
-#if 0\r
-      if ( GetThreadContext(hThread, &c) != 0) {\r
-#else\r
-      __asm\r
-      {\r
-        call x\r
-        x: pop eax\r
-        mov c.Eip, eax\r
-        mov c.Ebp, ebp\r
-      }\r
-      {\r
-#endif\r
-        // Ok\r
-        IMallocHashInsert(pActual, c, m_cbRequest);\r
-      }\r
-      CloseHandle(hThread);\r
-    }\r
-    return pActual;\r
-  }\r
-  STDMETHOD_(void *, PreFree) (void *pRequest, BOOL fSpyed) {\r
-    IMallocHashRemove(pRequest);\r
-    return pRequest;\r
-  }\r
-  STDMETHOD_(void, PostFree) (BOOL fSpyed) {\r
-    return;\r
-  }\r
-  STDMETHOD_(ULONG, PreRealloc) (void *pRequest, ULONG cbRequest,\r
-    void **ppNewRequest, BOOL fSpyed) {\r
-    IMallocHashRemove(pRequest);\r
-    m_cbRequest = cbRequest;\r
-    *ppNewRequest = pRequest;  // Bug fixed. Thanx to Christoph Weber\r
-    return cbRequest;\r
-  }\r
-  STDMETHOD_(void *, PostRealloc) (void *pActual, BOOL fSpyed) {\r
-    HANDLE hThread;\r
-    if (DuplicateHandle( GetCurrentProcess(), GetCurrentThread(),\r
-      GetCurrentProcess(), &hThread, 0, false, DUPLICATE_SAME_ACCESS ) != 0) {\r
-      // Ok\r
-      CONTEXT c;\r
-      memset( &c, '\0', sizeof c );\r
-      c.ContextFlags = CONTEXT_FULL;\r
-#if 0\r
-      if ( GetThreadContext(hThread, &c) != 0) {\r
-#else\r
-      __asm\r
-      {\r
-        call x\r
-        x: pop eax\r
-        mov c.Eip, eax\r
-        mov c.Ebp, ebp\r
-      }\r
-      {\r
-#endif\r
-        // Ok\r
-        IMallocHashInsert(pActual, c, m_cbRequest);\r
-      }\r
-      CloseHandle(hThread);\r
-    }\r
-    return pActual;\r
-  }\r
-  STDMETHOD_(void *, PreGetSize) (void *pRequest, BOOL fSpyed) {\r
-    return pRequest;\r
-  }\r
-  STDMETHOD_(ULONG, PostGetSize) (ULONG cbActual, BOOL fSpyed) {\r
-    return cbActual;\r
-  }\r
-  STDMETHOD_(void *, PreDidAlloc) (void *pRequest, BOOL fSpyed) {\r
-    return pRequest;\r
-  }\r
-  STDMETHOD_(BOOL, PostDidAlloc) (void *pRequest, BOOL fSpyed, BOOL fActual) {\r
-    return fActual;\r
-  }\r
-  STDMETHOD_(void, PreHeapMinimize) (void) {\r
-    return;\r
-  }\r
-  STDMETHOD_(void, PostHeapMinimize) (void) {\r
-    return;\r
-  }\r
-private:\r
-  LONG    m_cRef;\r
-  ULONG m_cbRequest;\r
-};\r
-#endif\r
-\r
-// #############################################################################################\r
-// Here I have included the API-Version 9 declarations, so it will also compile on systems, where the new PSDK is not installed\r
-// Normally we just need to include the "dbghelp.h" file\r
-#include <imagehlp.h>\r
-#if API_VERSION_NUMBER < 9\r
-typedef\r
-BOOL\r
-(__stdcall *PREAD_PROCESS_MEMORY_ROUTINE64)(\r
-    HANDLE      hProcess,\r
-    DWORD64     qwBaseAddress,\r
-    PVOID       lpBuffer,\r
-    DWORD       nSize,\r
-    LPDWORD     lpNumberOfBytesRead\r
-    );\r
-\r
-typedef struct _IMAGEHLP_LINE64 {\r
-    DWORD                       SizeOfStruct;           // set to sizeof(IMAGEHLP_LINE64)\r
-    PVOID                       Key;                    // internal\r
-    DWORD                       LineNumber;             // line number in file\r
-    PCHAR                       FileName;               // full filename\r
-    DWORD64                     Address;                // first instruction of line\r
-} IMAGEHLP_LINE64, *PIMAGEHLP_LINE64;\r
-\r
-\r
-typedef struct _IMAGEHLP_MODULE64 {\r
-    DWORD                       SizeOfStruct;           // set to sizeof(IMAGEHLP_MODULE64)\r
-    DWORD64                     BaseOfImage;            // base load address of module\r
-    DWORD                       ImageSize;              // virtual size of the loaded module\r
-    DWORD                       TimeDateStamp;          // date/time stamp from pe header\r
-    DWORD                       CheckSum;               // checksum from the pe header\r
-    DWORD                       NumSyms;                // number of symbols in the symbol table\r
-    SYM_TYPE                    SymType;                // type of symbols loaded\r
-    CHAR                        ModuleName[32];         // module name\r
-    CHAR                        ImageName[256];         // image name\r
-    CHAR                        LoadedImageName[256];   // symbol file name\r
-} IMAGEHLP_MODULE64, *PIMAGEHLP_MODULE64;\r
-\r
-typedef struct _IMAGEHLP_SYMBOL64 {\r
-    DWORD                       SizeOfStruct;           // set to sizeof(IMAGEHLP_SYMBOL64)\r
-    DWORD64                     Address;                // virtual address including dll base address\r
-    DWORD                       Size;                   // estimated size of symbol, can be zero\r
-    DWORD                       Flags;                  // info about the symbols, see the SYMF defines\r
-    DWORD                       MaxNameLength;          // maximum size of symbol name in 'Name'\r
-    CHAR                        Name[1];                // symbol name (null terminated string)\r
-} IMAGEHLP_SYMBOL64, *PIMAGEHLP_SYMBOL64;\r
-\r
-typedef struct _tagADDRESS64 {\r
-    DWORD64       Offset;\r
-    WORD          Segment;\r
-    ADDRESS_MODE  Mode;\r
-} ADDRESS64, *LPADDRESS64;\r
-\r
-typedef struct _KDHELP64 {\r
-\r
-    //\r
-    // address of kernel thread object, as provided in the\r
-    // WAIT_STATE_CHANGE packet.\r
-    //\r
-    DWORD64   Thread;\r
-\r
-    //\r
-    // offset in thread object to pointer to the current callback frame\r
-    // in kernel stack.\r
-    //\r
-    DWORD   ThCallbackStack;\r
-\r
-    //\r
-    // offset in thread object to pointer to the current callback backing\r
-    // store frame in kernel stack.\r
-    //\r
-    DWORD   ThCallbackBStore;\r
-\r
-    //\r
-    // offsets to values in frame:\r
-    //\r
-    // address of next callback frame\r
-    DWORD   NextCallback;\r
-\r
-    // address of saved frame pointer (if applicable)\r
-    DWORD   FramePointer;\r
-\r
-\r
-    //\r
-    // Address of the kernel function that calls out to user mode\r
-    //\r
-    DWORD64   KiCallUserMode;\r
-\r
-    //\r
-    // Address of the user mode dispatcher function\r
-    //\r
-    DWORD64   KeUserCallbackDispatcher;\r
-\r
-    //\r
-    // Lowest kernel mode address\r
-    //\r
-    DWORD64   SystemRangeStart;\r
-\r
-    DWORD64  Reserved[8];\r
-\r
-} KDHELP64, *PKDHELP64;\r
-\r
-\r
-typedef struct _tagSTACKFRAME64 {\r
-    ADDRESS64   AddrPC;               // program counter\r
-    ADDRESS64   AddrReturn;           // return address\r
-    ADDRESS64   AddrFrame;            // frame pointer\r
-    ADDRESS64   AddrStack;            // stack pointer\r
-    ADDRESS64   AddrBStore;           // backing store pointer\r
-    PVOID       FuncTableEntry;       // pointer to pdata/fpo or NULL\r
-    DWORD64     Params[4];            // possible arguments to the function\r
-    BOOL        Far;                  // WOW far call\r
-    BOOL        Virtual;              // is this a virtual frame?\r
-    DWORD64     Reserved[3];\r
-    KDHELP64    KdHelp;\r
-} STACKFRAME64, *LPSTACKFRAME64;\r
-\r
-typedef\r
-PVOID\r
-(__stdcall *PFUNCTION_TABLE_ACCESS_ROUTINE64)(\r
-    HANDLE  hProcess,\r
-    DWORD64 AddrBase\r
-    );\r
-\r
-typedef\r
-DWORD64\r
-(__stdcall *PGET_MODULE_BASE_ROUTINE64)(\r
-    HANDLE  hProcess,\r
-    DWORD64 Address\r
-    );\r
-\r
-typedef\r
-DWORD64\r
-(__stdcall *PTRANSLATE_ADDRESS_ROUTINE64)(\r
-    HANDLE    hProcess,\r
-    HANDLE    hThread,\r
-    LPADDRESS64 lpaddr\r
-    );\r
-#endif\r
-// #############################################################################################\r
-\r
-\r
-\r
-// Forward definitions of functions:\r
-static void ShowStackRM( HANDLE hThread, CONTEXT& c, FILE *fLogFile, PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryFunction, HANDLE hProcess);\r
-static void ShowStack( HANDLE hThread, CONTEXT& c, FILE *fLogFile);\r
-\r
-//static void AllocHashOut(FILE*);\r
-static ULONG AllocHashOutLeaks(FILE*);\r
-\r
-\r
-\r
-// Globale Vars:\r
-static TCHAR *g_pszAllocLogName = NULL;\r
-static FILE *g_fFile = NULL;\r
-\r
-// AllocCheckFileOpen\r
-//  Checks if the log-file is already opened\r
-//  if not, try to open file (append or create if not exists)\r
-//  if open failed, redirect output to stdout\r
-static void AllocCheckFileOpen(bool bAppend = true) {\r
-  // is the File already open? If not open it...\r
-  if (g_fFile == NULL)\r
-    if (g_pszAllocLogName != NULL)\r
-    {\r
-      if (bAppend == false)\r
-        g_fFile = _tfopen(g_pszAllocLogName, _T("w"));\r
-      else\r
-        g_fFile = _tfopen(g_pszAllocLogName, _T("a"));\r
-    }\r
-  if (g_fFile == NULL)\r
-    g_fFile = stdout;\r
-}\r
-\r
-// Write Date/Time to specified file (will also work after 2038)\r
-static void WriteDateTime(FILE *fFile, BOOL asXMLAttrs = FALSE) {\r
-  TCHAR pszTemp[11], pszTemp2[11];\r
-\r
-  if (fFile != NULL) {\r
-    _tstrdate( pszTemp );\r
-    _tstrtime( pszTemp2 );\r
-    if (asXMLAttrs == FALSE)\r
-      _ftprintf(fFile,  _T("%s %s"), pszTemp, pszTemp2 );  // also ok after year 2038 (asctime is NOT ok)\r
-    else\r
-      _ftprintf(fFile,  _T("date=\"%s\" time=\"%s\" "), pszTemp, pszTemp2 );  // also ok after year 2038 (asctime is NOT ok)\r
-  }\r
-}  // WriteDateTime\r
-\r
-\r
-/*******************************************************************************\r
- * Hash-Tabelle\r
- *******************************************************************************/\r
-// Memory for the EIP-Address (is used by the ShowStack-method)\r
-#define MAX_EIP_LEN_BUF 4\r
-\r
-#define ALLOC_ENTRY_NOT_FOUND 0xFFFFFFFF\r
-\r
-typedef struct AllocHashEntryType {\r
-  long                       lRequestID;    // RequestID from CRT (if 0, then this entry is empty)\r
-  size_t                     nDataSize;     // Size of the allocated memory\r
-  char                       cRemovedFlag;  // 0 => memory was not yet released\r
-  struct AllocHashEntryType  *Next;\r
-  // Callstack for EIP\r
-  DWORD                      dwEIPOffset;\r
-  DWORD                      dwEIPLen;\r
-  char                       pcEIPAddr[MAX_EIP_LEN_BUF];\r
-  // Callstack for ESP\r
-  DWORD                      dwESPOffset;\r
-  DWORD                      dwESPLen;\r
-  char                       pcESPAddr[MAX_ESP_LEN_BUF];\r
-} AllocHashEntryType;\r
-\r
-static AllocHashEntryType AllocHashTable[ALLOC_HASH_ENTRIES];\r
-static ULONG AllocHashEntries = 0;\r
-static ULONG AllocHashCollisions = 0;\r
-static ULONG AllocHashFreed = 0;\r
-static ULONG AllocHashMaxUsed = 0; // maximal number of concurrent entries\r
-static ULONG AllocHashCurrentCount = 0;\r
-\r
-static ULONG AllocHashMaxCollisions = 0;\r
-static ULONG AllocHashCurrentCollisions = 0;\r
-\r
-// ##########################################################################################\r
-#ifdef WITH_IMALLOC_SPY\r
-// eigene Tabelle für die IMallocs:\r
-typedef struct IMallocHashEntryType {\r
-  void                       *pData;    // Key-Word\r
-  size_t                     nDataSize;     // größe des Datenblocks (optional)\r
-  char                       cRemovedFlag;  // 0 => nicht wurde noch nicht freigegeben\r
-  struct IMallocHashEntryType  *Next;\r
-  // Callstack für EIP\r
-  DWORD                      dwEIPOffset;\r
-  DWORD                      dwEIPLen;\r
-  char                       pcEIPAddr[MAX_EIP_LEN_BUF];\r
-  // Callstack für ESP\r
-  DWORD                      dwESPOffset;\r
-  DWORD                      dwESPLen;\r
-  char                       pcESPAddr[MAX_ESP_LEN_BUF];\r
-} IMallocHashEntryType;\r
-\r
-static IMallocHashEntryType IMallocHashTable[ALLOC_HASH_ENTRIES];\r
-\r
-static ULONG IMallocHashEntries = 0;\r
-static ULONG IMallocHashCollisions = 0;\r
-static ULONG IMallocHashFreed = 0;\r
-static ULONG IMallocHashMaxUsed = 0; // maximal number of concurrent entries\r
-static ULONG IMallocHashCurrentCount = 0;\r
-\r
-static ULONG IMallocHashMaxCollisions = 0;\r
-static ULONG IMallocHashCurrentCollisions = 0;\r
-\r
-\r
-//static void AllocHashOut(FILE*);\r
-static ULONG IMallocHashOutLeaks(FILE*);\r
-\r
-// AllocHashFunction\r
-//   Die eigentliche Hash-Funktion (hier ganz simpel)\r
-static ULONG IMallocHashFunction(void *pData) {\r
-  ULONG ulTemp;\r
-  DWORD dwPointer = (DWORD) pData;\r
-\r
-  // relativ simpler Mechanismus für die Hash-Funktion,\r
-  // mir ist nur nix besseres eingefallen...\r
-  ulTemp = dwPointer % ALLOC_HASH_ENTRIES;\r
-\r
-  _ASSERTE( (ulTemp >= 0) && (ulTemp < ALLOC_HASH_ENTRIES) );\r
-\r
-  return ulTemp;\r
-}  // AllocHashFunction\r
-\r
-// IMallocHashInsert\r
-//   pData: Key-Word (Pointer to address)\r
-//   pContext:   Context-Record, for retrieving Callstack (EIP and EBP is only needed)\r
-//   nDataSize:  How many bytes\r
-void IMallocHashInsert(void *pData, CONTEXT &Context, size_t nDataSize) {\r
-  ULONG HashIdx;\r
-  IMallocHashEntryType *pHashEntry;\r
-\r
-  // ermittle Statistische Werte\r
-  IMallocHashEntries++;\r
-  IMallocHashCurrentCount++;\r
-  if (IMallocHashCurrentCount > IMallocHashMaxUsed)\r
-    IMallocHashMaxUsed = IMallocHashCurrentCount;\r
-\r
-  // ermittle den Hash-Wert\r
-  HashIdx = IMallocHashFunction(pData);\r
-\r
-  // Eintrag darf nicht größer als die Hash-Tabelle sein\r
-  _ASSERTE(HashIdx < ALLOC_HASH_ENTRIES);\r
-\r
-  pHashEntry = &IMallocHashTable[HashIdx];\r
-  if (pHashEntry->pData == 0) {\r
-    // es ist noch kein Eintrag da\r
-  }\r
-  else {\r
-    //Statistische Daten:\r
-    IMallocHashCollisions++;\r
-    IMallocHashCurrentCollisions++;\r
-    if (IMallocHashCurrentCollisions > IMallocHashMaxCollisions)\r
-      IMallocHashMaxCollisions = IMallocHashCurrentCollisions;\r
-\r
-    // Eintrag ist schon belegt, verkette die Einträge\r
-    // wenn dies oft vorkommt, sollte man entweder die Tabelle vergrößern oder eine\r
-    // andere Hash-Funktion wählen\r
-    while(pHashEntry->Next != NULL) {\r
-      pHashEntry = pHashEntry->Next;\r
-    }\r
-\r
-    pHashEntry->Next = (IMallocHashEntryType*) _calloc_dbg(sizeof(IMallocHashEntryType), 1, _CRT_BLOCK, __FILE__, __LINE__);\r
-    pHashEntry = pHashEntry->Next;\r
-\r
-  }\r
-  pHashEntry->pData = pData;  // Key-Word\r
-  pHashEntry->nDataSize = nDataSize;\r
-  pHashEntry->Next = NULL;\r
-  // Get EIP and save it in the record\r
-  pHashEntry->dwEIPOffset = Context.Eip;\r
-  if (ReadProcessMemory(GetCurrentProcess(), (LPCVOID) Context.Eip, &(pHashEntry->pcEIPAddr), MAX_EIP_LEN_BUF, &(pHashEntry->dwEIPLen)) == 0) {\r
-    // Could not read memory... remove everything...\r
-    memset(pHashEntry->pcEIPAddr, 0, MAX_EIP_LEN_BUF);\r
-    pHashEntry->dwEIPLen = 0;\r
-    pHashEntry->dwEIPOffset = 0;\r
-  }\r
-\r
-  // Get ESP and save it in the record\r
-  pHashEntry->dwESPOffset = Context.Ebp;\r
-  if (ReadProcessMemory(GetCurrentProcess(), (LPCVOID) Context.Ebp, &(pHashEntry->pcESPAddr), MAX_ESP_LEN_BUF, &(pHashEntry->dwESPLen)) == 0) {\r
-    // Could not read memory... remove everything...\r
-    memset(pHashEntry->pcESPAddr, 0, MAX_ESP_LEN_BUF);\r
-    pHashEntry->dwESPLen = 0;\r
-    pHashEntry->dwESPOffset = 0;\r
-\r
-    // Check if I tried to read too much...\r
-    if (GetLastError() == ERROR_PARTIAL_COPY)\r
-    {\r
-      // ask how many I can read:\r
-      MEMORY_BASIC_INFORMATION MemBuffer;\r
-      DWORD dwRet = VirtualQuery((LPCVOID) Context.Ebp, &MemBuffer, sizeof(MemBuffer));\r
-      if (dwRet > 0)\r
-      {\r
-        // calculate the length\r
-        DWORD len = ((DWORD) MemBuffer.BaseAddress + MemBuffer.RegionSize) - Context.Ebp;\r
-        if ( (len > 0) && (len < MAX_ESP_LEN_BUF) )\r
-        {\r
-          // try to read it again (with the shorter length)\r
-          if (ReadProcessMemory(GetCurrentProcess(), (LPCVOID) Context.Ebp, &(pHashEntry->pcESPAddr), len, &(pHashEntry->dwESPLen)) == 0)\r
-          {\r
-            // ok, now everything goes wrong... remove it...\r
-            memset(pHashEntry->pcESPAddr, 0, MAX_ESP_LEN_BUF);\r
-            pHashEntry->dwESPLen = 0;\r
-            pHashEntry->dwESPOffset = 0;\r
-          }\r
-          else\r
-          {\r
-            pHashEntry->dwESPOffset = Context.Ebp;\r
-          }\r
-        }\r
-      } // VirtualQuery was successfully\r
-    }  // ERROR_PARTIAL_COPY\r
-  }\r
-}\r
-\r
-// IMallocHashFind\r
-//   Wird ALLOC_ENTRY_NOT_FOUND zurückgegeben, so wurde der Key nicht \r
-//   gefunden, ansonsten wird ein Zeiger auf den Hash-Eintrag zurückgegeben\r
-//   ACHTUNG: In einem preemptiven Tasking-System kann hier nicht \r
-//            garantiert werden, ob der Zeiger noch gültig ist, wenn er \r
-//            zurückgegeben wird, da er von einem anderen Thread schon\r
-//            freigegeben sein könnte. \r
-//            Die synchronisation muß eine Ebene höher erfolgen\r
-static IMallocHashEntryType *IMallocHashFind(void *pData) {\r
-  ULONG HashIdx;\r
-  IMallocHashEntryType *pHashEntry;\r
-\r
-  // ermittle den Hash-Wert\r
-  HashIdx = IMallocHashFunction(pData);\r
-\r
-  // Eintrag darf nicht größer als die Hash-Tabelle sein\r
-  _ASSERTE(HashIdx < ALLOC_HASH_ENTRIES);\r
-\r
-  pHashEntry = &IMallocHashTable[HashIdx];\r
-  while(pHashEntry != NULL) {\r
-    if (pHashEntry->pData == pData) {\r
-      return pHashEntry;\r
-    }\r
-    pHashEntry = pHashEntry->Next;\r
-  }\r
-\r
-  // wenn hier angelangt, dann wurde der Eintrag nicht gefunden!\r
-  return (IMallocHashEntryType*) ALLOC_ENTRY_NOT_FOUND;\r
-}  // AllocHashFind\r
-\r
-// IMallocHashRemove\r
-//   Return: FALSE (0) : Key wurde gefunden und entfernt/markiert\r
-//           TRUE (!=0): Key wurde nicht gefunden!\r
-BOOL IMallocHashRemove(void *pData) {\r
-  ULONG HashIdx;\r
-  IMallocHashEntryType *pHashEntry, *pHashEntryLast;\r
-\r
-  // ermittle den Hash-Wert\r
-  HashIdx = IMallocHashFunction(pData);\r
-\r
-  // Eintrag darf nicht größer als die Hash-Tabelle sein\r
-  _ASSERTE(HashIdx < ALLOC_HASH_ENTRIES);\r
-\r
-  pHashEntryLast = NULL;\r
-  pHashEntry = &IMallocHashTable[HashIdx];\r
-  while(pHashEntry != NULL) {\r
-    if (pHashEntry->pData == pData) {\r
-#ifdef HASH_ENTRY_REMOVE_AT_FREE\r
-      IMallocHashFreed++;\r
-      IMallocHashCurrentCount--;\r
-      // gebe den Speicher frei\r
-      if (pHashEntryLast == NULL) {\r
-        // Es ist ein Eintrag direkt in der Tabelle\r
-        if (pHashEntry->Next == NULL) {\r
-          // Es ist der letze Eintrag lösche also die Tabelle\r
-          memset(&IMallocHashTable[HashIdx], 0, sizeof(IMallocHashTable[HashIdx]));\r
-        }\r
-        else {\r
-          // Es sind noch Einträge verkettet, überschreibe einfach den nicht mehr gebrauchten...\r
-          IMallocHashEntryType *pTmp = pHashEntry->Next;\r
-          *pHashEntry = *(pHashEntry->Next);\r
-          _free_dbg(pTmp, _CRT_BLOCK);\r
-        }\r
-        return TRUE;\r
-      }\r
-      else {\r
-        // ich bin in einem dynamischen Bereich\r
-        // dies war eine kollisions, zähle also wieder zurück:\r
-        IMallocHashCurrentCollisions--;\r
-        pHashEntryLast->Next = pHashEntry->Next;\r
-        _free_dbg(pHashEntry, _CRT_BLOCK);\r
-        return TRUE;\r
-      }\r
-#else\r
-      // erhöhe nur den Removed counter und behalte das Object im Speicher\r
-      pHashEntry->cRemovedFlag++;\r
-      return TRUE;  // erfolgreich\r
-#endif\r
-    }\r
-    pHashEntryLast = pHashEntry;\r
-    pHashEntry = pHashEntry->Next;\r
-  }\r
-\r
-  // wenn hier angelangt, dann wurde der Eintrag nicht gefunden!\r
-  return FALSE;\r
-}\r
-\r
-\r
-\r
-//   Callback-Funtion for StackWalk für meine CallStack-Ausgabe aus der Hash-Tabelle\r
-static BOOL __stdcall ReadProcMemoryFromIMallocHash(HANDLE pData, DWORD64 lpBaseAddress, PVOID lpBuffer, DWORD nSize, PDWORD lpNumberOfBytesRead) {\r
-  // Versuche die hRequestID zu finden\r
-  IMallocHashEntryType *pHashEntry;\r
-  *lpNumberOfBytesRead = 0;\r
-\r
-  pHashEntry = IMallocHashFind((PVOID) pData);\r
-  if (pHashEntry == (IMallocHashEntryType*) ALLOC_ENTRY_NOT_FOUND) {\r
-    // nicht gefunden, somit kann ich den Speicher nicht lesen\r
-    *lpNumberOfBytesRead = 0;\r
-    return FALSE;\r
-  }\r
-  if ( ((DWORD) lpBaseAddress >= pHashEntry->dwESPOffset) && ((DWORD) lpBaseAddress <= (pHashEntry->dwESPOffset+pHashEntry->dwESPLen)) ) {\r
-    // Speicher liegt im ESP:\r
-    // Errechne den Offset\r
-    DWORD dwOffset = (DWORD) lpBaseAddress - pHashEntry->dwESPOffset;\r
-    DWORD dwSize = __min(nSize, MAX_ESP_LEN_BUF-dwOffset);\r
-    memcpy(lpBuffer, &(pHashEntry->pcESPAddr[dwOffset]), dwSize);\r
-    *lpNumberOfBytesRead = dwSize;\r
-    if (dwSize != nSize)\r
-      return FALSE;\r
-  }\r
-\r
-  if ( ((DWORD) lpBaseAddress >= pHashEntry->dwEIPOffset) && ((DWORD) lpBaseAddress <= (pHashEntry->dwEIPOffset+pHashEntry->dwEIPLen)) ) {\r
-    // Speicher liegt im EIP:\r
-    // Errechne den Offset\r
-    DWORD dwOffset = (DWORD) lpBaseAddress - pHashEntry->dwEIPOffset;\r
-    DWORD dwSize = __min(nSize, MAX_ESP_LEN_BUF-dwOffset);\r
-    memcpy(lpBuffer, &(pHashEntry->pcEIPAddr[dwOffset]), dwSize);\r
-    *lpNumberOfBytesRead = dwSize;\r
-    if (dwSize != nSize)\r
-      return FALSE;\r
-  }\r
-  \r
-  if (*lpNumberOfBytesRead == 0)  // Der Speicher konnte nicht gefunden werden\r
-    return FALSE;\r
-\r
-  return TRUE;\r
-}\r
-// AllocHashOutLeaks\r
-// Gibt allen Speicher aus, der noch nicht wieder freigegeben wurde\r
-//   Returns the number of bytes, that are not freed (leaks)\r
-ULONG IMallocHashOutLeaks(FILE *fFile) {\r
-  ULONG ulTemp;\r
-  IMallocHashEntryType *pHashEntry;\r
-  ULONG ulCount = 0;\r
-  ULONG ulLeaksByte = 0;\r
-\r
-  // Gehe jeden Eintrag durch und gebe ihn aus\r
-  for(ulTemp = 0; ulTemp < ALLOC_HASH_ENTRIES; ulTemp++) {\r
-    pHashEntry = &IMallocHashTable[ulTemp];\r
-    if (pHashEntry->pData != 0) {\r
-      while(pHashEntry != NULL) {\r
-        // gebe die Zeile aus\r
-        if ( (pHashEntry->cRemovedFlag <= 0) || (pHashEntry->cRemovedFlag > 1) ) {\r
-          ulCount++;\r
-          if (g_CallstackOutputType == ACOutput_XML)\r
-            _ftprintf(fFile, _T("<LEAK requestID=\"%u\" size=\"%u\">\n"), pHashEntry->pData, pHashEntry->nDataSize);\r
-          else\r
-            _ftprintf(fFile, _T("Pointer (RequestID): %12i, Removed: %i, Size: %12i\n"), pHashEntry->pData, pHashEntry->cRemovedFlag, pHashEntry->nDataSize);\r
-          CONTEXT c;\r
-          memset( &c, '\0', sizeof c );\r
-          c.Eip = pHashEntry->dwEIPOffset;\r
-          c.Ebp = pHashEntry->dwESPOffset;\r
-          ShowStackRM( NULL, c, fFile, &ReadProcMemoryFromIMallocHash, (HANDLE) pHashEntry->pData);\r
-          // Zähle zusammen wieviel Byte noch nicht freigegeben wurden\r
-          if (pHashEntry->nDataSize > 0)\r
-            ulLeaksByte += pHashEntry->nDataSize;\r
-          else\r
-            ulLeaksByte++;  // Wenn zwar Speicher allokiert wurde, dieser aber 0 Bytes lang war, so reserviere für diesen zumindest 1 Byte\r
-\r
-          if (g_CallstackOutputType == ACOutput_XML)\r
-            _ftprintf(fFile, _T("</LEAK>\n"));  // terminate the xml-node\r
-        }\r
-        pHashEntry = pHashEntry->Next;\r
-      }\r
-    }\r
-  }\r
-  if (g_CallstackOutputType != ACOutput_XML)\r
-    _ftprintf(fFile, _T("\n**** Number of leaks: %i\n"), ulCount);\r
-  return ulLeaksByte;\r
-}  // AllocHashOutLeaks\r
-#endif\r
-\r
-\r
-static void AllocHashInit(void) {\r
-\r
-  memset(AllocHashTable, 0, sizeof(AllocHashTable));\r
-  AllocHashEntries = 0;\r
-  AllocHashCollisions = 0;\r
-  AllocHashFreed = 0;\r
-  AllocHashCurrentCount = 0;\r
-  AllocHashMaxUsed = 0;\r
-\r
-  AllocHashMaxCollisions = 0;\r
-  AllocHashCurrentCollisions = 0;\r
-\r
-#ifdef WITH_IMALLOC_SPY\r
-  memset(IMallocHashTable, 0, sizeof(IMallocHashTable));\r
-  IMallocHashEntries = 0;\r
-  IMallocHashCollisions = 0;\r
-  IMallocHashFreed = 0;\r
-  IMallocHashCurrentCount = 0;\r
-  IMallocHashMaxUsed = 0;\r
-\r
-  IMallocHashMaxCollisions = 0;\r
-  IMallocHashCurrentCollisions = 0;\r
-#endif\r
-  return;\r
-}  // AllocHashInit\r
-\r
-\r
-// AllocHashDeinit\r
-// Returns the number of bytes, that are not freed (leaks)\r
-static ULONG AllocHashDeinit(void) {\r
-  ULONG ulRet = 0;\r
-  bool bAppend = g_CallstackOutputType != ACOutput_XML;\r
-  AllocCheckFileOpen(false);//bAppend);  // open global log-file\r
-\r
-  if (g_CallstackOutputType == ACOutput_XML)\r
-  {\r
-    _ftprintf(g_fFile, _T("<MEMREPORT "));\r
-    WriteDateTime(g_fFile, TRUE);\r
-    _ftprintf(g_fFile, _T(">\n"));\r
-  }\r
-  else\r
-  {\r
-    _ftprintf(g_fFile, _T("\n##### Memory Report ########################################\n"));\r
-    WriteDateTime(g_fFile);\r
-    _ftprintf(g_fFile, _T("\n"));\r
-  }\r
-\r
-#ifndef HASH_ENTRY_REMOVE_AT_FREE\r
-  // output the used memory\r
-  if (g_CallstackOutputType != ACOutput_XML)\r
-    _ftprintf(g_fFile, _T("##### Memory used: #########################################\n"));\r
-  AllocHashOut(g_fFile);\r
-#endif\r
-\r
-  // output the Memoty leaks\r
-  if (g_CallstackOutputType != ACOutput_XML)\r
-    _ftprintf(g_fFile, _T("\n##### Leaks: ###############################################\n"));\r
-  ulRet = AllocHashOutLeaks(g_fFile);\r
-\r
-  if (g_CallstackOutputType == ACOutput_Advanced)\r
-  {\r
-    // output some statistics from the hash-table\r
-    _ftprintf(g_fFile, _T("***** Hash-Table statistics:\n"));\r
-    _ftprintf(g_fFile, _T("      Table-Size:     %i\n"), ALLOC_HASH_ENTRIES);\r
-    _ftprintf(g_fFile, _T("      Inserts:        %i\n"), AllocHashEntries);\r
-    _ftprintf(g_fFile, _T("      Freed:          %i\n"), AllocHashFreed);\r
-    _ftprintf(g_fFile, _T("      Sum Collisions: %i\n"), AllocHashCollisions);\r
-    _ftprintf(g_fFile, _T("\n"));\r
-    _ftprintf(g_fFile, _T("      Max used:       %i\n"), AllocHashMaxUsed);\r
-    _ftprintf(g_fFile, _T("      Max Collisions: %i\n"), AllocHashMaxCollisions);\r
-  }\r
-\r
-  // Free Hash-Table\r
-  ULONG ulTemp;\r
-  AllocHashEntryType *pHashEntry, *pHashEntryOld;\r
-\r
-  // Now, free my own memory\r
-  for(ulTemp = 0; ulTemp < ALLOC_HASH_ENTRIES; ulTemp++) {\r
-    pHashEntry = &AllocHashTable[ulTemp];\r
-    while(pHashEntry != NULL) {\r
-      pHashEntryOld = pHashEntry;\r
-      pHashEntry = pHashEntry->Next;\r
-      if (pHashEntryOld != &AllocHashTable[ulTemp]) {\r
-        // now free the dynamically allocated memory\r
-        free(pHashEntryOld);\r
-      }\r
-    }  // while\r
-  }  // for\r
-  // empty the hash-table\r
-  memset(AllocHashTable, 0, sizeof(AllocHashTable));\r
-\r
-#ifdef WITH_IMALLOC_SPY\r
-  // output the Memoty leaks\r
-  if (g_CallstackOutputType != ACOutput_XML)\r
-    _ftprintf(g_fFile, _T("\n##### COM-Leaks: ###############################################\n"));\r
-  ulRet = IMallocHashOutLeaks(g_fFile);\r
-\r
-  if (g_CallstackOutputType == ACOutput_Advanced)\r
-  {\r
-    // output some statistics from the hash-table\r
-    _ftprintf(g_fFile, _T("***** Hash-Table statistics:\n"));\r
-    _ftprintf(g_fFile, _T("      Table-Size:     %i\n"), ALLOC_HASH_ENTRIES);\r
-    _ftprintf(g_fFile, _T("      Inserts:        %i\n"), IMallocHashEntries);\r
-    _ftprintf(g_fFile, _T("      Freed:          %i\n"), IMallocHashFreed);\r
-    _ftprintf(g_fFile, _T("      Sum Collisions: %i\n"), IMallocHashCollisions);\r
-    _ftprintf(g_fFile, _T("\n"));\r
-    _ftprintf(g_fFile, _T("      Max used:       %i\n"), IMallocHashMaxUsed);\r
-    _ftprintf(g_fFile, _T("      Max Collisions: %i\n"), IMallocHashMaxCollisions);\r
-  }\r
-\r
-  // Free Hash-Table\r
-  //ULONG ulTemp;\r
-  IMallocHashEntryType *pIMHashEntry, *pIMHashEntryOld;\r
-\r
-  // Gehe jeden Eintrag durch und gebe ihn frei\r
-  for(ulTemp = 0; ulTemp < ALLOC_HASH_ENTRIES; ulTemp++) {\r
-    pIMHashEntry = &IMallocHashTable[ulTemp];\r
-    while(pHashEntry != NULL) {\r
-      pIMHashEntryOld = pIMHashEntry;\r
-      pIMHashEntry = pIMHashEntry->Next;\r
-      if (pIMHashEntryOld != &IMallocHashTable[ulTemp]) {\r
-        // es ist dynamischer Speicher, gebe ihn also frei:\r
-        _free_dbg(pIMHashEntryOld, _CRT_BLOCK);\r
-      }\r
-    }  // while\r
-  }  // for\r
-  // Lösche die gesamte Hash-Tabelle\r
-  memset(IMallocHashTable, 0, sizeof(IMallocHashTable));\r
-#endif\r
-\r
-\r
-  if (g_CallstackOutputType == ACOutput_XML)\r
-    _ftprintf(g_fFile, _T("</MEMREPORT>\n"));\r
-\r
-  return ulRet;\r
-}  // AllocHashDeinit\r
-\r
-// AllocHashFunction\r
-// The has-function (very simple)\r
-static inline ULONG AllocHashFunction(long lRequestID) {\r
-  // I couldn´t find any better and faster\r
-  return lRequestID % ALLOC_HASH_ENTRIES;\r
-}  // AllocHashFunction\r
-\r
-// AllocHashInsert\r
-//   lRequestID: Key-Word (RequestID from AllocHook)\r
-//   pContext:   Context-Record, for retrieving Callstack (EIP and EBP is only needed)\r
-//   nDataSize:  How many bytes\r
-static void AllocHashInsert(long lRequestID, CONTEXT &Context, size_t nDataSize) {\r
-  ULONG HashIdx;\r
-  AllocHashEntryType *pHashEntry;\r
-\r
-  // change statistical data\r
-  AllocHashEntries++;\r
-  AllocHashCurrentCount++;\r
-  if (AllocHashCurrentCount > AllocHashMaxUsed)\r
-    AllocHashMaxUsed = AllocHashCurrentCount;\r
-\r
-  // generate hash-value\r
-  HashIdx = AllocHashFunction(lRequestID);\r
-\r
-  pHashEntry = &AllocHashTable[HashIdx];\r
-  if (pHashEntry->lRequestID == 0) {\r
-    // Entry is empty...\r
-  }\r
-  else {\r
-    // Entry is not empy! make a list of entries for this hash value...\r
-    // change statistical data\r
-    // if this happens often, you should increase the hah size or change the heash-function; \r
-    // to fasten the allocation time\r
-    AllocHashCollisions++;\r
-    AllocHashCurrentCollisions++;\r
-    if (AllocHashCurrentCollisions > AllocHashMaxCollisions)\r
-      AllocHashMaxCollisions = AllocHashCurrentCollisions;\r
-\r
-    while(pHashEntry->Next != NULL) {\r
-      pHashEntry = pHashEntry->Next;\r
-    }\r
-\r
-    pHashEntry->Next = (AllocHashEntryType*) calloc(sizeof(AllocHashEntryType), 1);\r
-    pHashEntry = pHashEntry->Next;\r
-\r
-  }\r
-  pHashEntry->lRequestID = lRequestID;  // Key-Word\r
-  pHashEntry->nDataSize = nDataSize;\r
-  pHashEntry->Next = NULL;\r
-  // Get EIP and save it in the record\r
-  pHashEntry->dwEIPOffset = Context.Eip;\r
-  if (ReadProcessMemory(GetCurrentProcess(), (LPCVOID) Context.Eip, &(pHashEntry->pcEIPAddr), MAX_EIP_LEN_BUF, &(pHashEntry->dwEIPLen)) == 0) {\r
-    // Could not read memory... remove everything...\r
-    memset(pHashEntry->pcEIPAddr, 0, MAX_EIP_LEN_BUF);\r
-    pHashEntry->dwEIPLen = 0;\r
-    pHashEntry->dwEIPOffset = 0;\r
-  }\r
-\r
-  // Get ESP and save it in the record\r
-  pHashEntry->dwESPOffset = Context.Ebp;\r
-  if (ReadProcessMemory(GetCurrentProcess(), (LPCVOID) Context.Ebp, &(pHashEntry->pcESPAddr), MAX_ESP_LEN_BUF, &(pHashEntry->dwESPLen)) == 0) {\r
-    // Could not read memory... remove everything...\r
-    memset(pHashEntry->pcESPAddr, 0, MAX_ESP_LEN_BUF);\r
-    pHashEntry->dwESPLen = 0;\r
-    pHashEntry->dwESPOffset = 0;\r
-\r
-    // Check if I tried to read too much...\r
-    if (GetLastError() == ERROR_PARTIAL_COPY)\r
-    {\r
-      // ask how many I can read:\r
-      MEMORY_BASIC_INFORMATION MemBuffer;\r
-      DWORD dwRet = VirtualQuery((LPCVOID) Context.Ebp, &MemBuffer, sizeof(MemBuffer));\r
-      if (dwRet > 0)\r
-      {\r
-        // calculate the length\r
-        DWORD len = ((DWORD) MemBuffer.BaseAddress + MemBuffer.RegionSize) - Context.Ebp;\r
-        if ( (len > 0) && (len < MAX_ESP_LEN_BUF) )\r
-        {\r
-          // try to read it again (with the shorter length)\r
-          if (ReadProcessMemory(GetCurrentProcess(), (LPCVOID) Context.Ebp, &(pHashEntry->pcESPAddr), len, &(pHashEntry->dwESPLen)) == 0)\r
-          {\r
-            // ok, now everything goes wrong... remove it...\r
-            memset(pHashEntry->pcESPAddr, 0, MAX_ESP_LEN_BUF);\r
-            pHashEntry->dwESPLen = 0;\r
-            pHashEntry->dwESPOffset = 0;\r
-          }\r
-          else\r
-          {\r
-            pHashEntry->dwESPOffset = Context.Ebp;\r
-          }\r
-        }\r
-      } // VirtualQuery was successfully\r
-    }  // ERROR_PARTIAL_COPY\r
-  }\r
-}\r
-\r
-// AllocHashFind\r
-//   If ALLOC_ENTRY_NOT_FOUND is returned, the Key was not found!\r
-//   If the Key was found, a pointer to the entry is returned\r
-static AllocHashEntryType *AllocHashFind(long lRequestID) {\r
-  ULONG HashIdx;\r
-  AllocHashEntryType *pHashEntry;\r
-\r
-  // get the Hash-Value\r
-  HashIdx = AllocHashFunction(lRequestID);\r
-\r
-  // Just do some simple checks:\r
-  _ASSERTE(HashIdx < ALLOC_HASH_ENTRIES);\r
-\r
-  pHashEntry = &AllocHashTable[HashIdx];\r
-  while(pHashEntry != NULL) {\r
-    if (pHashEntry->lRequestID == lRequestID) {\r
-      return pHashEntry;\r
-    }\r
-    pHashEntry = pHashEntry->Next;\r
-  }\r
-\r
-  // entry was not found!\r
-  return (AllocHashEntryType*) ALLOC_ENTRY_NOT_FOUND;\r
-}  // AllocHashFind\r
-\r
-// AllocHashRemove\r
-//   Return: FALSE (0) : Key was found and removed/marked\r
-//           TRUE (!=0): Key was not found\r
-static BOOL AllocHashRemove(long lRequestID) {\r
-  ULONG HashIdx;\r
-  AllocHashEntryType *pHashEntry, *pHashEntryLast;\r
-\r
-  // get the Hash-Value\r
-  HashIdx = AllocHashFunction(lRequestID);\r
-\r
-  // Just do some simple checks:\r
-  _ASSERTE(HashIdx < ALLOC_HASH_ENTRIES);\r
-\r
-  pHashEntryLast = NULL;\r
-  pHashEntry = &AllocHashTable[HashIdx];\r
-  while(pHashEntry != NULL) {\r
-    if (pHashEntry->lRequestID == lRequestID) {\r
-#ifdef HASH_ENTRY_REMOVE_AT_FREE\r
-      AllocHashFreed++;\r
-      AllocHashCurrentCount--;\r
-      // release my memory\r
-      if (pHashEntryLast == NULL) {\r
-        // It is an entry in the table, so do not release this memory\r
-        if (pHashEntry->Next == NULL) {\r
-          // It was the last entry, so empty the table entry\r
-          memset(&AllocHashTable[HashIdx], 0, sizeof(AllocHashTable[HashIdx]));\r
-        }\r
-        else {\r
-          // There are some more entries, so shorten the list\r
-          AllocHashEntryType *pTmp = pHashEntry->Next;\r
-          *pHashEntry = *(pHashEntry->Next);\r
-          free(pTmp);\r
-        }\r
-        return TRUE;\r
-      }\r
-      else {\r
-        // now, I am in an dynamic allocated entry\r
-        // it was a collision, so decrease the current collision count\r
-        AllocHashCurrentCollisions--;\r
-        pHashEntryLast->Next = pHashEntry->Next;\r
-        free(pHashEntry);\r
-        return TRUE;\r
-      }\r
-#else\r
-      // increase the Remove-Count and let the objet stay in memory\r
-      pHashEntry->cRemovedFlag++;\r
-      return TRUE;\r
-#endif\r
-    }\r
-    pHashEntryLast = pHashEntry;\r
-    pHashEntry = pHashEntry->Next;\r
-  }\r
-\r
-  // if we are here, we could not find the RequestID\r
-  return FALSE;\r
-}\r
-\r
-// ReadProcMemoryFromHash\r
-//   Callback-Funtion for StackWalk for my own CallStack from the Hash-Table-Entries\r
-static BOOL __stdcall ReadProcMemoryFromHash(HANDLE hRequestID, DWORD64 lpBaseAddress, PVOID lpBuffer, DWORD nSize, PDWORD lpNumberOfBytesRead) {\r
-  // Try to find the RequestID\r
-  AllocHashEntryType *pHashEntry;\r
-  *lpNumberOfBytesRead = 0;\r
-\r
-  pHashEntry = AllocHashFind((LONG) hRequestID);\r
-  if (pHashEntry == (AllocHashEntryType*) ALLOC_ENTRY_NOT_FOUND) {\r
-    // Not found, so I cannot return any memory\r
-    *lpNumberOfBytesRead = 0;\r
-    return FALSE;\r
-  }\r
-  if ( ((DWORD) lpBaseAddress >= pHashEntry->dwESPOffset) && ((DWORD) lpBaseAddress <= (pHashEntry->dwESPOffset+pHashEntry->dwESPLen)) ) {\r
-    // Memory is located in ESP:\r
-    // Calculate the offset\r
-    DWORD dwOffset = (DWORD) lpBaseAddress - pHashEntry->dwESPOffset;\r
-    DWORD dwSize = __min(nSize, MAX_ESP_LEN_BUF-dwOffset);\r
-    memcpy(lpBuffer, &(pHashEntry->pcESPAddr[dwOffset]), dwSize);\r
-    *lpNumberOfBytesRead = dwSize;\r
-    if (dwSize != nSize)\r
-      return FALSE;\r
-  }\r
-\r
-  if ( ((DWORD) lpBaseAddress >= pHashEntry->dwEIPOffset) && ((DWORD) lpBaseAddress <= (pHashEntry->dwEIPOffset+pHashEntry->dwEIPLen)) ) {\r
-    // Memory is located in EIP:\r
-    // Calculate the offset\r
-    DWORD dwOffset = (DWORD) lpBaseAddress - pHashEntry->dwEIPOffset;\r
-    DWORD dwSize = __min(nSize, MAX_ESP_LEN_BUF-dwOffset);\r
-    memcpy(lpBuffer, &(pHashEntry->pcEIPAddr[dwOffset]), dwSize);\r
-    *lpNumberOfBytesRead = dwSize;\r
-    if (dwSize != nSize)\r
-      return FALSE;\r
-  }\r
-  \r
-  if (*lpNumberOfBytesRead == 0)  // Memory could not be found\r
-    return FALSE;\r
-\r
-  return TRUE;\r
-}\r
-\r
-// AllocHashOutLeaks\r
-// Write all Memory (with callstack) which was not freed yet\r
-//   Returns the number of bytes, that are not freed (leaks)\r
-ULONG AllocHashOutLeaks(FILE *fFile) {\r
-  ULONG ulTemp;\r
-  AllocHashEntryType *pHashEntry;\r
-  ULONG ulCount = 0;\r
-  ULONG ulLeaksByte = 0;\r
-\r
-  // Move throu every entry\r
-  for(ulTemp = 0; ulTemp < ALLOC_HASH_ENTRIES; ulTemp++) {\r
-    pHashEntry = &AllocHashTable[ulTemp];\r
-    if (pHashEntry->lRequestID != 0) {\r
-      while(pHashEntry != NULL) {\r
-        if ( (pHashEntry->cRemovedFlag <= 0) || (pHashEntry->cRemovedFlag > 1) ) {\r
-          ulCount++;\r
-          if (g_CallstackOutputType == ACOutput_XML)\r
-            _ftprintf(fFile, _T("<LEAK requestID=\"%u\" size=\"%u\">\n"), pHashEntry->lRequestID, pHashEntry->nDataSize);\r
-          else\r
-            _ftprintf(fFile, _T("RequestID: %12i, Removed: %i, Size: %12i\n"), pHashEntry->lRequestID, pHashEntry->cRemovedFlag, pHashEntry->nDataSize);\r
-          CONTEXT c;\r
-          memset( &c, '\0', sizeof c );\r
-          c.Eip = pHashEntry->dwEIPOffset;\r
-          c.Ebp = pHashEntry->dwESPOffset;\r
-          ShowStackRM( NULL, c, fFile, &ReadProcMemoryFromHash, (HANDLE) pHashEntry->lRequestID);\r
-          // Count the number of leaky bytes\r
-          if (pHashEntry->nDataSize > 0)\r
-            ulLeaksByte += pHashEntry->nDataSize;\r
-          else\r
-            ulLeaksByte++;  // If memory was allocated with zero bytes, then just increase the counter 1\r
-\r
-          if (g_CallstackOutputType == ACOutput_XML)\r
-            _ftprintf(fFile, _T("</LEAK>\n"));  // terminate the xml-node\r
-        }\r
-        pHashEntry = pHashEntry->Next;\r
-      }\r
-    }\r
-  }\r
-  if (g_CallstackOutputType != ACOutput_XML)\r
-    _ftprintf(fFile, _T("\n**** Number of leaks: %i\n"), ulCount);\r
-  return ulLeaksByte;\r
-}  // AllocHashOutLeaks\r
-\r
-// Write all used memory to a file\r
-void AllocHashOut(FILE *fFile) {\r
-  ULONG ulTemp;\r
-  AllocHashEntryType *pHashEntry;\r
-\r
-  for(ulTemp = 0; ulTemp < ALLOC_HASH_ENTRIES; ulTemp++) {\r
-    pHashEntry = &AllocHashTable[ulTemp];\r
-    if (pHashEntry->lRequestID != 0) {\r
-      while(pHashEntry != NULL) {\r
-        if (g_CallstackOutputType == ACOutput_XML)\r
-          _ftprintf(fFile, _T("<MEMUSED requestID=\"%u\" size=\"%u\"\n"), pHashEntry->lRequestID, pHashEntry->nDataSize);\r
-        else\r
-          _ftprintf(fFile, _T("RequestID: %12i, Removed: %i, Size: %12i\n"), pHashEntry->lRequestID, pHashEntry->cRemovedFlag, pHashEntry->nDataSize);\r
-        pHashEntry = pHashEntry->Next;\r
-      }\r
-    }\r
-  }\r
-}  // AllocHashOut\r
-\r
-/*******************************************************************************\r
- * Ende der Hash-Tabelle\r
- *******************************************************************************/\r
-\r
-\r
-// The follwoing is copied from dbgint.h:\r
-// <CRT_INTERNALS>\r
-/*\r
- * For diagnostic purpose, blocks are allocated with extra information and\r
- * stored in a doubly-linked list.  This makes all blocks registered with\r
- * how big they are, when they were allocated, and what they are used for.\r
- */\r
-\r
-#define nNoMansLandSize 4\r
-\r
-typedef struct _CrtMemBlockHeader\r
-{\r
-        struct _CrtMemBlockHeader * pBlockHeaderNext;\r
-        struct _CrtMemBlockHeader * pBlockHeaderPrev;\r
-        char *                      szFileName;\r
-        int                         nLine;\r
-#ifdef _WIN64\r
-        /* These items are reversed on Win64 to eliminate gaps in the struct\r
-         * and ensure that sizeof(struct)%16 == 0, so 16-byte alignment is\r
-         * maintained in the debug heap.\r
-         */\r
-        int                         nBlockUse;\r
-        size_t                      nDataSize;\r
-#else  /* _WIN64 */\r
-        size_t                      nDataSize;\r
-        int                         nBlockUse;\r
-#endif  /* _WIN64 */\r
-        long                        lRequest;\r
-        unsigned char               gap[nNoMansLandSize];\r
-        /* followed by:\r
-         *  unsigned char           data[nDataSize];\r
-         *  unsigned char           anotherGap[nNoMansLandSize];\r
-         */\r
-} _CrtMemBlockHeader;\r
-#define pbData(pblock) ((unsigned char *)((_CrtMemBlockHeader *)pblock + 1))\r
-#define pHdr(pbData) (((_CrtMemBlockHeader *)pbData)-1)\r
\r
-// </CRT_INTERNALS>\r
-\r
-\r
-\r
-\r
-// Global data:\r
-static BOOL g_bInitialized = FALSE;\r
-static HINSTANCE g_hImagehlpDll = NULL;\r
-\r
-static DWORD g_dwShowCount = 0;  // increase at every ShowStack-Call\r
-static CRITICAL_SECTION g_csFileOpenClose = {0};\r
-\r
-// Is used for syncronising call to MyAllocHook (to prevent reentrant calls)\r
-static LONG g_lMallocCalled = 0;\r
-\r
-static _CRT_ALLOC_HOOK pfnOldCrtAllocHook = NULL;\r
-\r
-// Deaktivate AllocHook, by increasing the Syncronisation-Counter\r
-//static void DeactivateMallocStackwalker(void) {\r
-//  InterlockedIncrement(&g_lMallocCalled);\r
-//}\r
-\r
-\r
-// MyAllocHook is Single-Threaded, that means the the calls are serialized in the calling function!\r
-// Special case for VC 5\r
-#if _MSC_VER <= 1100 \r
-static int MyAllocHook(int nAllocType, void *pvData, \r
-      size_t nSize, int nBlockUse, long lRequest, \r
-      const char * szFileName, int nLine ) {\r
-#else\r
-static int MyAllocHook(int nAllocType, void *pvData, \r
-      size_t nSize, int nBlockUse, long lRequest, \r
-      const unsigned char * szFileName, int nLine ) {\r
-#endif\r
-  static TCHAR *operation[] = { _T(""), _T("ALLOCATIONG"), _T("RE-ALLOCATING"), _T("FREEING") };\r
-  static TCHAR *blockType[] = { _T("Free"), _T("Normal"), _T("CRT"), _T("Ignore"), _T("Client") };\r
-\r
-#ifdef IGNORE_CRT_ALLOC\r
-  if (_BLOCK_TYPE(nBlockUse) == _CRT_BLOCK)  // Ignore internal C runtime library allocations\r
-    return TRUE;\r
-#endif\r
-  extern int _crtDbgFlag;\r
-  if  ( ((_CRTDBG_ALLOC_MEM_DF & _crtDbgFlag) == 0) && ( (nAllocType == _HOOK_ALLOC) || (nAllocType == _HOOK_REALLOC) ) )\r
-  {\r
-    // Someone has disabled that the runtime should log this allocation\r
-    // so we do not log this allocation\r
-    if (pfnOldCrtAllocHook != NULL)\r
-      pfnOldCrtAllocHook(nAllocType, pvData, nSize, nBlockUse, lRequest, szFileName, nLine);\r
-    return TRUE;\r
-  }\r
-\r
-  // Prevent from reentrat calls\r
-  if (InterlockedIncrement(&g_lMallocCalled) > 1) { // I was already called\r
-    InterlockedDecrement(&g_lMallocCalled);\r
-    // call the previous alloc hook\r
-    if (pfnOldCrtAllocHook != NULL)\r
-      pfnOldCrtAllocHook(nAllocType, pvData, nSize, nBlockUse, lRequest, szFileName, nLine);\r
-    return TRUE;\r
-  }\r
-\r
-  if (g_ulShowStackAtAlloc > 0) {\r
-    AllocCheckFileOpen();  // Open logfile\r
-  }\r
-\r
-   _ASSERT( (nAllocType == _HOOK_ALLOC) || (nAllocType == _HOOK_REALLOC) || (nAllocType == _HOOK_FREE) );\r
-   _ASSERT( ( _BLOCK_TYPE(nBlockUse) >= 0 ) && ( _BLOCK_TYPE(nBlockUse) < 5 ) );\r
-\r
-  if (nAllocType == _HOOK_FREE) { // freeing\r
-    // Try to get the header information\r
-    if (_CrtIsValidHeapPointer(pvData)) {  // it is a valid Heap-Pointer\r
-      // get the ID\r
-      _CrtMemBlockHeader *pHead;\r
-      // get a pointer to memory block header\r
-      pHead = pHdr(pvData);\r
-      nSize = pHead->nDataSize;\r
-      lRequest = pHead->lRequest; // This is the ID!\r
-\r
-      if (pHead->nBlockUse == _IGNORE_BLOCK)\r
-      {\r
-        InterlockedDecrement(&g_lMallocCalled);\r
-        if (pfnOldCrtAllocHook != NULL)\r
-          pfnOldCrtAllocHook(nAllocType, pvData, nSize, nBlockUse, lRequest, szFileName, nLine);\r
-        return TRUE;\r
-      }\r
-    }\r
-  }\r
-\r
-  if (g_ulShowStackAtAlloc > 0) {\r
-    _ftprintf( g_fFile, _T("##### Memory operation: %s a %d-byte '%s' block (# %ld)"),\r
-      operation[nAllocType], nSize, blockType[_BLOCK_TYPE(nBlockUse)], lRequest );\r
-    if ( pvData != NULL )\r
-      _ftprintf( g_fFile, _T(" at 0x%X"), pvData );\r
-    _ftprintf(g_fFile, _T("\n"));\r
-  }\r
-\r
-  if (nAllocType == _HOOK_FREE) { // freeing:\r
-    if (lRequest != 0) {  // RequestID was found\r
-      BOOL bRet;\r
-      // Try to find the RequestID in the Hash-Table, mark it that it was freed\r
-      bRet = AllocHashRemove(lRequest);\r
-      if(g_ulShowStackAtAlloc > 0) {\r
-        if (bRet == FALSE) {\r
-          // RequestID not found!\r
-          _ftprintf(g_fFile, _T("###### RequestID not found in hash table for FREEING (%i)!\n"), lRequest);\r
-        }\r
-      } // g_ulShowStackAtAlloc > 0\r
-    }\r
-    else {\r
-      if(g_ulShowStackAtAlloc > 0) {\r
-      // No valid RequestID found, display error\r
-      _ftprintf(g_fFile, _T("###### No valid RequestID for FREEING! (0x%X)\n"), pvData);\r
\r
-      }\r
-    }\r
-  }  // freeing\r
-\r
-  if (nAllocType == _HOOK_REALLOC) { // re-allocating\r
-    // Try to get the header information\r
-    if (_CrtIsValidHeapPointer(pvData)) {  // it is a valid Heap-Pointer\r
-      BOOL bRet;\r
-      LONG lReallocRequest;\r
-      // get the ID\r
-      _CrtMemBlockHeader *pHead;\r
-      // get a pointer to memory block header\r
-      pHead = pHdr(pvData);\r
-      // Try to find the RequestID in the Hash-Table, mark it that it was freed\r
-      lReallocRequest = pHead->lRequest;\r
-      bRet = AllocHashRemove(lReallocRequest);\r
-      if (g_ulShowStackAtAlloc > 0) {\r
-        if (bRet == FALSE) {\r
-          // RequestID not found!\r
-          _ftprintf(g_fFile, _T("###### RequestID not found in hash table for RE-ALLOCATING (%i)!\n"), lReallocRequest);\r
-        }\r
-        else {\r
-          _ftprintf(g_fFile, _T("##### Implicit freeing because of re-allocation (# old: %ld, new: %ld)\n"), lReallocRequest, lRequest);\r
-        }\r
-      }  // g_ulShowStackAtAlloc > 0\r
-    }  // ValidHeapPointer\r
-  }  // re-allocating\r
-\r
-  if ( (g_ulShowStackAtAlloc < 3) && (nAllocType == _HOOK_FREE) ) {\r
-    InterlockedDecrement(&g_lMallocCalled);\r
-    // call the previous alloc hook\r
-    if (pfnOldCrtAllocHook != NULL)\r
-      pfnOldCrtAllocHook(nAllocType, pvData, nSize, nBlockUse, lRequest, szFileName, nLine);\r
-    return TRUE;\r
-  }\r
-\r
-  HANDLE hThread;\r
-  if (DuplicateHandle( GetCurrentProcess(), GetCurrentThread(),\r
-    GetCurrentProcess(), &hThread, 0, false, DUPLICATE_SAME_ACCESS ) == 0) {\r
-      // Something was wrong...\r
-      _ftprintf(g_fFile, _T("###### Could not call 'DuplicateHandle' successfully\n"));\r
-      InterlockedDecrement(&g_lMallocCalled);\r
-      // call the previous alloc hook\r
-      if (pfnOldCrtAllocHook != NULL)\r
-        pfnOldCrtAllocHook(nAllocType, pvData, nSize, nBlockUse, lRequest, szFileName, nLine);\r
-      return TRUE;\r
-  }\r
-\r
-  CONTEXT c;\r
-  memset( &c, '\0', sizeof c );\r
-  c.ContextFlags = CONTEXT_FULL;\r
-\r
-  // Get the context of this thread\r
-#if 0\r
-  // init CONTEXT record so we know where to start the stackwalk\r
-  if ( MyGetCurrentThreadContext( hThread, &c )  == 0) {\r
-    if(g_ulShowStackAtAlloc > 1) {\r
-      _ftprintf(g_fFile, _T("###### Could not call 'GetThreadContext' successfully\n"));\r
-    }\r
-    InterlockedDecrement(&g_lMallocCalled);\r
-    // call the previous alloc hook\r
-    if (pfnOldCrtAllocHook != NULL)\r
-      pfnOldCrtAllocHook(nAllocType, pvData, nSize, nBlockUse, lRequest, szFileName, nLine);\r
-    CloseHandle(hThread);\r
-    return TRUE; // could not get context\r
-  }\r
-#else\r
-  __asm\r
-  {\r
-      call x\r
- x:   pop eax\r
-      mov c.Eip, eax\r
-      mov c.Ebp, ebp\r
-  }\r
-#endif\r
-\r
-  if(g_ulShowStackAtAlloc > 1) {\r
-    if(g_ulShowStackAtAlloc > 2) {\r
-      // output the callstack\r
-      ShowStack( hThread, c, g_fFile);\r
-    }\r
-    else {\r
-      // Output only (re)allocs\r
-      if (nAllocType != _HOOK_FREE) {\r
-        ShowStack( hThread, c, g_fFile);\r
-      }\r
-    }\r
-  }  // g_ulShowStackAtAlloc > 1\r
-  CloseHandle( hThread );\r
-\r
-  // Only isert in the Hash-Table if it is not a "freeing"\r
-  if (nAllocType != _HOOK_FREE) {\r
-    if(lRequest != 0) // Always a valid RequestID should be provided (see comments in the header)\r
-      AllocHashInsert(lRequest, c, nSize);\r
-  }\r
-\r
-  InterlockedDecrement(&g_lMallocCalled);\r
-  // call the previous alloc hook\r
-  if (pfnOldCrtAllocHook != NULL)\r
-    pfnOldCrtAllocHook(nAllocType, pvData, nSize, nBlockUse, lRequest, szFileName, nLine);\r
-  return TRUE; // allow the memory operation to proceed\r
-}\r
-\r
-\r
-\r
-\r
-// ##########################################################################################\r
-// ##########################################################################################\r
-// ##########################################################################################\r
-// ##########################################################################################\r
-\r
-#define gle (GetLastError())\r
-#define lenof(a) (sizeof(a) / sizeof((a)[0]))\r
-#define MAXNAMELEN 1024 // max name length for found symbols\r
-#define IMGSYMLEN ( sizeof IMAGEHLP_SYMBOL64 )\r
-#define TTBUFLEN 8096 // for a temp buffer (2^13)\r
-\r
-\r
-\r
-// SymCleanup()\r
-typedef BOOL (__stdcall *tSC)( IN HANDLE hProcess );\r
-tSC pSC = NULL;\r
-\r
-// SymFunctionTableAccess64()\r
-typedef PVOID (__stdcall *tSFTA)( HANDLE hProcess, DWORD64 AddrBase );\r
-tSFTA pSFTA = NULL;\r
-\r
-// SymGetLineFromAddr64()\r
-typedef BOOL (__stdcall *tSGLFA)( IN HANDLE hProcess, IN DWORD64 dwAddr,\r
-  OUT PDWORD pdwDisplacement, OUT PIMAGEHLP_LINE64 Line );\r
-tSGLFA pSGLFA = NULL;\r
-\r
-// SymGetModuleBase64()\r
-typedef DWORD64 (__stdcall *tSGMB)( IN HANDLE hProcess, IN DWORD64 dwAddr );\r
-tSGMB pSGMB = NULL;\r
-\r
-// SymGetModuleInfo64()\r
-typedef BOOL (__stdcall *tSGMI)( IN HANDLE hProcess, IN DWORD64 dwAddr, OUT PIMAGEHLP_MODULE64 ModuleInfo );\r
-tSGMI pSGMI = NULL;\r
-\r
-// SymGetOptions()\r
-typedef DWORD (__stdcall *tSGO)( VOID );\r
-tSGO pSGO = NULL;\r
-\r
-// SymGetSymFromAddr64()\r
-typedef BOOL (__stdcall *tSGSFA)( IN HANDLE hProcess, IN DWORD64 dwAddr,\r
-  OUT PDWORD64 pdwDisplacement, OUT PIMAGEHLP_SYMBOL64 Symbol );\r
-tSGSFA pSGSFA = NULL;\r
-\r
-// SymInitialize()\r
-typedef BOOL (__stdcall *tSI)( IN HANDLE hProcess, IN PSTR UserSearchPath, IN BOOL fInvadeProcess );\r
-tSI pSI = NULL;\r
-\r
-// SymLoadModule64()\r
-typedef DWORD (__stdcall *tSLM)( IN HANDLE hProcess, IN HANDLE hFile,\r
-  IN PSTR ImageName, IN PSTR ModuleName, IN DWORD64 BaseOfDll, IN DWORD SizeOfDll );\r
-tSLM pSLM = NULL;\r
-\r
-// SymSetOptions()\r
-typedef DWORD (__stdcall *tSSO)( IN DWORD SymOptions );\r
-tSSO pSSO = NULL;\r
-\r
-// StackWalk64()\r
-typedef BOOL (__stdcall *tSW)( \r
-  DWORD MachineType, \r
-  HANDLE hProcess,\r
-  HANDLE hThread, \r
-  LPSTACKFRAME64 StackFrame, \r
-  PVOID ContextRecord,\r
-  PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,\r
-  PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,\r
-  PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,\r
-  PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress );\r
-tSW pSW = NULL;\r
-\r
-// UnDecorateSymbolName()\r
-typedef DWORD (__stdcall WINAPI *tUDSN)( PCSTR DecoratedName, PSTR UnDecoratedName,\r
-  DWORD UndecoratedLength, DWORD Flags );\r
-tUDSN pUDSN = NULL;\r
-\r
-\r
-\r
-struct ModuleEntry\r
-{\r
-  std::string imageName;\r
-  std::string moduleName;\r
-  DWORD baseAddress;\r
-  DWORD size;\r
-};\r
-typedef std::vector< ModuleEntry > ModuleList;\r
-typedef ModuleList::iterator ModuleListIter;\r
-\r
-// **************************************** ToolHelp32 ************************\r
-#define MAX_MODULE_NAME32 255\r
-#define TH32CS_SNAPMODULE   0x00000008\r
-#pragma pack( push, 8 )\r
-typedef struct tagMODULEENTRY32\r
-{\r
-    DWORD   dwSize;\r
-    DWORD   th32ModuleID;       // This module\r
-    DWORD   th32ProcessID;      // owning process\r
-    DWORD   GlblcntUsage;       // Global usage count on the module\r
-    DWORD   ProccntUsage;       // Module usage count in th32ProcessID's context\r
-    BYTE  * modBaseAddr;        // Base address of module in th32ProcessID's context\r
-    DWORD   modBaseSize;        // Size in bytes of module starting at modBaseAddr\r
-    HMODULE hModule;            // The hModule of this module in th32ProcessID's context\r
-    char    szModule[MAX_MODULE_NAME32 + 1];\r
-    char    szExePath[MAX_PATH];\r
-} MODULEENTRY32;\r
-typedef MODULEENTRY32 *  PMODULEENTRY32;\r
-typedef MODULEENTRY32 *  LPMODULEENTRY32;\r
-#pragma pack( pop )\r
-\r
-\r
-\r
-static bool GetModuleListTH32(ModuleList& modules, DWORD pid, FILE *fLogFile)\r
-{\r
-  // CreateToolhelp32Snapshot()\r
-  typedef HANDLE (__stdcall *tCT32S)(DWORD dwFlags, DWORD th32ProcessID);\r
-  // Module32First()\r
-  typedef BOOL (__stdcall *tM32F)(HANDLE hSnapshot, LPMODULEENTRY32 lpme);\r
-  // Module32Next()\r
-  typedef BOOL (__stdcall *tM32N)(HANDLE hSnapshot, LPMODULEENTRY32 lpme);\r
-\r
-  // try both dlls...\r
-  const TCHAR *dllname[] = { _T("kernel32.dll"), _T("tlhelp32.dll") };\r
-  HINSTANCE hToolhelp;\r
-  tCT32S pCT32S;\r
-  tM32F pM32F;\r
-  tM32N pM32N;\r
-\r
-  HANDLE hSnap;\r
-  MODULEENTRY32 me;\r
-  me.dwSize = sizeof(me);\r
-  bool keepGoing;\r
-  ModuleEntry e;\r
-  int i;\r
-\r
-  for (i = 0; i<lenof(dllname); i++ )\r
-  {\r
-    hToolhelp = LoadLibrary( dllname[i] );\r
-    if (hToolhelp == NULL)\r
-      continue;\r
-    pCT32S = (tCT32S) GetProcAddress(hToolhelp, "CreateToolhelp32Snapshot");\r
-    pM32F = (tM32F) GetProcAddress(hToolhelp, "Module32First");\r
-    pM32N = (tM32N) GetProcAddress(hToolhelp, "Module32Next");\r
-    if ( pCT32S != 0 && pM32F != 0 && pM32N != 0 )\r
-      break; // found the functions!\r
-    FreeLibrary(hToolhelp);\r
-    hToolhelp = NULL;\r
-  }\r
-\r
-  if (hToolhelp == NULL)\r
-    return false;\r
-\r
-  hSnap = pCT32S( TH32CS_SNAPMODULE, pid );\r
-  if (hSnap == (HANDLE) -1)\r
-    return false;\r
-\r
-  keepGoing = !!pM32F( hSnap, &me );\r
-  while (keepGoing)\r
-  {\r
-    e.imageName = me.szExePath;\r
-    e.moduleName = me.szModule;\r
-    e.baseAddress = (DWORD) me.modBaseAddr;\r
-    e.size = me.modBaseSize;\r
-    modules.push_back( e );\r
-    keepGoing = !!pM32N( hSnap, &me );\r
-  }\r
-\r
-  CloseHandle(hSnap);\r
-  FreeLibrary(hToolhelp);\r
-\r
-  return modules.size() != 0;\r
-}  // GetModuleListTH32\r
-\r
-\r
-// **************************************** PSAPI ************************\r
-typedef struct _MODULEINFO {\r
-    LPVOID lpBaseOfDll;\r
-    DWORD SizeOfImage;\r
-    LPVOID EntryPoint;\r
-} MODULEINFO, *LPMODULEINFO;\r
-\r
-static bool GetModuleListPSAPI(ModuleList &modules, DWORD pid, HANDLE hProcess, FILE *fLogFile)\r
-{\r
-  // EnumProcessModules()\r
-  typedef BOOL (__stdcall *tEPM)(HANDLE hProcess, HMODULE *lphModule, DWORD cb, LPDWORD lpcbNeeded );\r
-  // GetModuleFileNameEx()\r
-  typedef DWORD (__stdcall *tGMFNE)(HANDLE hProcess, HMODULE hModule, LPSTR lpFilename, DWORD nSize );\r
-  // GetModuleBaseName()\r
-  typedef DWORD (__stdcall *tGMBN)(HANDLE hProcess, HMODULE hModule, LPSTR lpFilename, DWORD nSize );\r
-  // GetModuleInformation()\r
-  typedef BOOL (__stdcall *tGMI)(HANDLE hProcess, HMODULE hModule, LPMODULEINFO pmi, DWORD nSize );\r
-\r
-  HINSTANCE hPsapi;\r
-  tEPM pEPM;\r
-  tGMFNE pGMFNE;\r
-  tGMBN pGMBN;\r
-  tGMI pGMI;\r
-\r
-  DWORD i;\r
-  ModuleEntry e;\r
-  DWORD cbNeeded;\r
-  MODULEINFO mi;\r
-  HMODULE *hMods = 0;\r
-  char *tt = 0;\r
-\r
-  hPsapi = LoadLibrary( _T("psapi.dll") );\r
-  if ( hPsapi == 0 )\r
-    return false;\r
-\r
-  modules.clear();\r
-\r
-  pEPM = (tEPM) GetProcAddress( hPsapi, "EnumProcessModules" );\r
-  pGMFNE = (tGMFNE) GetProcAddress( hPsapi, "GetModuleFileNameExA" );\r
-  pGMBN = (tGMFNE) GetProcAddress( hPsapi, "GetModuleBaseNameA" );\r
-  pGMI = (tGMI) GetProcAddress( hPsapi, "GetModuleInformation" );\r
-  if ( pEPM == 0 || pGMFNE == 0 || pGMBN == 0 || pGMI == 0 )\r
-  {\r
-    // we couldn´t find all functions\r
-    FreeLibrary( hPsapi );\r
-    return false;\r
-  }\r
-\r
-  hMods = (HMODULE*) malloc(sizeof(HMODULE) * (TTBUFLEN / sizeof HMODULE));\r
-  tt = (char*) malloc(sizeof(char) * TTBUFLEN);\r
-\r
-  if ( ! pEPM( hProcess, hMods, TTBUFLEN, &cbNeeded ) )\r
-  {\r
-    _ftprintf(fLogFile, _T("%lu: EPM failed, GetLastError = %lu\n"), g_dwShowCount, gle );\r
-    goto cleanup;\r
-  }\r
-\r
-  if ( cbNeeded > TTBUFLEN )\r
-  {\r
-    _ftprintf(fLogFile, _T("%lu: More than %lu module handles. Huh?\n"), g_dwShowCount, lenof( hMods ) );\r
-    goto cleanup;\r
-  }\r
-\r
-  for ( i = 0; i < cbNeeded / sizeof hMods[0]; i++ )\r
-  {\r
-    // base address, size\r
-    pGMI(hProcess, hMods[i], &mi, sizeof mi );\r
-    e.baseAddress = (DWORD) mi.lpBaseOfDll;\r
-    e.size = mi.SizeOfImage;\r
-    // image file name\r
-    tt[0] = 0;\r
-    pGMFNE(hProcess, hMods[i], tt, TTBUFLEN );\r
-    e.imageName = tt;\r
-    // module name\r
-    tt[0] = 0;\r
-    pGMBN(hProcess, hMods[i], tt, TTBUFLEN );\r
-    e.moduleName = tt;\r
-\r
-    modules.push_back(e);\r
-  }\r
-\r
-cleanup:\r
-  if (hPsapi)\r
-    FreeLibrary(hPsapi);\r
-  free(tt);\r
-  free(hMods);\r
-\r
-  return modules.size() != 0;\r
-}  // GetModuleListPSAPI\r
-\r
-\r
-static bool GetModuleList(ModuleList& modules, DWORD pid, HANDLE hProcess, FILE *fLogFile)\r
-{\r
-  // first try toolhelp32\r
-  if (GetModuleListTH32(modules, pid, fLogFile) )\r
-    return true;\r
-  // then try psapi\r
-  return GetModuleListPSAPI(modules, pid, hProcess, fLogFile);\r
-}  // GetModuleList\r
-\r
-\r
-static void EnumAndLoadModuleSymbols( HANDLE hProcess, DWORD pid, FILE *fLogFile )\r
-{\r
-  static ModuleList modules;\r
-  static ModuleListIter it;\r
-  char *img, *mod;\r
-\r
-  // fill in module list\r
-  GetModuleList(modules, pid, hProcess, fLogFile);\r
-\r
-  for ( it = modules.begin(); it != modules.end(); ++ it )\r
-  {\r
-    // SymLoadModule() wants writeable strings\r
-    img = strdup(it->imageName.c_str());\r
-    mod = strdup(it->moduleName.c_str());\r
-\r
-    pSLM( hProcess, 0, img, mod, it->baseAddress, it->size );\r
-\r
-    free(img);\r
-    free(mod);\r
-    std::string s;\r
-  }\r
-}  // EnumAndLoadModuleSymbols\r
-\r
-static int InitStackWalk(void)\r
-{\r
-  if (g_bInitialized != FALSE)\r
-    return 0;  // already initialized\r
-\r
-  // 02-12-19: Now we only support dbghelp.dll!\r
-  //           To use it on NT you have to install the redistrubutable for DBGHELP.DLL\r
-  g_hImagehlpDll = LoadLibrary( _T("dbghelp.dll") );\r
-  if ( g_hImagehlpDll == NULL )\r
-  {\r
-    printf( "LoadLibrary( \"dbghelp.dll\" ): GetLastError = %lu\n", gle );\r
-    g_bInitialized = FALSE;\r
-    return 1;\r
-  }\r
-\r
-  // now we only support the newer dbghlp.dll with the "64"-functions (StackWalk64, a.s.o.)\r
-  // If your dbghlp.dll does not support this, please download the redistributable from MS\r
-  // Normally from: http://www.microsoft.com/downloads/details.aspx?displaylang=en&FamilyID=CD1FC4B2-0885-47F4-AF45-7FD5E14DB6C0\r
-\r
-  pSC = (tSC) GetProcAddress( g_hImagehlpDll, "SymCleanup" );\r
-  pSFTA = (tSFTA) GetProcAddress( g_hImagehlpDll, "SymFunctionTableAccess64" );\r
-  pSGLFA = (tSGLFA) GetProcAddress( g_hImagehlpDll, "SymGetLineFromAddr64" );\r
-  pSGMB = (tSGMB) GetProcAddress( g_hImagehlpDll, "SymGetModuleBase64" );\r
-  pSGMI = (tSGMI) GetProcAddress( g_hImagehlpDll, "SymGetModuleInfo64" );\r
-  pSGO = (tSGO) GetProcAddress( g_hImagehlpDll, "SymGetOptions" );\r
-  pSGSFA = (tSGSFA) GetProcAddress( g_hImagehlpDll, "SymGetSymFromAddr64" );\r
-  pSI = (tSI) GetProcAddress( g_hImagehlpDll, "SymInitialize" );\r
-  pSSO = (tSSO) GetProcAddress( g_hImagehlpDll, "SymSetOptions" );\r
-  pSW = (tSW) GetProcAddress( g_hImagehlpDll, "StackWalk64" );\r
-  pUDSN = (tUDSN) GetProcAddress( g_hImagehlpDll, "UnDecorateSymbolName" );\r
-  pSLM = (tSLM) GetProcAddress( g_hImagehlpDll, "SymLoadModule64" );\r
-\r
-  if ( pSC == NULL || pSFTA == NULL || pSGMB == NULL || pSGMI == NULL ||\r
-    pSGO == NULL || pSGSFA == NULL || pSI == NULL || pSSO == NULL ||\r
-    pSW == NULL || pUDSN == NULL || pSLM == NULL )\r
-  {\r
-    printf( "GetProcAddress(): some required function not found.\n" );\r
-    FreeLibrary( g_hImagehlpDll );\r
-    g_bInitialized = FALSE;\r
-    return 1;\r
-  }\r
-\r
-  g_bInitialized = TRUE;\r
-  InitializeCriticalSection(&g_csFileOpenClose);\r
-  return 0;\r
-}\r
-\r
-// This function if NOT multi-threading capable\r
-// It should only be called from the main-Function!\r
-int InitAllocCheckWN(eAllocCheckOutput eOutput, LPCTSTR pszFileName, ULONG ulShowStackAtAlloc) {\r
-  if (g_bInitialized) {\r
-    return 2;  // already initialized!\r
-  }\r
-  if (ulShowStackAtAlloc <= 3)\r
-    g_ulShowStackAtAlloc = ulShowStackAtAlloc;\r
-  else\r
-    g_ulShowStackAtAlloc = 0;\r
-\r
-  if (pszFileName != NULL) \r
-    g_pszAllocLogName = _tcsdup(pszFileName);\r
-  else\r
-    g_pszAllocLogName = NULL;\r
-\r
-  g_CallstackOutputType = eOutput;\r
-\r
-#ifdef _DEBUG\r
-  AllocHashInit();\r
-\r
-#ifdef WITH_IMALLOC_SPY\r
-  HRESULT hr;\r
-  // erzeuge mein malloc-Spy object\r
-  LPMALLOCSPY pMallocSpy = new CMallocSpy(); // wird später durch Release freigegeben\r
-  if (pMallocSpy != NULL)\r
-  {\r
-    // CoInitilize(); // ??? Ist dies notwendig ?\r
-    hr = CoRegisterMallocSpy(pMallocSpy);\r
-    if FAILED(hr)\r
-    {\r
-      _tprintf(_T("\nCoRegisterMallocSpay failed with %.8x"), hr);\r
-    }\r
-  }\r
-#endif\r
-\r
-  // save the previous alloc hook\r
-  pfnOldCrtAllocHook = _CrtSetAllocHook(MyAllocHook);\r
-#endif\r
-\r
-  return InitStackWalk();\r
-}  // InitAllocCheckWN\r
-\r
-static TCHAR s_szExceptionLogFileName[_MAX_PATH] = _T("\\exceptions.log");  // default\r
-static BOOL s_bUnhandledExeptionFilterSet = FALSE;\r
-static LONG __stdcall CrashHandlerExceptionFilter(EXCEPTION_POINTERS* pExPtrs)\r
-{\r
-  if (pExPtrs->ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW)\r
-  {\r
-    static char MyStack[1024*128];  // be sure that we have enought space...\r
-    // it assumes that DS and SS are the same!!! (this is the case for Win32)\r
-    // change the stack only if the selectors are the same (this is the case for Win32)\r
-    //__asm push offset MyStack[1024*128];\r
-    //__asm pop esp;\r
-  __asm mov eax,offset MyStack[1024*128];\r
-  __asm mov esp,eax;\r
-  }\r
-\r
-   LONG lRet;\r
-   lRet = StackwalkFilter(pExPtrs, /*EXCEPTION_CONTINUE_SEARCH*/EXCEPTION_EXECUTE_HANDLER, s_szExceptionLogFileName);\r
-   TCHAR lString[500];\r
-   _stprintf(lString,\r
-      _T("*** Unhandled Exception!\n")\r
-      _T("   ExpCode: 0x%8.8X\n")\r
-      _T("   ExpFlags: %d\n")\r
-      _T("   ExpAddress: 0x%8.8X\n")\r
-      _T("   Please report!"),\r
-      pExPtrs->ExceptionRecord->ExceptionCode,\r
-      pExPtrs->ExceptionRecord->ExceptionFlags,\r
-      pExPtrs->ExceptionRecord->ExceptionAddress);\r
-   FatalAppExit(-1,lString);\r
-   return lRet;\r
-}\r
-\r
-int InitAllocCheck(eAllocCheckOutput eOutput, BOOL bSetUnhandledExeptionFilter, ULONG ulShowStackAtAlloc)  // will create the filename by itself\r
-{\r
-  TCHAR szModName[_MAX_PATH];\r
-  if (GetModuleFileName(NULL, szModName, sizeof(szModName)/sizeof(TCHAR)) != 0)\r
-  {\r
-    _tcscpy(s_szExceptionLogFileName, szModName);\r
-    if (eOutput == ACOutput_XML)\r
-      _tcscat(s_szExceptionLogFileName, _T(".exp.xml"));\r
-    else\r
-      _tcscat(s_szExceptionLogFileName, _T(".exp.log"));\r
-\r
-    if (eOutput == ACOutput_XML)\r
-      _tcscat(szModName, _T(".mem.xml-leaks"));\r
-    else\r
-      _tcscat(szModName, _T(".mem.log"));\r
-  }\r
-  else\r
-  {\r
-    if (eOutput == ACOutput_XML)\r
-      _tcscpy(szModName, _T("\\mem-leaks.xml-leaks"));  // default\r
-    else\r
-      _tcscpy(szModName, _T("\\mem-leaks.log"));  // default\r
-  }\r
-\r
-  if ((bSetUnhandledExeptionFilter != FALSE) && (s_bUnhandledExeptionFilterSet == FALSE) )\r
-  {\r
-    // set global exception handler (for handling all unhandled exceptions)\r
-    SetUnhandledExceptionFilter(CrashHandlerExceptionFilter);\r
-    s_bUnhandledExeptionFilterSet = TRUE;\r
-  }\r
-\r
-  return InitAllocCheckWN(eOutput, szModName, ulShowStackAtAlloc);\r
-}\r
-\r
-\r
-// This function if NOT multi-threading capable\r
-// It should only be called from the main-Function!\r
-//   Returns the number of bytes that are not freed (leaks)\r
-ULONG DeInitAllocCheck(void) {\r
-  ULONG ulRet = 0;\r
-  if (g_bInitialized) {\r
-\r
-#ifdef _DEBUG\r
-    InterlockedIncrement(&g_lMallocCalled); // No deactivate MyAllocHook, because StackWalker will allocate some memory)\r
-    ulRet = AllocHashDeinit();  // output the not freed memory\r
-    // remove the hook and set the old one\r
-    _CrtSetAllocHook(pfnOldCrtAllocHook);\r
-\r
-#ifdef WITH_IMALLOC_SPY\r
-    CoRevokeMallocSpy();\r
-#endif\r
-\r
-#endif\r
-\r
-    EnterCriticalSection(&g_csFileOpenClose);  // wait until a running stack dump was created\r
-    g_bInitialized = FALSE;\r
-\r
-    // de-init symbol handler etc. (SymCleanup())\r
-    if (pSC != NULL)\r
-      pSC( GetCurrentProcess() );\r
-    FreeLibrary( g_hImagehlpDll );\r
-\r
-    LeaveCriticalSection(&g_csFileOpenClose);\r
-    if (g_pszAllocLogName != NULL) {\r
-      free(g_pszAllocLogName);\r
-      g_pszAllocLogName = NULL;\r
-    }\r
-    if (g_fFile != NULL) {\r
-       fclose(g_fFile);\r
-       g_fFile = NULL;\r
-    }\r
-\r
-    DeleteCriticalSection(&g_csFileOpenClose);\r
-    InterlockedDecrement(&g_lMallocCalled);\r
-  }\r
-\r
-  if (s_bUnhandledExeptionFilterSet != TRUE)\r
-  {\r
-    SetUnhandledExceptionFilter(NULL);\r
-    s_bUnhandledExeptionFilterSet = FALSE;\r
-  }\r
-  return ulRet;\r
-}  // DeInitAllocCheck\r
-\r
-\r
-\r
-void OnlyInstallUnhandeldExceptionFilter(eAllocCheckOutput eOutput)\r
-{\r
-  if (s_bUnhandledExeptionFilterSet == FALSE)\r
-  {\r
-    TCHAR szModName[_MAX_PATH];\r
-    if (GetModuleFileName(NULL, szModName, sizeof(szModName)/sizeof(TCHAR)) != 0)\r
-    {\r
-      _tcscpy(s_szExceptionLogFileName, szModName);\r
-      if (eOutput == ACOutput_XML)\r
-        _tcscat(s_szExceptionLogFileName, _T(".exp.xml"));\r
-      else\r
-        _tcscat(s_szExceptionLogFileName, _T(".exp.log"));\r
-\r
-      if (eOutput == ACOutput_XML)\r
-        _tcscat(szModName, _T(".mem.xml-leaks"));\r
-      else\r
-        _tcscat(szModName, _T(".mem.log"));\r
-    }\r
-    else\r
-    {\r
-      if (eOutput == ACOutput_XML)\r
-        _tcscpy(szModName, _T("\\mem-leaks.xml-leaks"));  // default\r
-      else\r
-        _tcscpy(szModName, _T("\\mem-leaks.log"));  // default\r
-    }\r
-    // set it again; WARNING: this will override the setting for a possible AllocCheck-Setting\r
-    g_CallstackOutputType = eOutput;\r
-\r
-    // set global exception handler (for handling all unhandled exceptions)\r
-    SetUnhandledExceptionFilter(CrashHandlerExceptionFilter);\r
-    s_bUnhandledExeptionFilterSet = TRUE;\r
-  }\r
-}\r
-\r
-\r
-\r
-static TCHAR *GetExpectionCodeText(DWORD dwExceptionCode) {\r
-  switch(dwExceptionCode) {\r
-  case EXCEPTION_ACCESS_VIOLATION: return _T("ACCESS VIOLATION");\r
-  case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: return _T("ARRAY BOUNDS EXCEEDED");\r
-  case EXCEPTION_BREAKPOINT: return _T("BREAKPOINT");\r
-  case EXCEPTION_DATATYPE_MISALIGNMENT: return _T("DATATYPE MISALIGNMENT");\r
-  case EXCEPTION_FLT_DENORMAL_OPERAND: return _T("FLT DENORMAL OPERAND");\r
-  case EXCEPTION_FLT_DIVIDE_BY_ZERO: return _T("FLT DIVIDE BY ZERO");\r
-  case EXCEPTION_FLT_INEXACT_RESULT: return _T("FLT INEXACT RESULT");\r
-  case EXCEPTION_FLT_INVALID_OPERATION: return _T("FLT INVALID OPERATION");\r
-  case EXCEPTION_FLT_OVERFLOW: return _T("FLT OVERFLOW");\r
-  case EXCEPTION_FLT_STACK_CHECK: return _T("FLT STACK CHECK");\r
-  case EXCEPTION_FLT_UNDERFLOW: return _T("FLT UNDERFLOW");\r
-  case EXCEPTION_ILLEGAL_INSTRUCTION: return _T("ILLEGAL INSTRUCTION");\r
-  case EXCEPTION_IN_PAGE_ERROR: return _T("IN PAGE ERROR");\r
-  case EXCEPTION_INT_DIVIDE_BY_ZERO: return _T("INT DIVIDE BY ZERO");\r
-  case EXCEPTION_INT_OVERFLOW: return _T("INT OVERFLOW");\r
-  case EXCEPTION_INVALID_DISPOSITION: return _T("INVALID DISPOSITION");\r
-  case EXCEPTION_NONCONTINUABLE_EXCEPTION: return _T("NONCONTINUABLE EXCEPTION");\r
-  case EXCEPTION_PRIV_INSTRUCTION: return _T("PRIV INSTRUCTION");\r
-  case EXCEPTION_SINGLE_STEP: return _T("SINGLE STEP");\r
-  case EXCEPTION_STACK_OVERFLOW: return _T("STACK OVERFLOW");\r
-  case DBG_CONTROL_C : return _T("DBG CONTROL C ");\r
-  default:\r
-    return _T("<unkown exception>");\r
-  }\r
-}  // GetExpectionCodeText\r
-\r
-// Function is not multi-threading safe, because of static char!\r
-static TCHAR *GetAdditionalExpectionCodeText(PEXCEPTION_RECORD pExceptionRecord) {\r
-  static TCHAR szTemp[100];\r
-\r
-  switch(pExceptionRecord->ExceptionCode) {\r
-  case EXCEPTION_ACCESS_VIOLATION:\r
-    if (pExceptionRecord->NumberParameters == 2) {\r
-      switch(pExceptionRecord->ExceptionInformation[0]) {\r
-      case 0: // read attempt\r
-        _stprintf(szTemp, _T(" read attempt to address 0x%8.8X "), pExceptionRecord->ExceptionInformation[1]);\r
-        return szTemp;\r
-      case 1: // write attempt\r
-        _stprintf(szTemp, _T(" write attempt to address 0x%8.8X "), pExceptionRecord->ExceptionInformation[1]);\r
-        return szTemp;\r
-      default:\r
-        return _T("");\r
-      }\r
-    }  // if (pExceptionRecord->NumberParameters == 2)\r
-    return _T("");\r
-  default:\r
-    return _T("");\r
-  }  // switch(pExceptionRecord->ExceptionCode)\r
-}  // GetAdditionalExpectionCodeText\r
-\r
-std::string SimpleXMLEncode(PCSTR szText)\r
-{\r
-  std::string szRet;\r
-\r
-  for (size_t i=0; i<strlen(szText); i++)\r
-  {\r
-    switch(szText[i])\r
-    {\r
-    case '&':\r
-      szRet.append("&amp;");\r
-      break;\r
-    case '<':\r
-      szRet.append("&lt;");\r
-      break;\r
-    case '>':\r
-      szRet.append("&gt;");\r
-      break;\r
-    case '"':\r
-      szRet.append("&quot;");\r
-      break;\r
-    case '\'':\r
-      szRet.append("&apos;");\r
-      break;\r
-    default:\r
-      szRet += szText[i];\r
-    }\r
-  }\r
-  return szRet;\r
-}\r
-\r
-\r
-// #################################################################################\r
-// #################################################################################\r
-// Here the Stackwalk-Part begins.\r
-//   Some of the code is from an example from a book \r
-//   But I couldn´t find the reference anymore... sorry...\r
-//   If someone knowns, please let me know...\r
-// #################################################################################\r
-// #################################################################################\r
-\r
-\r
-// if you use C++ exception handling: install a translator function\r
-// with set_se_translator(). In the context of that function (but *not*\r
-// afterwards), you can either do your stack dump, or save the CONTEXT\r
-// record as a local copy. Note that you must do the stack sump at the\r
-// earliest opportunity, to avoid the interesting stackframes being gone\r
-// by the time you do the dump.\r
-\r
-// status: \r
-// - EXCEPTION_CONTINUE_SEARCH: exception wird weitergereicht\r
-// - EXCEPTION_CONTINUE_EXECUTION: \r
-// - EXCEPTION_EXECUTE_HANDLER:\r
-DWORD StackwalkFilter( EXCEPTION_POINTERS *ep, DWORD status, LPCTSTR pszLogFile)\r
-{\r
-  HANDLE hThread;\r
-  FILE *fFile = stdout;  // default to stdout\r
-\r
-  if (pszLogFile != NULL) {  // a filename is provided\r
-    // Open the logfile\r
-    fFile = _tfopen(pszLogFile, _T("a"));\r
-    if (fFile != NULL) {  // Is the file too big?\r
-      long size;\r
-      fseek(fFile, 0, SEEK_END);\r
-      size = ftell(fFile);  // Get the size of the file\r
-      if (size >= LOG_FILE_MAX_SIZE) {\r
-        TCHAR *pszTemp = (TCHAR*) malloc(MAX_PATH);\r
-        // It is too big...\r
-        fclose(fFile);\r
-        _tcscpy(pszTemp, pszLogFile);\r
-        _tcscat(pszTemp, _T(".old"));\r
-        _tremove(pszTemp);  // Remove an old file, if exists\r
-        _trename(pszLogFile, pszTemp);  // rename the actual file\r
-        fFile = _tfopen(pszLogFile, _T("w"));  // create a new file\r
-        free(pszTemp);\r
-      }\r
-    }\r
-  }  // if (pszLogFile != NULL) \r
-  if (fFile == NULL) {\r
-    fFile = stdout;\r
-  }\r
-\r
-  // Write infos about the exception\r
-  if (g_CallstackOutputType == ACOutput_XML)\r
-  {\r
-    _ftprintf(fFile, _T("<EXCEPTION code=\"%8.8X\" addr=\"%8.8X\" "), \r
-      ep->ExceptionRecord->ExceptionCode,\r
-      ep->ExceptionRecord->ExceptionAddress);\r
-    WriteDateTime(fFile, TRUE);\r
-    _ftprintf(fFile, _T("code_desc=\"%s\" more_desc=\"%s\">\n"), GetExpectionCodeText(ep->ExceptionRecord->ExceptionCode),\r
-      GetAdditionalExpectionCodeText(ep->ExceptionRecord));\r
-  }\r
-  else\r
-  {\r
-    _ftprintf(fFile, _T("######## EXCEPTION: 0x%8.8X at address: 0x%8.8X"), \r
-      ep->ExceptionRecord->ExceptionCode,\r
-      ep->ExceptionRecord->ExceptionAddress);\r
-    _ftprintf(fFile, _T(": %s %s\n"), GetExpectionCodeText(ep->ExceptionRecord->ExceptionCode),\r
-      GetAdditionalExpectionCodeText(ep->ExceptionRecord));\r
-  }\r
-\r
-  DuplicateHandle( GetCurrentProcess(), GetCurrentThread(),\r
-    GetCurrentProcess(), &hThread, 0, false, DUPLICATE_SAME_ACCESS );\r
-  ShowStack( hThread, *(ep->ContextRecord), fFile);\r
-  CloseHandle( hThread );\r
-\r
-  if (g_CallstackOutputType == ACOutput_XML)\r
-    _ftprintf(fFile, _T("</EXCEPTION>\n"));\r
-\r
-  fclose(fFile);\r
-\r
-  return status;\r
-}  // StackwalkFilter\r
-\r
-void ShowStack( HANDLE hThread, CONTEXT& c, LPCTSTR pszLogFile)\r
-{\r
-  FILE *fFile = stdout;  // default to stdout\r
-\r
-  if (pszLogFile != NULL) {  // a filename is available\r
-    // Open the logfile\r
-    fFile = _tfopen(pszLogFile, _T("a"));\r
-    if (fFile != NULL) {  // Is the file too big?\r
-      long size;\r
-      fseek(fFile, 0, SEEK_END);\r
-      size = ftell(fFile);  // Get the size of the file\r
-      if (size >= LOG_FILE_MAX_SIZE) {\r
-        TCHAR *pszTemp = (TCHAR*) malloc(MAX_PATH);\r
-        // It is too big...\r
-        fclose(fFile);\r
-        _tcscpy(pszTemp, pszLogFile);\r
-        _tcscat(pszTemp, _T(".old"));\r
-        _tremove(pszTemp);  // Remove an old file, if exists\r
-        _trename(pszLogFile, pszTemp);  // rename the actual file\r
-        fFile = _tfopen(pszLogFile, _T("w"));  // open new file\r
-        free(pszTemp);\r
-      }\r
-    }\r
-  }  // if (pszLogFile != NULL) \r
-  if (fFile == NULL) {\r
-    fFile = stdout;\r
-  }\r
-\r
-  ShowStack( hThread, c, fFile);\r
-\r
-  fclose(fFile);\r
-}\r
-\r
-\r
-static void ShowStack( HANDLE hThread, CONTEXT& c, FILE *fLogFile) {\r
-  ShowStackRM(hThread, c, fLogFile, NULL, GetCurrentProcess());\r
-}\r
-\r
-static void ShowStackRM( HANDLE hThread, CONTEXT& c, FILE *fLogFile, PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryFunction, HANDLE hSWProcess) {\r
-  // normally, call ImageNtHeader() and use machine info from PE header\r
-  // but we assume that it is an I386 image...\r
-  DWORD imageType = IMAGE_FILE_MACHINE_I386;\r
-  HANDLE hProcess = GetCurrentProcess(); // hProcess normally comes from outside but we only do the stackdump in our own process\r
-  int frameNum; // counts walked frames\r
-  DWORD64 offsetFromSymbol; // tells us how far from the symbol we were\r
-  DWORD offsetFromLine; // tells us how far from the line we were\r
-  DWORD symOptions; // symbol handler settings\r
-\r
-  static IMAGEHLP_SYMBOL64 *pSym = NULL;\r
-  char undName[MAXNAMELEN]; // undecorated name\r
-  char undFullName[MAXNAMELEN]; // undecorated name with all shenanigans\r
-  IMAGEHLP_MODULE64 Module;\r
-  IMAGEHLP_LINE64 Line;\r
-  BOOL bXMLTagWrote;\r
-\r
-  std::string symSearchPath;\r
-\r
-  static bool bFirstTime = TRUE;\r
-\r
-  // If no logfile is present, outpur to "stdout"\r
-  if (fLogFile == NULL) {\r
-    fLogFile = stdout;\r
-  }\r
-\r
-  STACKFRAME64 s; // in/out stackframe\r
-  memset( &s, '\0', sizeof s );\r
-\r
-  if ( (g_bInitialized == FALSE) && (bFirstTime == TRUE) ) {\r
-    InitStackWalk();\r
-  }\r
-\r
-  if (g_bInitialized == FALSE)\r
-  {\r
-    // Could not init!!!!\r
-    bFirstTime = FALSE;\r
-    _ftprintf(fLogFile, _T("%lu: Stackwalker not initialized (or was not able to initialize)!\n"), g_dwShowCount);\r
-    return;\r
-  }\r
-\r
-// Critical section begin...\r
-  EnterCriticalSection(&g_csFileOpenClose);\r
-\r
-  InterlockedIncrement((long*) &g_dwShowCount);  // erhöhe counter\r
-\r
-\r
-  // NOTE: normally, the exe directory and the current directory should be taken\r
-  // from the target process. The current dir would be gotten through injection\r
-  // of a remote thread; the exe fir through either ToolHelp32 or PSAPI.\r
-\r
-  if (pSym == NULL) {\r
-    pSym = (IMAGEHLP_SYMBOL64 *) malloc( IMGSYMLEN + MAXNAMELEN );\r
-    if (!pSym) goto cleanup;  // not enough memory...\r
-  }\r
-\r
-  if (g_CallstackOutputType != ACOutput_XML)\r
-  {\r
-    _ftprintf(fLogFile, _T("%lu: "), g_dwShowCount);\r
-    WriteDateTime(fLogFile);\r
-    _ftprintf(fLogFile, _T("\n"));\r
-  }\r
-\r
-\r
-  if (bFirstTime) {\r
-\r
-    CHAR *tt, *p;\r
-\r
-    tt = (CHAR*) malloc(sizeof(CHAR) * TTBUFLEN); // Get the temporary buffer\r
-    if (!tt) goto cleanup;  // not enough memory...\r
-\r
-    // build symbol search path from:\r
-    symSearchPath = "";\r
-    // current directory\r
-    if ( GetCurrentDirectoryA( TTBUFLEN, tt ) )\r
-      symSearchPath += tt + std::string( ";" );\r
-    // dir with executable\r
-    if ( GetModuleFileNameA( 0, tt, TTBUFLEN ) )\r
-    {\r
-      for ( p = tt + strlen( tt ) - 1; p >= tt; -- p )\r
-      {\r
-        // locate the rightmost path separator\r
-        if ( *p == '\\' || *p == '/' || *p == ':' )\r
-          break;\r
-      }\r
-      // if we found one, p is pointing at it; if not, tt only contains\r
-      // an exe name (no path), and p points before its first byte\r
-      if ( p != tt ) // path sep found?\r
-      {\r
-        if ( *p == ':' ) // we leave colons in place\r
-          ++ p;\r
-        *p = '\0'; // eliminate the exe name and last path sep\r
-        symSearchPath += tt + std::string( ";" );\r
-      }\r
-    }\r
-    // environment variable _NT_SYMBOL_PATH\r
-    if ( GetEnvironmentVariableA( "_NT_SYMBOL_PATH", tt, TTBUFLEN ) )\r
-      symSearchPath += tt + std::string( ";" );\r
-    // environment variable _NT_ALTERNATE_SYMBOL_PATH\r
-    if ( GetEnvironmentVariableA( "_NT_ALTERNATE_SYMBOL_PATH", tt, TTBUFLEN ) )\r
-      symSearchPath += tt + std::string( ";" );\r
-    // environment variable SYSTEMROOT\r
-    if ( GetEnvironmentVariableA( "SYSTEMROOT", tt, TTBUFLEN ) )\r
-      symSearchPath += tt + std::string( ";" );\r
-\r
-\r
-\r
-    if ( symSearchPath.size() > 0 ) // if we added anything, we have a trailing semicolon\r
-      symSearchPath = symSearchPath.substr( 0, symSearchPath.size() - 1 );\r
-\r
-    // why oh why does SymInitialize() want a writeable string?\r
-    strncpy( tt, symSearchPath.c_str(), TTBUFLEN );\r
-    tt[TTBUFLEN - 1] = '\0'; // if strncpy() overruns, it doesn't add the null terminator\r
-\r
-    // init symbol handler stuff (SymInitialize())\r
-    if ( ! pSI( hProcess, tt, false ) )\r
-    {\r
-      if (g_CallstackOutputType != ACOutput_XML)\r
-        _ftprintf(fLogFile, _T("%lu: SymInitialize(): GetLastError = %lu\n"), g_dwShowCount, gle );\r
-      if (tt) free( tt );\r
-      goto cleanup;\r
-    }\r
-\r
-    // SymGetOptions()\r
-    symOptions = pSGO();\r
-    symOptions |= SYMOPT_LOAD_LINES;\r
-    symOptions &= ~SYMOPT_UNDNAME;\r
-    symOptions &= ~SYMOPT_DEFERRED_LOADS;\r
-    pSSO( symOptions ); // SymSetOptions()\r
-\r
-    // Enumerate modules and tell dbghlp.dll about them.\r
-    // On NT, this is not necessary, but it won't hurt.\r
-    EnumAndLoadModuleSymbols( hProcess, GetCurrentProcessId(), fLogFile );\r
-\r
-    if (tt) \r
-      free( tt );\r
-  }  // bFirstTime = TRUE\r
-  bFirstTime = FALSE;\r
-\r
-  // init STACKFRAME for first call\r
-  // Notes: AddrModeFlat is just an assumption. I hate VDM debugging.\r
-  // Notes: will have to be #ifdef-ed for Alphas; MIPSes are dead anyway,\r
-  // and good riddance.\r
-  s.AddrPC.Offset = c.Eip;\r
-  s.AddrPC.Mode = AddrModeFlat;\r
-  s.AddrFrame.Offset = c.Ebp;\r
-  s.AddrFrame.Mode = AddrModeFlat;\r
-  s.AddrStack.Offset = c.Ebp;\r
-  s.AddrStack.Mode = AddrModeFlat;\r
-\r
-  memset( pSym, '\0', IMGSYMLEN + MAXNAMELEN );\r
-  pSym->SizeOfStruct = IMGSYMLEN;\r
-  pSym->MaxNameLength = MAXNAMELEN;\r
-\r
-  memset( &Line, '\0', sizeof Line );\r
-  Line.SizeOfStruct = sizeof Line;\r
-\r
-  memset( &Module, '\0', sizeof Module );\r
-  Module.SizeOfStruct = sizeof Module;\r
-\r
-  for ( frameNum = 0; ; ++ frameNum )\r
-  {\r
-    // get next stack frame (StackWalk64(), SymFunctionTableAccess64(), SymGetModuleBase64())\r
-    // if this returns ERROR_INVALID_ADDRESS (487) or ERROR_NOACCESS (998), you can\r
-    // assume that either you are done, or that the stack is so hosed that the next\r
-    // deeper frame could not be found.\r
-    // CONTEXT need not to be suplied if imageTyp is IMAGE_FILE_MACHINE_I386!\r
-    if ( ! pSW( imageType, hSWProcess, hThread, &s, NULL, ReadMemoryFunction, pSFTA, pSGMB, NULL ) )\r
-      break;\r
-\r
-    bXMLTagWrote = FALSE;\r
-\r
-    if (g_CallstackOutputType == ACOutput_Advanced)\r
-      _ftprintf(fLogFile, _T("\n%lu: %3d"), g_dwShowCount, frameNum);\r
-    if ( s.AddrPC.Offset == 0 )\r
-    {\r
-      // Special case: If we are here, we have no valid callstack entry!\r
-      switch(g_CallstackOutputType)\r
-      {\r
-      case ACOutput_Simple:\r
-        _ftprintf(fLogFile, _T("%lu: (-nosymbols- PC == 0)\n"), g_dwShowCount);\r
-        break;\r
-      case ACOutput_Advanced:\r
-        _ftprintf(fLogFile, _T("   (-nosymbols- PC == 0)\n"));\r
-        break;\r
-      case ACOutput_XML:\r
-        // TODO: ....\r
-        _ftprintf(fLogFile, _T("<STACKENTRY decl=\"(-nosymbols- PC == 0)\"/>\n"));\r
-        break;\r
-      }\r
-    }\r
-    else\r
-    {\r
-      // we seem to have a valid PC\r
-      undName[0] = 0;\r
-      undFullName[0] = 0;\r
-      offsetFromSymbol = 0;\r
-      // show procedure info (SymGetSymFromAddr())\r
-      if ( ! pSGSFA( hProcess, s.AddrPC.Offset, &offsetFromSymbol, pSym ) )\r
-      {\r
-        if (g_CallstackOutputType == ACOutput_Advanced)\r
-        {\r
-          if ( gle != 487 )\r
-            _ftprintf(fLogFile, _T("   SymGetSymFromAddr(): GetLastError = %lu\n"), gle );\r
-          else\r
-            _ftprintf(fLogFile, _T("\n"));\r
-        }\r
-      }\r
-      else\r
-      {\r
-        // UnDecorateSymbolName()\r
-        pUDSN( pSym->Name, undName, MAXNAMELEN, UNDNAME_NAME_ONLY );\r
-        pUDSN( pSym->Name, undFullName, MAXNAMELEN, UNDNAME_COMPLETE );\r
-        if (g_CallstackOutputType == ACOutput_Advanced)\r
-        {\r
-          if (strlen(undName) > 0)\r
-            fprintf(fLogFile, "     %s %+ld bytes\n", undName, (long) offsetFromSymbol );\r
-          else\r
-          {\r
-            fprintf(fLogFile, "     Sig:  %s %+ld bytes\n", pSym->Name, (long) offsetFromSymbol );\r
-            strcpy(undName, pSym->Name);\r
-          }\r
-          fprintf(fLogFile, "%lu:     Decl: %s\n", g_dwShowCount, undFullName );\r
-        }\r
-      }\r
-      //if (g_CallstackOutputType == ACOutput_XML)\r
-      //  fprintf(fLogFile, "decl=\"%s\" decl_offset=\"%+ld\" ", SimpleXMLEncode(undName).c_str(), (long) offsetFromSymbol);\r
-\r
-      // show line number info, NT5.0-method (SymGetLineFromAddr())\r
-      offsetFromLine = 0;\r
-      if ( pSGLFA != NULL )\r
-      { // yes, we have SymGetLineFromAddr()\r
-        if ( ! pSGLFA( hProcess, s.AddrPC.Offset, &offsetFromLine, &Line ) )\r
-        {\r
-          if ( (gle != 487) && (frameNum > 0) )  // ignore error for first frame\r
-          {\r
-            if (g_CallstackOutputType == ACOutput_XML)\r
-            {\r
-              _ftprintf(fLogFile, _T("<STACKENTRY "));\r
-              bXMLTagWrote = TRUE;\r
-              fprintf(fLogFile, "decl=\"%s\" decl_offset=\"%+ld\" ", SimpleXMLEncode(undName).c_str(), (long) offsetFromSymbol);\r
-              _ftprintf(fLogFile, _T("srcfile=\"SymGetLineFromAddr(): GetLastError = %lu\" "), gle);\r
-            }\r
-            else\r
-              _ftprintf(fLogFile, _T("%lu: SymGetLineFromAddr(): GetLastError = %lu\n"), g_dwShowCount, gle );\r
-          }\r
-        }\r
-        else\r
-        {\r
-          switch(g_CallstackOutputType)\r
-          {\r
-          case ACOutput_Advanced:\r
-            fprintf(fLogFile, "%lu:     Line: %s(%lu) %+ld bytes\n", g_dwShowCount,\r
-              Line.FileName, Line.LineNumber, offsetFromLine );\r
-            break;\r
-          case ACOutput_Simple:\r
-            fprintf(fLogFile, "%lu: %s(%lu) %+ld bytes (%s)\n", g_dwShowCount,\r
-              Line.FileName, Line.LineNumber, offsetFromLine, undName);\r
-            break;\r
-          case ACOutput_XML:\r
-            _ftprintf(fLogFile, _T("<STACKENTRY "));\r
-            bXMLTagWrote = TRUE;\r
-            fprintf(fLogFile, "decl=\"%s\" decl_offset=\"%+ld\" ", SimpleXMLEncode(undName).c_str(), (long) offsetFromSymbol);\r
-            fprintf(fLogFile, "srcfile=\"%s\" line=\"%lu\" line_offset=\"%+ld\" ", \r
-              SimpleXMLEncode(Line.FileName).c_str(), Line.LineNumber, offsetFromLine, undName);\r
-            break;\r
-          }\r
-        }\r
-      } // yes, we have SymGetLineFromAddr()\r
-\r
-      // show module info (SymGetModuleInfo())\r
-      if ( (g_CallstackOutputType == ACOutput_Advanced) || (g_CallstackOutputType == ACOutput_XML) )\r
-      {\r
-        if ( ! pSGMI( hProcess, s.AddrPC.Offset, &Module ) )\r
-        {\r
-          if (g_CallstackOutputType == ACOutput_Advanced)\r
-            _ftprintf(fLogFile, _T("%lu: SymGetModuleInfo): GetLastError = %lu\n"), g_dwShowCount, gle );\r
-        }\r
-        else\r
-        { // got module info OK\r
-          char ty[80];\r
-          switch ( Module.SymType )\r
-          {\r
-          case SymNone:\r
-            strcpy( ty, "-nosymbols-" );\r
-            break;\r
-          case SymCoff:\r
-            strcpy( ty, "COFF" );\r
-            break;\r
-          case SymCv:\r
-            strcpy( ty, "CV" );\r
-            break;\r
-          case SymPdb:\r
-            strcpy( ty, "PDB" );\r
-            break;\r
-          case SymExport:\r
-            strcpy( ty, "-exported-" );\r
-            break;\r
-          case SymDeferred:\r
-            strcpy( ty, "-deferred-" );\r
-            break;\r
-          case SymSym:\r
-            strcpy( ty, "SYM" );\r
-            break;\r
-#if API_VERSION_NUMBER >= 9\r
-          case SymDia:\r
-            strcpy( ty, "DIA" );\r
-            break;\r
-#endif\r
-          default:\r
-            _snprintf( ty, sizeof ty, "symtype=%ld", (long) Module.SymType );\r
-            break;\r
-          }\r
-\r
-          if (g_CallstackOutputType == ACOutput_XML)\r
-          {\r
-            // now, check if the XML-Entry is written...\r
-            if (bXMLTagWrote == FALSE) \r
-            {\r
-              _ftprintf(fLogFile, _T("<STACKENTRY "));\r
-              bXMLTagWrote = TRUE;\r
-              fprintf(fLogFile, "decl=\"%s\" decl_offset=\"%+ld\" ", SimpleXMLEncode(undName).c_str(), (long) offsetFromSymbol);\r
-              _ftprintf(fLogFile, _T("srcfile=\"\" "));\r
-              bXMLTagWrote = TRUE;\r
-            }\r
-          }\r
-\r
-          if (g_CallstackOutputType == ACOutput_Advanced)\r
-          {\r
-            fprintf(fLogFile, "%lu:     Mod:  %s, base: %08lxh\n", g_dwShowCount,\r
-              Module.ModuleName, Module.BaseOfImage );\r
-            if (Module.SymType == SymNone) { // Gebe nur aus, wenn keine Symbole vorhanden sind!\r
-              _ftprintf(fLogFile, _T("%lu:     Offset: 0x%8.8x\n"), g_dwShowCount, s.AddrPC.Offset);\r
-              fprintf(fLogFile, "%lu:     Sym:  type: %s, file: %s\n", g_dwShowCount,\r
-                ty, Module.LoadedImageName );\r
-            }\r
-          }\r
-          else\r
-          {\r
-            // XML:\r
-            if (bXMLTagWrote == TRUE)\r
-              fprintf(fLogFile, "module=\"%s\" base=\"%08lx\" ", Module.ModuleName, Module.BaseOfImage);\r
-          }\r
-        } // got module info OK\r
-      }\r
-      if ( (g_CallstackOutputType == ACOutput_XML) && (bXMLTagWrote == TRUE) )\r
-        _ftprintf(fLogFile, _T("/>\n"));  // terminate the XML node\r
-\r
-    } // we seem to have a valid PC\r
-\r
-    // no return address means no deeper stackframe\r
-    if ( s.AddrReturn.Offset == 0 )\r
-    {\r
-      // avoid misunderstandings in the printf() following the loop\r
-      SetLastError( 0 );\r
-      break;\r
-    }\r
-\r
-  } // for ( frameNum )\r
-\r
-  if ( (g_CallstackOutputType != ACOutput_XML) && (gle != 0) )\r
-    _ftprintf(fLogFile, _T("\n%lu: StackWalk(): GetLastError = %lu\n"), g_dwShowCount, gle );\r
-\r
-cleanup:\r
-  //if (pSym) free( pSym );\r
-  if (fLogFile) {\r
-    _ftprintf(fLogFile, _T("\n\n"));\r
-    if (g_dwShowCount % 1000)\r
-      fflush(fLogFile);\r
-  }\r
-\r
-  LeaveCriticalSection(&g_csFileOpenClose);\r
-\r
-\r
-// Critical section end...\r
-}  // ShowStackRM\r
-\r
-#pragma warning(pop)\r
+/*////////////////////////////////////////////////////////////////////////////
+ *  Project:
+ *    Memory_and_Exception_Trace
+ *
+ * ///////////////////////////////////////////////////////////////////////////
+ *     File:
+ *             Stackwalker.cpp
+ *
+ *     Remarks:
+ *    Dumps memory leaks (unreleased allocations) for CRT-Allocs and COM-Allocs
+ *    Dumps the stack of an thread if an exepction occurs
+ *
+ *  Known bugs:
+ *    - If the allocation-RequestID wrap, then allocations will get lost...
+ *
+ *     Author:
+ *             Jochen Kalmbach, Germany
+ *    (c) 2002-2005 (Freeware)
+ *    http://www.codeproject.com/tools/leakfinder.asp
+ * 
+ * License (The zlib/libpng License, http://www.opensource.org/licenses/zlib-license.php):
+ *
+ * Copyright (c) 2005 Jochen Kalmbach
+ *
+ * This software is provided 'as-is', without any express or implied warranty. 
+ * In no event will the authors be held liable for any damages arising from the 
+ * use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose, including 
+ * commercial applications, and to alter it and redistribute it freely, subject to 
+ * the following restrictions:
+ * 
+ * 1. The origin of this software must not be misrepresented; you must not claim 
+ *    that you wrote the original software. If you use this software in a product, 
+ *    an acknowledgment in the product documentation would be appreciated but is 
+ *    not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be 
+ *    misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source distribution.
+ *
+ *//////////////////////////////////////////////////////////////////////////////
+
+//#include "stdafx.h"  // should be uncommented for precompiled headers
+
+#include <windows.h>
+#include <string>
+#include <vector>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <crtdbg.h>
+#include <tchar.h>
+
+#include "Stackwalker.h"
+
+#pragma warning(push)
+#pragma warning(disable : 4100)
+#pragma warning(disable : 4996)
+#pragma warning(disable : 4189)
+#pragma warning(disable : 4245)
+#pragma warning(disable : 4701)
+
+// If the following is defined, only the used memories are stored in the hash-table. 
+// If the memory is freed, it will be removed from the hash-table (to reduce memory)
+// Consequences: At DeInitAllocHook, only Leaks will be reported
+#define HASH_ENTRY_REMOVE_AT_FREE
+
+
+// 0 = Do not write any output during runtime-alloc-call
+// 1 = Write only the alloc action (malloc, realloc, free)
+// 2 = Write alloc action and callstack only for malloc/realloc
+// 3 = Write alloc action and callstack for all actions
+static ULONG g_ulShowStackAtAlloc = 0;
+
+// the form of the output file
+static eAllocCheckOutput g_CallstackOutputType = ACOutput_Simple;
+
+
+// Size of Hash-Table (this should be a prime number to avoid collisions)
+#define ALLOC_HASH_ENTRIES 1023
+
+
+// Size of Callstack-trace in bytes (0x500 => appr. 5-9 functions, depending on parameter count for each function)
+#define MAX_ESP_LEN_BUF 0x500
+
+
+// Normally we can ignore allocations from the Runtime-System
+#define IGNORE_CRT_ALLOC
+
+// MaxSize: 1 MByte (only for StackwalkFilter)
+#define LOG_FILE_MAX_SIZE 1024*1024
+
+// If the following is defined, then COM-Leaks will also be tracked
+#define WITH_IMALLOC_SPY
+
+
+// #############################################################################################
+#ifdef WITH_IMALLOC_SPY
+//forwards:
+void IMallocHashInsert(void *pData, CONTEXT &Context, size_t nDataSize);
+BOOL IMallocHashRemove(void *pData);
+
+// IMallocSpy-Interface
+class CMallocSpy : public IMallocSpy
+{
+public:
+  CMallocSpy(void) {
+    m_cbRequest = 0;
+  }
+  ~CMallocSpy(void) {
+  }
+  // IUnknown methods
+  STDMETHOD(QueryInterface) (REFIID riid, LPVOID *ppUnk) {
+    HRESULT hr = S_OK;
+    if (IsEqualIID(riid, IID_IUnknown)) {
+        *ppUnk = (IUnknown *) this;
+    }
+    else if (IsEqualIID(riid, IID_IMallocSpy)) {
+        *ppUnk =  (IMalloc *) this;
+    }
+    else {
+        *ppUnk = NULL;
+        hr =  E_NOINTERFACE;
+    }
+    AddRef();
+    return hr;
+  }
+  STDMETHOD_(ULONG, AddRef) (void) {
+    return InterlockedIncrement(&m_cRef);
+  }
+  STDMETHOD_(ULONG, Release) (void) {
+    LONG cRef;
+    cRef = InterlockedDecrement(&m_cRef);
+    if (cRef == 0)
+    {
+      delete this;
+    }
+    return cRef;
+  }
+  // IMallocSpy methods
+  STDMETHOD_(ULONG, PreAlloc) (ULONG cbRequest) {
+    m_cbRequest = cbRequest;
+    return cbRequest;
+  }
+  STDMETHOD_(void *, PostAlloc) (void *pActual) {
+    HANDLE hThread;
+    if (DuplicateHandle( GetCurrentProcess(), GetCurrentThread(),
+      GetCurrentProcess(), &hThread, 0, false, DUPLICATE_SAME_ACCESS ) != 0) {
+      // Ok
+      CONTEXT c;
+      memset( &c, '\0', sizeof c );
+      c.ContextFlags = CONTEXT_FULL;
+#if 0
+      if ( GetThreadContext(hThread, &c) != 0) {
+#else
+      __asm
+      {
+        call x
+        x: pop eax
+        mov c.Eip, eax
+        mov c.Ebp, ebp
+      }
+      {
+#endif
+        // Ok
+        IMallocHashInsert(pActual, c, m_cbRequest);
+      }
+      CloseHandle(hThread);
+    }
+    return pActual;
+  }
+  STDMETHOD_(void *, PreFree) (void *pRequest, BOOL fSpyed) {
+    IMallocHashRemove(pRequest);
+    return pRequest;
+  }
+  STDMETHOD_(void, PostFree) (BOOL fSpyed) {
+    return;
+  }
+  STDMETHOD_(ULONG, PreRealloc) (void *pRequest, ULONG cbRequest,
+    void **ppNewRequest, BOOL fSpyed) {
+    IMallocHashRemove(pRequest);
+    m_cbRequest = cbRequest;
+    *ppNewRequest = pRequest;  // Bug fixed. Thanx to Christoph Weber
+    return cbRequest;
+  }
+  STDMETHOD_(void *, PostRealloc) (void *pActual, BOOL fSpyed) {
+    HANDLE hThread;
+    if (DuplicateHandle( GetCurrentProcess(), GetCurrentThread(),
+      GetCurrentProcess(), &hThread, 0, false, DUPLICATE_SAME_ACCESS ) != 0) {
+      // Ok
+      CONTEXT c;
+      memset( &c, '\0', sizeof c );
+      c.ContextFlags = CONTEXT_FULL;
+#if 0
+      if ( GetThreadContext(hThread, &c) != 0) {
+#else
+      __asm
+      {
+        call x
+        x: pop eax
+        mov c.Eip, eax
+        mov c.Ebp, ebp
+      }
+      {
+#endif
+        // Ok
+        IMallocHashInsert(pActual, c, m_cbRequest);
+      }
+      CloseHandle(hThread);
+    }
+    return pActual;
+  }
+  STDMETHOD_(void *, PreGetSize) (void *pRequest, BOOL fSpyed) {
+    return pRequest;
+  }
+  STDMETHOD_(ULONG, PostGetSize) (ULONG cbActual, BOOL fSpyed) {
+    return cbActual;
+  }
+  STDMETHOD_(void *, PreDidAlloc) (void *pRequest, BOOL fSpyed) {
+    return pRequest;
+  }
+  STDMETHOD_(BOOL, PostDidAlloc) (void *pRequest, BOOL fSpyed, BOOL fActual) {
+    return fActual;
+  }
+  STDMETHOD_(void, PreHeapMinimize) (void) {
+    return;
+  }
+  STDMETHOD_(void, PostHeapMinimize) (void) {
+    return;
+  }
+private:
+  LONG    m_cRef;
+  ULONG m_cbRequest;
+};
+#endif
+
+// #############################################################################################
+// Here I have included the API-Version 9 declarations, so it will also compile on systems, where the new PSDK is not installed
+// Normally we just need to include the "dbghelp.h" file
+#include <imagehlp.h>
+#if API_VERSION_NUMBER < 9
+typedef
+BOOL
+(__stdcall *PREAD_PROCESS_MEMORY_ROUTINE64)(
+    HANDLE      hProcess,
+    DWORD64     qwBaseAddress,
+    PVOID       lpBuffer,
+    DWORD       nSize,
+    LPDWORD     lpNumberOfBytesRead
+    );
+
+typedef struct _IMAGEHLP_LINE64 {
+    DWORD                       SizeOfStruct;           // set to sizeof(IMAGEHLP_LINE64)
+    PVOID                       Key;                    // internal
+    DWORD                       LineNumber;             // line number in file
+    PCHAR                       FileName;               // full filename
+    DWORD64                     Address;                // first instruction of line
+} IMAGEHLP_LINE64, *PIMAGEHLP_LINE64;
+
+
+typedef struct _IMAGEHLP_MODULE64 {
+    DWORD                       SizeOfStruct;           // set to sizeof(IMAGEHLP_MODULE64)
+    DWORD64                     BaseOfImage;            // base load address of module
+    DWORD                       ImageSize;              // virtual size of the loaded module
+    DWORD                       TimeDateStamp;          // date/time stamp from pe header
+    DWORD                       CheckSum;               // checksum from the pe header
+    DWORD                       NumSyms;                // number of symbols in the symbol table
+    SYM_TYPE                    SymType;                // type of symbols loaded
+    CHAR                        ModuleName[32];         // module name
+    CHAR                        ImageName[256];         // image name
+    CHAR                        LoadedImageName[256];   // symbol file name
+} IMAGEHLP_MODULE64, *PIMAGEHLP_MODULE64;
+
+typedef struct _IMAGEHLP_SYMBOL64 {
+    DWORD                       SizeOfStruct;           // set to sizeof(IMAGEHLP_SYMBOL64)
+    DWORD64                     Address;                // virtual address including dll base address
+    DWORD                       Size;                   // estimated size of symbol, can be zero
+    DWORD                       Flags;                  // info about the symbols, see the SYMF defines
+    DWORD                       MaxNameLength;          // maximum size of symbol name in 'Name'
+    CHAR                        Name[1];                // symbol name (null terminated string)
+} IMAGEHLP_SYMBOL64, *PIMAGEHLP_SYMBOL64;
+
+typedef struct _tagADDRESS64 {
+    DWORD64       Offset;
+    WORD          Segment;
+    ADDRESS_MODE  Mode;
+} ADDRESS64, *LPADDRESS64;
+
+typedef struct _KDHELP64 {
+
+    //
+    // address of kernel thread object, as provided in the
+    // WAIT_STATE_CHANGE packet.
+    //
+    DWORD64   Thread;
+
+    //
+    // offset in thread object to pointer to the current callback frame
+    // in kernel stack.
+    //
+    DWORD   ThCallbackStack;
+
+    //
+    // offset in thread object to pointer to the current callback backing
+    // store frame in kernel stack.
+    //
+    DWORD   ThCallbackBStore;
+
+    //
+    // offsets to values in frame:
+    //
+    // address of next callback frame
+    DWORD   NextCallback;
+
+    // address of saved frame pointer (if applicable)
+    DWORD   FramePointer;
+
+
+    //
+    // Address of the kernel function that calls out to user mode
+    //
+    DWORD64   KiCallUserMode;
+
+    //
+    // Address of the user mode dispatcher function
+    //
+    DWORD64   KeUserCallbackDispatcher;
+
+    //
+    // Lowest kernel mode address
+    //
+    DWORD64   SystemRangeStart;
+
+    DWORD64  Reserved[8];
+
+} KDHELP64, *PKDHELP64;
+
+
+typedef struct _tagSTACKFRAME64 {
+    ADDRESS64   AddrPC;               // program counter
+    ADDRESS64   AddrReturn;           // return address
+    ADDRESS64   AddrFrame;            // frame pointer
+    ADDRESS64   AddrStack;            // stack pointer
+    ADDRESS64   AddrBStore;           // backing store pointer
+    PVOID       FuncTableEntry;       // pointer to pdata/fpo or NULL
+    DWORD64     Params[4];            // possible arguments to the function
+    BOOL        Far;                  // WOW far call
+    BOOL        Virtual;              // is this a virtual frame?
+    DWORD64     Reserved[3];
+    KDHELP64    KdHelp;
+} STACKFRAME64, *LPSTACKFRAME64;
+
+typedef
+PVOID
+(__stdcall *PFUNCTION_TABLE_ACCESS_ROUTINE64)(
+    HANDLE  hProcess,
+    DWORD64 AddrBase
+    );
+
+typedef
+DWORD64
+(__stdcall *PGET_MODULE_BASE_ROUTINE64)(
+    HANDLE  hProcess,
+    DWORD64 Address
+    );
+
+typedef
+DWORD64
+(__stdcall *PTRANSLATE_ADDRESS_ROUTINE64)(
+    HANDLE    hProcess,
+    HANDLE    hThread,
+    LPADDRESS64 lpaddr
+    );
+#endif
+// #############################################################################################
+
+
+
+// Forward definitions of functions:
+static void ShowStackRM( HANDLE hThread, CONTEXT& c, FILE *fLogFile, PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryFunction, HANDLE hProcess);
+static void ShowStack( HANDLE hThread, CONTEXT& c, FILE *fLogFile);
+
+//static void AllocHashOut(FILE*);
+static ULONG AllocHashOutLeaks(FILE*);
+
+
+
+// Globale Vars:
+static TCHAR *g_pszAllocLogName = NULL;
+static FILE *g_fFile = NULL;
+
+// AllocCheckFileOpen
+//  Checks if the log-file is already opened
+//  if not, try to open file (append or create if not exists)
+//  if open failed, redirect output to stdout
+static void AllocCheckFileOpen(bool bAppend = true) {
+  // is the File already open? If not open it...
+  if (g_fFile == NULL)
+    if (g_pszAllocLogName != NULL)
+    {
+      if (bAppend == false)
+        g_fFile = _tfopen(g_pszAllocLogName, _T("w"));
+      else
+        g_fFile = _tfopen(g_pszAllocLogName, _T("a"));
+    }
+  if (g_fFile == NULL)
+    g_fFile = stdout;
+}
+
+// Write Date/Time to specified file (will also work after 2038)
+static void WriteDateTime(FILE *fFile, BOOL asXMLAttrs = FALSE) {
+  TCHAR pszTemp[11], pszTemp2[11];
+
+  if (fFile != NULL) {
+    _tstrdate( pszTemp );
+    _tstrtime( pszTemp2 );
+    if (asXMLAttrs == FALSE)
+      _ftprintf(fFile,  _T("%s %s"), pszTemp, pszTemp2 );  // also ok after year 2038 (asctime is NOT ok)
+    else
+      _ftprintf(fFile,  _T("date=\"%s\" time=\"%s\" "), pszTemp, pszTemp2 );  // also ok after year 2038 (asctime is NOT ok)
+  }
+}  // WriteDateTime
+
+
+/*******************************************************************************
+ * Hash-Tabelle
+ *******************************************************************************/
+// Memory for the EIP-Address (is used by the ShowStack-method)
+#define MAX_EIP_LEN_BUF 4
+
+#define ALLOC_ENTRY_NOT_FOUND 0xFFFFFFFF
+
+typedef struct AllocHashEntryType {
+  long                       lRequestID;    // RequestID from CRT (if 0, then this entry is empty)
+  size_t                     nDataSize;     // Size of the allocated memory
+  char                       cRemovedFlag;  // 0 => memory was not yet released
+  struct AllocHashEntryType  *Next;
+  // Callstack for EIP
+  DWORD                      dwEIPOffset;
+  DWORD                      dwEIPLen;
+  char                       pcEIPAddr[MAX_EIP_LEN_BUF];
+  // Callstack for ESP
+  DWORD                      dwESPOffset;
+  DWORD                      dwESPLen;
+  char                       pcESPAddr[MAX_ESP_LEN_BUF];
+} AllocHashEntryType;
+
+static AllocHashEntryType AllocHashTable[ALLOC_HASH_ENTRIES];
+static ULONG AllocHashEntries = 0;
+static ULONG AllocHashCollisions = 0;
+static ULONG AllocHashFreed = 0;
+static ULONG AllocHashMaxUsed = 0; // maximal number of concurrent entries
+static ULONG AllocHashCurrentCount = 0;
+
+static ULONG AllocHashMaxCollisions = 0;
+static ULONG AllocHashCurrentCollisions = 0;
+
+// ##########################################################################################
+#ifdef WITH_IMALLOC_SPY
+// eigene Tabelle für die IMallocs:
+typedef struct IMallocHashEntryType {
+  void                       *pData;    // Key-Word
+  size_t                     nDataSize;     // größe des Datenblocks (optional)
+  char                       cRemovedFlag;  // 0 => nicht wurde noch nicht freigegeben
+  struct IMallocHashEntryType  *Next;
+  // Callstack für EIP
+  DWORD                      dwEIPOffset;
+  DWORD                      dwEIPLen;
+  char                       pcEIPAddr[MAX_EIP_LEN_BUF];
+  // Callstack für ESP
+  DWORD                      dwESPOffset;
+  DWORD                      dwESPLen;
+  char                       pcESPAddr[MAX_ESP_LEN_BUF];
+} IMallocHashEntryType;
+
+static IMallocHashEntryType IMallocHashTable[ALLOC_HASH_ENTRIES];
+
+static ULONG IMallocHashEntries = 0;
+static ULONG IMallocHashCollisions = 0;
+static ULONG IMallocHashFreed = 0;
+static ULONG IMallocHashMaxUsed = 0; // maximal number of concurrent entries
+static ULONG IMallocHashCurrentCount = 0;
+
+static ULONG IMallocHashMaxCollisions = 0;
+static ULONG IMallocHashCurrentCollisions = 0;
+
+
+//static void AllocHashOut(FILE*);
+static ULONG IMallocHashOutLeaks(FILE*);
+
+// AllocHashFunction
+//   Die eigentliche Hash-Funktion (hier ganz simpel)
+static ULONG IMallocHashFunction(void *pData) {
+  ULONG ulTemp;
+  DWORD dwPointer = (DWORD) pData;
+
+  // relativ simpler Mechanismus für die Hash-Funktion,
+  // mir ist nur nix besseres eingefallen...
+  ulTemp = dwPointer % ALLOC_HASH_ENTRIES;
+
+  _ASSERTE( (ulTemp >= 0) && (ulTemp < ALLOC_HASH_ENTRIES) );
+
+  return ulTemp;
+}  // AllocHashFunction
+
+// IMallocHashInsert
+//   pData: Key-Word (Pointer to address)
+//   pContext:   Context-Record, for retrieving Callstack (EIP and EBP is only needed)
+//   nDataSize:  How many bytes
+void IMallocHashInsert(void *pData, CONTEXT &Context, size_t nDataSize) {
+  ULONG HashIdx;
+  IMallocHashEntryType *pHashEntry;
+
+  // ermittle Statistische Werte
+  IMallocHashEntries++;
+  IMallocHashCurrentCount++;
+  if (IMallocHashCurrentCount > IMallocHashMaxUsed)
+    IMallocHashMaxUsed = IMallocHashCurrentCount;
+
+  // ermittle den Hash-Wert
+  HashIdx = IMallocHashFunction(pData);
+
+  // Eintrag darf nicht größer als die Hash-Tabelle sein
+  _ASSERTE(HashIdx < ALLOC_HASH_ENTRIES);
+
+  pHashEntry = &IMallocHashTable[HashIdx];
+  if (pHashEntry->pData == 0) {
+    // es ist noch kein Eintrag da
+  }
+  else {
+    //Statistische Daten:
+    IMallocHashCollisions++;
+    IMallocHashCurrentCollisions++;
+    if (IMallocHashCurrentCollisions > IMallocHashMaxCollisions)
+      IMallocHashMaxCollisions = IMallocHashCurrentCollisions;
+
+    // Eintrag ist schon belegt, verkette die Einträge
+    // wenn dies oft vorkommt, sollte man entweder die Tabelle vergrößern oder eine
+    // andere Hash-Funktion wählen
+    while(pHashEntry->Next != NULL) {
+      pHashEntry = pHashEntry->Next;
+    }
+
+    pHashEntry->Next = (IMallocHashEntryType*) _calloc_dbg(sizeof(IMallocHashEntryType), 1, _CRT_BLOCK, __FILE__, __LINE__);
+    pHashEntry = pHashEntry->Next;
+
+  }
+  pHashEntry->pData = pData;  // Key-Word
+  pHashEntry->nDataSize = nDataSize;
+  pHashEntry->Next = NULL;
+  // Get EIP and save it in the record
+  pHashEntry->dwEIPOffset = Context.Eip;
+  if (ReadProcessMemory(GetCurrentProcess(), (LPCVOID) Context.Eip, &(pHashEntry->pcEIPAddr), MAX_EIP_LEN_BUF, &(pHashEntry->dwEIPLen)) == 0) {
+    // Could not read memory... remove everything...
+    memset(pHashEntry->pcEIPAddr, 0, MAX_EIP_LEN_BUF);
+    pHashEntry->dwEIPLen = 0;
+    pHashEntry->dwEIPOffset = 0;
+  }
+
+  // Get ESP and save it in the record
+  pHashEntry->dwESPOffset = Context.Ebp;
+  if (ReadProcessMemory(GetCurrentProcess(), (LPCVOID) Context.Ebp, &(pHashEntry->pcESPAddr), MAX_ESP_LEN_BUF, &(pHashEntry->dwESPLen)) == 0) {
+    // Could not read memory... remove everything...
+    memset(pHashEntry->pcESPAddr, 0, MAX_ESP_LEN_BUF);
+    pHashEntry->dwESPLen = 0;
+    pHashEntry->dwESPOffset = 0;
+
+    // Check if I tried to read too much...
+    if (GetLastError() == ERROR_PARTIAL_COPY)
+    {
+      // ask how many I can read:
+      MEMORY_BASIC_INFORMATION MemBuffer;
+      DWORD dwRet = VirtualQuery((LPCVOID) Context.Ebp, &MemBuffer, sizeof(MemBuffer));
+      if (dwRet > 0)
+      {
+        // calculate the length
+        DWORD len = ((DWORD) MemBuffer.BaseAddress + MemBuffer.RegionSize) - Context.Ebp;
+        if ( (len > 0) && (len < MAX_ESP_LEN_BUF) )
+        {
+          // try to read it again (with the shorter length)
+          if (ReadProcessMemory(GetCurrentProcess(), (LPCVOID) Context.Ebp, &(pHashEntry->pcESPAddr), len, &(pHashEntry->dwESPLen)) == 0)
+          {
+            // ok, now everything goes wrong... remove it...
+            memset(pHashEntry->pcESPAddr, 0, MAX_ESP_LEN_BUF);
+            pHashEntry->dwESPLen = 0;
+            pHashEntry->dwESPOffset = 0;
+          }
+          else
+          {
+            pHashEntry->dwESPOffset = Context.Ebp;
+          }
+        }
+      } // VirtualQuery was successfully
+    }  // ERROR_PARTIAL_COPY
+  }
+}
+
+// IMallocHashFind
+//   Wird ALLOC_ENTRY_NOT_FOUND zurückgegeben, so wurde der Key nicht 
+//   gefunden, ansonsten wird ein Zeiger auf den Hash-Eintrag zurückgegeben
+//   ACHTUNG: In einem preemptiven Tasking-System kann hier nicht 
+//            garantiert werden, ob der Zeiger noch gültig ist, wenn er 
+//            zurückgegeben wird, da er von einem anderen Thread schon
+//            freigegeben sein könnte. 
+//            Die synchronisation muß eine Ebene höher erfolgen
+static IMallocHashEntryType *IMallocHashFind(void *pData) {
+  ULONG HashIdx;
+  IMallocHashEntryType *pHashEntry;
+
+  // ermittle den Hash-Wert
+  HashIdx = IMallocHashFunction(pData);
+
+  // Eintrag darf nicht größer als die Hash-Tabelle sein
+  _ASSERTE(HashIdx < ALLOC_HASH_ENTRIES);
+
+  pHashEntry = &IMallocHashTable[HashIdx];
+  while(pHashEntry != NULL) {
+    if (pHashEntry->pData == pData) {
+      return pHashEntry;
+    }
+    pHashEntry = pHashEntry->Next;
+  }
+
+  // wenn hier angelangt, dann wurde der Eintrag nicht gefunden!
+  return (IMallocHashEntryType*) ALLOC_ENTRY_NOT_FOUND;
+}  // AllocHashFind
+
+// IMallocHashRemove
+//   Return: FALSE (0) : Key wurde gefunden und entfernt/markiert
+//           TRUE (!=0): Key wurde nicht gefunden!
+BOOL IMallocHashRemove(void *pData) {
+  ULONG HashIdx;
+  IMallocHashEntryType *pHashEntry, *pHashEntryLast;
+
+  // ermittle den Hash-Wert
+  HashIdx = IMallocHashFunction(pData);
+
+  // Eintrag darf nicht größer als die Hash-Tabelle sein
+  _ASSERTE(HashIdx < ALLOC_HASH_ENTRIES);
+
+  pHashEntryLast = NULL;
+  pHashEntry = &IMallocHashTable[HashIdx];
+  while(pHashEntry != NULL) {
+    if (pHashEntry->pData == pData) {
+#ifdef HASH_ENTRY_REMOVE_AT_FREE
+      IMallocHashFreed++;
+      IMallocHashCurrentCount--;
+      // gebe den Speicher frei
+      if (pHashEntryLast == NULL) {
+        // Es ist ein Eintrag direkt in der Tabelle
+        if (pHashEntry->Next == NULL) {
+          // Es ist der letze Eintrag lösche also die Tabelle
+          memset(&IMallocHashTable[HashIdx], 0, sizeof(IMallocHashTable[HashIdx]));
+        }
+        else {
+          // Es sind noch Einträge verkettet, überschreibe einfach den nicht mehr gebrauchten...
+          IMallocHashEntryType *pTmp = pHashEntry->Next;
+          *pHashEntry = *(pHashEntry->Next);
+          _free_dbg(pTmp, _CRT_BLOCK);
+        }
+        return TRUE;
+      }
+      else {
+        // ich bin in einem dynamischen Bereich
+        // dies war eine kollisions, zähle also wieder zurück:
+        IMallocHashCurrentCollisions--;
+        pHashEntryLast->Next = pHashEntry->Next;
+        _free_dbg(pHashEntry, _CRT_BLOCK);
+        return TRUE;
+      }
+#else
+      // erhöhe nur den Removed counter und behalte das Object im Speicher
+      pHashEntry->cRemovedFlag++;
+      return TRUE;  // erfolgreich
+#endif
+    }
+    pHashEntryLast = pHashEntry;
+    pHashEntry = pHashEntry->Next;
+  }
+
+  // wenn hier angelangt, dann wurde der Eintrag nicht gefunden!
+  return FALSE;
+}
+
+
+
+//   Callback-Funtion for StackWalk für meine CallStack-Ausgabe aus der Hash-Tabelle
+static BOOL __stdcall ReadProcMemoryFromIMallocHash(HANDLE pData, DWORD64 lpBaseAddress, PVOID lpBuffer, DWORD nSize, PDWORD lpNumberOfBytesRead) {
+  // Versuche die hRequestID zu finden
+  IMallocHashEntryType *pHashEntry;
+  *lpNumberOfBytesRead = 0;
+
+  pHashEntry = IMallocHashFind((PVOID) pData);
+  if (pHashEntry == (IMallocHashEntryType*) ALLOC_ENTRY_NOT_FOUND) {
+    // nicht gefunden, somit kann ich den Speicher nicht lesen
+    *lpNumberOfBytesRead = 0;
+    return FALSE;
+  }
+  if ( ((DWORD) lpBaseAddress >= pHashEntry->dwESPOffset) && ((DWORD) lpBaseAddress <= (pHashEntry->dwESPOffset+pHashEntry->dwESPLen)) ) {
+    // Speicher liegt im ESP:
+    // Errechne den Offset
+    DWORD dwOffset = (DWORD) lpBaseAddress - pHashEntry->dwESPOffset;
+    DWORD dwSize = __min(nSize, MAX_ESP_LEN_BUF-dwOffset);
+    memcpy(lpBuffer, &(pHashEntry->pcESPAddr[dwOffset]), dwSize);
+    *lpNumberOfBytesRead = dwSize;
+    if (dwSize != nSize)
+      return FALSE;
+  }
+
+  if ( ((DWORD) lpBaseAddress >= pHashEntry->dwEIPOffset) && ((DWORD) lpBaseAddress <= (pHashEntry->dwEIPOffset+pHashEntry->dwEIPLen)) ) {
+    // Speicher liegt im EIP:
+    // Errechne den Offset
+    DWORD dwOffset = (DWORD) lpBaseAddress - pHashEntry->dwEIPOffset;
+    DWORD dwSize = __min(nSize, MAX_ESP_LEN_BUF-dwOffset);
+    memcpy(lpBuffer, &(pHashEntry->pcEIPAddr[dwOffset]), dwSize);
+    *lpNumberOfBytesRead = dwSize;
+    if (dwSize != nSize)
+      return FALSE;
+  }
+  
+  if (*lpNumberOfBytesRead == 0)  // Der Speicher konnte nicht gefunden werden
+    return FALSE;
+
+  return TRUE;
+}
+// AllocHashOutLeaks
+// Gibt allen Speicher aus, der noch nicht wieder freigegeben wurde
+//   Returns the number of bytes, that are not freed (leaks)
+ULONG IMallocHashOutLeaks(FILE *fFile) {
+  ULONG ulTemp;
+  IMallocHashEntryType *pHashEntry;
+  ULONG ulCount = 0;
+  ULONG ulLeaksByte = 0;
+
+  // Gehe jeden Eintrag durch und gebe ihn aus
+  for(ulTemp = 0; ulTemp < ALLOC_HASH_ENTRIES; ulTemp++) {
+    pHashEntry = &IMallocHashTable[ulTemp];
+    if (pHashEntry->pData != 0) {
+      while(pHashEntry != NULL) {
+        // gebe die Zeile aus
+        if ( (pHashEntry->cRemovedFlag <= 0) || (pHashEntry->cRemovedFlag > 1) ) {
+          ulCount++;
+          if (g_CallstackOutputType == ACOutput_XML)
+            _ftprintf(fFile, _T("<LEAK requestID=\"%u\" size=\"%u\">\n"), pHashEntry->pData, pHashEntry->nDataSize);
+          else
+            _ftprintf(fFile, _T("Pointer (RequestID): %12i, Removed: %i, Size: %12i\n"), pHashEntry->pData, pHashEntry->cRemovedFlag, pHashEntry->nDataSize);
+          CONTEXT c;
+          memset( &c, '\0', sizeof c );
+          c.Eip = pHashEntry->dwEIPOffset;
+          c.Ebp = pHashEntry->dwESPOffset;
+          ShowStackRM( NULL, c, fFile, &ReadProcMemoryFromIMallocHash, (HANDLE) pHashEntry->pData);
+          // Zähle zusammen wieviel Byte noch nicht freigegeben wurden
+          if (pHashEntry->nDataSize > 0)
+            ulLeaksByte += pHashEntry->nDataSize;
+          else
+            ulLeaksByte++;  // Wenn zwar Speicher allokiert wurde, dieser aber 0 Bytes lang war, so reserviere für diesen zumindest 1 Byte
+
+          if (g_CallstackOutputType == ACOutput_XML)
+            _ftprintf(fFile, _T("</LEAK>\n"));  // terminate the xml-node
+        }
+        pHashEntry = pHashEntry->Next;
+      }
+    }
+  }
+  if (g_CallstackOutputType != ACOutput_XML)
+    _ftprintf(fFile, _T("\n**** Number of leaks: %i\n"), ulCount);
+  return ulLeaksByte;
+}  // AllocHashOutLeaks
+#endif
+
+
+static void AllocHashInit(void) {
+
+  memset(AllocHashTable, 0, sizeof(AllocHashTable));
+  AllocHashEntries = 0;
+  AllocHashCollisions = 0;
+  AllocHashFreed = 0;
+  AllocHashCurrentCount = 0;
+  AllocHashMaxUsed = 0;
+
+  AllocHashMaxCollisions = 0;
+  AllocHashCurrentCollisions = 0;
+
+#ifdef WITH_IMALLOC_SPY
+  memset(IMallocHashTable, 0, sizeof(IMallocHashTable));
+  IMallocHashEntries = 0;
+  IMallocHashCollisions = 0;
+  IMallocHashFreed = 0;
+  IMallocHashCurrentCount = 0;
+  IMallocHashMaxUsed = 0;
+
+  IMallocHashMaxCollisions = 0;
+  IMallocHashCurrentCollisions = 0;
+#endif
+  return;
+}  // AllocHashInit
+
+
+// AllocHashDeinit
+// Returns the number of bytes, that are not freed (leaks)
+static ULONG AllocHashDeinit(void) {
+  ULONG ulRet = 0;
+  bool bAppend = g_CallstackOutputType != ACOutput_XML;
+  AllocCheckFileOpen(false);//bAppend);  // open global log-file
+
+  if (g_CallstackOutputType == ACOutput_XML)
+  {
+    _ftprintf(g_fFile, _T("<MEMREPORT "));
+    WriteDateTime(g_fFile, TRUE);
+    _ftprintf(g_fFile, _T(">\n"));
+  }
+  else
+  {
+    _ftprintf(g_fFile, _T("\n##### Memory Report ########################################\n"));
+    WriteDateTime(g_fFile);
+    _ftprintf(g_fFile, _T("\n"));
+  }
+
+#ifndef HASH_ENTRY_REMOVE_AT_FREE
+  // output the used memory
+  if (g_CallstackOutputType != ACOutput_XML)
+    _ftprintf(g_fFile, _T("##### Memory used: #########################################\n"));
+  AllocHashOut(g_fFile);
+#endif
+
+  // output the Memoty leaks
+  if (g_CallstackOutputType != ACOutput_XML)
+    _ftprintf(g_fFile, _T("\n##### Leaks: ###############################################\n"));
+  ulRet = AllocHashOutLeaks(g_fFile);
+
+  if (g_CallstackOutputType == ACOutput_Advanced)
+  {
+    // output some statistics from the hash-table
+    _ftprintf(g_fFile, _T("***** Hash-Table statistics:\n"));
+    _ftprintf(g_fFile, _T("      Table-Size:     %i\n"), ALLOC_HASH_ENTRIES);
+    _ftprintf(g_fFile, _T("      Inserts:        %i\n"), AllocHashEntries);
+    _ftprintf(g_fFile, _T("      Freed:          %i\n"), AllocHashFreed);
+    _ftprintf(g_fFile, _T("      Sum Collisions: %i\n"), AllocHashCollisions);
+    _ftprintf(g_fFile, _T("\n"));
+    _ftprintf(g_fFile, _T("      Max used:       %i\n"), AllocHashMaxUsed);
+    _ftprintf(g_fFile, _T("      Max Collisions: %i\n"), AllocHashMaxCollisions);
+  }
+
+  // Free Hash-Table
+  ULONG ulTemp;
+  AllocHashEntryType *pHashEntry, *pHashEntryOld;
+
+  // Now, free my own memory
+  for(ulTemp = 0; ulTemp < ALLOC_HASH_ENTRIES; ulTemp++) {
+    pHashEntry = &AllocHashTable[ulTemp];
+    while(pHashEntry != NULL) {
+      pHashEntryOld = pHashEntry;
+      pHashEntry = pHashEntry->Next;
+      if (pHashEntryOld != &AllocHashTable[ulTemp]) {
+        // now free the dynamically allocated memory
+        free(pHashEntryOld);
+      }
+    }  // while
+  }  // for
+  // empty the hash-table
+  memset(AllocHashTable, 0, sizeof(AllocHashTable));
+
+#ifdef WITH_IMALLOC_SPY
+  // output the Memoty leaks
+  if (g_CallstackOutputType != ACOutput_XML)
+    _ftprintf(g_fFile, _T("\n##### COM-Leaks: ###############################################\n"));
+  ulRet = IMallocHashOutLeaks(g_fFile);
+
+  if (g_CallstackOutputType == ACOutput_Advanced)
+  {
+    // output some statistics from the hash-table
+    _ftprintf(g_fFile, _T("***** Hash-Table statistics:\n"));
+    _ftprintf(g_fFile, _T("      Table-Size:     %i\n"), ALLOC_HASH_ENTRIES);
+    _ftprintf(g_fFile, _T("      Inserts:        %i\n"), IMallocHashEntries);
+    _ftprintf(g_fFile, _T("      Freed:          %i\n"), IMallocHashFreed);
+    _ftprintf(g_fFile, _T("      Sum Collisions: %i\n"), IMallocHashCollisions);
+    _ftprintf(g_fFile, _T("\n"));
+    _ftprintf(g_fFile, _T("      Max used:       %i\n"), IMallocHashMaxUsed);
+    _ftprintf(g_fFile, _T("      Max Collisions: %i\n"), IMallocHashMaxCollisions);
+  }
+
+  // Free Hash-Table
+  //ULONG ulTemp;
+  IMallocHashEntryType *pIMHashEntry, *pIMHashEntryOld;
+
+  // Gehe jeden Eintrag durch und gebe ihn frei
+  for(ulTemp = 0; ulTemp < ALLOC_HASH_ENTRIES; ulTemp++) {
+    pIMHashEntry = &IMallocHashTable[ulTemp];
+    while(pHashEntry != NULL) {
+      pIMHashEntryOld = pIMHashEntry;
+      pIMHashEntry = pIMHashEntry->Next;
+      if (pIMHashEntryOld != &IMallocHashTable[ulTemp]) {
+        // es ist dynamischer Speicher, gebe ihn also frei:
+        _free_dbg(pIMHashEntryOld, _CRT_BLOCK);
+      }
+    }  // while
+  }  // for
+  // Lösche die gesamte Hash-Tabelle
+  memset(IMallocHashTable, 0, sizeof(IMallocHashTable));
+#endif
+
+
+  if (g_CallstackOutputType == ACOutput_XML)
+    _ftprintf(g_fFile, _T("</MEMREPORT>\n"));
+
+  return ulRet;
+}  // AllocHashDeinit
+
+// AllocHashFunction
+// The has-function (very simple)
+static inline ULONG AllocHashFunction(long lRequestID) {
+  // I couldn´t find any better and faster
+  return lRequestID % ALLOC_HASH_ENTRIES;
+}  // AllocHashFunction
+
+// AllocHashInsert
+//   lRequestID: Key-Word (RequestID from AllocHook)
+//   pContext:   Context-Record, for retrieving Callstack (EIP and EBP is only needed)
+//   nDataSize:  How many bytes
+static void AllocHashInsert(long lRequestID, CONTEXT &Context, size_t nDataSize) {
+  ULONG HashIdx;
+  AllocHashEntryType *pHashEntry;
+
+  // change statistical data
+  AllocHashEntries++;
+  AllocHashCurrentCount++;
+  if (AllocHashCurrentCount > AllocHashMaxUsed)
+    AllocHashMaxUsed = AllocHashCurrentCount;
+
+  // generate hash-value
+  HashIdx = AllocHashFunction(lRequestID);
+
+  pHashEntry = &AllocHashTable[HashIdx];
+  if (pHashEntry->lRequestID == 0) {
+    // Entry is empty...
+  }
+  else {
+    // Entry is not empy! make a list of entries for this hash value...
+    // change statistical data
+    // if this happens often, you should increase the hah size or change the heash-function; 
+    // to fasten the allocation time
+    AllocHashCollisions++;
+    AllocHashCurrentCollisions++;
+    if (AllocHashCurrentCollisions > AllocHashMaxCollisions)
+      AllocHashMaxCollisions = AllocHashCurrentCollisions;
+
+    while(pHashEntry->Next != NULL) {
+      pHashEntry = pHashEntry->Next;
+    }
+
+    pHashEntry->Next = (AllocHashEntryType*) calloc(sizeof(AllocHashEntryType), 1);
+    pHashEntry = pHashEntry->Next;
+
+  }
+  pHashEntry->lRequestID = lRequestID;  // Key-Word
+  pHashEntry->nDataSize = nDataSize;
+  pHashEntry->Next = NULL;
+  // Get EIP and save it in the record
+  pHashEntry->dwEIPOffset = Context.Eip;
+  if (ReadProcessMemory(GetCurrentProcess(), (LPCVOID) Context.Eip, &(pHashEntry->pcEIPAddr), MAX_EIP_LEN_BUF, &(pHashEntry->dwEIPLen)) == 0) {
+    // Could not read memory... remove everything...
+    memset(pHashEntry->pcEIPAddr, 0, MAX_EIP_LEN_BUF);
+    pHashEntry->dwEIPLen = 0;
+    pHashEntry->dwEIPOffset = 0;
+  }
+
+  // Get ESP and save it in the record
+  pHashEntry->dwESPOffset = Context.Ebp;
+  if (ReadProcessMemory(GetCurrentProcess(), (LPCVOID) Context.Ebp, &(pHashEntry->pcESPAddr), MAX_ESP_LEN_BUF, &(pHashEntry->dwESPLen)) == 0) {
+    // Could not read memory... remove everything...
+    memset(pHashEntry->pcESPAddr, 0, MAX_ESP_LEN_BUF);
+    pHashEntry->dwESPLen = 0;
+    pHashEntry->dwESPOffset = 0;
+
+    // Check if I tried to read too much...
+    if (GetLastError() == ERROR_PARTIAL_COPY)
+    {
+      // ask how many I can read:
+      MEMORY_BASIC_INFORMATION MemBuffer;
+      DWORD dwRet = VirtualQuery((LPCVOID) Context.Ebp, &MemBuffer, sizeof(MemBuffer));
+      if (dwRet > 0)
+      {
+        // calculate the length
+        DWORD len = ((DWORD) MemBuffer.BaseAddress + MemBuffer.RegionSize) - Context.Ebp;
+        if ( (len > 0) && (len < MAX_ESP_LEN_BUF) )
+        {
+          // try to read it again (with the shorter length)
+          if (ReadProcessMemory(GetCurrentProcess(), (LPCVOID) Context.Ebp, &(pHashEntry->pcESPAddr), len, &(pHashEntry->dwESPLen)) == 0)
+          {
+            // ok, now everything goes wrong... remove it...
+            memset(pHashEntry->pcESPAddr, 0, MAX_ESP_LEN_BUF);
+            pHashEntry->dwESPLen = 0;
+            pHashEntry->dwESPOffset = 0;
+          }
+          else
+          {
+            pHashEntry->dwESPOffset = Context.Ebp;
+          }
+        }
+      } // VirtualQuery was successfully
+    }  // ERROR_PARTIAL_COPY
+  }
+}
+
+// AllocHashFind
+//   If ALLOC_ENTRY_NOT_FOUND is returned, the Key was not found!
+//   If the Key was found, a pointer to the entry is returned
+static AllocHashEntryType *AllocHashFind(long lRequestID) {
+  ULONG HashIdx;
+  AllocHashEntryType *pHashEntry;
+
+  // get the Hash-Value
+  HashIdx = AllocHashFunction(lRequestID);
+
+  // Just do some simple checks:
+  _ASSERTE(HashIdx < ALLOC_HASH_ENTRIES);
+
+  pHashEntry = &AllocHashTable[HashIdx];
+  while(pHashEntry != NULL) {
+    if (pHashEntry->lRequestID == lRequestID) {
+      return pHashEntry;
+    }
+    pHashEntry = pHashEntry->Next;
+  }
+
+  // entry was not found!
+  return (AllocHashEntryType*) ALLOC_ENTRY_NOT_FOUND;
+}  // AllocHashFind
+
+// AllocHashRemove
+//   Return: FALSE (0) : Key was found and removed/marked
+//           TRUE (!=0): Key was not found
+static BOOL AllocHashRemove(long lRequestID) {
+  ULONG HashIdx;
+  AllocHashEntryType *pHashEntry, *pHashEntryLast;
+
+  // get the Hash-Value
+  HashIdx = AllocHashFunction(lRequestID);
+
+  // Just do some simple checks:
+  _ASSERTE(HashIdx < ALLOC_HASH_ENTRIES);
+
+  pHashEntryLast = NULL;
+  pHashEntry = &AllocHashTable[HashIdx];
+  while(pHashEntry != NULL) {
+    if (pHashEntry->lRequestID == lRequestID) {
+#ifdef HASH_ENTRY_REMOVE_AT_FREE
+      AllocHashFreed++;
+      AllocHashCurrentCount--;
+      // release my memory
+      if (pHashEntryLast == NULL) {
+        // It is an entry in the table, so do not release this memory
+        if (pHashEntry->Next == NULL) {
+          // It was the last entry, so empty the table entry
+          memset(&AllocHashTable[HashIdx], 0, sizeof(AllocHashTable[HashIdx]));
+        }
+        else {
+          // There are some more entries, so shorten the list
+          AllocHashEntryType *pTmp = pHashEntry->Next;
+          *pHashEntry = *(pHashEntry->Next);
+          free(pTmp);
+        }
+        return TRUE;
+      }
+      else {
+        // now, I am in an dynamic allocated entry
+        // it was a collision, so decrease the current collision count
+        AllocHashCurrentCollisions--;
+        pHashEntryLast->Next = pHashEntry->Next;
+        free(pHashEntry);
+        return TRUE;
+      }
+#else
+      // increase the Remove-Count and let the objet stay in memory
+      pHashEntry->cRemovedFlag++;
+      return TRUE;
+#endif
+    }
+    pHashEntryLast = pHashEntry;
+    pHashEntry = pHashEntry->Next;
+  }
+
+  // if we are here, we could not find the RequestID
+  return FALSE;
+}
+
+// ReadProcMemoryFromHash
+//   Callback-Funtion for StackWalk for my own CallStack from the Hash-Table-Entries
+static BOOL __stdcall ReadProcMemoryFromHash(HANDLE hRequestID, DWORD64 lpBaseAddress, PVOID lpBuffer, DWORD nSize, PDWORD lpNumberOfBytesRead) {
+  // Try to find the RequestID
+  AllocHashEntryType *pHashEntry;
+  *lpNumberOfBytesRead = 0;
+
+  pHashEntry = AllocHashFind((LONG) hRequestID);
+  if (pHashEntry == (AllocHashEntryType*) ALLOC_ENTRY_NOT_FOUND) {
+    // Not found, so I cannot return any memory
+    *lpNumberOfBytesRead = 0;
+    return FALSE;
+  }
+  if ( ((DWORD) lpBaseAddress >= pHashEntry->dwESPOffset) && ((DWORD) lpBaseAddress <= (pHashEntry->dwESPOffset+pHashEntry->dwESPLen)) ) {
+    // Memory is located in ESP:
+    // Calculate the offset
+    DWORD dwOffset = (DWORD) lpBaseAddress - pHashEntry->dwESPOffset;
+    DWORD dwSize = __min(nSize, MAX_ESP_LEN_BUF-dwOffset);
+    memcpy(lpBuffer, &(pHashEntry->pcESPAddr[dwOffset]), dwSize);
+    *lpNumberOfBytesRead = dwSize;
+    if (dwSize != nSize)
+      return FALSE;
+  }
+
+  if ( ((DWORD) lpBaseAddress >= pHashEntry->dwEIPOffset) && ((DWORD) lpBaseAddress <= (pHashEntry->dwEIPOffset+pHashEntry->dwEIPLen)) ) {
+    // Memory is located in EIP:
+    // Calculate the offset
+    DWORD dwOffset = (DWORD) lpBaseAddress - pHashEntry->dwEIPOffset;
+    DWORD dwSize = __min(nSize, MAX_ESP_LEN_BUF-dwOffset);
+    memcpy(lpBuffer, &(pHashEntry->pcEIPAddr[dwOffset]), dwSize);
+    *lpNumberOfBytesRead = dwSize;
+    if (dwSize != nSize)
+      return FALSE;
+  }
+  
+  if (*lpNumberOfBytesRead == 0)  // Memory could not be found
+    return FALSE;
+
+  return TRUE;
+}
+
+// AllocHashOutLeaks
+// Write all Memory (with callstack) which was not freed yet
+//   Returns the number of bytes, that are not freed (leaks)
+ULONG AllocHashOutLeaks(FILE *fFile) {
+  ULONG ulTemp;
+  AllocHashEntryType *pHashEntry;
+  ULONG ulCount = 0;
+  ULONG ulLeaksByte = 0;
+
+  // Move throu every entry
+  for(ulTemp = 0; ulTemp < ALLOC_HASH_ENTRIES; ulTemp++) {
+    pHashEntry = &AllocHashTable[ulTemp];
+    if (pHashEntry->lRequestID != 0) {
+      while(pHashEntry != NULL) {
+        if ( (pHashEntry->cRemovedFlag <= 0) || (pHashEntry->cRemovedFlag > 1) ) {
+          ulCount++;
+          if (g_CallstackOutputType == ACOutput_XML)
+            _ftprintf(fFile, _T("<LEAK requestID=\"%u\" size=\"%u\">\n"), pHashEntry->lRequestID, pHashEntry->nDataSize);
+          else
+            _ftprintf(fFile, _T("RequestID: %12i, Removed: %i, Size: %12i\n"), pHashEntry->lRequestID, pHashEntry->cRemovedFlag, pHashEntry->nDataSize);
+          CONTEXT c;
+          memset( &c, '\0', sizeof c );
+          c.Eip = pHashEntry->dwEIPOffset;
+          c.Ebp = pHashEntry->dwESPOffset;
+          ShowStackRM( NULL, c, fFile, &ReadProcMemoryFromHash, (HANDLE) pHashEntry->lRequestID);
+          // Count the number of leaky bytes
+          if (pHashEntry->nDataSize > 0)
+            ulLeaksByte += pHashEntry->nDataSize;
+          else
+            ulLeaksByte++;  // If memory was allocated with zero bytes, then just increase the counter 1
+
+          if (g_CallstackOutputType == ACOutput_XML)
+            _ftprintf(fFile, _T("</LEAK>\n"));  // terminate the xml-node
+        }
+        pHashEntry = pHashEntry->Next;
+      }
+    }
+  }
+  if (g_CallstackOutputType != ACOutput_XML)
+    _ftprintf(fFile, _T("\n**** Number of leaks: %i\n"), ulCount);
+  return ulLeaksByte;
+}  // AllocHashOutLeaks
+
+// Write all used memory to a file
+void AllocHashOut(FILE *fFile) {
+  ULONG ulTemp;
+  AllocHashEntryType *pHashEntry;
+
+  for(ulTemp = 0; ulTemp < ALLOC_HASH_ENTRIES; ulTemp++) {
+    pHashEntry = &AllocHashTable[ulTemp];
+    if (pHashEntry->lRequestID != 0) {
+      while(pHashEntry != NULL) {
+        if (g_CallstackOutputType == ACOutput_XML)
+          _ftprintf(fFile, _T("<MEMUSED requestID=\"%u\" size=\"%u\"\n"), pHashEntry->lRequestID, pHashEntry->nDataSize);
+        else
+          _ftprintf(fFile, _T("RequestID: %12i, Removed: %i, Size: %12i\n"), pHashEntry->lRequestID, pHashEntry->cRemovedFlag, pHashEntry->nDataSize);
+        pHashEntry = pHashEntry->Next;
+      }
+    }
+  }
+}  // AllocHashOut
+
+/*******************************************************************************
+ * Ende der Hash-Tabelle
+ *******************************************************************************/
+
+
+// The follwoing is copied from dbgint.h:
+// <CRT_INTERNALS>
+/*
+ * For diagnostic purpose, blocks are allocated with extra information and
+ * stored in a doubly-linked list.  This makes all blocks registered with
+ * how big they are, when they were allocated, and what they are used for.
+ */
+
+#define nNoMansLandSize 4
+
+typedef struct _CrtMemBlockHeader
+{
+        struct _CrtMemBlockHeader * pBlockHeaderNext;
+        struct _CrtMemBlockHeader * pBlockHeaderPrev;
+        char *                      szFileName;
+        int                         nLine;
+#ifdef _WIN64
+        /* These items are reversed on Win64 to eliminate gaps in the struct
+         * and ensure that sizeof(struct)%16 == 0, so 16-byte alignment is
+         * maintained in the debug heap.
+         */
+        int                         nBlockUse;
+        size_t                      nDataSize;
+#else  /* _WIN64 */
+        size_t                      nDataSize;
+        int                         nBlockUse;
+#endif  /* _WIN64 */
+        long                        lRequest;
+        unsigned char               gap[nNoMansLandSize];
+        /* followed by:
+         *  unsigned char           data[nDataSize];
+         *  unsigned char           anotherGap[nNoMansLandSize];
+         */
+} _CrtMemBlockHeader;
+#define pbData(pblock) ((unsigned char *)((_CrtMemBlockHeader *)pblock + 1))
+#define pHdr(pbData) (((_CrtMemBlockHeader *)pbData)-1)
+// </CRT_INTERNALS>
+
+
+
+
+// Global data:
+static BOOL g_bInitialized = FALSE;
+static HINSTANCE g_hImagehlpDll = NULL;
+
+static DWORD g_dwShowCount = 0;  // increase at every ShowStack-Call
+static CRITICAL_SECTION g_csFileOpenClose = {0};
+
+// Is used for syncronising call to MyAllocHook (to prevent reentrant calls)
+static LONG g_lMallocCalled = 0;
+
+static _CRT_ALLOC_HOOK pfnOldCrtAllocHook = NULL;
+
+// Deaktivate AllocHook, by increasing the Syncronisation-Counter
+//static void DeactivateMallocStackwalker(void) {
+//  InterlockedIncrement(&g_lMallocCalled);
+//}
+
+
+// MyAllocHook is Single-Threaded, that means the the calls are serialized in the calling function!
+// Special case for VC 5
+#if _MSC_VER <= 1100 
+static int MyAllocHook(int nAllocType, void *pvData, 
+      size_t nSize, int nBlockUse, long lRequest, 
+      const char * szFileName, int nLine ) {
+#else
+static int MyAllocHook(int nAllocType, void *pvData, 
+      size_t nSize, int nBlockUse, long lRequest, 
+      const unsigned char * szFileName, int nLine ) {
+#endif
+  static TCHAR *operation[] = { _T(""), _T("ALLOCATIONG"), _T("RE-ALLOCATING"), _T("FREEING") };
+  static TCHAR *blockType[] = { _T("Free"), _T("Normal"), _T("CRT"), _T("Ignore"), _T("Client") };
+
+#ifdef IGNORE_CRT_ALLOC
+  if (_BLOCK_TYPE(nBlockUse) == _CRT_BLOCK)  // Ignore internal C runtime library allocations
+    return TRUE;
+#endif
+  extern int _crtDbgFlag;
+  if  ( ((_CRTDBG_ALLOC_MEM_DF & _crtDbgFlag) == 0) && ( (nAllocType == _HOOK_ALLOC) || (nAllocType == _HOOK_REALLOC) ) )
+  {
+    // Someone has disabled that the runtime should log this allocation
+    // so we do not log this allocation
+    if (pfnOldCrtAllocHook != NULL)
+      pfnOldCrtAllocHook(nAllocType, pvData, nSize, nBlockUse, lRequest, szFileName, nLine);
+    return TRUE;
+  }
+
+  // Prevent from reentrat calls
+  if (InterlockedIncrement(&g_lMallocCalled) > 1) { // I was already called
+    InterlockedDecrement(&g_lMallocCalled);
+    // call the previous alloc hook
+    if (pfnOldCrtAllocHook != NULL)
+      pfnOldCrtAllocHook(nAllocType, pvData, nSize, nBlockUse, lRequest, szFileName, nLine);
+    return TRUE;
+  }
+
+  if (g_ulShowStackAtAlloc > 0) {
+    AllocCheckFileOpen();  // Open logfile
+  }
+
+   _ASSERT( (nAllocType == _HOOK_ALLOC) || (nAllocType == _HOOK_REALLOC) || (nAllocType == _HOOK_FREE) );
+   _ASSERT( ( _BLOCK_TYPE(nBlockUse) >= 0 ) && ( _BLOCK_TYPE(nBlockUse) < 5 ) );
+
+  if (nAllocType == _HOOK_FREE) { // freeing
+    // Try to get the header information
+    if (_CrtIsValidHeapPointer(pvData)) {  // it is a valid Heap-Pointer
+      // get the ID
+      _CrtMemBlockHeader *pHead;
+      // get a pointer to memory block header
+      pHead = pHdr(pvData);
+      nSize = pHead->nDataSize;
+      lRequest = pHead->lRequest; // This is the ID!
+
+      if (pHead->nBlockUse == _IGNORE_BLOCK)
+      {
+        InterlockedDecrement(&g_lMallocCalled);
+        if (pfnOldCrtAllocHook != NULL)
+          pfnOldCrtAllocHook(nAllocType, pvData, nSize, nBlockUse, lRequest, szFileName, nLine);
+        return TRUE;
+      }
+    }
+  }
+
+  if (g_ulShowStackAtAlloc > 0) {
+    _ftprintf( g_fFile, _T("##### Memory operation: %s a %d-byte '%s' block (# %ld)"),
+      operation[nAllocType], nSize, blockType[_BLOCK_TYPE(nBlockUse)], lRequest );
+    if ( pvData != NULL )
+      _ftprintf( g_fFile, _T(" at 0x%X"), pvData );
+    _ftprintf(g_fFile, _T("\n"));
+  }
+
+  if (nAllocType == _HOOK_FREE) { // freeing:
+    if (lRequest != 0) {  // RequestID was found
+      BOOL bRet;
+      // Try to find the RequestID in the Hash-Table, mark it that it was freed
+      bRet = AllocHashRemove(lRequest);
+      if(g_ulShowStackAtAlloc > 0) {
+        if (bRet == FALSE) {
+          // RequestID not found!
+          _ftprintf(g_fFile, _T("###### RequestID not found in hash table for FREEING (%i)!\n"), lRequest);
+        }
+      } // g_ulShowStackAtAlloc > 0
+    }
+    else {
+      if(g_ulShowStackAtAlloc > 0) {
+      // No valid RequestID found, display error
+      _ftprintf(g_fFile, _T("###### No valid RequestID for FREEING! (0x%X)\n"), pvData);
+      }
+    }
+  }  // freeing
+
+  if (nAllocType == _HOOK_REALLOC) { // re-allocating
+    // Try to get the header information
+    if (_CrtIsValidHeapPointer(pvData)) {  // it is a valid Heap-Pointer
+      BOOL bRet;
+      LONG lReallocRequest;
+      // get the ID
+      _CrtMemBlockHeader *pHead;
+      // get a pointer to memory block header
+      pHead = pHdr(pvData);
+      // Try to find the RequestID in the Hash-Table, mark it that it was freed
+      lReallocRequest = pHead->lRequest;
+      bRet = AllocHashRemove(lReallocRequest);
+      if (g_ulShowStackAtAlloc > 0) {
+        if (bRet == FALSE) {
+          // RequestID not found!
+          _ftprintf(g_fFile, _T("###### RequestID not found in hash table for RE-ALLOCATING (%i)!\n"), lReallocRequest);
+        }
+        else {
+          _ftprintf(g_fFile, _T("##### Implicit freeing because of re-allocation (# old: %ld, new: %ld)\n"), lReallocRequest, lRequest);
+        }
+      }  // g_ulShowStackAtAlloc > 0
+    }  // ValidHeapPointer
+  }  // re-allocating
+
+  if ( (g_ulShowStackAtAlloc < 3) && (nAllocType == _HOOK_FREE) ) {
+    InterlockedDecrement(&g_lMallocCalled);
+    // call the previous alloc hook
+    if (pfnOldCrtAllocHook != NULL)
+      pfnOldCrtAllocHook(nAllocType, pvData, nSize, nBlockUse, lRequest, szFileName, nLine);
+    return TRUE;
+  }
+
+  HANDLE hThread;
+  if (DuplicateHandle( GetCurrentProcess(), GetCurrentThread(),
+    GetCurrentProcess(), &hThread, 0, false, DUPLICATE_SAME_ACCESS ) == 0) {
+      // Something was wrong...
+      _ftprintf(g_fFile, _T("###### Could not call 'DuplicateHandle' successfully\n"));
+      InterlockedDecrement(&g_lMallocCalled);
+      // call the previous alloc hook
+      if (pfnOldCrtAllocHook != NULL)
+        pfnOldCrtAllocHook(nAllocType, pvData, nSize, nBlockUse, lRequest, szFileName, nLine);
+      return TRUE;
+  }
+
+  CONTEXT c;
+  memset( &c, '\0', sizeof c );
+  c.ContextFlags = CONTEXT_FULL;
+
+  // Get the context of this thread
+#if 0
+  // init CONTEXT record so we know where to start the stackwalk
+  if ( MyGetCurrentThreadContext( hThread, &c )  == 0) {
+    if(g_ulShowStackAtAlloc > 1) {
+      _ftprintf(g_fFile, _T("###### Could not call 'GetThreadContext' successfully\n"));
+    }
+    InterlockedDecrement(&g_lMallocCalled);
+    // call the previous alloc hook
+    if (pfnOldCrtAllocHook != NULL)
+      pfnOldCrtAllocHook(nAllocType, pvData, nSize, nBlockUse, lRequest, szFileName, nLine);
+    CloseHandle(hThread);
+    return TRUE; // could not get context
+  }
+#else
+  __asm
+  {
+      call x
+ x:   pop eax
+      mov c.Eip, eax
+      mov c.Ebp, ebp
+  }
+#endif
+
+  if(g_ulShowStackAtAlloc > 1) {
+    if(g_ulShowStackAtAlloc > 2) {
+      // output the callstack
+      ShowStack( hThread, c, g_fFile);
+    }
+    else {
+      // Output only (re)allocs
+      if (nAllocType != _HOOK_FREE) {
+        ShowStack( hThread, c, g_fFile);
+      }
+    }
+  }  // g_ulShowStackAtAlloc > 1
+  CloseHandle( hThread );
+
+  // Only isert in the Hash-Table if it is not a "freeing"
+  if (nAllocType != _HOOK_FREE) {
+    if(lRequest != 0) // Always a valid RequestID should be provided (see comments in the header)
+      AllocHashInsert(lRequest, c, nSize);
+  }
+
+  InterlockedDecrement(&g_lMallocCalled);
+  // call the previous alloc hook
+  if (pfnOldCrtAllocHook != NULL)
+    pfnOldCrtAllocHook(nAllocType, pvData, nSize, nBlockUse, lRequest, szFileName, nLine);
+  return TRUE; // allow the memory operation to proceed
+}
+
+
+
+
+// ##########################################################################################
+// ##########################################################################################
+// ##########################################################################################
+// ##########################################################################################
+
+#define gle (GetLastError())
+#define lenof(a) (sizeof(a) / sizeof((a)[0]))
+#define MAXNAMELEN 1024 // max name length for found symbols
+#define IMGSYMLEN ( sizeof IMAGEHLP_SYMBOL64 )
+#define TTBUFLEN 8096 // for a temp buffer (2^13)
+
+
+
+// SymCleanup()
+typedef BOOL (__stdcall *tSC)( IN HANDLE hProcess );
+tSC pSC = NULL;
+
+// SymFunctionTableAccess64()
+typedef PVOID (__stdcall *tSFTA)( HANDLE hProcess, DWORD64 AddrBase );
+tSFTA pSFTA = NULL;
+
+// SymGetLineFromAddr64()
+typedef BOOL (__stdcall *tSGLFA)( IN HANDLE hProcess, IN DWORD64 dwAddr,
+  OUT PDWORD pdwDisplacement, OUT PIMAGEHLP_LINE64 Line );
+tSGLFA pSGLFA = NULL;
+
+// SymGetModuleBase64()
+typedef DWORD64 (__stdcall *tSGMB)( IN HANDLE hProcess, IN DWORD64 dwAddr );
+tSGMB pSGMB = NULL;
+
+// SymGetModuleInfo64()
+typedef BOOL (__stdcall *tSGMI)( IN HANDLE hProcess, IN DWORD64 dwAddr, OUT PIMAGEHLP_MODULE64 ModuleInfo );
+tSGMI pSGMI = NULL;
+
+// SymGetOptions()
+typedef DWORD (__stdcall *tSGO)( VOID );
+tSGO pSGO = NULL;
+
+// SymGetSymFromAddr64()
+typedef BOOL (__stdcall *tSGSFA)( IN HANDLE hProcess, IN DWORD64 dwAddr,
+  OUT PDWORD64 pdwDisplacement, OUT PIMAGEHLP_SYMBOL64 Symbol );
+tSGSFA pSGSFA = NULL;
+
+// SymInitialize()
+typedef BOOL (__stdcall *tSI)( IN HANDLE hProcess, IN PSTR UserSearchPath, IN BOOL fInvadeProcess );
+tSI pSI = NULL;
+
+// SymLoadModule64()
+typedef DWORD (__stdcall *tSLM)( IN HANDLE hProcess, IN HANDLE hFile,
+  IN PSTR ImageName, IN PSTR ModuleName, IN DWORD64 BaseOfDll, IN DWORD SizeOfDll );
+tSLM pSLM = NULL;
+
+// SymSetOptions()
+typedef DWORD (__stdcall *tSSO)( IN DWORD SymOptions );
+tSSO pSSO = NULL;
+
+// StackWalk64()
+typedef BOOL (__stdcall *tSW)( 
+  DWORD MachineType, 
+  HANDLE hProcess,
+  HANDLE hThread, 
+  LPSTACKFRAME64 StackFrame, 
+  PVOID ContextRecord,
+  PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
+  PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
+  PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,
+  PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress );
+tSW pSW = NULL;
+
+// UnDecorateSymbolName()
+typedef DWORD (__stdcall WINAPI *tUDSN)( PCSTR DecoratedName, PSTR UnDecoratedName,
+  DWORD UndecoratedLength, DWORD Flags );
+tUDSN pUDSN = NULL;
+
+
+
+struct ModuleEntry
+{
+  std::string imageName;
+  std::string moduleName;
+  DWORD baseAddress;
+  DWORD size;
+};
+typedef std::vector< ModuleEntry > ModuleList;
+typedef ModuleList::iterator ModuleListIter;
+
+// **************************************** ToolHelp32 ************************
+#define MAX_MODULE_NAME32 255
+#define TH32CS_SNAPMODULE   0x00000008
+#pragma pack( push, 8 )
+typedef struct tagMODULEENTRY32
+{
+    DWORD   dwSize;
+    DWORD   th32ModuleID;       // This module
+    DWORD   th32ProcessID;      // owning process
+    DWORD   GlblcntUsage;       // Global usage count on the module
+    DWORD   ProccntUsage;       // Module usage count in th32ProcessID's context
+    BYTE  * modBaseAddr;        // Base address of module in th32ProcessID's context
+    DWORD   modBaseSize;        // Size in bytes of module starting at modBaseAddr
+    HMODULE hModule;            // The hModule of this module in th32ProcessID's context
+    char    szModule[MAX_MODULE_NAME32 + 1];
+    char    szExePath[MAX_PATH];
+} MODULEENTRY32;
+typedef MODULEENTRY32 *  PMODULEENTRY32;
+typedef MODULEENTRY32 *  LPMODULEENTRY32;
+#pragma pack( pop )
+
+
+
+static bool GetModuleListTH32(ModuleList& modules, DWORD pid, FILE *fLogFile)
+{
+  // CreateToolhelp32Snapshot()
+  typedef HANDLE (__stdcall *tCT32S)(DWORD dwFlags, DWORD th32ProcessID);
+  // Module32First()
+  typedef BOOL (__stdcall *tM32F)(HANDLE hSnapshot, LPMODULEENTRY32 lpme);
+  // Module32Next()
+  typedef BOOL (__stdcall *tM32N)(HANDLE hSnapshot, LPMODULEENTRY32 lpme);
+
+  // try both dlls...
+  const TCHAR *dllname[] = { _T("kernel32.dll"), _T("tlhelp32.dll") };
+  HINSTANCE hToolhelp;
+  tCT32S pCT32S;
+  tM32F pM32F;
+  tM32N pM32N;
+
+  HANDLE hSnap;
+  MODULEENTRY32 me;
+  me.dwSize = sizeof(me);
+  bool keepGoing;
+  ModuleEntry e;
+  int i;
+
+  for (i = 0; i<lenof(dllname); i++ )
+  {
+    hToolhelp = LoadLibrary( dllname[i] );
+    if (hToolhelp == NULL)
+      continue;
+    pCT32S = (tCT32S) GetProcAddress(hToolhelp, "CreateToolhelp32Snapshot");
+    pM32F = (tM32F) GetProcAddress(hToolhelp, "Module32First");
+    pM32N = (tM32N) GetProcAddress(hToolhelp, "Module32Next");
+    if ( pCT32S != 0 && pM32F != 0 && pM32N != 0 )
+      break; // found the functions!
+    FreeLibrary(hToolhelp);
+    hToolhelp = NULL;
+  }
+
+  if (hToolhelp == NULL)
+    return false;
+
+  hSnap = pCT32S( TH32CS_SNAPMODULE, pid );
+  if (hSnap == (HANDLE) -1)
+    return false;
+
+  keepGoing = !!pM32F( hSnap, &me );
+  while (keepGoing)
+  {
+    e.imageName = me.szExePath;
+    e.moduleName = me.szModule;
+    e.baseAddress = (DWORD) me.modBaseAddr;
+    e.size = me.modBaseSize;
+    modules.push_back( e );
+    keepGoing = !!pM32N( hSnap, &me );
+  }
+
+  CloseHandle(hSnap);
+  FreeLibrary(hToolhelp);
+
+  return modules.size() != 0;
+}  // GetModuleListTH32
+
+
+// **************************************** PSAPI ************************
+typedef struct _MODULEINFO {
+    LPVOID lpBaseOfDll;
+    DWORD SizeOfImage;
+    LPVOID EntryPoint;
+} MODULEINFO, *LPMODULEINFO;
+
+static bool GetModuleListPSAPI(ModuleList &modules, DWORD pid, HANDLE hProcess, FILE *fLogFile)
+{
+  // EnumProcessModules()
+  typedef BOOL (__stdcall *tEPM)(HANDLE hProcess, HMODULE *lphModule, DWORD cb, LPDWORD lpcbNeeded );
+  // GetModuleFileNameEx()
+  typedef DWORD (__stdcall *tGMFNE)(HANDLE hProcess, HMODULE hModule, LPSTR lpFilename, DWORD nSize );
+  // GetModuleBaseName()
+  typedef DWORD (__stdcall *tGMBN)(HANDLE hProcess, HMODULE hModule, LPSTR lpFilename, DWORD nSize );
+  // GetModuleInformation()
+  typedef BOOL (__stdcall *tGMI)(HANDLE hProcess, HMODULE hModule, LPMODULEINFO pmi, DWORD nSize );
+
+  HINSTANCE hPsapi;
+  tEPM pEPM;
+  tGMFNE pGMFNE;
+  tGMBN pGMBN;
+  tGMI pGMI;
+
+  DWORD i;
+  ModuleEntry e;
+  DWORD cbNeeded;
+  MODULEINFO mi;
+  HMODULE *hMods = 0;
+  char *tt = 0;
+
+  hPsapi = LoadLibrary( _T("psapi.dll") );
+  if ( hPsapi == 0 )
+    return false;
+
+  modules.clear();
+
+  pEPM = (tEPM) GetProcAddress( hPsapi, "EnumProcessModules" );
+  pGMFNE = (tGMFNE) GetProcAddress( hPsapi, "GetModuleFileNameExA" );
+  pGMBN = (tGMFNE) GetProcAddress( hPsapi, "GetModuleBaseNameA" );
+  pGMI = (tGMI) GetProcAddress( hPsapi, "GetModuleInformation" );
+  if ( pEPM == 0 || pGMFNE == 0 || pGMBN == 0 || pGMI == 0 )
+  {
+    // we couldn´t find all functions
+    FreeLibrary( hPsapi );
+    return false;
+  }
+
+  hMods = (HMODULE*) malloc(sizeof(HMODULE) * (TTBUFLEN / sizeof HMODULE));
+  tt = (char*) malloc(sizeof(char) * TTBUFLEN);
+
+  if ( ! pEPM( hProcess, hMods, TTBUFLEN, &cbNeeded ) )
+  {
+    _ftprintf(fLogFile, _T("%lu: EPM failed, GetLastError = %lu\n"), g_dwShowCount, gle );
+    goto cleanup;
+  }
+
+  if ( cbNeeded > TTBUFLEN )
+  {
+    _ftprintf(fLogFile, _T("%lu: More than %lu module handles. Huh?\n"), g_dwShowCount, lenof( hMods ) );
+    goto cleanup;
+  }
+
+  for ( i = 0; i < cbNeeded / sizeof hMods[0]; i++ )
+  {
+    // base address, size
+    pGMI(hProcess, hMods[i], &mi, sizeof mi );
+    e.baseAddress = (DWORD) mi.lpBaseOfDll;
+    e.size = mi.SizeOfImage;
+    // image file name
+    tt[0] = 0;
+    pGMFNE(hProcess, hMods[i], tt, TTBUFLEN );
+    e.imageName = tt;
+    // module name
+    tt[0] = 0;
+    pGMBN(hProcess, hMods[i], tt, TTBUFLEN );
+    e.moduleName = tt;
+
+    modules.push_back(e);
+  }
+
+cleanup:
+  if (hPsapi)
+    FreeLibrary(hPsapi);
+  free(tt);
+  free(hMods);
+
+  return modules.size() != 0;
+}  // GetModuleListPSAPI
+
+
+static bool GetModuleList(ModuleList& modules, DWORD pid, HANDLE hProcess, FILE *fLogFile)
+{
+  // first try toolhelp32
+  if (GetModuleListTH32(modules, pid, fLogFile) )
+    return true;
+  // then try psapi
+  return GetModuleListPSAPI(modules, pid, hProcess, fLogFile);
+}  // GetModuleList
+
+
+static void EnumAndLoadModuleSymbols( HANDLE hProcess, DWORD pid, FILE *fLogFile )
+{
+  static ModuleList modules;
+  static ModuleListIter it;
+  char *img, *mod;
+
+  // fill in module list
+  GetModuleList(modules, pid, hProcess, fLogFile);
+
+  for ( it = modules.begin(); it != modules.end(); ++ it )
+  {
+    // SymLoadModule() wants writeable strings
+    img = strdup(it->imageName.c_str());
+    mod = strdup(it->moduleName.c_str());
+
+    pSLM( hProcess, 0, img, mod, it->baseAddress, it->size );
+
+    free(img);
+    free(mod);
+    std::string s;
+  }
+}  // EnumAndLoadModuleSymbols
+
+static int InitStackWalk(void)
+{
+  if (g_bInitialized != FALSE)
+    return 0;  // already initialized
+
+  // 02-12-19: Now we only support dbghelp.dll!
+  //           To use it on NT you have to install the redistrubutable for DBGHELP.DLL
+  g_hImagehlpDll = LoadLibrary( _T("dbghelp.dll") );
+  if ( g_hImagehlpDll == NULL )
+  {
+    printf( "LoadLibrary( \"dbghelp.dll\" ): GetLastError = %lu\n", gle );
+    g_bInitialized = FALSE;
+    return 1;
+  }
+
+  // now we only support the newer dbghlp.dll with the "64"-functions (StackWalk64, a.s.o.)
+  // If your dbghlp.dll does not support this, please download the redistributable from MS
+  // Normally from: http://www.microsoft.com/downloads/details.aspx?displaylang=en&FamilyID=CD1FC4B2-0885-47F4-AF45-7FD5E14DB6C0
+
+  pSC = (tSC) GetProcAddress( g_hImagehlpDll, "SymCleanup" );
+  pSFTA = (tSFTA) GetProcAddress( g_hImagehlpDll, "SymFunctionTableAccess64" );
+  pSGLFA = (tSGLFA) GetProcAddress( g_hImagehlpDll, "SymGetLineFromAddr64" );
+  pSGMB = (tSGMB) GetProcAddress( g_hImagehlpDll, "SymGetModuleBase64" );
+  pSGMI = (tSGMI) GetProcAddress( g_hImagehlpDll, "SymGetModuleInfo64" );
+  pSGO = (tSGO) GetProcAddress( g_hImagehlpDll, "SymGetOptions" );
+  pSGSFA = (tSGSFA) GetProcAddress( g_hImagehlpDll, "SymGetSymFromAddr64" );
+  pSI = (tSI) GetProcAddress( g_hImagehlpDll, "SymInitialize" );
+  pSSO = (tSSO) GetProcAddress( g_hImagehlpDll, "SymSetOptions" );
+  pSW = (tSW) GetProcAddress( g_hImagehlpDll, "StackWalk64" );
+  pUDSN = (tUDSN) GetProcAddress( g_hImagehlpDll, "UnDecorateSymbolName" );
+  pSLM = (tSLM) GetProcAddress( g_hImagehlpDll, "SymLoadModule64" );
+
+  if ( pSC == NULL || pSFTA == NULL || pSGMB == NULL || pSGMI == NULL ||
+    pSGO == NULL || pSGSFA == NULL || pSI == NULL || pSSO == NULL ||
+    pSW == NULL || pUDSN == NULL || pSLM == NULL )
+  {
+    printf( "GetProcAddress(): some required function not found.\n" );
+    FreeLibrary( g_hImagehlpDll );
+    g_bInitialized = FALSE;
+    return 1;
+  }
+
+  g_bInitialized = TRUE;
+  InitializeCriticalSection(&g_csFileOpenClose);
+  return 0;
+}
+
+// This function if NOT multi-threading capable
+// It should only be called from the main-Function!
+int InitAllocCheckWN(eAllocCheckOutput eOutput, LPCTSTR pszFileName, ULONG ulShowStackAtAlloc) {
+  if (g_bInitialized) {
+    return 2;  // already initialized!
+  }
+  if (ulShowStackAtAlloc <= 3)
+    g_ulShowStackAtAlloc = ulShowStackAtAlloc;
+  else
+    g_ulShowStackAtAlloc = 0;
+
+  if (pszFileName != NULL) 
+    g_pszAllocLogName = _tcsdup(pszFileName);
+  else
+    g_pszAllocLogName = NULL;
+
+  g_CallstackOutputType = eOutput;
+
+#ifdef _DEBUG
+  AllocHashInit();
+
+#ifdef WITH_IMALLOC_SPY
+  HRESULT hr;
+  // erzeuge mein malloc-Spy object
+  LPMALLOCSPY pMallocSpy = new CMallocSpy(); // wird später durch Release freigegeben
+  if (pMallocSpy != NULL)
+  {
+    // CoInitilize(); // ??? Ist dies notwendig ?
+    hr = CoRegisterMallocSpy(pMallocSpy);
+    if FAILED(hr)
+    {
+      _tprintf(_T("\nCoRegisterMallocSpay failed with %.8x"), hr);
+    }
+  }
+#endif
+
+  // save the previous alloc hook
+  pfnOldCrtAllocHook = _CrtSetAllocHook(MyAllocHook);
+#endif
+
+  return InitStackWalk();
+}  // InitAllocCheckWN
+
+static TCHAR s_szExceptionLogFileName[_MAX_PATH] = _T("\\exceptions.log");  // default
+static BOOL s_bUnhandledExeptionFilterSet = FALSE;
+static LONG __stdcall CrashHandlerExceptionFilter(EXCEPTION_POINTERS* pExPtrs)
+{
+  if (pExPtrs->ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW)
+  {
+    static char MyStack[1024*128];  // be sure that we have enought space...
+    // it assumes that DS and SS are the same!!! (this is the case for Win32)
+    // change the stack only if the selectors are the same (this is the case for Win32)
+    //__asm push offset MyStack[1024*128];
+    //__asm pop esp;
+  __asm mov eax,offset MyStack[1024*128];
+  __asm mov esp,eax;
+  }
+
+   LONG lRet;
+   lRet = StackwalkFilter(pExPtrs, /*EXCEPTION_CONTINUE_SEARCH*/EXCEPTION_EXECUTE_HANDLER, s_szExceptionLogFileName);
+   TCHAR lString[500];
+   _stprintf(lString,
+      _T("*** Unhandled Exception!\n")
+      _T("   ExpCode: 0x%8.8X\n")
+      _T("   ExpFlags: %d\n")
+      _T("   ExpAddress: 0x%8.8X\n")
+      _T("   Please report!"),
+      pExPtrs->ExceptionRecord->ExceptionCode,
+      pExPtrs->ExceptionRecord->ExceptionFlags,
+      pExPtrs->ExceptionRecord->ExceptionAddress);
+   FatalAppExit(-1,lString);
+   return lRet;
+}
+
+int InitAllocCheck(eAllocCheckOutput eOutput, BOOL bSetUnhandledExeptionFilter, ULONG ulShowStackAtAlloc)  // will create the filename by itself
+{
+  TCHAR szModName[_MAX_PATH];
+  if (GetModuleFileName(NULL, szModName, sizeof(szModName)/sizeof(TCHAR)) != 0)
+  {
+    _tcscpy(s_szExceptionLogFileName, szModName);
+    if (eOutput == ACOutput_XML)
+      _tcscat(s_szExceptionLogFileName, _T(".exp.xml"));
+    else
+      _tcscat(s_szExceptionLogFileName, _T(".exp.log"));
+
+    if (eOutput == ACOutput_XML)
+      _tcscat(szModName, _T(".mem.xml-leaks"));
+    else
+      _tcscat(szModName, _T(".mem.log"));
+  }
+  else
+  {
+    if (eOutput == ACOutput_XML)
+      _tcscpy(szModName, _T("\\mem-leaks.xml-leaks"));  // default
+    else
+      _tcscpy(szModName, _T("\\mem-leaks.log"));  // default
+  }
+
+  if ((bSetUnhandledExeptionFilter != FALSE) && (s_bUnhandledExeptionFilterSet == FALSE) )
+  {
+    // set global exception handler (for handling all unhandled exceptions)
+    SetUnhandledExceptionFilter(CrashHandlerExceptionFilter);
+    s_bUnhandledExeptionFilterSet = TRUE;
+  }
+
+  return InitAllocCheckWN(eOutput, szModName, ulShowStackAtAlloc);
+}
+
+
+// This function if NOT multi-threading capable
+// It should only be called from the main-Function!
+//   Returns the number of bytes that are not freed (leaks)
+ULONG DeInitAllocCheck(void) {
+  ULONG ulRet = 0;
+  if (g_bInitialized) {
+
+#ifdef _DEBUG
+    InterlockedIncrement(&g_lMallocCalled); // No deactivate MyAllocHook, because StackWalker will allocate some memory)
+    ulRet = AllocHashDeinit();  // output the not freed memory
+    // remove the hook and set the old one
+    _CrtSetAllocHook(pfnOldCrtAllocHook);
+
+#ifdef WITH_IMALLOC_SPY
+    CoRevokeMallocSpy();
+#endif
+
+#endif
+
+    EnterCriticalSection(&g_csFileOpenClose);  // wait until a running stack dump was created
+    g_bInitialized = FALSE;
+
+    // de-init symbol handler etc. (SymCleanup())
+    if (pSC != NULL)
+      pSC( GetCurrentProcess() );
+    FreeLibrary( g_hImagehlpDll );
+
+    LeaveCriticalSection(&g_csFileOpenClose);
+    if (g_pszAllocLogName != NULL) {
+      free(g_pszAllocLogName);
+      g_pszAllocLogName = NULL;
+    }
+    if (g_fFile != NULL) {
+       fclose(g_fFile);
+       g_fFile = NULL;
+    }
+
+    DeleteCriticalSection(&g_csFileOpenClose);
+    InterlockedDecrement(&g_lMallocCalled);
+  }
+
+  if (s_bUnhandledExeptionFilterSet != TRUE)
+  {
+    SetUnhandledExceptionFilter(NULL);
+    s_bUnhandledExeptionFilterSet = FALSE;
+  }
+  return ulRet;
+}  // DeInitAllocCheck
+
+
+
+void OnlyInstallUnhandeldExceptionFilter(eAllocCheckOutput eOutput)
+{
+  if (s_bUnhandledExeptionFilterSet == FALSE)
+  {
+    TCHAR szModName[_MAX_PATH];
+    if (GetModuleFileName(NULL, szModName, sizeof(szModName)/sizeof(TCHAR)) != 0)
+    {
+      _tcscpy(s_szExceptionLogFileName, szModName);
+      if (eOutput == ACOutput_XML)
+        _tcscat(s_szExceptionLogFileName, _T(".exp.xml"));
+      else
+        _tcscat(s_szExceptionLogFileName, _T(".exp.log"));
+
+      if (eOutput == ACOutput_XML)
+        _tcscat(szModName, _T(".mem.xml-leaks"));
+      else
+        _tcscat(szModName, _T(".mem.log"));
+    }
+    else
+    {
+      if (eOutput == ACOutput_XML)
+        _tcscpy(szModName, _T("\\mem-leaks.xml-leaks"));  // default
+      else
+        _tcscpy(szModName, _T("\\mem-leaks.log"));  // default
+    }
+    // set it again; WARNING: this will override the setting for a possible AllocCheck-Setting
+    g_CallstackOutputType = eOutput;
+
+    // set global exception handler (for handling all unhandled exceptions)
+    SetUnhandledExceptionFilter(CrashHandlerExceptionFilter);
+    s_bUnhandledExeptionFilterSet = TRUE;
+  }
+}
+
+
+
+static TCHAR *GetExpectionCodeText(DWORD dwExceptionCode) {
+  switch(dwExceptionCode) {
+  case EXCEPTION_ACCESS_VIOLATION: return _T("ACCESS VIOLATION");
+  case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: return _T("ARRAY BOUNDS EXCEEDED");
+  case EXCEPTION_BREAKPOINT: return _T("BREAKPOINT");
+  case EXCEPTION_DATATYPE_MISALIGNMENT: return _T("DATATYPE MISALIGNMENT");
+  case EXCEPTION_FLT_DENORMAL_OPERAND: return _T("FLT DENORMAL OPERAND");
+  case EXCEPTION_FLT_DIVIDE_BY_ZERO: return _T("FLT DIVIDE BY ZERO");
+  case EXCEPTION_FLT_INEXACT_RESULT: return _T("FLT INEXACT RESULT");
+  case EXCEPTION_FLT_INVALID_OPERATION: return _T("FLT INVALID OPERATION");
+  case EXCEPTION_FLT_OVERFLOW: return _T("FLT OVERFLOW");
+  case EXCEPTION_FLT_STACK_CHECK: return _T("FLT STACK CHECK");
+  case EXCEPTION_FLT_UNDERFLOW: return _T("FLT UNDERFLOW");
+  case EXCEPTION_ILLEGAL_INSTRUCTION: return _T("ILLEGAL INSTRUCTION");
+  case EXCEPTION_IN_PAGE_ERROR: return _T("IN PAGE ERROR");
+  case EXCEPTION_INT_DIVIDE_BY_ZERO: return _T("INT DIVIDE BY ZERO");
+  case EXCEPTION_INT_OVERFLOW: return _T("INT OVERFLOW");
+  case EXCEPTION_INVALID_DISPOSITION: return _T("INVALID DISPOSITION");
+  case EXCEPTION_NONCONTINUABLE_EXCEPTION: return _T("NONCONTINUABLE EXCEPTION");
+  case EXCEPTION_PRIV_INSTRUCTION: return _T("PRIV INSTRUCTION");
+  case EXCEPTION_SINGLE_STEP: return _T("SINGLE STEP");
+  case EXCEPTION_STACK_OVERFLOW: return _T("STACK OVERFLOW");
+  case DBG_CONTROL_C : return _T("DBG CONTROL C ");
+  default:
+    return _T("<unkown exception>");
+  }
+}  // GetExpectionCodeText
+
+// Function is not multi-threading safe, because of static char!
+static TCHAR *GetAdditionalExpectionCodeText(PEXCEPTION_RECORD pExceptionRecord) {
+  static TCHAR szTemp[100];
+
+  switch(pExceptionRecord->ExceptionCode) {
+  case EXCEPTION_ACCESS_VIOLATION:
+    if (pExceptionRecord->NumberParameters == 2) {
+      switch(pExceptionRecord->ExceptionInformation[0]) {
+      case 0: // read attempt
+        _stprintf(szTemp, _T(" read attempt to address 0x%8.8X "), pExceptionRecord->ExceptionInformation[1]);
+        return szTemp;
+      case 1: // write attempt
+        _stprintf(szTemp, _T(" write attempt to address 0x%8.8X "), pExceptionRecord->ExceptionInformation[1]);
+        return szTemp;
+      default:
+        return _T("");
+      }
+    }  // if (pExceptionRecord->NumberParameters == 2)
+    return _T("");
+  default:
+    return _T("");
+  }  // switch(pExceptionRecord->ExceptionCode)
+}  // GetAdditionalExpectionCodeText
+
+std::string SimpleXMLEncode(PCSTR szText)
+{
+  std::string szRet;
+
+  for (size_t i=0; i<strlen(szText); i++)
+  {
+    switch(szText[i])
+    {
+    case '&':
+      szRet.append("&amp;");
+      break;
+    case '<':
+      szRet.append("&lt;");
+      break;
+    case '>':
+      szRet.append("&gt;");
+      break;
+    case '"':
+      szRet.append("&quot;");
+      break;
+    case '\'':
+      szRet.append("&apos;");
+      break;
+    default:
+      szRet += szText[i];
+    }
+  }
+  return szRet;
+}
+
+
+// #################################################################################
+// #################################################################################
+// Here the Stackwalk-Part begins.
+//   Some of the code is from an example from a book 
+//   But I couldn´t find the reference anymore... sorry...
+//   If someone knowns, please let me know...
+// #################################################################################
+// #################################################################################
+
+
+// if you use C++ exception handling: install a translator function
+// with set_se_translator(). In the context of that function (but *not*
+// afterwards), you can either do your stack dump, or save the CONTEXT
+// record as a local copy. Note that you must do the stack sump at the
+// earliest opportunity, to avoid the interesting stackframes being gone
+// by the time you do the dump.
+
+// status: 
+// - EXCEPTION_CONTINUE_SEARCH: exception wird weitergereicht
+// - EXCEPTION_CONTINUE_EXECUTION: 
+// - EXCEPTION_EXECUTE_HANDLER:
+DWORD StackwalkFilter( EXCEPTION_POINTERS *ep, DWORD status, LPCTSTR pszLogFile)
+{
+  HANDLE hThread;
+  FILE *fFile = stdout;  // default to stdout
+
+  if (pszLogFile != NULL) {  // a filename is provided
+    // Open the logfile
+    fFile = _tfopen(pszLogFile, _T("a"));
+    if (fFile != NULL) {  // Is the file too big?
+      long size;
+      fseek(fFile, 0, SEEK_END);
+      size = ftell(fFile);  // Get the size of the file
+      if (size >= LOG_FILE_MAX_SIZE) {
+        TCHAR *pszTemp = (TCHAR*) malloc(MAX_PATH);
+        // It is too big...
+        fclose(fFile);
+        _tcscpy(pszTemp, pszLogFile);
+        _tcscat(pszTemp, _T(".old"));
+        _tremove(pszTemp);  // Remove an old file, if exists
+        _trename(pszLogFile, pszTemp);  // rename the actual file
+        fFile = _tfopen(pszLogFile, _T("w"));  // create a new file
+        free(pszTemp);
+      }
+    }
+  }  // if (pszLogFile != NULL) 
+  if (fFile == NULL) {
+    fFile = stdout;
+  }
+
+  // Write infos about the exception
+  if (g_CallstackOutputType == ACOutput_XML)
+  {
+    _ftprintf(fFile, _T("<EXCEPTION code=\"%8.8X\" addr=\"%8.8X\" "), 
+      ep->ExceptionRecord->ExceptionCode,
+      ep->ExceptionRecord->ExceptionAddress);
+    WriteDateTime(fFile, TRUE);
+    _ftprintf(fFile, _T("code_desc=\"%s\" more_desc=\"%s\">\n"), GetExpectionCodeText(ep->ExceptionRecord->ExceptionCode),
+      GetAdditionalExpectionCodeText(ep->ExceptionRecord));
+  }
+  else
+  {
+    _ftprintf(fFile, _T("######## EXCEPTION: 0x%8.8X at address: 0x%8.8X"), 
+      ep->ExceptionRecord->ExceptionCode,
+      ep->ExceptionRecord->ExceptionAddress);
+    _ftprintf(fFile, _T(": %s %s\n"), GetExpectionCodeText(ep->ExceptionRecord->ExceptionCode),
+      GetAdditionalExpectionCodeText(ep->ExceptionRecord));
+  }
+
+  DuplicateHandle( GetCurrentProcess(), GetCurrentThread(),
+    GetCurrentProcess(), &hThread, 0, false, DUPLICATE_SAME_ACCESS );
+  ShowStack( hThread, *(ep->ContextRecord), fFile);
+  CloseHandle( hThread );
+
+  if (g_CallstackOutputType == ACOutput_XML)
+    _ftprintf(fFile, _T("</EXCEPTION>\n"));
+
+  fclose(fFile);
+
+  return status;
+}  // StackwalkFilter
+
+void ShowStack( HANDLE hThread, CONTEXT& c, LPCTSTR pszLogFile)
+{
+  FILE *fFile = stdout;  // default to stdout
+
+  if (pszLogFile != NULL) {  // a filename is available
+    // Open the logfile
+    fFile = _tfopen(pszLogFile, _T("a"));
+    if (fFile != NULL) {  // Is the file too big?
+      long size;
+      fseek(fFile, 0, SEEK_END);
+      size = ftell(fFile);  // Get the size of the file
+      if (size >= LOG_FILE_MAX_SIZE) {
+        TCHAR *pszTemp = (TCHAR*) malloc(MAX_PATH);
+        // It is too big...
+        fclose(fFile);
+        _tcscpy(pszTemp, pszLogFile);
+        _tcscat(pszTemp, _T(".old"));
+        _tremove(pszTemp);  // Remove an old file, if exists
+        _trename(pszLogFile, pszTemp);  // rename the actual file
+        fFile = _tfopen(pszLogFile, _T("w"));  // open new file
+        free(pszTemp);
+      }
+    }
+  }  // if (pszLogFile != NULL) 
+  if (fFile == NULL) {
+    fFile = stdout;
+  }
+
+  ShowStack( hThread, c, fFile);
+
+  fclose(fFile);
+}
+
+
+static void ShowStack( HANDLE hThread, CONTEXT& c, FILE *fLogFile) {
+  ShowStackRM(hThread, c, fLogFile, NULL, GetCurrentProcess());
+}
+
+static void ShowStackRM( HANDLE hThread, CONTEXT& c, FILE *fLogFile, PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryFunction, HANDLE hSWProcess) {
+  // normally, call ImageNtHeader() and use machine info from PE header
+  // but we assume that it is an I386 image...
+  DWORD imageType = IMAGE_FILE_MACHINE_I386;
+  HANDLE hProcess = GetCurrentProcess(); // hProcess normally comes from outside but we only do the stackdump in our own process
+  int frameNum; // counts walked frames
+  DWORD64 offsetFromSymbol; // tells us how far from the symbol we were
+  DWORD offsetFromLine; // tells us how far from the line we were
+  DWORD symOptions; // symbol handler settings
+
+  static IMAGEHLP_SYMBOL64 *pSym = NULL;
+  char undName[MAXNAMELEN]; // undecorated name
+  char undFullName[MAXNAMELEN]; // undecorated name with all shenanigans
+  IMAGEHLP_MODULE64 Module;
+  IMAGEHLP_LINE64 Line;
+  BOOL bXMLTagWrote;
+
+  std::string symSearchPath;
+
+  static bool bFirstTime = TRUE;
+
+  // If no logfile is present, outpur to "stdout"
+  if (fLogFile == NULL) {
+    fLogFile = stdout;
+  }
+
+  STACKFRAME64 s; // in/out stackframe
+  memset( &s, '\0', sizeof s );
+
+  if ( (g_bInitialized == FALSE) && (bFirstTime == TRUE) ) {
+    InitStackWalk();
+  }
+
+  if (g_bInitialized == FALSE)
+  {
+    // Could not init!!!!
+    bFirstTime = FALSE;
+    _ftprintf(fLogFile, _T("%lu: Stackwalker not initialized (or was not able to initialize)!\n"), g_dwShowCount);
+    return;
+  }
+
+// Critical section begin...
+  EnterCriticalSection(&g_csFileOpenClose);
+
+  InterlockedIncrement((long*) &g_dwShowCount);  // erhöhe counter
+
+
+  // NOTE: normally, the exe directory and the current directory should be taken
+  // from the target process. The current dir would be gotten through injection
+  // of a remote thread; the exe fir through either ToolHelp32 or PSAPI.
+
+  if (pSym == NULL) {
+    pSym = (IMAGEHLP_SYMBOL64 *) malloc( IMGSYMLEN + MAXNAMELEN );
+    if (!pSym) goto cleanup;  // not enough memory...
+  }
+
+  if (g_CallstackOutputType != ACOutput_XML)
+  {
+    _ftprintf(fLogFile, _T("%lu: "), g_dwShowCount);
+    WriteDateTime(fLogFile);
+    _ftprintf(fLogFile, _T("\n"));
+  }
+
+
+  if (bFirstTime) {
+
+    CHAR *tt, *p;
+
+    tt = (CHAR*) malloc(sizeof(CHAR) * TTBUFLEN); // Get the temporary buffer
+    if (!tt) goto cleanup;  // not enough memory...
+
+    // build symbol search path from:
+    symSearchPath = "";
+    // current directory
+    if ( GetCurrentDirectoryA( TTBUFLEN, tt ) )
+      symSearchPath += tt + std::string( ";" );
+    // dir with executable
+    if ( GetModuleFileNameA( 0, tt, TTBUFLEN ) )
+    {
+      for ( p = tt + strlen( tt ) - 1; p >= tt; -- p )
+      {
+        // locate the rightmost path separator
+        if ( *p == '\\' || *p == '/' || *p == ':' )
+          break;
+      }
+      // if we found one, p is pointing at it; if not, tt only contains
+      // an exe name (no path), and p points before its first byte
+      if ( p != tt ) // path sep found?
+      {
+        if ( *p == ':' ) // we leave colons in place
+          ++ p;
+        *p = '\0'; // eliminate the exe name and last path sep
+        symSearchPath += tt + std::string( ";" );
+      }
+    }
+    // environment variable _NT_SYMBOL_PATH
+    if ( GetEnvironmentVariableA( "_NT_SYMBOL_PATH", tt, TTBUFLEN ) )
+      symSearchPath += tt + std::string( ";" );
+    // environment variable _NT_ALTERNATE_SYMBOL_PATH
+    if ( GetEnvironmentVariableA( "_NT_ALTERNATE_SYMBOL_PATH", tt, TTBUFLEN ) )
+      symSearchPath += tt + std::string( ";" );
+    // environment variable SYSTEMROOT
+    if ( GetEnvironmentVariableA( "SYSTEMROOT", tt, TTBUFLEN ) )
+      symSearchPath += tt + std::string( ";" );
+
+
+
+    if ( symSearchPath.size() > 0 ) // if we added anything, we have a trailing semicolon
+      symSearchPath = symSearchPath.substr( 0, symSearchPath.size() - 1 );
+
+    // why oh why does SymInitialize() want a writeable string?
+    strncpy( tt, symSearchPath.c_str(), TTBUFLEN );
+    tt[TTBUFLEN - 1] = '\0'; // if strncpy() overruns, it doesn't add the null terminator
+
+    // init symbol handler stuff (SymInitialize())
+    if ( ! pSI( hProcess, tt, false ) )
+    {
+      if (g_CallstackOutputType != ACOutput_XML)
+        _ftprintf(fLogFile, _T("%lu: SymInitialize(): GetLastError = %lu\n"), g_dwShowCount, gle );
+      if (tt) free( tt );
+      goto cleanup;
+    }
+
+    // SymGetOptions()
+    symOptions = pSGO();
+    symOptions |= SYMOPT_LOAD_LINES;
+    symOptions &= ~SYMOPT_UNDNAME;
+    symOptions &= ~SYMOPT_DEFERRED_LOADS;
+    pSSO( symOptions ); // SymSetOptions()
+
+    // Enumerate modules and tell dbghlp.dll about them.
+    // On NT, this is not necessary, but it won't hurt.
+    EnumAndLoadModuleSymbols( hProcess, GetCurrentProcessId(), fLogFile );
+
+    if (tt) 
+      free( tt );
+  }  // bFirstTime = TRUE
+  bFirstTime = FALSE;
+
+  // init STACKFRAME for first call
+  // Notes: AddrModeFlat is just an assumption. I hate VDM debugging.
+  // Notes: will have to be #ifdef-ed for Alphas; MIPSes are dead anyway,
+  // and good riddance.
+  s.AddrPC.Offset = c.Eip;
+  s.AddrPC.Mode = AddrModeFlat;
+  s.AddrFrame.Offset = c.Ebp;
+  s.AddrFrame.Mode = AddrModeFlat;
+  s.AddrStack.Offset = c.Ebp;
+  s.AddrStack.Mode = AddrModeFlat;
+
+  memset( pSym, '\0', IMGSYMLEN + MAXNAMELEN );
+  pSym->SizeOfStruct = IMGSYMLEN;
+  pSym->MaxNameLength = MAXNAMELEN;
+
+  memset( &Line, '\0', sizeof Line );
+  Line.SizeOfStruct = sizeof Line;
+
+  memset( &Module, '\0', sizeof Module );
+  Module.SizeOfStruct = sizeof Module;
+
+  for ( frameNum = 0; ; ++ frameNum )
+  {
+    // get next stack frame (StackWalk64(), SymFunctionTableAccess64(), SymGetModuleBase64())
+    // if this returns ERROR_INVALID_ADDRESS (487) or ERROR_NOACCESS (998), you can
+    // assume that either you are done, or that the stack is so hosed that the next
+    // deeper frame could not be found.
+    // CONTEXT need not to be suplied if imageTyp is IMAGE_FILE_MACHINE_I386!
+    if ( ! pSW( imageType, hSWProcess, hThread, &s, NULL, ReadMemoryFunction, pSFTA, pSGMB, NULL ) )
+      break;
+
+    bXMLTagWrote = FALSE;
+
+    if (g_CallstackOutputType == ACOutput_Advanced)
+      _ftprintf(fLogFile, _T("\n%lu: %3d"), g_dwShowCount, frameNum);
+    if ( s.AddrPC.Offset == 0 )
+    {
+      // Special case: If we are here, we have no valid callstack entry!
+      switch(g_CallstackOutputType)
+      {
+      case ACOutput_Simple:
+        _ftprintf(fLogFile, _T("%lu: (-nosymbols- PC == 0)\n"), g_dwShowCount);
+        break;
+      case ACOutput_Advanced:
+        _ftprintf(fLogFile, _T("   (-nosymbols- PC == 0)\n"));
+        break;
+      case ACOutput_XML:
+        // TODO: ....
+        _ftprintf(fLogFile, _T("<STACKENTRY decl=\"(-nosymbols- PC == 0)\"/>\n"));
+        break;
+      }
+    }
+    else
+    {
+      // we seem to have a valid PC
+      undName[0] = 0;
+      undFullName[0] = 0;
+      offsetFromSymbol = 0;
+      // show procedure info (SymGetSymFromAddr())
+      if ( ! pSGSFA( hProcess, s.AddrPC.Offset, &offsetFromSymbol, pSym ) )
+      {
+        if (g_CallstackOutputType == ACOutput_Advanced)
+        {
+          if ( gle != 487 )
+            _ftprintf(fLogFile, _T("   SymGetSymFromAddr(): GetLastError = %lu\n"), gle );
+          else
+            _ftprintf(fLogFile, _T("\n"));
+        }
+      }
+      else
+      {
+        // UnDecorateSymbolName()
+        pUDSN( pSym->Name, undName, MAXNAMELEN, UNDNAME_NAME_ONLY );
+        pUDSN( pSym->Name, undFullName, MAXNAMELEN, UNDNAME_COMPLETE );
+        if (g_CallstackOutputType == ACOutput_Advanced)
+        {
+          if (strlen(undName) > 0)
+            fprintf(fLogFile, "     %s %+ld bytes\n", undName, (long) offsetFromSymbol );
+          else
+          {
+            fprintf(fLogFile, "     Sig:  %s %+ld bytes\n", pSym->Name, (long) offsetFromSymbol );
+            strcpy(undName, pSym->Name);
+          }
+          fprintf(fLogFile, "%lu:     Decl: %s\n", g_dwShowCount, undFullName );
+        }
+      }
+      //if (g_CallstackOutputType == ACOutput_XML)
+      //  fprintf(fLogFile, "decl=\"%s\" decl_offset=\"%+ld\" ", SimpleXMLEncode(undName).c_str(), (long) offsetFromSymbol);
+
+      // show line number info, NT5.0-method (SymGetLineFromAddr())
+      offsetFromLine = 0;
+      if ( pSGLFA != NULL )
+      { // yes, we have SymGetLineFromAddr()
+        if ( ! pSGLFA( hProcess, s.AddrPC.Offset, &offsetFromLine, &Line ) )
+        {
+          if ( (gle != 487) && (frameNum > 0) )  // ignore error for first frame
+          {
+            if (g_CallstackOutputType == ACOutput_XML)
+            {
+              _ftprintf(fLogFile, _T("<STACKENTRY "));
+              bXMLTagWrote = TRUE;
+              fprintf(fLogFile, "decl=\"%s\" decl_offset=\"%+ld\" ", SimpleXMLEncode(undName).c_str(), (long) offsetFromSymbol);
+              _ftprintf(fLogFile, _T("srcfile=\"SymGetLineFromAddr(): GetLastError = %lu\" "), gle);
+            }
+            else
+              _ftprintf(fLogFile, _T("%lu: SymGetLineFromAddr(): GetLastError = %lu\n"), g_dwShowCount, gle );
+          }
+        }
+        else
+        {
+          switch(g_CallstackOutputType)
+          {
+          case ACOutput_Advanced:
+            fprintf(fLogFile, "%lu:     Line: %s(%lu) %+ld bytes\n", g_dwShowCount,
+              Line.FileName, Line.LineNumber, offsetFromLine );
+            break;
+          case ACOutput_Simple:
+            fprintf(fLogFile, "%lu: %s(%lu) %+ld bytes (%s)\n", g_dwShowCount,
+              Line.FileName, Line.LineNumber, offsetFromLine, undName);
+            break;
+          case ACOutput_XML:
+            _ftprintf(fLogFile, _T("<STACKENTRY "));
+            bXMLTagWrote = TRUE;
+            fprintf(fLogFile, "decl=\"%s\" decl_offset=\"%+ld\" ", SimpleXMLEncode(undName).c_str(), (long) offsetFromSymbol);
+            fprintf(fLogFile, "srcfile=\"%s\" line=\"%lu\" line_offset=\"%+ld\" ", 
+              SimpleXMLEncode(Line.FileName).c_str(), Line.LineNumber, offsetFromLine, undName);
+            break;
+          }
+        }
+      } // yes, we have SymGetLineFromAddr()
+
+      // show module info (SymGetModuleInfo())
+      if ( (g_CallstackOutputType == ACOutput_Advanced) || (g_CallstackOutputType == ACOutput_XML) )
+      {
+        if ( ! pSGMI( hProcess, s.AddrPC.Offset, &Module ) )
+        {
+          if (g_CallstackOutputType == ACOutput_Advanced)
+            _ftprintf(fLogFile, _T("%lu: SymGetModuleInfo): GetLastError = %lu\n"), g_dwShowCount, gle );
+        }
+        else
+        { // got module info OK
+          char ty[80];
+          switch ( Module.SymType )
+          {
+          case SymNone:
+            strcpy( ty, "-nosymbols-" );
+            break;
+          case SymCoff:
+            strcpy( ty, "COFF" );
+            break;
+          case SymCv:
+            strcpy( ty, "CV" );
+            break;
+          case SymPdb:
+            strcpy( ty, "PDB" );
+            break;
+          case SymExport:
+            strcpy( ty, "-exported-" );
+            break;
+          case SymDeferred:
+            strcpy( ty, "-deferred-" );
+            break;
+          case SymSym:
+            strcpy( ty, "SYM" );
+            break;
+#if API_VERSION_NUMBER >= 9
+          case SymDia:
+            strcpy( ty, "DIA" );
+            break;
+#endif
+          default:
+            _snprintf( ty, sizeof ty, "symtype=%ld", (long) Module.SymType );
+            break;
+          }
+
+          if (g_CallstackOutputType == ACOutput_XML)
+          {
+            // now, check if the XML-Entry is written...
+            if (bXMLTagWrote == FALSE) 
+            {
+              _ftprintf(fLogFile, _T("<STACKENTRY "));
+              bXMLTagWrote = TRUE;
+              fprintf(fLogFile, "decl=\"%s\" decl_offset=\"%+ld\" ", SimpleXMLEncode(undName).c_str(), (long) offsetFromSymbol);
+              _ftprintf(fLogFile, _T("srcfile=\"\" "));
+              bXMLTagWrote = TRUE;
+            }
+          }
+
+          if (g_CallstackOutputType == ACOutput_Advanced)
+          {
+            fprintf(fLogFile, "%lu:     Mod:  %s, base: %08lxh\n", g_dwShowCount,
+              Module.ModuleName, Module.BaseOfImage );
+            if (Module.SymType == SymNone) { // Gebe nur aus, wenn keine Symbole vorhanden sind!
+              _ftprintf(fLogFile, _T("%lu:     Offset: 0x%8.8x\n"), g_dwShowCount, s.AddrPC.Offset);
+              fprintf(fLogFile, "%lu:     Sym:  type: %s, file: %s\n", g_dwShowCount,
+                ty, Module.LoadedImageName );
+            }
+          }
+          else
+          {
+            // XML:
+            if (bXMLTagWrote == TRUE)
+              fprintf(fLogFile, "module=\"%s\" base=\"%08lx\" ", Module.ModuleName, Module.BaseOfImage);
+          }
+        } // got module info OK
+      }
+      if ( (g_CallstackOutputType == ACOutput_XML) && (bXMLTagWrote == TRUE) )
+        _ftprintf(fLogFile, _T("/>\n"));  // terminate the XML node
+
+    } // we seem to have a valid PC
+
+    // no return address means no deeper stackframe
+    if ( s.AddrReturn.Offset == 0 )
+    {
+      // avoid misunderstandings in the printf() following the loop
+      SetLastError( 0 );
+      break;
+    }
+
+  } // for ( frameNum )
+
+  if ( (g_CallstackOutputType != ACOutput_XML) && (gle != 0) )
+    _ftprintf(fLogFile, _T("\n%lu: StackWalk(): GetLastError = %lu\n"), g_dwShowCount, gle );
+
+cleanup:
+  //if (pSym) free( pSym );
+  if (fLogFile) {
+    _ftprintf(fLogFile, _T("\n\n"));
+    if (g_dwShowCount % 1000)
+      fflush(fLogFile);
+  }
+
+  LeaveCriticalSection(&g_csFileOpenClose);
+
+
+// Critical section end...
+}  // ShowStackRM
+
+#pragma warning(pop)