]> git.lyx.org Git - lyx.git/blobdiff - development/Win32/vld/src/vld.cpp
Add support for glue length in parskip (#12867)
[lyx.git] / development / Win32 / vld / src / vld.cpp
index ffaa43ac71a9bfb316a9a8334fbd09101774bb44..797a89401f0638821e54a3e2a21a28ca746a0db7 100644 (file)
@@ -1,8 +1,7 @@
 ////////////////////////////////////////////////////////////////////////////////
-//  $Id: vld.cpp,v 1.69 2006/11/18 05:07:04 dmouldin Exp $
 //
 //  Visual Leak Detector - VisualLeakDetector Class Implementation
-//  Copyright (c) 2005-2006 Dan Moulding
+//  Copyright (c) 2005-2009 Dan Moulding
 //
 //  This library is free software; you can redistribute it and/or
 //  modify it under the terms of the GNU Lesser General Public
 #include <cstdio>
 #include <sys/stat.h>
 #include <windows.h>
+#ifndef __out_xcount
 #define __out_xcount(x) // Workaround for the specstrings.h bug in the Platform SDK.
+#endif
 #define DBGHELP_TRANSLATE_TCHAR
-#include <dbghelp.h>    // Provides symbol handling services.
-#define VLDBUILD        // Declares that we are building Visual Leak Detector.
-#include "callstack.h"  // Provides a class for handling call stacks.
-#include "map.h"        // Provides a lightweight STL-like map template.
-#include "ntapi.h"      // Provides access to NT APIs.
-#include "set.h"        // Provides a lightweight STL-like set template.
-#include "utility.h"    // Provides various utility functions.
-#include "vldheap.h"    // Provides internal new and delete operators.
-#include "vldint.h"     // Provides access to the Visual Leak Detector internals.
+#include <dbghelp.h>     // Provides symbol handling services.
+#define VLDBUILD         // Declares that we are building Visual Leak Detector.
+#include "callstack.h"   // Provides a class for handling call stacks.
+#include "crtmfcpatch.h" // Provides CRT and MFC patch functions.
+#include "map.h"         // Provides a lightweight STL-like map template.
+#include "ntapi.h"       // Provides access to NT APIs.
+#include "set.h"         // Provides a lightweight STL-like set template.
+#include "utility.h"     // Provides various utility functions.
+#include "vldheap.h"     // Provides internal new and delete operators.
+#include "vldint.h"      // Provides access to the Visual Leak Detector internals.
 
 #define BLOCKMAPRESERVE     64  // This should strike a balance between memory use and a desire to minimize heap hits.
 #define HEAPMAPRESERVE      2   // Usually there won't be more than a few heaps in the process, so this should be small.
@@ -57,57 +59,15 @@ HANDLE           currentthread;  // Pseudo-handle for the current thread.
 CRITICAL_SECTION imagelock;      // Serializes calls to the Debug Help Library PE image access APIs.
 HANDLE           processheap;    // Handle to the process's heap (COM allocations come from here).
 CRITICAL_SECTION stackwalklock;  // Serializes calls to StackWalk64 from the Debug Help Library.
-CRITICAL_SECTION symbollock;     // Serializes calls to the Debug Help Library symbold handling APIs.
-
-// Function pointer types for explicit dynamic linking with functions listed in
-// the import patch table.
-typedef void* (__cdecl *_calloc_dbg_t) (size_t, size_t, int, const char*, int);
-typedef void* (__cdecl *_malloc_dbg_t) (size_t, int, const char *, int);
-typedef void* (__cdecl *_realloc_dbg_t) (void *, size_t, int, const char *, int);
-typedef void* (__cdecl *calloc_t) (size_t, size_t);
-typedef HRESULT (__stdcall *CoGetMalloc_t) (DWORD, LPMALLOC *);
-typedef LPVOID (__stdcall *CoTaskMemAlloc_t) (ULONG);
-typedef LPVOID (__stdcall *CoTaskMemRealloc_t) (LPVOID, ULONG);
-typedef void* (__cdecl *crt_new_dbg_t) (unsigned int, int, const char *, int);
-typedef void* (__cdecl *malloc_t) (size_t);
-typedef void* (__cdecl *mfc_new_dbg_t) (unsigned int, const char *, int);
-typedef void* (__cdecl *new_t) (unsigned int);
-typedef void* (__cdecl *realloc_t) (void *, size_t);
+CRITICAL_SECTION symbollock;     // Serializes calls to the Debug Help Library symbols handling APIs.
+
+// The one and only VisualLeakDetector object instance.
+__declspec(dllexport) VisualLeakDetector vld;
 
 // Global function pointers for explicit dynamic linking with functions listed
 // in the import patch table. Using explicit dynamic linking minimizes VLD's
 // footprint by loading only modules that are actually used. These pointers will
 // be linked to the real functions the first time they are used.
-static CoGetMalloc_t      pCoGetMalloc            = NULL;
-static CoTaskMemAlloc_t   pCoTaskMemAlloc         = NULL;
-static CoTaskMemRealloc_t pCoTaskMemRealloc       = NULL;
-static _calloc_dbg_t      pcrt80d__calloc_dbg     = NULL;
-static _malloc_dbg_t      pcrt80d__malloc_dbg     = NULL;
-static _realloc_dbg_t     pcrt80d__realloc_dbg    = NULL;
-static crt_new_dbg_t      pcrt80d__scalar_new_dbg = NULL;
-static crt_new_dbg_t      pcrt80d__vector_new_dbg = NULL;
-static calloc_t           pcrt80d_calloc          = NULL;
-static malloc_t           pcrt80d_malloc          = NULL;
-static realloc_t          pcrt80d_realloc         = NULL;
-static new_t              pcrt80d_scalar_new      = NULL;
-static new_t              pcrt80d_vector_new      = NULL;
-static _calloc_dbg_t      pcrtd__calloc_dbg       = NULL;
-static _malloc_dbg_t      pcrtd__malloc_dbg       = NULL;
-static _realloc_dbg_t     pcrtd__realloc_dbg      = NULL;
-static crt_new_dbg_t      pcrtd__scalar_new_dbg   = NULL;
-static calloc_t           pcrtd_calloc            = NULL;
-static malloc_t           pcrtd_malloc            = NULL;
-static realloc_t          pcrtd_realloc           = NULL;
-static new_t              pcrtd_scalar_new        = NULL;
-static mfc_new_dbg_t      pmfc42d__scalar_new_dbg = NULL;
-static new_t              pmfc42d_scalar_new      = NULL;
-static mfc_new_dbg_t      pmfc80d__scalar_new_dbg = NULL;
-static mfc_new_dbg_t      pmfc80d__vector_new_dbg = NULL;
-static new_t              pmfc80d_scalar_new      = NULL;
-static new_t              pmfc80d_vector_new      = NULL;
-
-// The one and only VisualLeakDetector object instance.
-__declspec(dllexport) VisualLeakDetector vld;
 
 // The import patch table: lists the heap-related API imports that VLD patches
 // through to replacement functions provided by VLD. Having this table simply
@@ -122,34 +82,135 @@ patchentry_t VisualLeakDetector::m_patchtable [] = {
     "kernel32.dll", "HeapReAlloc",        0x0, _RtlReAllocateHeap,
 
     // MFC new operators (exported by ordinal).
-    "mfc42d.dll",   (LPCSTR)714,          0x0, _mfc42d__scalar_new_dbg,
-    "mfc42d.dll",   (LPCSTR)711,          0x0, _mfc42d_scalar_new,
-    // XXX MFC 7.x DLL new operators still need to be added to this
-    //   table, but I don't know their ordinals.
-    "mfc80d.dll",   (LPCSTR)895,          0x0, _mfc80d__scalar_new_dbg,
-    "mfc80d.dll",   (LPCSTR)269,          0x0, _mfc80d__vector_new_dbg,
-    "mfc80d.dll",   (LPCSTR)893,          0x0, _mfc80d_scalar_new,
-    "mfc80d.dll",   (LPCSTR)267,          0x0, _mfc80d_vector_new,
+    // XXX why are the vector new operators missing for mfc42d.dll?
+    "mfc42d.dll",   (LPCSTR)711,          0x0, VS60::mfcd_scalar_new,
+    "mfc42d.dll",   (LPCSTR)712,          0x0, VS60::mfcd__scalar_new_dbg_4p,
+    "mfc42d.dll",   (LPCSTR)714,          0x0, VS60::mfcd__scalar_new_dbg_3p,
+    "mfc42ud.dll",  (LPCSTR)711,          0x0, VS60::mfcud_scalar_new,
+    "mfc42ud.dll",  (LPCSTR)712,          0x0, VS60::mfcud__scalar_new_dbg_4p,
+    "mfc42ud.dll",  (LPCSTR)714,          0x0, VS60::mfcud__scalar_new_dbg_3p,
+    "mfc70d.dll",   (LPCSTR)257,          0x0, VS70::mfcd_vector_new,
+    "mfc70d.dll",   (LPCSTR)258,          0x0, VS70::mfcd__vector_new_dbg_4p,
+    "mfc70d.dll",   (LPCSTR)259,          0x0, VS70::mfcd__vector_new_dbg_3p,
+    "mfc70d.dll",   (LPCSTR)832,          0x0, VS70::mfcd_scalar_new,
+    "mfc70d.dll",   (LPCSTR)833,          0x0, VS70::mfcd__scalar_new_dbg_4p,
+    "mfc70d.dll",   (LPCSTR)834,          0x0, VS70::mfcd__scalar_new_dbg_3p,
+    "mfc70ud.dll",  (LPCSTR)258,          0x0, VS70::mfcud_vector_new,
+    "mfc70ud.dll",  (LPCSTR)259,          0x0, VS70::mfcud__vector_new_dbg_4p,
+    "mfc70ud.dll",  (LPCSTR)260,          0x0, VS70::mfcud__vector_new_dbg_3p,
+    "mfc70ud.dll",  (LPCSTR)833,          0x0, VS70::mfcud_scalar_new,
+    "mfc70ud.dll",  (LPCSTR)834,          0x0, VS70::mfcud__scalar_new_dbg_4p,
+    "mfc70ud.dll",  (LPCSTR)835,          0x0, VS70::mfcud__scalar_new_dbg_3p,
+    "mfc71d.dll",   (LPCSTR)267,          0x0, VS71::mfcd_vector_new,
+    "mfc71d.dll",   (LPCSTR)268,          0x0, VS71::mfcd__vector_new_dbg_4p,
+    "mfc71d.dll",   (LPCSTR)269,          0x0, VS71::mfcd__vector_new_dbg_3p,
+    "mfc71d.dll",   (LPCSTR)893,          0x0, VS71::mfcd_scalar_new,
+    "mfc71d.dll",   (LPCSTR)894,          0x0, VS71::mfcd__scalar_new_dbg_4p,
+    "mfc71d.dll",   (LPCSTR)895,          0x0, VS71::mfcd__scalar_new_dbg_3p,
+    "mfc71ud.dll",  (LPCSTR)267,          0x0, VS71::mfcud_vector_new,
+    "mfc71ud.dll",  (LPCSTR)268,          0x0, VS71::mfcud__vector_new_dbg_4p,
+    "mfc71ud.dll",  (LPCSTR)269,          0x0, VS71::mfcud__vector_new_dbg_3p,
+    "mfc71ud.dll",  (LPCSTR)893,          0x0, VS71::mfcud_scalar_new,
+    "mfc71ud.dll",  (LPCSTR)894,          0x0, VS71::mfcud__scalar_new_dbg_4p,
+    "mfc71ud.dll",  (LPCSTR)895,          0x0, VS71::mfcud__scalar_new_dbg_3p,
+    "mfc80d.dll",   (LPCSTR)267,          0x0, VS80::mfcd_vector_new,
+    "mfc80d.dll",   (LPCSTR)268,          0x0, VS80::mfcd__vector_new_dbg_4p,
+    "mfc80d.dll",   (LPCSTR)269,          0x0, VS80::mfcd__vector_new_dbg_3p,
+    "mfc80d.dll",   (LPCSTR)893,          0x0, VS80::mfcd_scalar_new,
+    "mfc80d.dll",   (LPCSTR)894,          0x0, VS80::mfcd__scalar_new_dbg_4p,
+    "mfc80d.dll",   (LPCSTR)895,          0x0, VS80::mfcd__scalar_new_dbg_3p,
+    "mfc80ud.dll",  (LPCSTR)267,          0x0, VS80::mfcud_vector_new,
+    "mfc80ud.dll",  (LPCSTR)268,          0x0, VS80::mfcud__vector_new_dbg_4p,
+    "mfc80ud.dll",  (LPCSTR)269,          0x0, VS80::mfcud__vector_new_dbg_3p,
+    "mfc80ud.dll",  (LPCSTR)893,          0x0, VS80::mfcud_scalar_new,
+    "mfc80ud.dll",  (LPCSTR)894,          0x0, VS80::mfcud__scalar_new_dbg_4p,
+    "mfc80ud.dll",  (LPCSTR)895,          0x0, VS80::mfcud__scalar_new_dbg_3p,
+    "mfc90d.dll",   (LPCSTR)267,          0x0, VS90::mfcd_vector_new,
+    "mfc90d.dll",   (LPCSTR)268,          0x0, VS90::mfcd__vector_new_dbg_4p,
+    "mfc90d.dll",   (LPCSTR)269,          0x0, VS90::mfcd__vector_new_dbg_3p,
+    "mfc90d.dll",   (LPCSTR)931,          0x0, VS90::mfcd_scalar_new,
+    "mfc90d.dll",   (LPCSTR)932,          0x0, VS90::mfcd__scalar_new_dbg_4p,
+    "mfc90d.dll",   (LPCSTR)933,          0x0, VS90::mfcd__scalar_new_dbg_3p,
+    "mfc90ud.dll",  (LPCSTR)267,          0x0, VS90::mfcud_vector_new,
+    "mfc90ud.dll",  (LPCSTR)268,          0x0, VS90::mfcud__vector_new_dbg_4p,
+    "mfc90ud.dll",  (LPCSTR)269,          0x0, VS90::mfcud__vector_new_dbg_3p,
+    "mfc90ud.dll",  (LPCSTR)935,          0x0, VS90::mfcud_scalar_new,
+    "mfc90ud.dll",  (LPCSTR)936,          0x0, VS90::mfcud__scalar_new_dbg_4p,
+    "mfc90ud.dll",  (LPCSTR)937,          0x0, VS90::mfcud__scalar_new_dbg_3p,
+    "mfc100d.dll",   (LPCSTR)267,          0x0, VS100::mfcd_vector_new,
+    "mfc100d.dll",   (LPCSTR)268,          0x0, VS100::mfcd__vector_new_dbg_4p,
+    "mfc100d.dll",   (LPCSTR)269,          0x0, VS100::mfcd__vector_new_dbg_3p,
+    "mfc100d.dll",   (LPCSTR)1427,         0x0, VS100::mfcd_scalar_new,
+    "mfc100d.dll",   (LPCSTR)1428,         0x0, VS100::mfcd__scalar_new_dbg_4p,
+    "mfc100d.dll",   (LPCSTR)1429,         0x0, VS100::mfcd__scalar_new_dbg_3p,
+    "mfc100ud.dll",  (LPCSTR)267,          0x0, VS100::mfcud_vector_new,
+    "mfc100ud.dll",  (LPCSTR)268,          0x0, VS100::mfcud__vector_new_dbg_4p,
+    "mfc100ud.dll",  (LPCSTR)269,          0x0, VS100::mfcud__vector_new_dbg_3p,
+    "mfc100ud.dll",  (LPCSTR)1434,         0x0, VS100::mfcud_scalar_new,
+    "mfc100ud.dll",  (LPCSTR)1435,         0x0, VS100::mfcud__scalar_new_dbg_4p,
+    "mfc100ud.dll",  (LPCSTR)1436,         0x0, VS100::mfcud__scalar_new_dbg_3p,
 
     // CRT new operators and heap APIs.
-    "msvcr80d.dll", "_calloc_dbg",        0x0, _crt80d__calloc_dbg,
-    "msvcr80d.dll", "_malloc_dbg",        0x0, _crt80d__malloc_dbg,
-    "msvcr80d.dll", "_realloc_dbg",       0x0, _crt80d__realloc_dbg,
-    "msvcr80d.dll", "??2@YAPAXIHPBDH@Z",  0x0, _crt80d__scalar_new_dbg,
-    "msvcr80d.dll", "??_U@YAPAXIHPBDH@Z", 0x0, _crt80d__vector_new_dbg,
-    "msvcr80d.dll", "calloc",             0x0, _crt80d_calloc,
-    "msvcr80d.dll", "malloc",             0x0, _crt80d_malloc,
-    "msvcr80d.dll", "realloc",            0x0, _crt80d_realloc,
-    "msvcr80d.dll", "??2@YAPAXI@Z",       0x0, _crt80d_scalar_new,
-    "msvcr80d.dll", "??_U@YAPAXI@Z",      0x0, _crt80d_vector_new,
-    "msvcrtd.dll",  "_calloc_dbg",        0x0, _crtd__calloc_dbg,
-    "msvcrtd.dll",  "_malloc_dbg",        0x0, _crtd__malloc_dbg,
-    "msvcrtd.dll",  "??2@YAPAXIHPBDH@Z",  0x0, _crtd__scalar_new_dbg,
-    "msvcrtd.dll",  "_realloc_dbg",       0x0, _crtd__realloc_dbg,
-    "msvcrtd.dll",  "calloc",             0x0, _crtd_calloc,
-    "msvcrtd.dll",  "malloc",             0x0, _crtd_malloc,
-    "msvcrtd.dll",  "realloc",            0x0, _crtd_realloc,
-    "msvcrtd.dll",  "??2@YAPAXI@Z",       0x0, _crtd_scalar_new,
+    "msvcrtd.dll",  "_calloc_dbg",        0x0, VS60::crtd__calloc_dbg,
+    "msvcrtd.dll",  "_malloc_dbg",        0x0, VS60::crtd__malloc_dbg,
+    "msvcrtd.dll",  "_realloc_dbg",       0x0, VS60::crtd__realloc_dbg,
+    "msvcrtd.dll",  "??2@YAPAXIHPBDH@Z",  0x0, VS60::crtd__scalar_new_dbg,
+//  "msvcrtd.dll",  "??_U@YAPAXIHPBDH@Z", 0x0, VS60::crtd__vector_new_dbg,
+    "msvcrtd.dll",  "calloc",             0x0, VS60::crtd_calloc,
+    "msvcrtd.dll",  "malloc",             0x0, VS60::crtd_malloc,
+    "msvcrtd.dll",  "realloc",            0x0, VS60::crtd_realloc,
+    "msvcrtd.dll",  "??2@YAPAXI@Z",       0x0, VS60::crtd_scalar_new,
+//  "msvcrtd.dll",  "??_U@YAPAXI@Z",      0x0, VS60::crtd_vector_new,
+    "msvcr70d.dll", "_calloc_dbg",        0x0, VS70::crtd__calloc_dbg,
+    "msvcr70d.dll", "_malloc_dbg",        0x0, VS70::crtd__malloc_dbg,
+    "msvcr70d.dll", "_realloc_dbg",       0x0, VS70::crtd__realloc_dbg,
+    "msvcr70d.dll", "??2@YAPAXIHPBDH@Z",  0x0, VS70::crtd__scalar_new_dbg,
+    "msvcr70d.dll", "??_U@YAPAXIHPBDH@Z", 0x0, VS70::crtd__vector_new_dbg,
+    "msvcr70d.dll", "calloc",             0x0, VS70::crtd_calloc,
+    "msvcr70d.dll", "malloc",             0x0, VS70::crtd_malloc,
+    "msvcr70d.dll", "realloc",            0x0, VS70::crtd_realloc,
+    "msvcr70d.dll", "??2@YAPAXI@Z",       0x0, VS70::crtd_scalar_new,
+    "msvcr70d.dll", "??_U@YAPAXI@Z",      0x0, VS70::crtd_vector_new,
+    "msvcr71d.dll", "_calloc_dbg",        0x0, VS71::crtd__calloc_dbg,
+    "msvcr71d.dll", "_malloc_dbg",        0x0, VS71::crtd__malloc_dbg,
+    "msvcr71d.dll", "_realloc_dbg",       0x0, VS71::crtd__realloc_dbg,
+    "msvcr71d.dll", "??2@YAPAXIHPBDH@Z",  0x0, VS71::crtd__scalar_new_dbg,
+    "msvcr71d.dll", "??_U@YAPAXIHPBDH@Z", 0x0, VS71::crtd__vector_new_dbg,
+    "msvcr71d.dll", "calloc",             0x0, VS71::crtd_calloc,
+    "msvcr71d.dll", "malloc",             0x0, VS71::crtd_malloc,
+    "msvcr71d.dll", "realloc",            0x0, VS71::crtd_realloc,
+    "msvcr71d.dll", "??2@YAPAXI@Z",       0x0, VS71::crtd_scalar_new,
+    "msvcr71d.dll", "??_U@YAPAXI@Z",      0x0, VS71::crtd_vector_new,
+    "msvcr80d.dll", "_calloc_dbg",        0x0, VS80::crtd__calloc_dbg,
+    "msvcr80d.dll", "_malloc_dbg",        0x0, VS80::crtd__malloc_dbg,
+    "msvcr80d.dll", "_realloc_dbg",       0x0, VS80::crtd__realloc_dbg,
+    "msvcr80d.dll", "??2@YAPAXIHPBDH@Z",  0x0, VS80::crtd__scalar_new_dbg,
+    "msvcr80d.dll", "??_U@YAPAXIHPBDH@Z", 0x0, VS80::crtd__vector_new_dbg,
+    "msvcr80d.dll", "calloc",             0x0, VS80::crtd_calloc,
+    "msvcr80d.dll", "malloc",             0x0, VS80::crtd_malloc,
+    "msvcr80d.dll", "realloc",            0x0, VS80::crtd_realloc,
+    "msvcr80d.dll", "??2@YAPAXI@Z",       0x0, VS80::crtd_scalar_new,
+    "msvcr80d.dll", "??_U@YAPAXI@Z",      0x0, VS80::crtd_vector_new,
+    "msvcr90d.dll", "_calloc_dbg",        0x0, VS90::crtd__calloc_dbg,
+    "msvcr90d.dll", "_malloc_dbg",        0x0, VS90::crtd__malloc_dbg,
+    "msvcr90d.dll", "_realloc_dbg",       0x0, VS90::crtd__realloc_dbg,
+    "msvcr90d.dll", "??2@YAPAXIHPBDH@Z",  0x0, VS90::crtd__scalar_new_dbg,
+    "msvcr90d.dll", "??_U@YAPAXIHPBDH@Z", 0x0, VS90::crtd__vector_new_dbg,
+    "msvcr90d.dll", "calloc",             0x0, VS90::crtd_calloc,
+    "msvcr90d.dll", "malloc",             0x0, VS90::crtd_malloc,
+    "msvcr90d.dll", "realloc",            0x0, VS90::crtd_realloc,
+    "msvcr90d.dll", "??2@YAPAXI@Z",       0x0, VS90::crtd_scalar_new,
+    "msvcr90d.dll", "??_U@YAPAXI@Z",      0x0, VS90::crtd_vector_new,
+    "msvcr100d.dll", "_calloc_dbg",        0x0, VS100::crtd__calloc_dbg,
+    "msvcr100d.dll", "_malloc_dbg",        0x0, VS100::crtd__malloc_dbg,
+    "msvcr100d.dll", "_realloc_dbg",       0x0, VS100::crtd__realloc_dbg,
+    "msvcr100d.dll", scalar_new_dbg_name,  0x0, VS100::crtd__scalar_new_dbg,
+    "msvcr100d.dll", vector_new_dbg_name,  0x0, VS100::crtd__vector_new_dbg,
+    "msvcr100d.dll", "calloc",             0x0, VS100::crtd_calloc,
+    "msvcr100d.dll", "malloc",             0x0, VS100::crtd_malloc,
+    "msvcr100d.dll", "realloc",            0x0, VS100::crtd_realloc,
+    "msvcr100d.dll", scalar_new_name,      0x0, VS100::crtd_scalar_new,
+    "msvcr100d.dll", vector_new_name,      0x0, VS100::crtd_vector_new,
 
     // NT APIs.
     "ntdll.dll",    "RtlAllocateHeap",    0x0, _RtlAllocateHeap,
@@ -330,7 +391,6 @@ VisualLeakDetector::~VisualLeakDetector ()
     BlockMap::Iterator   blockit;
     BlockMap            *blockmap;
     size_t               count;
-    DWORD                exitcode;
     vldblockheader_t    *header;
     HANDLE               heap;
     HeapMap::Iterator    heapit;
@@ -339,10 +399,10 @@ VisualLeakDetector::~VisualLeakDetector ()
     WCHAR                leakfilew [MAX_PATH];
     int                  leakline = 0;
     ModuleSet::Iterator  moduleit;
-    SIZE_T               sleepcount;
     HANDLE               thread;
     BOOL                 threadsactive= FALSE;
     TlsSet::Iterator     tlsit;
+    DWORD                dwCurProcessID;
 
     if (m_options & VLD_OPT_VLDOFF) {
         // VLD has been turned off.
@@ -353,6 +413,8 @@ VisualLeakDetector::~VisualLeakDetector ()
         // Detach Visual Leak Detector from all previously attached modules.
         EnumerateLoadedModulesW64(currentprocess, detachfrommodule, NULL);
 
+        dwCurProcessID = GetCurrentProcessId();
+
         // See if any threads that have ever entered VLD's code are still active.
         EnterCriticalSection(&m_tlslock);
         for (tlsit = m_tlsset->begin(); tlsit != m_tlsset->end(); ++tlsit) {
@@ -361,33 +423,29 @@ VisualLeakDetector::~VisualLeakDetector ()
                 continue;
             }
 
-            sleepcount = 0;
-            thread = OpenThread(THREAD_QUERY_INFORMATION, FALSE, (*tlsit)->threadid);
+            thread = OpenThread(SYNCHRONIZE | THREAD_QUERY_INFORMATION, FALSE, (*tlsit)->threadid);
             if (thread == NULL) {
                 // Couldn't query this thread. We'll assume that it exited.
                 continue; // XXX should we check GetLastError()?
             }
-            while (GetExitCodeThread(thread, &exitcode) == TRUE) {
-                if (exitcode != STILL_ACTIVE) {
-                    // This thread exited.
-                    break;
-                }
-                else {
-                    // There is still at least one other thread running. The CRT
-                    // will stomp it dead when it cleans up, which is not a
-                    // graceful way for a thread to go down. Warn about this,
-                    // and wait until the thread has exited so that we know it
-                    // can't still be off running somewhere in VLD's code.
-                    threadsactive = TRUE;
-                    Sleep(100);
-                    sleepcount++;
-                    if ((sleepcount % 100) == 0) {
-                        // Just in case this takes a long time, let the human
-                        // know we are still here and alive.
-                        report(L"Visual Leak Detector: Waiting for threads to terminate...\n");
-                    }
-                }
+            if (GetProcessIdOfThread(thread) != dwCurProcessID) {
+                //The thread ID has been recycled.
+                CloseHandle(thread);
+                continue;
+            }
+            while (WaitForSingleObject(thread, 10000) == WAIT_TIMEOUT) { // 10 seconds
+                // There is still at least one other thread running. The CRT
+                // will stomp it dead when it cleans up, which is not a
+                // graceful way for a thread to go down. Warn about this,
+                // and wait until the thread has exited so that we know it
+                // can't still be off running somewhere in VLD's code.
+                // 
+                // Since we've been waiting a while, let the human know we are
+                // still here and alive.
+                threadsactive = TRUE;
+                report(L"Visual Leak Detector: Waiting for threads to terminate...\n");
             }
+            CloseHandle(thread);
         }
         LeaveCriticalSection(&m_tlslock);
 
@@ -508,768 +566,1057 @@ VisualLeakDetector::~VisualLeakDetector ()
     }
 }
 
-// _CoGetMalloc - Calls to CoGetMalloc are patched through to this function.
-//   This function returns a pointer to Visual Leak Detector's implementation
-//   of the IMalloc interface, instead of returning a pointer to the system
-//   implementation. This allows VLD's implementation of the IMalloc interface
-//   (which is basically a thin wrapper around the system implementation) to be
-//   invoked in place of the system implementation.
+
+////////////////////////////////////////////////////////////////////////////////
 //
-//  - context (IN): Reserved; value must be 1.
+// Private Leak Detection Functions
 //
-//  - imalloc (IN): Address of a pointer to receive the address of VLD's
-//      implementation of the IMalloc interface.
+////////////////////////////////////////////////////////////////////////////////
+
+// attachtoloadedmodules - Attaches VLD to all modules contained in the provided
+//   ModuleSet. Not all modules are in the ModuleSet will actually be included
+//   in leak detection. Only modules that import the global VisualLeakDetector
+//   class object, or those that are otherwise explicitly included in leak
+//   detection, will be checked for memory leaks.
+//
+//   When VLD attaches to a module, it means that any of the imports listed in
+//   the import patch table which are imported by the module, will be redirected
+//   to VLD's designated replacements.
+//
+//  - newmodules (IN): Pointer to a ModuleSet containing information about any
+//      loaded modules that need to be attached.
 //
 //  Return Value:
 //
-//    Always returns S_OK.
+//    None.
 //
-HRESULT VisualLeakDetector::_CoGetMalloc (DWORD context, LPMALLOC *imalloc)
+VOID VisualLeakDetector::attachtoloadedmodules (ModuleSet *newmodules)
 {
-    HMODULE ole32;
+    size_t                count;
+    DWORD64               modulebase;
+    UINT32                moduleflags;
+    IMAGEHLP_MODULE64     moduleimageinfo;
+    LPCSTR                modulename;
+#define MAXMODULENAME (_MAX_FNAME + _MAX_EXT)
+    WCHAR                 modulenamew [MAXMODULENAME];
+    LPCSTR                modulepath;
+    DWORD                 modulesize;
+    ModuleSet::Iterator   newit;
+    ModuleSet::Iterator   oldit;
+    ModuleSet            *oldmodules;
+    BOOL                  refresh;
+    UINT                  tablesize = sizeof(m_patchtable) / sizeof(patchentry_t);
+    ModuleSet::Muterator  updateit;
 
-    *imalloc = (LPMALLOC)&vld;
+    // Iterate through the supplied set, until all modules have been attached.
+    for (newit = newmodules->begin(); newit != newmodules->end(); ++newit) {
+        modulebase  = (DWORD64)(*newit).addrlow;
+        moduleflags = 0x0;
+        modulename  = (*newit).name;
+        modulepath  = (*newit).path;
+        modulesize  = (DWORD)((*newit).addrhigh - (*newit).addrlow) + 1;
 
-    if (pCoGetMalloc == NULL) {
-        // This is the first call to this function. Link to the real
-        // CoGetMalloc and get a pointer to the system implementation of the
-        // IMalloc interface.
-        ole32 = GetModuleHandle(L"ole32.dll");
-        pCoGetMalloc = (CoGetMalloc_t)GetProcAddress(ole32, "CoGetMalloc");
-        pCoGetMalloc(context, &vld.m_imalloc);
-    }
+        refresh = FALSE;
+        EnterCriticalSection(&m_moduleslock);
+        oldmodules = m_loadedmodules;
+        if (oldmodules != NULL) {
+            // This is not the first time we have been called to attach to the
+            // currently loaded modules.
+            oldit = oldmodules->find(*newit);
+            if (oldit != oldmodules->end()) {
+                // We've seen this "new" module loaded in the process before.
+                moduleflags = (*oldit).flags;
+                LeaveCriticalSection(&m_moduleslock);
+                if (moduleispatched((HMODULE)modulebase, m_patchtable, tablesize)) {
+                    // This module is already attached. Just update the module's
+                    // flags, nothing more.
+                    updateit = newit;
+                    (*updateit).flags = moduleflags;
+                    continue;
+                }
+                else {
+                    // This module may have been attached before and has been
+                    // detached. We'll need to try reattaching to it in case it
+                    // was unloaded and then subsequently reloaded.
+                    refresh = TRUE;
+                }
+            }
+            else {
+                LeaveCriticalSection(&m_moduleslock);
+            }
+        }
+        else {
+            LeaveCriticalSection(&m_moduleslock);
+        }
 
-    return S_OK;
-}
+        EnterCriticalSection(&symbollock);
+        if ((refresh == TRUE) && (moduleflags & VLD_MODULE_SYMBOLSLOADED)) {
+            // Discard the previously loaded symbols, so we can refresh them.
+            if (SymUnloadModule64(currentprocess, modulebase) == FALSE) {
+                report(L"WARNING: Visual Leak Detector: Failed to unload the symbols for %s. Function names and line"
+                       L" numbers shown in the memory leak report for %s may be inaccurate.", modulename, modulename);
+            }
+        }
 
-// _CoTaskMemAlloc - Calls to CoTaskMemAlloc are patched through to this
-//   function. This function is just a wrapper around the real CoTaskMemAlloc
-//   that sets appropriate flags to be consulted when the memory is actually
-//   allocated by RtlAllocateHeap.
-//
-//  - size (IN): Size of the memory block to allocate.
-//
-//  Return Value:
-//
-//    Returns the value returned from CoTaskMemAlloc.
-//
-LPVOID VisualLeakDetector::_CoTaskMemAlloc (ULONG size)
-{
-    LPVOID   block;
-    SIZE_T   fp;
-    HMODULE  ole32;
-    tls_t   *tls = vld.gettls();
+        // Try to load the module's symbols. This ensures that we have loaded
+        // the symbols for every module that has ever been loaded into the
+        // process, guaranteeing the symbols' availability when generating the
+        // leak report.
+        moduleimageinfo.SizeOfStruct = sizeof(IMAGEHLP_MODULE64);
+        if ((SymGetModuleInfoW64(currentprocess, (DWORD64)modulebase, &moduleimageinfo) == TRUE) ||
+            ((SymLoadModule64(currentprocess, NULL, modulepath, NULL, modulebase, modulesize) == modulebase) &&
+            (SymGetModuleInfoW64(currentprocess, modulebase, &moduleimageinfo) == TRUE))) {
+            moduleflags |= VLD_MODULE_SYMBOLSLOADED;
+        }
+        LeaveCriticalSection(&symbollock);
 
-    if (tls->addrfp == 0x0) {
-        // This is the first call to enter VLD for the current allocation.
-        // Record the current frame pointer.
-        FRAMEPOINTER(fp);
-        tls->addrfp = fp;
-    }
+        if (_stricmp("vld.dll", modulename) == 0) {
+            // What happens when a module goes through it's own portal? Bad things.
+            // Like infinite recursion. And ugly bald men wearing dresses. VLD
+            // should not, therefore, attach to itself.
+            continue;
+        }
 
-    if (pCoTaskMemAlloc == NULL) {
-        // This is the first call to this function. Link to the real
-        // CoTaskMemAlloc.
-        ole32 = GetModuleHandle(L"ole32.dll");
-        pCoTaskMemAlloc = (CoTaskMemAlloc_t)GetProcAddress(ole32, "CoTaskMemAlloc");
-    }
+        mbstowcs_s(&count, modulenamew, MAXMODULENAME, modulename, _TRUNCATE);
+        if ((findimport((HMODULE)modulebase, m_vldbase, "vld.dll", "?vld@@3VVisualLeakDetector@@A") == FALSE) &&
+            (wcsstr(vld.m_forcedmodulelist, modulenamew) == NULL)) {
+            // This module does not import VLD. This means that none of the module's
+            // sources #included vld.h. Exclude this module from leak detection.
+            moduleflags |= VLD_MODULE_EXCLUDED;
+        }
+        else if (!(moduleflags & VLD_MODULE_SYMBOLSLOADED) || (moduleimageinfo.SymType == SymExport)) {
+            // This module is going to be included in leak detection, but complete
+            // symbols for this module couldn't be loaded. This means that any stack
+            // traces through this module may lack information, like line numbers
+            // and function names.
+            report(L"WARNING: Visual Leak Detector: A module, %s, included in memory leak detection\n"
+                   L"  does not have any debugging symbols available, or they could not be located.\n"
+                   L"  Function names and/or line numbers for this module may not be available.\n", modulename);
+        }
 
-    // Do the allocation. The block will be mapped by _RtlAllocateHeap.
-    block = pCoTaskMemAlloc(size);
+        // Update the module's flags in the "new modules" set.
+        updateit = newit;
+        (*updateit).flags = moduleflags;
 
-    // Reset thread local flags and variables for the next allocation.
-    tls->addrfp = 0x0;
-    tls->flags &= ~VLD_TLS_CRTALLOC;
-    
-    return block;
+        // Attach to the module.
+        patchmodule((HMODULE)modulebase, m_patchtable, tablesize);
+    }
 }
 
-// _CoTaskMemRealloc - Calls to CoTaskMemRealloc are patched through to this
-//   function. This function is just a wrapper around the real CoTaskMemRealloc
-//   that sets appropriate flags to be consulted when the memory is actually
-//   allocated by RtlAllocateHeap.
-//
-//  - mem (IN): Pointer to the memory block to reallocate.
-//
-//  - size (IN): Size, in bytes, of the block to reallocate.
+// buildsymbolsearchpath - Builds the symbol search path for the symbol handler.
+//   This helps the symbol handler find the symbols for the application being
+//   debugged.
 //
 //  Return Value:
 //
-//    Returns the value returned from CoTaskMemRealloc.
+//    Returns a string containing the search path. The caller is responsible for
+//    freeing the string.
 //
-LPVOID VisualLeakDetector::_CoTaskMemRealloc (LPVOID mem, ULONG size)
+LPWSTR VisualLeakDetector::buildsymbolsearchpath ()
 {
-    LPVOID   block;
-    SIZE_T   fp;
-    HMODULE  ole32;
-    tls_t   *tls = vld.gettls();
+    WCHAR   directory [_MAX_DIR];
+    WCHAR   drive [_MAX_DRIVE];
+    LPWSTR  env;
+    DWORD   envlen;
+    SIZE_T  index;
+    SIZE_T  length;
+    HMODULE module;
+    LPWSTR  path = new WCHAR [MAX_PATH];
+    SIZE_T  pos = 0;
+    WCHAR   system [MAX_PATH];
+    WCHAR   windows [MAX_PATH];
 
-    if (tls->addrfp == 0x0) {
-        // This is the first call to enter VLD for the current allocation.
-        // Record the current frame pointer.
-        FRAMEPOINTER(fp);
-        tls->addrfp = fp;
-    }
+    // Oddly, the symbol handler ignores the link to the PDB embedded in the
+    // executable image. So, we'll manually add the location of the executable
+    // to the search path since that is often where the PDB will be located.
+    path[0] = L'\0';
+    module = GetModuleHandle(NULL);
+    GetModuleFileName(module, path, MAX_PATH);
+    _wsplitpath_s(path, drive, _MAX_DRIVE, directory, _MAX_DIR, NULL, 0, NULL, 0);
+    wcsncpy_s(path, MAX_PATH, drive, _TRUNCATE);
+    strapp(&path, directory);
 
-    if (pCoTaskMemRealloc == NULL) {
-        // This is the first call to this function. Link to the real
-        // CoTaskMemRealloc.
-        ole32 = GetModuleHandle(L"ole32.dll");
-        pCoTaskMemRealloc = (CoTaskMemRealloc_t)GetProcAddress(ole32, "CoTaskMemRealloc");
-    }
+    // When the symbol handler is given a custom symbol search path, it will no
+    // longer search the default directories (working directory, system root,
+    // etc). But we'd like it to still search those directories, so we'll add
+    // them to our custom search path.
+    //
+    // Append the working directory.
+    strapp(&path, L";.\\");
 
-    // Do the allocation. The block will be mapped by _RtlReAllocateHeap.
-    block = pCoTaskMemRealloc(mem, size);
+    // Append the Windows directory.
+    if (GetWindowsDirectory(windows, MAX_PATH) != 0) {
+        strapp(&path, L";");
+        strapp(&path, windows);
+    }
 
-    // Reset thread local flags and variables for the next allocation.
-    tls->addrfp = 0x0;
-    tls->flags &= ~VLD_TLS_CRTALLOC;
+    // Append the system directory.
+    if (GetSystemDirectory(system, MAX_PATH) != 0) {
+        strapp(&path, L";");
+        strapp(&path, system);
+    }
 
-    return block;
+    // Append %_NT_SYMBOL_PATH%.
+    envlen = GetEnvironmentVariable(L"_NT_SYMBOL_PATH", NULL, 0);
+    if (envlen != 0) {
+        env = new WCHAR [envlen];
+        if (GetEnvironmentVariable(L"_NT_SYMBOL_PATH", env, envlen) != 0) {
+            strapp(&path, L";");
+            strapp(&path, env);
+        }
+        delete [] env;
+    }
+
+    //  Append %_NT_ALT_SYMBOL_PATH%.
+    envlen = GetEnvironmentVariable(L"_NT_ALT_SYMBOL_PATH", NULL, 0);
+    if (envlen != 0) {
+        env = new WCHAR [envlen];
+        if (GetEnvironmentVariable(L"_NT_ALT_SYMBOL_PATH", env, envlen) != 0) {
+            strapp(&path, L";");
+            strapp(&path, env);
+        }
+        delete [] env;
+    }
+
+    // Remove any quotes from the path. The symbol handler doesn't like them.
+    pos = 0;
+    length = wcslen(path);
+    while (pos < length) {
+        if (path[pos] == L'\"') {
+            for (index = pos; index < length; index++) {
+                path[index] = path[index + 1];
+            }
+        }
+        pos++;
+    }
+
+    return path;
 }
 
-// _crt80d__calloc_dbg - Calls to _calloc_dbg from msvcr80d.dll are patched
-//   through to this function. This function is just a wrapper around the real
-//   _calloc_dbg that sets appropriate flags to be consulted when the memory is
-//   actually allocated by RtlAllocateHeap.
-//
-//  - size (IN): The size, in bytes, of the memory block to be allocated.
-//
-//  - type (IN): The CRT "use type" of the block to be allocated.
-//
-//  - file (IN): The name of the file from which this function is being called.
-//
-//  - line (IN): The line number, in the above file, at which this function is
-//      being called.
+// configure - Configures VLD using values read from the vld.ini file.
 //
 //  Return Value:
 //
-//    Returns the value returned by _calloc_dbg.
+//    None.
 //
-void* VisualLeakDetector::_crt80d__calloc_dbg (size_t num, size_t size, int type, const char *file, int line)
+VOID VisualLeakDetector::configure ()
 {
-    void    *block;
-    SIZE_T   fp;
-    HMODULE  msvcr80d;
-    tls_t   *tls = vld.gettls();
-
-    // _malloc_dbg is a CRT function and allocates from the CRT heap.
-    tls->flags |= VLD_TLS_CRTALLOC;
+#define BSIZE 64
+    WCHAR        buffer [BSIZE];
+    WCHAR        filename [MAX_PATH];
+    WCHAR        inipath [MAX_PATH];
+    BOOL         keyopen = FALSE;
+    DWORD        length;
+    HKEY         productkey;
+    LONG         regstatus;
+    struct _stat s;
+    DWORD        valuetype;
 
-    if (tls->addrfp == 0x0) {
-        // This is the first call to enter VLD for the current allocation.
-        // Record the current frame pointer.
-        FRAMEPOINTER(fp);
-        tls->addrfp = fp;
+    if (_wstat(L".\\vld.ini", &s) == 0) {
+        // Found a copy of vld.ini in the working directory. Use it.
+        wcsncpy_s(inipath, MAX_PATH, L".\\vld.ini", _TRUNCATE);
     }
-
-    if (pcrt80d__calloc_dbg == NULL) {
-        // This is the first call to this function. Link to the real
-        // _malloc_dbg.
-        msvcr80d = GetModuleHandle(L"msvcr80d.dll");
-        pcrt80d__calloc_dbg = (_calloc_dbg_t)GetProcAddress(msvcr80d, "_calloc_dbg");
+    else {
+        // Get the location of the vld.ini file from the registry.
+        regstatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE, VLDREGKEYPRODUCT, 0, KEY_QUERY_VALUE, &productkey);
+        if (regstatus == ERROR_SUCCESS) {
+            keyopen = TRUE;
+            regstatus = RegQueryValueEx(productkey, L"IniFile", NULL, &valuetype, (LPBYTE)&inipath, &length);
+        }
+        if (keyopen) {
+            RegCloseKey(productkey);
+        }
+        if ((regstatus != ERROR_SUCCESS) || (_wstat(inipath, &s) != 0)) {
+            // The location of vld.ini could not be read from the registry. As a
+            // last resort, look in the Windows directory.
+            wcsncpy_s(inipath, MAX_PATH, L"vld.ini", _TRUNCATE);
+        }
     }
 
-    // Do the allocation. The block will be mapped by _RtlAllocateHeap.
-    block = pcrt80d__calloc_dbg(num, size, type, file, line);
+    // Read the boolean options.
+    GetPrivateProfileString(L"Options", L"VLD", L"on", buffer, BSIZE, inipath);
+    if (strtobool(buffer) == FALSE) {
+        m_options |= VLD_OPT_VLDOFF;
+        return;
+    }
 
-    // Reset thread local flags and variables for the next allocation.
-    tls->addrfp = 0x0;
-    tls->flags &= ~VLD_TLS_CRTALLOC;
+    GetPrivateProfileString(L"Options", L"AggregateDuplicates", L"", buffer, BSIZE, inipath);
+    if (strtobool(buffer) == TRUE) {
+        m_options |= VLD_OPT_AGGREGATE_DUPLICATES;
+    }
 
-    return block;
-}
+    GetPrivateProfileString(L"Options", L"SelfTest", L"", buffer, BSIZE, inipath);
+    if (strtobool(buffer) == TRUE) {
+        m_options |= VLD_OPT_SELF_TEST;
+    }
 
-// _crt80d__malloc_dbg - Calls to _malloc_dbg from msvcr80d.dll are patched
-//   through to this function. This function is just a wrapper around the real
-//   _malloc_dbg that sets appropriate flags to be consulted when the memory is
-//   actually allocated by RtlAllocateHeap.
-//
-//  - size (IN): The size, in bytes, of the memory block to be allocated.
-//
-//  - type (IN): The CRT "use type" of the block to be allocated.
-//
-//  - file (IN): The name of the file from which this function is being called.
-//
-//  - line (IN): The line number, in the above file, at which this function is
-//      being called.
-//
-//  Return Value:
-//
-//    Returns the value returned by _malloc_dbg.
-//
-void* VisualLeakDetector::_crt80d__malloc_dbg (size_t size, int type, const char *file, int line)
-{
-    void    *block;
-    SIZE_T   fp;
-    HMODULE  msvcr80d;
-    tls_t   *tls = vld.gettls();
+    GetPrivateProfileString(L"Options", L"SlowDebuggerDump", L"", buffer, BSIZE, inipath);
+    if (strtobool(buffer) == TRUE) {
+        m_options |= VLD_OPT_SLOW_DEBUGGER_DUMP;
+    }
 
-    // _malloc_dbg is a CRT function and allocates from the CRT heap.
-    tls->flags |= VLD_TLS_CRTALLOC;
+    GetPrivateProfileString(L"Options", L"StartDisabled", L"", buffer, BSIZE, inipath);
+    if (strtobool(buffer) == TRUE) {
+        m_options |= VLD_OPT_START_DISABLED;
+    }
 
-    if (tls->addrfp == 0x0) {
-        // This is the first call to enter VLD for the current allocation.
-        // Record the current frame pointer.
-        FRAMEPOINTER(fp);
-        tls->addrfp = fp;
+    GetPrivateProfileString(L"Options", L"TraceInternalFrames", L"", buffer, BSIZE, inipath);
+    if (strtobool(buffer) == TRUE) {
+        m_options |= VLD_OPT_TRACE_INTERNAL_FRAMES;
     }
 
-    if (pcrt80d__malloc_dbg == NULL) {
-        // This is the first call to this function. Link to the real
-        // _malloc_dbg.
-        msvcr80d = GetModuleHandle(L"msvcr80d.dll");
-        pcrt80d__malloc_dbg = (_malloc_dbg_t)GetProcAddress(msvcr80d, "_malloc_dbg");
+    // Read the integer configuration options.
+    m_maxdatadump = GetPrivateProfileInt(L"Options", L"MaxDataDump", VLD_DEFAULT_MAX_DATA_DUMP, inipath);
+    m_maxtraceframes = GetPrivateProfileInt(L"Options", L"MaxTraceFrames", VLD_DEFAULT_MAX_TRACE_FRAMES, inipath);
+    if (m_maxtraceframes < 1) {
+        m_maxtraceframes = VLD_DEFAULT_MAX_TRACE_FRAMES;
     }
 
-    // Do the allocation. The block will be mapped by _RtlAllocateHeap.
-    block = pcrt80d__malloc_dbg(size, type, file, line);
+    // Read the force-include module list.
+    GetPrivateProfileString(L"Options", L"ForceIncludeModules", L"", m_forcedmodulelist, MAXMODULELISTLENGTH, inipath);
+    _wcslwr_s(m_forcedmodulelist, MAXMODULELISTLENGTH);
 
-    // Reset thread local flags and variables for the next allocation.
-    tls->addrfp = 0x0;
-    tls->flags &= ~VLD_TLS_CRTALLOC;
+    // Read the report destination (debugger, file, or both).
+    GetPrivateProfileString(L"Options", L"ReportFile", L"", filename, MAX_PATH, inipath);
+    if (wcslen(filename) == 0) {
+        wcsncpy_s(filename, MAX_PATH, VLD_DEFAULT_REPORT_FILE_NAME, _TRUNCATE);
+    }
+    _wfullpath(m_reportfilepath, filename, MAX_PATH);
+    GetPrivateProfileString(L"Options", L"ReportTo", L"", buffer, BSIZE, inipath);
+    if (_wcsicmp(buffer, L"both") == 0) {
+        m_options |= (VLD_OPT_REPORT_TO_DEBUGGER | VLD_OPT_REPORT_TO_FILE);
+    }
+    else if (_wcsicmp(buffer, L"file") == 0) {
+        m_options |= VLD_OPT_REPORT_TO_FILE;
+    }
+    else {
+        m_options |= VLD_OPT_REPORT_TO_DEBUGGER;
+    }
 
-    return block;
+    // Read the report file encoding (ascii or unicode).
+    GetPrivateProfileString(L"Options", L"ReportEncoding", L"", buffer, BSIZE, inipath);
+    if (_wcsicmp(buffer, L"unicode") == 0) {
+        m_options |= VLD_OPT_UNICODE_REPORT;
+    }
+    if ((m_options & VLD_OPT_UNICODE_REPORT) && !(m_options & VLD_OPT_REPORT_TO_FILE)) {
+        // If Unicode report encoding is enabled, then the report needs to be
+        // sent to a file because the debugger will not display Unicode
+        // characters, it will display question marks in their place instead.
+        m_options |= VLD_OPT_REPORT_TO_FILE;
+        m_status |= VLD_STATUS_FORCE_REPORT_TO_FILE;
+    }
+
+    // Read the stack walking method.
+    GetPrivateProfileString(L"Options", L"StackWalkMethod", L"", buffer, BSIZE, inipath);
+    if (_wcsicmp(buffer, L"safe") == 0) {
+        m_options |= VLD_OPT_SAFE_STACK_WALK;
+    }
 }
 
-// _crt80d__realloc_dbg - Calls to _realloc_dbg from msvcr80d.dll are patched
-//   through to this function. This function is just a wrapper around the real
-//   _realloc_dbg that sets appropriate flags to be consulted when the memory is
-//   actually allocated by RtlAllocateHeap.
-//
-//  - mem (IN): Pointer to the memory block to be reallocated.
-//
-//  - size (IN): The size of the memory block to reallocate.
-//
-//  - type (IN): The CRT "use type" of the block to be reallocated.
-//
-//  - file (IN): The name of the file from which this function is being called.
-//
-//  - line (IN): The line number, in the above filel, at which this function is
-//      being called.
+// enabled - Determines if memory leak detection is enabled for the current
+//   thread.
 //
 //  Return Value:
 //
-//    Returns the value returned by _realloc_dbg.
+//    Returns true if Visual Leak Detector is enabled for the current thread.
+//    Otherwise, returns false.
 //
-void* VisualLeakDetector::_crt80d__realloc_dbg (void *mem, size_t size, int type, const char *file, int line)
+BOOL VisualLeakDetector::enabled ()
 {
-    void    *block;
-    SIZE_T   fp;
-    HMODULE  msvcr80d;
-    tls_t   *tls = vld.gettls();
-
-    // _realloc_dbg is a CRT function and allocates from the CRT heap.
-    tls->flags |= VLD_TLS_CRTALLOC;
+    tls_t *tls = vld.gettls();
 
-    if (tls->addrfp == 0x0) {
-        // This is the first call to enter VLD for the current allocation.
-        // Record the current frame pointer.
-        FRAMEPOINTER(fp);
-        tls->addrfp = fp;
+    if (!(m_status & VLD_STATUS_INSTALLED)) {
+        // Memory leak detection is not yet enabled because VLD is still
+        // initializing.
+        return FALSE;
     }
 
-    if (pcrt80d__realloc_dbg == NULL) {
-        // This is the first call to this function. Link to the real
-        // _realloc_dbg.
-        msvcr80d = GetModuleHandle(L"msvcr80d.dll");
-        pcrt80d__realloc_dbg = (_realloc_dbg_t)GetProcAddress(msvcr80d, "_realloc_dbg");
+    if (!(tls->flags & VLD_TLS_DISABLED) && !(tls->flags & VLD_TLS_ENABLED)) {
+        // The enabled/disabled state for the current thread has not been 
+        // initialized yet. Use the default state.
+        if (m_options & VLD_OPT_START_DISABLED) {
+            tls->flags |= VLD_TLS_DISABLED;
+        }
+        else {
+            tls->flags |= VLD_TLS_ENABLED;
+        }
     }
 
-    // Do the allocation. The block will be mapped by _RtlReAllocateHeap.
-    block = pcrt80d__realloc_dbg(mem, size, type, file, line);
-
-    // Reset thread local flags and variables for the next allocation.
-    tls->addrfp = 0x0;
-    tls->flags &= ~VLD_TLS_CRTALLOC;
-
-    return block;
+    return ((tls->flags & VLD_TLS_ENABLED) != 0);
 }
 
-// _crt80d__scalar_new_dbg - Calls to the CRT's debug scalar new operator from
-//   msvcr80d.dll are patched through to this function. This function is just a
-//   wrapper around the real CRT debug scalar new operator that sets appropriate
-//   flags to be consulted when the memory is actually allocated by
-//   RtlAllocateHeap.
+// eraseduplicates - Erases, from the block maps, blocks that appear to be
+//   duplicate leaks of an already identified leak.
 //
-//  - size (IN): The size, in bytes, of the memory block to be allocated.
-//
-//  - type (IN): The CRT "use type" of the block to be allocated.
-//
-//  - file (IN): The name of the file from which this function is being called.
-//
-//  - line (IN): The line number, in the above file, at which this function is
-//      being called.
+//  - element (IN): BlockMap Iterator referencing the block of which to search
+//      for duplicates.
 //
 //  Return Value:
 //
-//    Returns the value returned by the CRT debug scalar new operator.
+//    Returns the number of duplicate blocks erased from the block map.
 //
-void* VisualLeakDetector::_crt80d__scalar_new_dbg (unsigned int size, int type, const char *file, int line)
+SIZE_T VisualLeakDetector::eraseduplicates (const BlockMap::Iterator &element)
 {
-    void    *block;
-    SIZE_T   fp;
-    HMODULE  msvcr80d;
-    tls_t   *tls = vld.gettls();
-
-    // The debug new operator is a CRT function and allocates from the CRT heap.
-    tls->flags |= VLD_TLS_CRTALLOC;
+    BlockMap::Iterator  blockit;
+    BlockMap           *blockmap;
+    blockinfo_t        *elementinfo;
+    SIZE_T              erased = 0;
+    HeapMap::Iterator   heapit;
+    blockinfo_t        *info;
+    BlockMap::Iterator  previt;
 
-    if (tls->addrfp == 0x0) {
-        // This is the first call to enter VLD for the current allocation.
-        // Record the current frame pointer.
-        FRAMEPOINTER(fp);
-        tls->addrfp = fp;
-    }
+    elementinfo = (*element).second;
 
-    if (pcrt80d__scalar_new_dbg == NULL) {
-        // This is the first call to this function. Link to the real CRT debug
-        // new operator.
-        msvcr80d = GetModuleHandle(L"msvcr80d.dll");
-        pcrt80d__scalar_new_dbg = (crt_new_dbg_t)GetProcAddress(msvcr80d, "??2@YAPAXIHPBDH@Z");
+    // Iteratate through all block maps, looking for blocks with the same size
+    // and callstack as the specified element.
+    for (heapit = m_heapmap->begin(); heapit != m_heapmap->end(); ++heapit) {
+        blockmap = &(*heapit).second->blockmap;
+        for (blockit = blockmap->begin(); blockit != blockmap->end(); ++blockit) {
+            if (blockit == element) {
+                // Don't delete the element of which we are searching for
+                // duplicates.
+                continue;
+            }
+            info = (*blockit).second;
+            if ((info->size == elementinfo->size) && (*(info->callstack) == *(elementinfo->callstack))) {
+                // Found a duplicate. Erase it.
+                delete info->callstack;
+                delete info;
+                previt = blockit - 1;
+                blockmap->erase(blockit);
+                blockit = previt;
+                erased++;
+            }
+        }
     }
 
-    // Do the allocation. The block will be mapped by _RtlAllocateHeap.
-    block = pcrt80d__scalar_new_dbg(size, type, file, line);
-
-    // Reset thread local flags and variables for the next allocation.
-    tls->addrfp = 0x0;
-    tls->flags &= ~VLD_TLS_CRTALLOC;
-
-    return block;
+    return erased;
 }
 
-// _crt80d__vector_new_dbg - Calls to the CRT's debug vector new operator from
-//   msvcr80d.dll are patched through to this function. This function is just a
-//   wrapper around the real CRT debug vector new operator that sets appropriate
-//   flags to be consulted when the memory is actually allocated by
-//   RtlAllocateHeap.
-//
-//  - size (IN): The size, in bytes, of the memory block to be allocated.
-//
-//  - type (IN): The CRT "use type" of the block to be allocated.
-//
-//  - file (IN): The name of the file from which this function is being called.
-//
-//  - line (IN): The line number, in the above file, at which this function is
-//      being called.
+// gettls - Obtains the thread local storage structure for the calling thread.
 //
 //  Return Value:
 //
-//    Returns the value returned by the CRT debug vector new operator.
+//    Returns a pointer to the thread local storage structure. (This function
+//    always succeeds).
 //
-void* VisualLeakDetector::_crt80d__vector_new_dbg (unsigned int size, int type, const char *file, int line)
+tls_t* VisualLeakDetector::gettls ()
 {
-    void    *block;
-    SIZE_T   fp;
-    HMODULE  msvcr80d;
-    tls_t   *tls = vld.gettls();
-
-    // The debug new operator is a CRT function and allocates from the CRT heap.
-    tls->flags |= VLD_TLS_CRTALLOC;
+    tls_t *tls;
+    
+    // Get the pointer to this thread's thread local storage structure.
+    tls = (tls_t*)TlsGetValue(m_tlsindex);
+    assert(GetLastError() == ERROR_SUCCESS);
 
-    if (tls->addrfp == 0x0) {
-        // This is the first call to enter VLD for the current allocation.
-        // Record the current frame pointer.
-        FRAMEPOINTER(fp);
-        tls->addrfp = fp;
-    }
+    if (tls == NULL) {
+        // This thread's thread local storage structure has not been allocated.
+        tls = new tls_t;
+        TlsSetValue(m_tlsindex, tls);
+        tls->addrfp = 0x0;
+        tls->flags = 0x0;
+        tls->threadid = GetCurrentThreadId();
 
-    if (pcrt80d__vector_new_dbg == NULL) {
-        // This is the first call to this function. Link to the real CRT debug
-        // new operator.
-        msvcr80d = GetModuleHandle(L"msvcr80d.dll");
-        pcrt80d__vector_new_dbg = (crt_new_dbg_t)GetProcAddress(msvcr80d, "??_U@YAPAXIHPBDH@Z");
+        // Add this thread's TLS to the TlsSet.
+        EnterCriticalSection(&m_tlslock);
+        m_tlsset->insert(tls);
+        LeaveCriticalSection(&m_tlslock);
     }
 
-    // Do the allocation. The block will be mapped by _RtlAllocateHeap.
-    block = pcrt80d__vector_new_dbg(size, type, file, line);
-
-    // Reset thread local flags and variables for the next allocation.
-    tls->addrfp = 0x0;
-    tls->flags &= ~VLD_TLS_CRTALLOC;
-
-    return block;
+    return tls;
 }
 
-// _crt80d_calloc - Calls to calloc from msvcr80d.dll are patched through to
-//   this function. This function is just a wrapper around the real calloc that
-//   sets appropriate flags to be consulted when the memory is actually
-//   allocated by RtlAllocateHeap.
+// mapblock - Tracks memory allocations. Information about allocated blocks is
+//   collected and then the block is mapped to this information.
 //
-//  - num (IN): The number of blocks, of size 'size', to be allocated.
+//  - heap (IN): Handle to the heap from which the block has been allocated.
 //
-//  - size (IN): The size, in bytes, of the memory block to be allocated.
+//  - mem (IN): Pointer to the memory block being allocated.
+//
+//  - size (IN): Size, in bytes, of the memory block being allocated.
+//
+//  - framepointer (IN): Framepointer at the time this allocation first entered
+//      VLD's code. This is used from determining the starting point for the
+//      stack trace.
+//
+//  - crtalloc (IN): Should be set to TRUE if this allocation is a CRT memory
+//      block. Otherwise should be FALSE.
 //
 //  Return Value:
 //
-//    Returns the valued returned from calloc.
+//    None.
 //
-void* VisualLeakDetector::_crt80d_calloc (size_t num, size_t size)
+VOID VisualLeakDetector::mapblock (HANDLE heap, LPCVOID mem, SIZE_T size, SIZE_T framepointer, BOOL crtalloc)
 {
-    void    *block;
-    SIZE_T   fp;
-    HMODULE  msvcr80d;
-    tls_t   *tls = vld.gettls();
-
-    // malloc is a CRT function and allocates from the CRT heap.
-    tls->flags |= VLD_TLS_CRTALLOC;
+    blockinfo_t        *blockinfo;
+    BlockMap::Iterator  blockit;
+    BlockMap           *blockmap;
+    HeapMap::Iterator   heapit;
+    static SIZE_T       serialnumber = 0;
 
-    if (tls->addrfp == 0x0) {
-        // This is the first call to enter VLD for the current allocation.
-        // Record the current frame pointer.
-        FRAMEPOINTER(fp);
-        tls->addrfp = fp;
+    // Record the block's information.
+    blockinfo = new blockinfo_t;
+    if (m_options & VLD_OPT_SAFE_STACK_WALK) {
+        blockinfo->callstack = new SafeCallStack;
     }
-
-    if (pcrt80d_calloc == NULL) {
-        // This is the first call to this function. Link to the real malloc.
-        msvcr80d = GetModuleHandle(L"msvcr80d.dll");
-        pcrt80d_calloc = (calloc_t)GetProcAddress(msvcr80d, "calloc");
+    else {
+        blockinfo->callstack = new FastCallStack;
     }
+    if (m_options & VLD_OPT_TRACE_INTERNAL_FRAMES) {
+        // Passing NULL for the frame pointer argument will force the stack
+        // trace to begin at the current frame.
+        blockinfo->callstack->getstacktrace(m_maxtraceframes, NULL);
+    }
+    else {
+        // Start the stack trace at the call that first entered VLD's code.
+        blockinfo->callstack->getstacktrace(m_maxtraceframes, (SIZE_T*)framepointer);
+    }
+    blockinfo->serialnumber = serialnumber++;
+    blockinfo->size = size;
 
-    // Do the allocation. The block will be mapped by _RtlAllocateHeap.
-    block = pcrt80d_calloc(num, size);
-
-    // Reset thread local flags and variables for the next allocation.
-    tls->addrfp = 0x0;
-    tls->flags &= ~VLD_TLS_CRTALLOC;
-
-    return block;
+    // Insert the block's information into the block map.
+    EnterCriticalSection(&m_maplock);
+    heapit = m_heapmap->find(heap);
+    if (heapit == m_heapmap->end()) {
+        // We haven't mapped this heap to a block map yet. Do it now.
+        mapheap(heap);
+        heapit = m_heapmap->find(heap);
+        assert(heapit != m_heapmap->end());
+    }
+    if (crtalloc == TRUE) {
+        // The heap that this block was allocated from is a CRT heap.
+        (*heapit).second->flags |= VLD_HEAP_CRT;
+    }
+    blockmap = &(*heapit).second->blockmap;
+    blockit = blockmap->insert(mem, blockinfo);
+    if (blockit == blockmap->end()) {
+        // A block with this address has already been allocated. The
+        // previously allocated block must have been freed (probably by some
+        // mechanism unknown to VLD), or the heap wouldn't have allocated it
+        // again. Replace the previously allocated info with the new info.
+        blockit = blockmap->find(mem);
+        delete (*blockit).second->callstack;
+        delete (*blockit).second;
+        blockmap->erase(blockit);
+        blockmap->insert(mem, blockinfo);
+    }
+    LeaveCriticalSection(&m_maplock);
 }
 
-// _crt80d_malloc - Calls to malloc from msvcr80d.dll are patched through to
-//   this function. This function is just a wrapper around the real malloc that
-//   sets appropriate flags to be consulted when the memory is actually
-//   allocated by RtlAllocateHeap.
+// mapheap - Tracks heap creation. Creates a block map for tracking individual
+//   allocations from the newly created heap and then maps the heap to this
+//   block map.
 //
-//  - size (IN): The size, in bytes, of the memory block to be allocated.
+//  - heap (IN): Handle to the newly created heap.
 //
 //  Return Value:
 //
-//    Returns the valued returned from malloc.
+//    None.
 //
-void* VisualLeakDetector::_crt80d_malloc (size_t size)
+VOID VisualLeakDetector::mapheap (HANDLE heap)
 {
-    void    *block;
-    SIZE_T   fp;
-    HMODULE  msvcr80d;
-    tls_t   *tls = vld.gettls();
-
-    // malloc is a CRT function and allocates from the CRT heap.
-    tls->flags |= VLD_TLS_CRTALLOC;
-
-    if (tls->addrfp == 0x0) {
-        // This is the first call to enter VLD for the current allocation.
-        // Record the current frame pointer.
-        FRAMEPOINTER(fp);
-        tls->addrfp = fp;
-    }
+    heapinfo_t        *heapinfo;
+    HeapMap::Iterator  heapit;
 
-    if (pcrt80d_malloc == NULL) {
-        // This is the first call to this function. Link to the real malloc.
-        msvcr80d = GetModuleHandle(L"msvcr80d.dll");
-        pcrt80d_malloc = (malloc_t)GetProcAddress(msvcr80d, "malloc");
+    // Create a new block map for this heap and insert it into the heap map.
+    heapinfo = new heapinfo_t;
+    heapinfo->blockmap.reserve(BLOCKMAPRESERVE);
+    heapinfo->flags = 0x0;
+    EnterCriticalSection(&m_maplock);
+    heapit = m_heapmap->insert(heap, heapinfo);
+    if (heapit == m_heapmap->end()) {
+        // Somehow this heap has been created twice without being destroyed,
+        // or at least it was destroyed without VLD's knowledge. Unmap the heap
+        // from the existing heapinfo, and remap it to the new one.
+        report(L"WARNING: Visual Leak Detector detected a duplicate heap (" ADDRESSFORMAT L").\n", heap);
+        heapit = m_heapmap->find(heap);
+        unmapheap((*heapit).first);
+        m_heapmap->insert(heap, heapinfo);
     }
-
-    // Do the allocation. The block will be mapped by _RtlAllocateHeap.
-    block = pcrt80d_malloc(size);
-
-    // Reset thread local flags and variables for the next allocation.
-    tls->addrfp = 0x0;
-    tls->flags &= ~VLD_TLS_CRTALLOC;
-
-    return block;
+    LeaveCriticalSection(&m_maplock);
 }
 
-// _crt80d_realloc - Calls to realloc from msvcr80d.dll are patched through to
-//   this function. This function is just a wrapper around the real realloc that
-//   sets appropriate flags to be consulted when the memory is actually
-//   allocated by RtlAllocateHeap.
+// remapblock - Tracks reallocations. Unmaps a block from its previously
+//   collected information and remaps it to updated information.
 //
-//  - mem (IN): Pointer to the memory block to reallocate.
+//  Note: If the block itself remains at the same address, then the block's
+//   information can simply be updated rather than having to actually erase and
+//   reinsert the block.
 //
-//  - size (IN): Size of the memory block to reallocate.
+//  - heap (IN): Handle to the heap from which the memory is being reallocated.
 //
-//  Return Value:
+//  - mem (IN): Pointer to the memory block being reallocated.
 //
-//    Returns the value returned from realloc.
+//  - newmem (IN): Pointer to the memory block being returned to the caller
+//      that requested the reallocation. This pointer may or may not be the same
+//      as the original memory block (as pointed to by "mem").
 //
-void* VisualLeakDetector::_crt80d_realloc (void *mem, size_t size)
+//  - size (IN): Size, in bytes, of the new memory block.
+//
+//  - framepointer (IN): The frame pointer at which this reallocation entered
+//      VLD's code. Used for determining the starting point of the stack trace.
+//
+//  - crtalloc (IN): Should be set to TRUE if this reallocation is for a CRT
+//      memory block. Otherwise should be set to FALSE.
+//
+//  Return Value:
+//
+//    None.
+//
+VOID VisualLeakDetector::remapblock (HANDLE heap, LPCVOID mem, LPCVOID newmem, SIZE_T size, SIZE_T framepointer,
+                                     BOOL crtalloc)
 {
-    void    *block;
-    SIZE_T   fp;
-    HMODULE  msvcr80d;
-    tls_t   *tls = vld.gettls();
-
-    // realloc is a CRT function and allocates from the CRT heap.
-    tls->flags |= VLD_TLS_CRTALLOC;
+    BlockMap::Iterator   blockit;
+    BlockMap            *blockmap;
+    HeapMap::Iterator    heapit;
+    blockinfo_t         *info;
 
-    if (tls->addrfp == 0x0) {
-        // This is the first call to enter VLD for the current allocation.
-        // Record the current frame pointer.
-        FRAMEPOINTER(fp);
-        tls->addrfp = fp;
+    if (newmem != mem) {
+        // The block was not reallocated in-place. Instead the old block was
+        // freed and a new block allocated to satisfy the new size.
+        unmapblock(heap, mem);
+        mapblock(heap, newmem, size, framepointer, crtalloc);
+        return;
     }
 
-    if (pcrt80d_realloc == NULL) {
-        // This is the first call to this function. Link to the real realloc.
-        msvcr80d = GetModuleHandle(L"msvcr80d.dll");
-        pcrt80d_realloc = (realloc_t)GetProcAddress(msvcr80d, "realloc");
+    // The block was reallocated in-place. Find the existing blockinfo_t
+    // entry in the block map and update it with the new callstack and size.
+    EnterCriticalSection(&m_maplock);
+    heapit = m_heapmap->find(heap);
+    if (heapit == m_heapmap->end()) {
+        // We haven't mapped this heap to a block map yet. Obviously the
+        // block has also not been mapped to a blockinfo_t entry yet either,
+        // so treat this reallocation as a brand-new allocation (this will
+        // also map the heap to a new block map).
+        mapblock(heap, newmem, size, framepointer, crtalloc);
+        LeaveCriticalSection(&m_maplock);
+        return;
     }
 
-    // Do the allocation. The block will be mapped by _RtlReAllocateHeap.
-    block = pcrt80d_realloc(mem, size);
+    // Find the block's blockinfo_t structure so that we can update it.
+    blockmap = &(*heapit).second->blockmap;
+    blockit = blockmap->find(mem);
+    if (blockit == blockmap->end()) {
+        // The block hasn't been mapped to a blockinfo_t entry yet.
+        // Treat this reallocation as a new allocation.
+        mapblock(heap, newmem, size, framepointer, crtalloc);
+        LeaveCriticalSection(&m_maplock);
+        return;
+    }
 
-    // Reset thread local flags and variables for the next allocation.
-    tls->addrfp = 0x0;
-    tls->flags &= ~VLD_TLS_CRTALLOC;
+    // Found the blockinfo_t entry for this block. Update it with
+    // a new callstack and new size.
+    info = (*blockit).second;
+    info->callstack->clear();
+    if (crtalloc) {
+        // The heap that this block was allocated from is a CRT heap.
+        (*heapit).second->flags |= VLD_HEAP_CRT;
+    }
+    LeaveCriticalSection(&m_maplock);
 
-    return block;
+    // Update the block's callstack and size.
+    if (m_options & VLD_OPT_TRACE_INTERNAL_FRAMES) {
+        // Passing NULL for the frame pointer argument will force
+        // the stack trace to begin at the current frame.
+        info->callstack->getstacktrace(m_maxtraceframes, NULL);
+    }
+    else {
+        // Start the stack trace at the call that first entered
+        // VLD's code.
+        info->callstack->getstacktrace(m_maxtraceframes, (SIZE_T*)framepointer);
+    }
+    info->size = size;
 }
 
-// _crt80d_scalar_new - Calls to the CRT's scalar new operator from msvcr80d.dll
-//   are patched through to this function. This function is just a wrapper
-//   around the real CRT scalar new operator that sets appropriate flags to be
-//   consulted when the memory is actually allocated by RtlAllocateHeap.
-//
-//  - size (IN): The size, in bytes, of the memory block to be allocated.
+// reportconfig - Generates a brief report summarizing Visual Leak Detector's
+//   configuration, as loaded from the vld.ini file.
 //
 //  Return Value:
 //
-//    Returns the value returned by the CRT scalar new operator.
+//    None.
 //
-void* VisualLeakDetector::_crt80d_scalar_new (unsigned int size)
+VOID VisualLeakDetector::reportconfig ()
 {
-    void    *block;
-    SIZE_T   fp;
-    HMODULE  msvcr80d;
-    tls_t   *tls = vld.gettls();
-
-    // The new operator is a CRT function and allocates from the CRT heap.
-    tls->flags |= VLD_TLS_CRTALLOC;
-
-    if (tls->addrfp == 0x0) {
-        // This is the first call to enter VLD for the current allocation.
-        // Record the current frame pointer.
-        FRAMEPOINTER(fp);
-        tls->addrfp = fp;
+    if (m_options & VLD_OPT_AGGREGATE_DUPLICATES) {
+        report(L"    Aggregating duplicate leaks.\n");
     }
-
-    if (pcrt80d_scalar_new == NULL) {
-        // This is the first call to this function. Link to the real CRT new
-        // operator.
-        msvcr80d = GetModuleHandle(L"msvcr80d.dll");
-        pcrt80d_scalar_new = (new_t)GetProcAddress(msvcr80d, "??2@YAPAXI@Z");
+    if (wcslen(m_forcedmodulelist) != 0) {
+        report(L"    Forcing inclusion of these modules in leak detection: %s\n", m_forcedmodulelist);
+    }
+    if (m_maxdatadump != VLD_DEFAULT_MAX_DATA_DUMP) {
+        if (m_maxdatadump == 0) {
+            report(L"    Suppressing data dumps.\n");
+        }
+        else {
+            report(L"    Limiting data dumps to %lu bytes.\n", m_maxdatadump);
+        }
+    }
+    if (m_maxtraceframes != VLD_DEFAULT_MAX_TRACE_FRAMES) {
+        report(L"    Limiting stack traces to %u frames.\n", m_maxtraceframes);
+    }
+    if (m_options & VLD_OPT_UNICODE_REPORT) {
+        report(L"    Generating a Unicode (UTF-16) encoded report.\n");
+    }
+    if (m_options & VLD_OPT_REPORT_TO_FILE) {
+        if (m_options & VLD_OPT_REPORT_TO_DEBUGGER) {
+            report(L"    Outputting the report to the debugger and to %s\n", m_reportfilepath);
+        }
+        else {
+            report(L"    Outputting the report to %s\n", m_reportfilepath);
+        }
+    }
+    if (m_options & VLD_OPT_SLOW_DEBUGGER_DUMP) {
+        report(L"    Outputting the report to the debugger at a slower rate.\n");
+    }
+    if (m_options & VLD_OPT_SAFE_STACK_WALK) {
+        report(L"    Using the \"safe\" (but slow) stack walking method.\n");
+    }
+    if (m_options & VLD_OPT_SELF_TEST) {
+        report(L"    Perfoming a memory leak self-test.\n");
+    }
+    if (m_options & VLD_OPT_START_DISABLED) {
+        report(L"    Starting with memory leak detection disabled.\n");
+    }
+    if (m_options & VLD_OPT_TRACE_INTERNAL_FRAMES) {
+        report(L"    Including heap and VLD internal frames in stack traces.\n");
     }
-
-    // Do tha allocation. The block will be mapped by _RtlAllocateHeap.
-    block = pcrt80d_scalar_new(size);
-
-    // Reset thread local flags and variables for the next allocation.
-    tls->addrfp = 0x0;
-    tls->flags &= ~VLD_TLS_CRTALLOC;
-
-    return block;
 }
 
-// _crt80d_vector_new - Calls to the CRT's vector new operator from msvcr80d.dll
-//   are patched through to this function. This function is just a wrapper
-//   around the real CRT vector new operator that sets appropriate flags to be
-//   consulted when the memory is actually allocated by RtlAllocateHeap.
+// reportleaks - Generates a memory leak report for the specified heap.
 //
-//  - size (IN): The size, in bytes, of the memory block to be allocated.
+//  - heap (IN): Handle to the heap for which to generate a memory leak
+//      report.
 //
 //  Return Value:
 //
-//    Returns the value returned by the CRT vector new operator.
+//    None.
 //
-void* VisualLeakDetector::_crt80d_vector_new (unsigned int size)
+VOID VisualLeakDetector::reportleaks (HANDLE heap)
 {
-    void    *block;
-    SIZE_T   fp;
-    HMODULE  msvcr80d;
-    tls_t   *tls = vld.gettls();
-
-    // The new operator is a CRT function and allocates from the CRT heap.
-    tls->flags |= VLD_TLS_CRTALLOC;
+    LPCVOID              address;
+    LPCVOID              block;
+    BlockMap::Iterator   blockit;
+    BlockMap            *blockmap;
+    crtdbgblockheader_t *crtheader;
+    SIZE_T               duplicates;
+    heapinfo_t          *heapinfo;
+    HeapMap::Iterator    heapit;
+    blockinfo_t         *info;
+    SIZE_T               size;
 
-    if (tls->addrfp == 0x0) {
-        // This is the first call to enter VLD for the current allocation.
-        // Record the current frame pointer.
-        FRAMEPOINTER(fp);
-        tls->addrfp = fp;
+    // Find the heap's information (blockmap, etc).
+    EnterCriticalSection(&m_maplock);
+    heapit = m_heapmap->find(heap);
+    if (heapit == m_heapmap->end()) {
+        // Nothing is allocated from this heap. No leaks.
+        LeaveCriticalSection(&m_maplock);
+        return;
     }
 
-    if (pcrt80d_vector_new == NULL) {
-        // This is the first call to this function. Link to the real CRT new
-        // operator.
-        msvcr80d = GetModuleHandle(L"msvcr80d.dll");
-        pcrt80d_vector_new = (new_t)GetProcAddress(msvcr80d, "??_U@YAPAXI@Z");
+    heapinfo = (*heapit).second;
+    blockmap = &heapinfo->blockmap;
+    for (blockit = blockmap->begin(); blockit != blockmap->end(); ++blockit) {
+        // Found a block which is still in the BlockMap. We've identified a
+        // potential memory leak.
+        block = (*blockit).first;
+        info = (*blockit).second;
+        address = block;
+        size = info->size;
+        if (heapinfo->flags & VLD_HEAP_CRT) {
+            // This block is allocated to a CRT heap, so the block has a CRT
+            // memory block header prepended to it.
+            crtheader = (crtdbgblockheader_t*)block;
+            if (CRT_USE_TYPE(crtheader->use) == CRT_USE_INTERNAL) {
+                // This block is marked as being used internally by the CRT.
+                // The CRT will free the block after VLD is destroyed.
+                continue;
+            }
+            // The CRT header is more or less transparent to the user, so
+            // the information about the contained block will probably be
+            // more useful to the user. Accordingly, that's the information
+            // we'll include in the report.
+            address = CRTDBGBLOCKDATA(block);
+            size = crtheader->size;
+        }
+        // It looks like a real memory leak.
+        if (m_leaksfound == 0) {
+            report(L"WARNING: Visual Leak Detector detected memory leaks!\n");
+        }
+        m_leaksfound++;
+        report(L"---------- Block %ld at " ADDRESSFORMAT L": %u bytes ----------\n", info->serialnumber, address, size);
+        if (m_options & VLD_OPT_AGGREGATE_DUPLICATES) {
+            // Aggregate all other leaks which are duplicates of this one
+            // under this same heading, to cut down on clutter.
+            duplicates = eraseduplicates(blockit);
+            if (duplicates) {
+                report(L"A total of %lu leaks match this size and call stack. Showing only the first one.\n",
+                       duplicates + 1);
+                m_leaksfound += duplicates;
+            }
+        }
+        // Dump the call stack.
+        report(L"  Call Stack:\n");
+        info->callstack->dump(m_options & VLD_OPT_TRACE_INTERNAL_FRAMES);
+        // Dump the data in the user data section of the memory block.
+        if (m_maxdatadump != 0) {
+            report(L"  Data:\n");
+            if (m_options & VLD_OPT_UNICODE_REPORT) {
+                dumpmemoryw(address, (m_maxdatadump < size) ? m_maxdatadump : size);
+            }
+            else {
+                dumpmemorya(address, (m_maxdatadump < size) ? m_maxdatadump : size);
+            }
+        }
+        report(L"\n");
     }
 
-    // Do tha allocation. The block will be mapped by _RtlAllocateHeap.
-    block = pcrt80d_vector_new(size);
-
-    // Reset thread local flags and variables for the next allocation.
-    tls->addrfp = 0x0;
-    tls->flags &= ~VLD_TLS_CRTALLOC;
-
-    return block;
+    LeaveCriticalSection(&m_maplock);
 }
 
-// _crtd__calloc_dbg - Calls to _calloc_dbg from msvcrtd.dll are patched through
-//   to this function. This function is just a wrapper around the real
-//   _calloc_dbg that sets appropriate flags to be consulted when the memory is
-//   actually allocated by RtlAllocateHeap.
+// unmapblock - Tracks memory blocks that are freed. Unmaps the specified block
+//   from the block's information, relinquishing internally allocated resources.
 //
-//  - num (IN): The number of blocks, of size 'size', to be allocated.
+//  - heap (IN): Handle to the heap to which this block is being freed.
 //
-//  - size (IN): The size, in bytes, of the memory block to be allocated.
+//  - mem (IN): Pointer to the memory block being freed.
 //
-//  - type (IN): The CRT "use type" of the block to be allocated.
+//  Return Value:
 //
-//  - file (IN): The name of the file from which this function is being called.
+//    None.
 //
-//  - line (IN): The line number, in the above file, at which this function is
-//      being called.
+VOID VisualLeakDetector::unmapblock (HANDLE heap, LPCVOID mem)
+{
+    BlockMap::Iterator  blockit;
+    BlockMap           *blockmap;
+    HeapMap::Iterator   heapit;
+    blockinfo_t        *info;
+
+    // Find this heap's block map.
+    EnterCriticalSection(&m_maplock);
+    heapit = m_heapmap->find(heap);
+    if (heapit == m_heapmap->end()) {
+        // We don't have a block map for this heap. We must not have monitored
+        // this allocation (probably happened before VLD was initialized).
+        LeaveCriticalSection(&m_maplock);
+        return;
+    }
+
+    // Find this block in the block map.
+    blockmap = &(*heapit).second->blockmap;
+    blockit = blockmap->find(mem);
+    if (blockit == blockmap->end()) {
+        // This block is not in the block map. We must not have monitored this
+        // allocation (probably happened before VLD was initialized).
+        LeaveCriticalSection(&m_maplock);
+        return;
+    }
+
+    // Free the blockinfo_t structure and erase it from the block map.
+    info = (*blockit).second;
+    delete info->callstack;
+    delete info;
+    blockmap->erase(blockit);
+    LeaveCriticalSection(&m_maplock);
+}
+
+// unmapheap - Tracks heap destruction. Unmaps the specified heap from its block
+//   map. The block map is cleared and deleted, relinquishing internally
+//   allocated resources.
+//
+//  - heap (IN): Handle to the heap which is being destroyed.
 //
 //  Return Value:
 //
-//    Returns the value returned by _calloc_dbg.
+//    None.
 //
-void* VisualLeakDetector::_crtd__calloc_dbg (size_t num, size_t size, int type, const char *file, int line)
+VOID VisualLeakDetector::unmapheap (HANDLE heap)
 {
-    void    *block;
-    SIZE_T   fp;
-    HMODULE  msvcrtd;
-    tls_t   *tls = vld.gettls();
-
-    // _malloc_dbg is a CRT function and allocates from the CRT heap.
-    tls->flags |= VLD_TLS_CRTALLOC;
+    BlockMap::Iterator  blockit;
+    BlockMap           *blockmap;
+    heapinfo_t         *heapinfo;
+    HeapMap::Iterator   heapit;
 
-    if (tls->addrfp == 0x0) {
-        // This is the first call to enter VLD for the current allocation.
-        // Record the current frame pointer.
-        FRAMEPOINTER(fp);
-        tls->addrfp = fp;
+    // Find this heap's block map.
+    EnterCriticalSection(&m_maplock);
+    heapit = m_heapmap->find(heap);
+    if (heapit == m_heapmap->end()) {
+        // This heap hasn't been mapped. We must not have monitored this heap's
+        // creation (probably happened before VLD was initialized).
+        LeaveCriticalSection(&m_maplock);
+        return;
     }
 
-    if (pcrtd__calloc_dbg == NULL) {
-        // This is the first call to this function. Link to the real
-        // _malloc_dbg.
-        msvcrtd = GetModuleHandle(L"msvcrtd.dll");
-        pcrtd__calloc_dbg = (_calloc_dbg_t)GetProcAddress(msvcrtd, "_calloc_dbg");
+    // Free all of the blockinfo_t structures stored in the block map.
+    heapinfo = (*heapit).second;
+    blockmap = &heapinfo->blockmap;
+    for (blockit = blockmap->begin(); blockit != blockmap->end(); ++blockit) {
+        delete (*blockit).second->callstack;
+        delete (*blockit).second;
     }
+    delete heapinfo;
 
-    // Do the allocation. The block will be mapped by _RtlAllocateHeap.
-    block = pcrtd__calloc_dbg(num, size, type, file, line);
+    // Remove this heap's block map from the heap map.
+    m_heapmap->erase(heapit);
+    LeaveCriticalSection(&m_maplock);
+}
 
-    // Reset thread local flags and variables for the next allocation.
-    tls->addrfp = 0x0;
-    tls->flags &= ~VLD_TLS_CRTALLOC;
 
-    return block;
-}
+////////////////////////////////////////////////////////////////////////////////
+//
+// Static Leak Detection Functions (Callbacks)
+//
+////////////////////////////////////////////////////////////////////////////////
 
-// _crtd__malloc_dbg - Calls to _malloc_dbg from msvcrtd.dll are patched through
-//   to this function. This function is just a wrapper around the real
-//   _malloc_dbg that sets appropriate flags to be consulted when the memory is
-//   actually allocated by RtlAllocateHeap.
+// addloadedmodule - Callback function for EnumerateLoadedModules64. This
+//   function records information about every module loaded in the process,
+//   each time adding the module's information to the provided ModuleSet (the
+//   "context" parameter).
 //
-//  - size (IN): The size, in bytes, of the memory block to be allocated.
+//   When EnumerateLoadedModules64 has finished calling this function for each
+//   loaded module, then the resulting ModuleSet can be used at any time to get
+//   information about any modules loaded into the process.
 //
-//  - type (IN): The CRT "use type" of the block to be allocated.
+//   - modulepath (IN): The fully qualified path from where the module was
+//       loaded.
 //
-//  - file (IN): The name of the file from which this function is being called.
+//   - modulebase (IN): The base address at which the module has been loaded.
 //
-//  - line (IN): The line number, in the above file, at which this function is
-//      being called.
+//   - modulesize (IN): The size, in bytes, of the loaded module.
+//
+//   - context (IN): Pointer to the ModuleSet to which information about each
+//       module is to be added.
 //
 //  Return Value:
 //
-//    Returns the value returned by _malloc_dbg.
+//    Always returns TRUE, which tells EnumerateLoadedModules64 to continue
+//    enumerating.
 //
-void* VisualLeakDetector::_crtd__malloc_dbg (size_t size, int type, const char *file, int line)
+BOOL VisualLeakDetector::addloadedmodule (PCWSTR modulepath, DWORD64 modulebase, ULONG modulesize, PVOID context)
 {
-    void    *block;
-    SIZE_T   fp;
-    HMODULE  msvcrtd;
-    tls_t   *tls = vld.gettls();
+    size_t        count;
+    patchentry_t *entry;
+    CHAR          extension [_MAX_EXT];
+    CHAR          filename [_MAX_FNAME];
+    UINT          index;
+    moduleinfo_t  moduleinfo;
+    LPSTR         modulenamea;
+    LPSTR         modulepatha;
+    ModuleSet*    newmodules = (ModuleSet*)context;
+    SIZE_T        size;
+    UINT          tablesize = sizeof(m_patchtable) / sizeof(patchentry_t);
 
-    // _malloc_dbg is a CRT function and allocates from the CRT heap.
-    tls->flags |= VLD_TLS_CRTALLOC;
+    // Convert the module path to ASCII.
+    size = wcslen(modulepath) + 1;
+    modulepatha = new CHAR [size];
+    wcstombs_s(&count, modulepatha, size, modulepath, _TRUNCATE);
 
-    if (tls->addrfp == 0x0) {
-        // This is the first call to enter VLD for the current allocation.
-        // Record the current frame pointer.
-        FRAMEPOINTER(fp);
-        tls->addrfp = fp;
-    }
+    // Extract just the filename and extension from the module path.
+    _splitpath_s(modulepatha, NULL, 0, NULL, 0, filename, _MAX_FNAME, extension, _MAX_EXT);
+    size = strlen(filename) + strlen(extension) + 1;
+    modulenamea = new CHAR [size];
+    strncpy_s(modulenamea, size, filename, _TRUNCATE);
+    strncat_s(modulenamea, size, extension, _TRUNCATE);
+    _strlwr_s(modulenamea, size);
 
-    if (pcrtd__malloc_dbg == NULL) {
-        // This is the first call to this function. Link to the real
-        // _malloc_dbg.
-        msvcrtd = GetModuleHandle(L"msvcrtd.dll");
-        pcrtd__malloc_dbg = (_malloc_dbg_t)GetProcAddress(msvcrtd, "_malloc_dbg");
+    if (_stricmp(modulenamea, "vld.dll") == 0) {
+        // Record Visual Leak Detector's own base address.
+        vld.m_vldbase = (HMODULE)modulebase;
+    }
+    else {
+        // See if this is a module listed in the patch table. If it is, update
+        // the corresponding patch table entries' module base address.
+        for (index = 0; index < tablesize; index++) {
+            entry = &m_patchtable[index];
+            if (_stricmp(entry->exportmodulename, modulenamea) == 0) {
+                entry->modulebase = (SIZE_T)modulebase;
+            }
+        }
     }
 
-    // Do the allocation. The block will be mapped by _RtlAllocateHeap.
-    block = pcrtd__malloc_dbg(size, type, file, line);
+    // Record the module's information and store it in the set.
+    moduleinfo.addrlow  = (SIZE_T)modulebase;
+    moduleinfo.addrhigh = (SIZE_T)(modulebase + modulesize) - 1;
+    moduleinfo.flags    = 0x0;
+    moduleinfo.name     = modulenamea;
+    moduleinfo.path     = modulepatha;
+    newmodules->insert(moduleinfo);
 
-    // Reset thread local flags and variables for the next allocation.
-    tls->addrfp = 0x0;
-    tls->flags &= ~VLD_TLS_CRTALLOC;
+    return TRUE;
+}
 
-    return block;
+// detachfrommodule - Callback function for EnumerateLoadedModules64 that
+//   detaches Visual Leak Detector from the specified module. If the specified
+//   module has not previously been attached to, then calling this function will
+//   not actually result in any changes.
+//
+//  - modulepath (IN): String containing the name, which may include a path, of
+//      the module to detach from (ignored).
+//
+//  - modulebase (IN): Base address of the module.
+//
+//  - modulesize (IN): Total size of the module (ignored).
+//
+//  - context (IN): User-supplied context (ignored).
+//
+//  Return Value:
+//
+//    Always returns TRUE.
+//
+BOOL VisualLeakDetector::detachfrommodule (PCWSTR /*modulepath*/, DWORD64 modulebase, ULONG /*modulesize*/,
+                                           PVOID /*context*/)
+{
+    UINT tablesize = sizeof(m_patchtable) / sizeof(patchentry_t);
+
+    restoremodule((HMODULE)modulebase, m_patchtable, tablesize);
+
+    return TRUE;
 }
 
-// _crtd__realloc_dbg - Calls to _realloc_dbg from msvcrtd.dll are patched
-//   through to this function. This function is just a wrapper around the real
-//   _realloc_dbg that sets appropriate flags to be consulted when the memory is
-//   actually allocated by RtlAllocateHeap.
+
+////////////////////////////////////////////////////////////////////////////////
 //
-//  - mem (IN): Pointer to the memory block to be reallocated.
+// Standard CRT and MFC IAT Replacement Functions
 //
-//  - size (IN): The size of the memory block to reallocate.
+// The addresses of these functions are not actually directly patched into the
+// import address tables, but these functions do get indirectly called by the
+// patch functions that are placed in the import address tables.
 //
-//  - type (IN): The CRT "use type" of the block to be reallocated.
+////////////////////////////////////////////////////////////////////////////////
+
+// _calloc - This function is just a wrapper around the real calloc that sets
+//   appropriate flags to be consulted when the memory is actually allocated by
+//   RtlAllocateHeap.
 //
-//  - file (IN): The name of the file from which this function is being called.
+//  - pcalloc (IN): Pointer to the particular calloc implementation to call.
 //
-//  - line (IN): The line number, in the above filel, at which this function is
-//      being called.
+//  - fp (IN): Frame pointer from the call that initiated this allocation.
+//
+//  - num (IN): The number of blocks, of size 'size', to be allocated.
+//
+//  - size (IN): The size, in bytes, of the memory block to be allocated.
 //
 //  Return Value:
 //
-//    Returns the value returned by _realloc_dbg.
+//    Returns the value returned from the specified calloc.
 //
-void* VisualLeakDetector::_crtd__realloc_dbg (void *mem, size_t size, int type, const char *file, int line)
+void* VisualLeakDetector::_calloc (calloc_t pcalloc,
+                                   SIZE_T   fp,
+                                   size_t   num,
+                                   size_t   size)
 {
-    void    *block;
-    SIZE_T   fp;
-    HMODULE  msvcrtd;
-    tls_t   *tls = vld.gettls();
+    void  *block;
+    tls_t *tls = vld.gettls();
 
-    // _realloc_dbg is a CRT function and allocates from the CRT heap.
+    // malloc is a CRT function and allocates from the CRT heap.
     tls->flags |= VLD_TLS_CRTALLOC;
 
     if (tls->addrfp == 0x0) {
         // This is the first call to enter VLD for the current allocation.
         // Record the current frame pointer.
-        FRAMEPOINTER(fp);
         tls->addrfp = fp;
     }
 
-    if (pcrtd__realloc_dbg == NULL) {
-        // This is the first call to this function. Link to the real
-        // _realloc_dbg.
-        msvcrtd = GetModuleHandle(L"msvcrtd.dll");
-        pcrtd__realloc_dbg = (_realloc_dbg_t)GetProcAddress(msvcrtd, "_realloc_dbg");
-    }
-
-    // Do the allocation. The block will be mapped by _RtlReAllocateHeap.
-    block = pcrtd__realloc_dbg(mem, size, type, file, line);
+    // Do the allocation. The block will be mapped by _RtlAllocateHeap.
+    block = pcalloc(num, size);
 
     // Reset thread local flags and variables for the next allocation.
     tls->addrfp = 0x0;
@@ -1278,51 +1625,36 @@ void* VisualLeakDetector::_crtd__realloc_dbg (void *mem, size_t size, int type,
     return block;
 }
 
-// _crtd__scalar_new_dbg - Calls to the CRT's debug scalar new operator from
-//   msvcrtd.dll are patched through to this function. This function is just a
-//   wrapper around the real CRT debug scalar new operator that sets appropriate
-//   flags to be consulted when the memory is actually allocated by
+// _malloc - This function is just a wrapper around the real malloc that sets
+//   appropriate flags to be consulted when the memory is actually allocated by
 //   RtlAllocateHeap.
 //
-//  - size (IN): The size, in bytes, of the memory block to be allocated.
-//
-//  - type (IN): The CRT "use type" of the block to be allocated.
+//  - pmalloc (IN): Pointer to the particular malloc implementation to call.
 //
-//  - file (IN): The name of the file from which this function is being called.
+//  - fp (IN): Frame pointer from the call that initiated this allocation.
 //
-//  - line (IN): The line number, in the above file, at which this function is
-//      being called.
+//  - size (IN): The size, in bytes, of the memory block to be allocated.
 //
 //  Return Value:
 //
-//    Returns the value returned by the CRT debug scalar new operator.
+//    Returns the value returned from the specified malloc.
 //
-void* VisualLeakDetector::_crtd__scalar_new_dbg (unsigned int size, int type, const char *file, int line)
+void *VisualLeakDetector::_malloc (malloc_t pmalloc, SIZE_T fp, size_t size)
 {
     void    *block;
-    SIZE_T   fp;
-    HMODULE  msvcrtd;
     tls_t   *tls = vld.gettls();
 
-    // The debug new operator is a CRT function and allocates from the CRT heap.
+    // malloc is a CRT function and allocates from the CRT heap.
     tls->flags |= VLD_TLS_CRTALLOC;
 
     if (tls->addrfp == 0x0) {
         // This is the first call to enter VLD for the current allocation.
         // Record the current frame pointer.
-        FRAMEPOINTER(fp);
         tls->addrfp = fp;
     }
 
-    if (pcrtd__scalar_new_dbg == NULL) {
-        // This is the first call to this function. Link to the real CRT debug
-        // new operator.
-        msvcrtd = GetModuleHandle(L"msvcrtd.dll");
-        pcrtd__scalar_new_dbg = (crt_new_dbg_t)GetProcAddress(msvcrtd, "??2@YAPAXIHPBDH@Z");
-    }
-
     // Do the allocation. The block will be mapped by _RtlAllocateHeap.
-    block = pcrtd__scalar_new_dbg(size, type, file, line);
+    block = pmalloc(size);
 
     // Reset thread local flags and variables for the next allocation.
     tls->addrfp = 0x0;
@@ -1331,44 +1663,36 @@ void* VisualLeakDetector::_crtd__scalar_new_dbg (unsigned int size, int type, co
     return block;
 }
 
-// _crtd_calloc - Calls to calloc from msvcrtd.dll are patched through to this
-//   function. This function is just a wrapper around the real calloc that sets
-//   appropriate flags to be consulted when the memory is actually allocated by
-//   RtlAllocateHeap.
+// _new - This function is just a wrapper around the real CRT and MFC new
+//   operators that sets appropriate flags to be consulted when the memory is
+//   actually allocated by RtlAllocateHeap.
 //
-//  - num (IN): The number of blocks, of size 'size', to be allocated.
+//  - pnew (IN): Pointer to the particular new implementation to call.
+//
+//  - fp (IN): Frame pointer from the call that initiated this allocation.
 //
 //  - size (IN): The size, in bytes, of the memory block to be allocated.
 //
 //  Return Value:
 //
-//    Returns the valued returned from calloc.
+//    Returns the value returned by the specified CRT new operator.
 //
-void* VisualLeakDetector::_crtd_calloc (size_t num, size_t size)
+void* VisualLeakDetector::_new (new_t pnew, SIZE_T fp, size_t size)
 {
-    void    *block;
-    SIZE_T   fp;
-    HMODULE  msvcrtd;
-    tls_t   *tls = vld.gettls();
+    void  *block;
+    tls_t *tls = vld.gettls();
 
-    // malloc is a CRT function and allocates from the CRT heap.
+    // The new operator is a CRT function and allocates from the CRT heap.
     tls->flags |= VLD_TLS_CRTALLOC;
 
     if (tls->addrfp == 0x0) {
         // This is the first call to enter VLD for the current allocation.
         // Record the current frame pointer.
-        FRAMEPOINTER(fp);
         tls->addrfp = fp;
     }
 
-    if (pcrtd_calloc == NULL) {
-        // This is the first call to this function. Link to the real malloc.
-        msvcrtd = GetModuleHandle(L"msvcrtd.dll");
-        pcrtd_calloc = (calloc_t)GetProcAddress(msvcrtd, "calloc");
-    }
-
     // Do the allocation. The block will be mapped by _RtlAllocateHeap.
-    block = pcrtd_calloc(num, size);
+    block = pnew(size);
 
     // Reset thread local flags and variables for the next allocation.
     tls->addrfp = 0x0;
@@ -1377,42 +1701,103 @@ void* VisualLeakDetector::_crtd_calloc (size_t num, size_t size)
     return block;
 }
 
-// _crtd_malloc - Calls to malloc from msvcrtd.dll are patched through to this
-//   function. This function is just a wrapper around the real malloc that sets
+// _realloc - This function is just a wrapper around the real realloc that sets
 //   appropriate flags to be consulted when the memory is actually allocated by
 //   RtlAllocateHeap.
 //
-//  - size (IN): The size, in bytes, of the memory block to be allocated.
+//  - prealloc (IN): Pointer to the particular realloc implementation to call.
+//
+//  - fp (IN): Frame pointer from the call that initiated this allocation.
+//
+//  - mem (IN): Pointer to the memory block to reallocate.
+//
+//  - size (IN): Size of the memory block to reallocate.
 //
 //  Return Value:
 //
-//    Returns the valued returned from malloc.
+//    Returns the value returned from the specified realloc.
 //
-void* VisualLeakDetector::_crtd_malloc (size_t size)
+void* VisualLeakDetector::_realloc (realloc_t  prealloc,
+                                    SIZE_T     fp,
+                                    void      *mem,
+                                    size_t     size)
 {
-    void    *block;
-    SIZE_T   fp;
-    HMODULE  msvcrtd;
-    tls_t   *tls = vld.gettls();
+    void  *block;
+    tls_t *tls = vld.gettls();
 
-    // malloc is a CRT function and allocates from the CRT heap.
+    // realloc is a CRT function and allocates from the CRT heap.
     tls->flags |= VLD_TLS_CRTALLOC;
 
     if (tls->addrfp == 0x0) {
         // This is the first call to enter VLD for the current allocation.
         // Record the current frame pointer.
-        FRAMEPOINTER(fp);
         tls->addrfp = fp;
     }
 
-    if (pcrtd_malloc == NULL) {
-        // This is the first call to this function. Link to the real malloc.
-        msvcrtd = GetModuleHandle(L"msvcrtd.dll");
-        pcrtd_malloc = (malloc_t)GetProcAddress(msvcrtd, "malloc");
+    // Do the allocation. The block will be mapped by _RtlReAllocateHeap.
+    block = prealloc(mem, size);
+
+    // Reset thread local flags and variables for the next allocation.
+    tls->addrfp = 0x0;
+    tls->flags &= ~VLD_TLS_CRTALLOC;
+
+    return block;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// Debug CRT and MFC IAT Replacement Functions
+//
+// The addresses of these functions are not actually directly patched into the
+// import address tables, but these functions do get indirectly called by the
+// patch functions that are placed in the import address tables.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+// __calloc_dbg - This function is just a wrapper around the real _calloc_dbg
+//   that sets appropriate flags to be consulted when the memory is actually
+//   allocated by RtlAllocateHeap.
+//
+//  - p_calloc_dbg: Pointer to the particular _calloc_dbg implementation to
+//      call.
+//
+//  - fp (IN): Frame pointer from the call that initiated this allocation.
+//
+//  - size (IN): The size, in bytes, of the memory block to be allocated.
+//
+//  - type (IN): The CRT "use type" of the block to be allocated.
+//
+//  - file (IN): The name of the file from which this function is being called.
+//
+//  - line (IN): The line number, in the above file, at which this function is
+//      being called.
+//
+//  Return Value:
+//
+//    Returns the value returned by the specified _calloc_dbg.
+//
+void* VisualLeakDetector::__calloc_dbg (_calloc_dbg_t  p_calloc_dbg,
+                                        SIZE_T         fp,
+                                        size_t         num,
+                                        size_t         size,
+                                        int            type,
+                                        char const    *file,
+                                        int            line)
+{
+    void  *block;
+    tls_t *tls = vld.gettls();
+
+    // _malloc_dbg is a CRT function and allocates from the CRT heap.
+    tls->flags |= VLD_TLS_CRTALLOC;
+
+    if (tls->addrfp == 0x0) {
+        // This is the first call to enter VLD for the current allocation.
+        // Record the current frame pointer.
+        tls->addrfp = fp;
     }
 
     // Do the allocation. The block will be mapped by _RtlAllocateHeap.
-    block = pcrtd_malloc(size);
+    block = p_calloc_dbg(num, size, type, file, line);
 
     // Reset thread local flags and variables for the next allocation.
     tls->addrfp = 0x0;
@@ -1421,44 +1806,100 @@ void* VisualLeakDetector::_crtd_malloc (size_t size)
     return block;
 }
 
-// _crtd_realloc - Calls to realloc from msvcrtd.dll are patched through to this
-//   function. This function is just a wrapper around the real realloc that sets
-//   appropriate flags to be consulted when the memory is actually allocated by
-//   RtlAllocateHeap.
+// __malloc_dbg - This function is just a wrapper around the real _malloc_dbg
+//   that sets appropriate flags to be consulted when the memory is actually
+//   allocated by RtlAllocateHeap.
 //
-//  - mem (IN): Pointer to the memory block to reallocate.
+//  - p_malloc_dbg (IN): Pointer to the particular _malloc_dbg implementation to
+//      call.
 //
-//  - size (IN): Size of the memory block to reallocate.
+//  - fp (IN): Frame pointer from the call that initiated this allocation.
+//
+//  - size (IN): The size, in bytes, of the memory block to be allocated.
+//
+//  - type (IN): The CRT "use type" of the block to be allocated.
+//
+//  - file (IN): The name of the file from which this function is being called.
+//
+//  - line (IN): The line number, in the above file, at which this function is
+//      being called.
 //
 //  Return Value:
 //
-//    Returns the value returned from realloc.
+//    Returns the value returned by the specified _malloc_dbg.
 //
-void* VisualLeakDetector::_crtd_realloc (void *mem, size_t size)
+void* VisualLeakDetector::__malloc_dbg (_malloc_dbg_t  p_malloc_dbg,
+                                        SIZE_T         fp,
+                                        size_t         size,
+                                        int            type,
+                                        char const    *file,
+                                        int            line)
 {
-    void    *block;
-    SIZE_T   fp;
-    HMODULE  msvcrtd;
-    tls_t   *tls = vld.gettls();
+    void  *block;
+    tls_t *tls = vld.gettls();
 
-    // realloc is a CRT function and allocates from the CRT heap.
+    // _malloc_dbg is a CRT function and allocates from the CRT heap.
     tls->flags |= VLD_TLS_CRTALLOC;
 
     if (tls->addrfp == 0x0) {
         // This is the first call to enter VLD for the current allocation.
         // Record the current frame pointer.
-        FRAMEPOINTER(fp);
         tls->addrfp = fp;
     }
 
-    if (pcrtd_realloc == NULL) {
-        // This is the first call to this function. Link to the real realloc.
-        msvcrtd = GetModuleHandle(L"msvcrtd.dll");
-        pcrtd_realloc = (realloc_t)GetProcAddress(msvcrtd, "realloc");
+    // Do the allocation. The block will be mapped by _RtlAllocateHeap.
+    block = p_malloc_dbg(size, type, file, line);
+
+    // Reset thread local flags and variables for the next allocation.
+    tls->addrfp = 0x0;
+    tls->flags &= ~VLD_TLS_CRTALLOC;
+
+    return block;
+}
+
+// new_dbg_crt - This function is just a wrapper around the real CRT debug new
+//   operators that sets appropriate flags to be consulted when the memory is
+//   actually allocated by RtlAllocateHeap.
+//
+//  - pnew_dbg_crt (IN): Pointer to the particular CRT new operator
+//      implementation to call.
+//
+//  - fp (IN): Frame pointer from the call that initiated this allocation.
+//
+//  - size (IN): The size, in bytes, of the memory block to be allocated.
+//
+//  - type (IN): The CRT "use type" of the block to be allocated.
+//
+//  - file (IN): The name of the file from which this function is being called.
+//
+//  - line (IN): The line number, in the above file, at which this function is
+//      being called.
+//
+//  Return Value:
+//
+//    Returns the value returned by the specified CRT debug new operator.
+//
+void* VisualLeakDetector::new_dbg_crt (new_dbg_crt_t  pnew_dbg_crt,
+                                       SIZE_T         fp,
+                                       size_t         size,
+                                       int            type,
+                                       char const    *file,
+                                       int            line)
+{
+    void  *block;
+    tls_t *tls = vld.gettls();
+
+    // The debug new operator is a CRT function and allocates from the CRT heap.
+    tls->flags |= VLD_TLS_CRTALLOC;
+
+    if (tls->addrfp == 0x0) {
+        // This is the first call to enter VLD for the current allocation.
+        // Record the current frame pointer.
+        tls->addrfp = fp;
     }
 
-    // Do the allocation. The block will be mapped by _RtlReAllocateHeap.
-    block = pcrtd_realloc(mem, size);
+    // Do the allocation. The block will be mapped by _RtlAllocateHeap.
+    block = pnew_dbg_crt(size, type, file, line);
 
     // Reset thread local flags and variables for the next allocation.
     tls->addrfp = 0x0;
@@ -1467,43 +1908,145 @@ void* VisualLeakDetector::_crtd_realloc (void *mem, size_t size)
     return block;
 }
 
-// _crtd_scalar_new - Calls to the CRT's scalar new operator from msvcrtd.dll
-//   are patched through to this function. This function is just a wrapper
-//   around the real CRT scalar new operator that sets appropriate flags to be
-//   consulted when the memory is actually allocated by RtlAllocateHeap.
+// new_dbg_mfc - This function is just a wrapper around the real MFC debug new
+//   operators that sets appropriate flags to be consulted when the memory is
+//   actually allocated by RtlAllocateHeap.
+//
+//  - pnew_dbg (IN): Pointer to the particular CRT new operator
+//      implementation to call.
+//
+//  - fp (IN): Frame pointer from the call that initiated this allocation.
 //
 //  - size (IN): The size, in bytes, of the memory block to be allocated.
 //
+//  - type (IN): The CRT "use type" of the block to be allocated.
+//
+//  - file (IN): The name of the file from which this function is being called.
+//
+//  - line (IN): The line number, in the above file, at which this function is
+//      being called.
+//
 //  Return Value:
 //
-//    Returns the value returned by the CRT scalar new operator.
+//    Returns the value returned by the specified CRT debug new operator.
 //
-void* VisualLeakDetector::_crtd_scalar_new (unsigned int size)
+void* VisualLeakDetector::new_dbg_mfc (new_dbg_crt_t  pnew_dbg,
+                                       SIZE_T         fp,
+                                       size_t         size,
+                                       int            type,
+                                       char const    *file,
+                                       int            line)
 {
-    void    *block;
-    SIZE_T   fp;
-    HMODULE  msvcrtd;
-    tls_t   *tls = vld.gettls();
+    void  *block;
+    tls_t *tls = vld.gettls();
 
-    // The new operator is a CRT function and allocates from the CRT heap.
-    tls->flags |= VLD_TLS_CRTALLOC;
+    if (tls->addrfp == 0x0) {
+        // This is the first call to enter VLD for the current allocation.
+        // Record the current frame pointer.
+        tls->addrfp = fp;
+    }
+
+    // Do the allocation. The block will be mapped by _RtlAllocateHeap.
+    block = pnew_dbg(size, type, file, line);
+
+    // Reset thread local flags and variables for the next allocation.
+    tls->addrfp = 0x0;
+    tls->flags &= ~VLD_TLS_CRTALLOC;
+
+    return block;
+}
+
+// new_dbg_mfc - This function is just a wrapper around the real MFC debug new
+//   operators that sets appropriate flags to be consulted when the memory is
+//   actually allocated by RtlAllocateHeap.
+//
+//  - pnew_dbg_mfc (IN): Pointer to the particular MFC new operator
+//      implementation to call.
+//
+//  - fp (IN): Frame pointer of the call that initiated this allocation.
+//
+//  - size (IN): The size, in bytes, of the memory block to be allocated.
+//
+//  - file (IN): The name of the file from which this function is being called.
+//
+//  - line (IN): The line number, in the above file, at which this function is
+//      being called.
+//
+//  Return Value:
+//
+//    Returns the value returned by the specified MFC debug new operator.
+//
+void* VisualLeakDetector::new_dbg_mfc (new_dbg_mfc_t  pnew_dbg_mfc,
+                                       SIZE_T         fp,
+                                       size_t         size,
+                                       char const    *file,
+                                       int            line)
+{
+    void  *block;
+    tls_t *tls = vld.gettls();
 
     if (tls->addrfp == 0x0) {
         // This is the first call to enter VLD for the current allocation.
         // Record the current frame pointer.
-        FRAMEPOINTER(fp);
         tls->addrfp = fp;
     }
 
-    if (pcrtd_scalar_new == NULL) {
-        // This is the first call to this function. Link to the real CRT new
-        // operator.
-        msvcrtd = GetModuleHandle(L"msvcrtd.dll");
-        pcrtd_scalar_new = (new_t)GetProcAddress(msvcrtd, "??2@YAPAXI@Z");
+    // Do the allocation. The block will be mapped by _RtlAllocateHeap.
+    block = pnew_dbg_mfc(size, file, line);
+
+    // Reset thread local flags and variables for the next allocation.
+    tls->addrfp = 0x0;
+    tls->flags &= ~VLD_TLS_CRTALLOC;
+
+    return block;
+}
+
+// __realloc_debug - This function is just a wrapper around the real
+//   _realloc_dbg that sets appropriate flags to be consulted when the memory is
+//   actually allocated by RtlAllocateHeap.
+//
+//  - p_realloc_dbg (IN): Pointer to the particular __realloc_dbg implementation
+//      to call.
+//
+//  - fp (IN): Frame pointer from the call that initiated this allocation.
+//
+//  - mem (IN): Pointer to the memory block to be reallocated.
+//
+//  - size (IN): The size of the memory block to reallocate.
+//
+//  - type (IN): The CRT "use type" of the block to be reallocated.
+//
+//  - file (IN): The name of the file from which this function is being called.
+//
+//  - line (IN): The line number, in the above file, at which this function is
+//      being called.
+//
+//  Return Value:
+//
+//    Returns the value returned by the specified _realloc_dbg.
+//
+void* VisualLeakDetector::__realloc_dbg (_realloc_dbg_t  p_realloc_dbg,
+                                         SIZE_T          fp,
+                                         void           *mem,
+                                         size_t          size,
+                                         int             type,
+                                         char const     *file,
+                                         int             line)
+{
+    void  *block;
+    tls_t *tls = vld.gettls();
+
+    // _realloc_dbg is a CRT function and allocates from the CRT heap.
+    tls->flags |= VLD_TLS_CRTALLOC;
+
+    if (tls->addrfp == 0x0) {
+        // This is the first call to enter VLD for the current allocation.
+        // Record the current frame pointer.
+        tls->addrfp = fp;
     }
 
-    // Do tha allocation. The block will be mapped by _RtlAllocateHeap.
-    block = pcrtd_scalar_new(size);
+    // Do the allocation. The block will be mapped by _RtlReAllocateHeap.
+    block = p_realloc_dbg(mem, size, type, file, line);
 
     // Reset thread local flags and variables for the next allocation.
     tls->addrfp = 0x0;
@@ -1512,6 +2055,12 @@ void* VisualLeakDetector::_crtd_scalar_new (unsigned int size)
     return block;
 }
 
+////////////////////////////////////////////////////////////////////////////////
+//
+// Win32 IAT Replacement Functions
+//
+////////////////////////////////////////////////////////////////////////////////
+
 // _GetProcAddress - Calls to GetProcAddress are patched through to this
 //   function. If the requested function is a function that has been patched
 //   through to one of VLD's handlers, then the address of VLD's handler
@@ -1555,1427 +2104,494 @@ FARPROC VisualLeakDetector::_GetProcAddress (HMODULE module, LPCSTR procname)
                 return (FARPROC)entry->replacement;
             }
         }
-        else {
-            if (strcmp(entry->importname, procname) == 0) {
-                return (FARPROC)entry->replacement;
-            }
-        }
-    }
-
-    // The requested function is not a patched function. Just return the real
-    // address of the requested function.
-    return GetProcAddress(module, procname);
-}
-
-// _HeapCreate - Calls to HeapCreate are patched through to this function. This
-//   function is just a wrapper around the real HeapCreate that calls VLD's heap
-//   creation tracking function after the heap has been created.
-//
-//  - options (IN): Heap options.
-//
-//  - initsize (IN): Initial size of the heap.
-//
-//  - maxsize (IN): Maximum size of the heap.
-//
-//  Return Value:
-//
-//    Returns the value returned by HeapCreate.
-//
-HANDLE VisualLeakDetector::_HeapCreate (DWORD options, SIZE_T initsize, SIZE_T maxsize)
-{
-    DWORD64            displacement;
-    SIZE_T             fp;
-    SYMBOL_INFO       *functioninfo;
-    HANDLE             heap;
-    HeapMap::Iterator  heapit;
-    SIZE_T             ra;
-    BYTE               symbolbuffer [sizeof(SYMBOL_INFO) + (MAXSYMBOLNAMELENGTH * sizeof(WCHAR)) - 1] = { 0 };
-    BOOL               symfound;
-
-    // Get the return address within the calling function.
-    FRAMEPOINTER(fp);
-    ra = *((SIZE_T*)fp + 1);
-
-    // Create the heap.
-    heap = HeapCreate(options, initsize, maxsize);
-
-    // Map the created heap handle to a new block map.
-    vld.mapheap(heap);
-
-    // Try to get the name of the function containing the return address.
-    functioninfo = (SYMBOL_INFO*)&symbolbuffer;
-    functioninfo->SizeOfStruct = sizeof(SYMBOL_INFO);
-    functioninfo->MaxNameLen = MAXSYMBOLNAMELENGTH;
-    EnterCriticalSection(&symbollock);
-    symfound = SymFromAddrW(currentprocess, ra, &displacement, functioninfo);
-    LeaveCriticalSection(&symbollock);
-    if (symfound == TRUE) {
-        if (wcscmp(L"_heap_init", functioninfo->Name) == 0) {
-            // HeapCreate was called by _heap_init. This is a static CRT heap.
-            EnterCriticalSection(&vld.m_maplock);
-            heapit = vld.m_heapmap->find(heap);
-            assert(heapit != vld.m_heapmap->end());
-            (*heapit).second->flags |= VLD_HEAP_CRT;
-            LeaveCriticalSection(&vld.m_maplock);
-        }
-    }
-
-    return heap;
-}
-
-// _HeapDestroy - Calls to HeapDestroy are patched through to this function.
-//   This function is just a wrapper around the real HeapDestroy that calls
-//   VLD's heap destruction tracking function after the heap has been destroyed.
-//
-//  - heap (IN): Handle to the heap to be destroyed.
-//
-//  Return Value:
-//
-//    Returns the valued returned by HeapDestroy.
-//
-BOOL VisualLeakDetector::_HeapDestroy (HANDLE heap)
-{
-    // After this heap is destroyed, the heap's address space will be unmapped
-    // from the process's address space. So, we'd better generate a leak report
-    // for this heap now, while we can still read from the memory blocks
-    // allocated to it.
-    vld.reportleaks(heap);
-
-    vld.unmapheap(heap);
-
-    return HeapDestroy(heap);
-}
-
-// _LdrLoadDll - Calls to LdrLoadDll are patched through to this function. This
-//   function invokes the real LdrLoadDll and then re-attaches VLD to all
-//   modules loaded in the process after loading of the new DLL is complete.
-//   All modules must be re-enumerated because the explicit load of the
-//   specified module may result in the implicit load of one or more additional
-//   modules which are dependencies of the specified module.
-//
-//  - searchpath (IN): The path to use for searching for the specified module to
-//      be loaded.
-//
-//  - flags (IN): Pointer to action flags.
-//
-//  - modulename (IN): Pointer to a unicodestring_t structure specifying the
-//      name of the module to be loaded.
-//
-//  - modulehandle (OUT): Address of a HANDLE to receive the newly loaded
-//      module's handle.
-//
-//  Return Value:
-//
-//    Returns the value returned by LdrLoadDll.
-//
-NTSTATUS VisualLeakDetector::_LdrLoadDll (LPWSTR searchpath, PDWORD flags, unicodestring_t *modulename,
-                                          PHANDLE modulehandle)
-{
-    ModuleSet::Iterator  moduleit;
-    ModuleSet           *newmodules;
-    ModuleSet           *oldmodules;
-    NTSTATUS             status;
-
-    // Load the DLL.
-    status = LdrLoadDll(searchpath, flags, modulename, modulehandle);
-    
-    if (STATUS_SUCCESS == status) {
-        // Create a new set of all loaded modules, including any newly loaded
-        // modules.
-        newmodules = new ModuleSet;
-        newmodules->reserve(MODULESETRESERVE);
-        EnterCriticalSection(&vld.m_loaderlock);
-        EnumerateLoadedModulesW64(currentprocess, addloadedmodule, newmodules);
-        LeaveCriticalSection(&vld.m_loaderlock);
-
-        // Attach to all modules included in the set.
-        vld.attachtoloadedmodules(newmodules);
-
-        // Start using the new set of loaded modules.
-        EnterCriticalSection(&vld.m_moduleslock);
-        oldmodules = vld.m_loadedmodules;
-        vld.m_loadedmodules = newmodules;
-        LeaveCriticalSection(&vld.m_moduleslock);
-
-        // Free resources used by the old module list.
-        for (moduleit = oldmodules->begin(); moduleit != oldmodules->end(); ++moduleit) {
-            delete (*moduleit).name;
-            delete (*moduleit).path;
-        }
-        delete oldmodules;
-    }
-
-    return status;
-}
-
-// _mfc42d__scalar_new_dbg - Calls to the MFC debug scalar new operator from
-//   mfc42d.dll are patched through to this function. This function is just a
-//   wrapper around the real MFC debug scalar new operator that sets appropriate
-//   flags to be consulted when the memory is actually allocated by
-//   RtlAllocateHeap.
-//
-//  - size (IN): The size, in bytes, of the memory block to be allocated.
-//
-//  - file (IN): The name of the file from which this function is being called.
-//
-//  - line (IN): The line number, in the above file, at which this function is
-//      being called.
-//
-//  Return Value:
-//
-//    Returns the value returned by the MFC debug scalar new operator.
-//
-void* VisualLeakDetector::_mfc42d__scalar_new_dbg (unsigned int size, const char *file, int line)
-{
-    void    *block;
-    SIZE_T   fp;
-    HMODULE  mfc42d;
-    tls_t   *tls = vld.gettls();
-
-    // The MFC new operators are CRT-based and allocate from the CRT heap.
-    tls->flags |= VLD_TLS_CRTALLOC;
-
-    if (tls->addrfp == 0x0) {
-        // This is the first call to enter VLD for the current allocation.
-        // Record the current frame pointer.
-        FRAMEPOINTER(fp);
-        tls->addrfp = fp;
-    }
-
-    if (pmfc42d__scalar_new_dbg == NULL) {
-        // This is the first call to this function. Link to the real MFC debug
-        // new operator.
-        mfc42d = GetModuleHandle(L"mfc42d.dll");
-        pmfc42d__scalar_new_dbg = (mfc_new_dbg_t)GetProcAddress(mfc42d, (LPCSTR)714);
-    }
-
-    // Do the allocation. The block will be mapped by _RtlAllocateHeap.
-    block = pmfc42d__scalar_new_dbg(size, file, line);
-
-    // Reset thread local flags and variables for the next allocation.
-    tls->addrfp = 0x0;
-    tls->flags &= ~VLD_TLS_CRTALLOC;
-
-    return block;
-}
-
-// _mfc42d_scalar_new - Calls to the MFC scalar new operator from mfc42d.dll are
-//   patched through to this function. This function is just a wrapper around
-//   the real MFC scalar new operator that sets appropriate flags to be
-//   consulted when the memory is actually allocated by RtlAllocateHeap.
-//
-//  - size (IN): The size, in bytes, of the memory block to be allocated.
-//
-//  Return Value:
-//
-//    Returns the value returned by the MFC scalar new operator.
-//
-void* VisualLeakDetector::_mfc42d_scalar_new (unsigned int size)
-{
-    void    *block;
-    SIZE_T   fp;
-    HMODULE  mfc42d;
-    tls_t   *tls = vld.gettls();
-
-    // The MFC new operators are CRT-based and allocate from the CRT heap.
-    tls->flags |= VLD_TLS_CRTALLOC;
-
-    if (tls->addrfp == 0x0) {
-        // This is the first call to enter VLD for the current allocation.
-        // Record the current frame pointer.
-        FRAMEPOINTER(fp);
-        tls->addrfp = fp;
-    }
-
-    if (pmfc42d_scalar_new == NULL) {
-        // This is the first call to this function. Link to the real MFC new
-        // operator.
-        mfc42d = GetModuleHandle(L"mfc42d.dll");
-        pmfc42d_scalar_new = (new_t)GetProcAddress(mfc42d, (LPCSTR)711);
-    }
-
-    // Do the allocation. The block will be mapped by _RtlAllocateHeap.
-    block = pmfc42d_scalar_new(size);
-
-    // Reset thread local flags and variables for the next allocation.
-    tls->addrfp = 0x0;
-    tls->flags &= ~VLD_TLS_CRTALLOC;
-
-    return block;
-}
-
-// _mfc80d__scalar_new_dbg - Calls to the MFC debug scalar new operator from
-//   mfc80d.dll are patched through to this function. This function is just a
-//   wrapper around the real MFC debug scalar new operator that sets appropriate
-//   flags to be consulted when the memory is actually allocated by
-//   RtlAllocateHeap.
-//
-//  - size (IN): The size, in bytes, of the memory block to be allocated.
-//
-//  - file (IN): The name of the file from which this function is being called.
-//
-//  - line (IN): The line number, in the above file, at which this function is
-//      being called.
-//
-//  Return Value:
-//
-//    Returns the value returned by the MFC debug scalar new operator.
-//
-void* VisualLeakDetector::_mfc80d__scalar_new_dbg (unsigned int size, const char *file, int line)
-{
-    void    *block;
-    SIZE_T   fp;
-    HMODULE  mfc80d;
-    tls_t   *tls = vld.gettls();
-
-    // The MFC new operators are CRT-based and allocate from the CRT heap.
-    tls->flags |= VLD_TLS_CRTALLOC;
-
-    if (tls->addrfp == 0x0) {
-        // This is the first call to enter VLD for the current allocation.
-        // Record the current frame pointer.
-        FRAMEPOINTER(fp);
-        tls->addrfp = fp;
-    }
-
-    if (pmfc80d__scalar_new_dbg == NULL) {
-        // This is the first call to this function. Link to the real MFC debug
-        // new operator.
-        mfc80d = GetModuleHandle(L"mfc80d.dll");
-        pmfc80d__scalar_new_dbg = (mfc_new_dbg_t)GetProcAddress(mfc80d, (LPCSTR)895);
-    }
-
-    // Do the allocation. The block will be mapped by _RtlAllocateHeap.
-    block = pmfc80d__scalar_new_dbg(size, file, line);
-
-    // Reset thread local flags and variables for the next allocation.
-    tls->addrfp = 0x0;
-    tls->flags &= ~VLD_TLS_CRTALLOC;
-
-    return block;
-}
-
-// _mfc80d__vector_new_dbg - Calls to the MFC debug vector new operator from
-//   mfc80d.dll are patched through to this function. This function is just a
-//   wrapper around the real MFC debug vector new operator that sets appropriate
-//   flags to be consulted when the memory is actually allocated by
-//   RtlAllocateHeap.
-//
-//  - size (IN): The size, in bytes, of the memory block to be allocated.
-//
-//  - file (IN): The name of the file from which this function is being called.
-//
-//  - line (IN): The line number, in the above file, at which this function is
-//      being called.
-//
-//  Return Value:
-//
-//    Returns the value returned by the MFC debug vector new operator.
-//
-void* VisualLeakDetector::_mfc80d__vector_new_dbg (unsigned int size, const char *file, int line)
-{
-    void    *block;
-    SIZE_T   fp;
-    HMODULE  mfc80d;
-    tls_t   *tls = vld.gettls();
-
-    // The MFC new operators are CRT-based and allocate from the CRT heap.
-    tls->flags |= VLD_TLS_CRTALLOC;
-
-    if (tls->addrfp == 0x0) {
-        // This is the first call to enter VLD for the current allocation.
-        // Record the current frame pointer.
-        FRAMEPOINTER(fp);
-        tls->addrfp = fp;
-    }
-
-    if (pmfc80d__vector_new_dbg == NULL) {
-        // This is the first call to this function. Link to the real MFC debug
-        // new operator.
-        mfc80d = GetModuleHandle(L"mfc80d.dll");
-        pmfc80d__vector_new_dbg = (mfc_new_dbg_t)GetProcAddress(mfc80d, (LPCSTR)269);
-    }
-
-    // Do the allocation. The block will be mapped by _RtlAllocateHeap.
-    block = pmfc80d__vector_new_dbg(size, file, line);
-
-    // Reset thread local flags and variables for the next allocation.
-    tls->addrfp = 0x0;
-    tls->flags &= ~VLD_TLS_CRTALLOC;
-
-    return block;
-}
-
-// _mfc80d_scalar_new - Calls to the MFC scalar new operator from mfc80d.dll are
-//   patched through to this function. This function is just a wrapper around
-//   the real MFC scalar new operator that sets appropriate flags to be
-//   consulted when the memory is actually allocated by RtlAllocateHeap.
-//
-//  - size (IN): The size, in bytes, of the memory block to be allocated.
-//
-//  Return Value:
-//
-//    Returns the value returned by the MFC scalar new operator.
-//
-void* VisualLeakDetector::_mfc80d_scalar_new (unsigned int size)
-{
-    void    *block;
-    SIZE_T   fp;
-    HMODULE  mfc80d;
-    tls_t   *tls = vld.gettls();
-
-    // The MFC new operators are CRT-based and allocate from the CRT heap.
-    tls->flags |= VLD_TLS_CRTALLOC;
-
-    if (tls->addrfp == 0x0) {
-        // This is the first call to enter VLD for the current allocation.
-        // Record the current frame pointer.
-        FRAMEPOINTER(fp);
-        tls->addrfp = fp;
-    }
-
-    if (pmfc80d_scalar_new == NULL) {
-        // This is the first call to this function. Link to the real MFC 8.0 new
-        // operator.
-        mfc80d = GetModuleHandle(L"mfc80d.dll");
-        pmfc80d_scalar_new = (new_t)GetProcAddress(mfc80d, (LPCSTR)893);
-    }
-
-    // Do the allocation. The block will be mapped by _RtlAllocateHeap.
-    block = pmfc80d_scalar_new(size);
-
-    // Reset thread local flags and variables for the next allocation.
-    tls->addrfp = 0x0;
-    tls->flags &= ~VLD_TLS_CRTALLOC;
-
-    return block;
-}
-
-// _mfc80d_vector_new - Calls to the MFC vector new operator from mfc80d.dll are
-//   patched through to this function. This function is just a wrapper around
-//   the real MFC vector new operator that sets appropriate flags to be
-//   consulted when the memory is actually allocated by RtlAllocateHeap.
-//
-//  - size (IN): The size, in bytes, of the memory block to be allocated.
-//
-//  Return Value:
-//
-//    Returns the value returned by the MFC vector new operator.
-//
-void* VisualLeakDetector::_mfc80d_vector_new (unsigned int size)
-{
-    void    *block;
-    SIZE_T   fp;
-    HMODULE  mfc80d;
-    tls_t   *tls = vld.gettls();
-
-    // The MFC new operators are CRT-based and allocate from the CRT heap.
-    tls->flags |= VLD_TLS_CRTALLOC;
-
-    if (tls->addrfp == 0x0) {
-        // This is the first call to enter VLD for the current allocation.
-        // Record the current frame pointer.
-        FRAMEPOINTER(fp);
-        tls->addrfp = fp;
-    }
-
-    if (pmfc80d_vector_new == NULL) {
-        // This is the first call to this function. Link to the real MFC 8.0 new
-        // operator.
-        mfc80d = GetModuleHandle(L"mfc80d.dll");
-        pmfc80d_vector_new = (new_t)GetProcAddress(mfc80d, (LPCSTR)267);
-    }
-
-    // Do the allocation. The block will be mapped by _RtlAllocateHeap.
-    block = pmfc80d_vector_new(size);
-
-    // Reset thread local flags and variables for the next allocation.
-    tls->addrfp = 0x0;
-    tls->flags &= ~VLD_TLS_CRTALLOC;
-
-    return block;
-}
-
-// _RtlAllocateHeap - Calls to RtlAllocateHeap are patched through to this
-//   function. This function invokes the real RtlAllocateHeap and then calls
-//   VLD's allocation tracking function. Pretty much all memory allocations
-//   will eventually result in a call to RtlAllocateHeap, so this is where we
-//   finally map the allocated block.
-//
-//  - heap (IN): Handle to the heap from which to allocate memory.
-//
-//  - flags (IN): Heap allocation control flags.
-//
-//  - size (IN): Size, in bytes, of the block to allocate.
-//
-//  Return Value:
-//
-//    Returns the return value from RtlAllocateHeap.
-//
-LPVOID VisualLeakDetector::_RtlAllocateHeap (HANDLE heap, DWORD flags, SIZE_T size)
-{
-    BOOL                 crtalloc;
-    BOOL                 excluded = FALSE;
-    SIZE_T               fp;
-    LPVOID               block;
-    moduleinfo_t         moduleinfo;
-    ModuleSet::Iterator  moduleit;
-    SIZE_T               returnaddress;
-    tls_t               *tls = vld.gettls();
-
-    // Allocate the block.
-    block = RtlAllocateHeap(heap, flags, size);
-    if ((block != NULL) && vld.enabled()) {
-        if (tls->addrfp == 0x0) {
-            // This is the first call to enter VLD for the current allocation.
-            // Record the current frame pointer.
-            FRAMEPOINTER(fp);
-        }
-        else {
-            fp = tls->addrfp;
-        }
-        crtalloc = (tls->flags & VLD_TLS_CRTALLOC) ? TRUE : FALSE;
-
-        // Reset thread local flags and variables, in case any libraries called
-        // into while mapping the block allocate some memory.
-        tls->addrfp = 0x0;
-        tls->flags &=~VLD_TLS_CRTALLOC;
-
-        // Find the information for the module that initiated this allocation.
-        returnaddress = *((SIZE_T*)fp + 1);
-        moduleinfo.addrhigh = returnaddress;
-        moduleinfo.addrlow  = returnaddress;
-        EnterCriticalSection(&vld.m_moduleslock);
-        moduleit = vld.m_loadedmodules->find(moduleinfo);
-        if (moduleit != vld.m_loadedmodules->end()) {
-            excluded = (*moduleit).flags & VLD_MODULE_EXCLUDED ? TRUE : FALSE;
-        }
-        LeaveCriticalSection(&vld.m_moduleslock);
-        if (!excluded) {
-            // The module that initiated this allocation is included in leak
-            // detection. Map this block to the specified heap.
-            vld.mapblock(heap, block, size, fp, crtalloc);
-        }
-    }
-
-    // Reset thread local flags and variables for the next allocation.
-    tls->addrfp = 0x0;
-    tls->flags &= ~VLD_TLS_CRTALLOC;
-
-    return block;
-}
-
-// _RtlFreeHeap - Calls to RtlFreeHeap are patched through to this function.
-//   This function calls VLD's free tracking function and then invokes the real
-//   RtlFreeHeap. Pretty much all memory frees will eventually result in a call
-//   to RtlFreeHeap, so this is where we finally unmap the freed block.
-//
-//  - heap (IN): Handle to the heap to which the block being freed belongs.
-//
-//  - flags (IN): Heap control flags.
-//
-//  - mem (IN): Pointer to the memory block being freed.
-//
-//  Return Value:
-//
-//    Returns the value returned by RtlFreeHeap.
-//
-BOOL VisualLeakDetector::_RtlFreeHeap (HANDLE heap, DWORD flags, LPVOID mem)
-{
-    BOOL status;
-
-    // Unmap the block from the specified heap.
-    vld.unmapblock(heap, mem);
-
-    status = RtlFreeHeap(heap, flags, mem);
-
-    return status;
-}
-
-// _RtlReAllocateHeap - Calls to RtlReAllocateHeap are patched through to this
-//   function. This function invokes the real RtlReAllocateHeap and then calls
-//   VLD's reallocation tracking function. All arguments passed to this function
-//   are passed on to the real RtlReAllocateHeap without modification. Pretty
-//   much all memory re-allocations will eventually result in a call to
-//   RtlReAllocateHeap, so this is where we finally remap the reallocated block.
-//
-//  - heap (IN): Handle to the heap to reallocate memory from.
-//
-//  - flags (IN): Heap control flags.
-//
-//  - mem (IN): Pointer to the currently allocated block which is to be
-//      reallocated.
-//
-//  - size (IN): Size, in bytes, of the block to reallocate.
-//
-//  Return Value:
-//
-//    Returns the value returned by RtlReAllocateHeap.
-//
-LPVOID VisualLeakDetector::_RtlReAllocateHeap (HANDLE heap, DWORD flags, LPVOID mem, SIZE_T size)
-{
-    BOOL                 crtalloc;
-    BOOL                 excluded = FALSE;
-    SIZE_T               fp;
-    moduleinfo_t         moduleinfo;
-    ModuleSet::Iterator  moduleit;
-    LPVOID               newmem;
-    SIZE_T               returnaddress;
-    tls_t               *tls = vld.gettls();
-
-    // Reallocate the block.
-    newmem = RtlReAllocateHeap(heap, flags, mem, size);
-
-    if (newmem != NULL) {
-        if (tls->addrfp == 0x0) {
-            // This is the first call to enter VLD for the current allocation.
-            // Record the current frame pointer.
-            FRAMEPOINTER(fp);
-        }
-        else {
-            fp = tls->addrfp;
-        }
-        crtalloc = (tls->flags & VLD_TLS_CRTALLOC) ? TRUE : FALSE;
-
-        // Reset thread local flags and variables, in case any libraries called
-        // into while remapping the block allocate some memory.
-        tls->addrfp = 0x0;
-        tls->flags &= ~VLD_TLS_CRTALLOC;
-
-        // Find the information for the module that initiated this reallocation.
-        returnaddress = *((SIZE_T*)fp + 1);
-        moduleinfo.addrhigh = returnaddress;
-        moduleinfo.addrlow  = returnaddress;
-        EnterCriticalSection(&vld.m_moduleslock);
-        moduleit = vld.m_loadedmodules->find(moduleinfo);
-        if (moduleit != vld.m_loadedmodules->end()) {
-            excluded = (*moduleit).flags & VLD_MODULE_EXCLUDED ? TRUE : FALSE;
-        }
-        LeaveCriticalSection(&vld.m_moduleslock);
-        if (!excluded) {
-            // The module that initiated this allocation is included in leak
-            // detection. Remap the block.
-            vld.remapblock(heap, mem, newmem, size, fp, crtalloc);
-        }
-    }
-
-    // Reset thread local flags and variables for the next allocation.
-    tls->addrfp = 0x0;
-    tls->flags &= ~VLD_TLS_CRTALLOC;
-
-    return newmem;
-}
-
-// AddRef - Calls to IMalloc::AddRef end up here. This function is just a
-//   wrapper around the real IMalloc::AddRef implementation.
-//
-//  Return Value:
-//
-//    Returns the value returned by the system implementation of
-//    IMalloc::AddRef.
-//
-ULONG VisualLeakDetector::AddRef ()
-{
-    assert(m_imalloc != NULL);
-    return m_imalloc->AddRef();
-}
-
-// Alloc - Calls to IMalloc::Alloc end up here. This function is just a wrapper
-//   around the real IMalloc::Alloc implementation that sets appropriate flags
-//   to be consulted when the memory is actually allocated by RtlAllocateHeap.
-//
-//  - size (IN): The size of the memory block to allocate.
-//
-//  Return Value:
-//
-//    Returns the value returned by the system's IMalloc::Alloc implementation.
-//
-LPVOID VisualLeakDetector::Alloc (ULONG size)
-{
-    LPVOID  block;
-    SIZE_T  fp;
-    tls_t  *tls = vld.gettls();
-
-    if (tls->addrfp == 0x0) {
-        // This is the first call to enter VLD for the current allocation.
-        // Record the current frame pointer.
-        FRAMEPOINTER(fp);
-        tls->addrfp = fp;
-    }
-
-    // Do the allocation. The block will be mapped by _RtlAllocateHeap.
-    assert(m_imalloc != NULL);
-    block = m_imalloc->Alloc(size);
-
-    // Reset thread local flags and variables for the next allocation.
-    tls->addrfp = 0x0;
-    tls->flags &= ~VLD_TLS_CRTALLOC;
-
-    return block;
-}
-
-// addloadedmodule - Callback function for EnumerateLoadedModules64. This
-//   function records information about every module loaded in the process,
-//   each time adding the module's information to the provided ModuleSet (the
-//   "context" parameter).
-//
-//   When EnumerateLoadedModules64 has finished calling this function for each
-//   loaded module, then the resulting ModuleSet can be used at any time to get
-//   information about any modules loaded into the process.
-//
-//   - modulepath (IN): The fully qualified path from where the module was
-//       loaded.
-//
-//   - modulebase (IN): The base address at which the module has been loaded.
-//
-//   - modulesize (IN): The size, in bytes, of the loaded module.
-//
-//   - context (IN): Pointer to the ModuleSet to which information about each
-//       module is to be added.
-//
-//  Return Value:
-//
-//    Always returns TRUE, which tells EnumerateLoadedModules64 to continue
-//    enumerating.
-//
-BOOL VisualLeakDetector::addloadedmodule (PCWSTR modulepath, DWORD64 modulebase, ULONG modulesize, PVOID context)
-{
-    size_t        count;
-    patchentry_t *entry;
-    CHAR          extension [_MAX_EXT];
-    CHAR          filename [_MAX_FNAME];
-    UINT          index;
-    moduleinfo_t  moduleinfo;
-    LPSTR         modulenamea;
-    LPSTR         modulepatha;
-    ModuleSet*    newmodules = (ModuleSet*)context;
-    SIZE_T        size;
-    UINT          tablesize = sizeof(m_patchtable) / sizeof(patchentry_t);
-
-    // Convert the module path to ASCII.
-    size = wcslen(modulepath) + 1;
-    modulepatha = new CHAR [size];
-    wcstombs_s(&count, modulepatha, size, modulepath, _TRUNCATE);
-
-    // Extract just the filename and extension from the module path.
-    _splitpath_s(modulepatha, NULL, 0, NULL, 0, filename, _MAX_FNAME, extension, _MAX_EXT);
-    size = strlen(filename) + strlen(extension) + 1;
-    modulenamea = new CHAR [size];
-    strncpy_s(modulenamea, size, filename, _TRUNCATE);
-    strncat_s(modulenamea, size, extension, _TRUNCATE);
-    _strlwr_s(modulenamea, size);
-
-    if (_stricmp(modulenamea, "vld.dll") == 0) {
-        // Record Visual Leak Detector's own base address.
-        vld.m_vldbase = (HMODULE)modulebase;
-    }
-    else {
-        // See if this is a module listed in the patch table. If it is, update
-        // the corresponding patch table entries' module base address.
-        for (index = 0; index < tablesize; index++) {
-            entry = &m_patchtable[index];
-            if (_stricmp(entry->exportmodulename, modulenamea) == 0) {
-                entry->modulebase = (SIZE_T)modulebase;
-            }
-        }
-    }
-
-    // Record the module's information and store it in the set.
-    moduleinfo.addrlow  = (SIZE_T)modulebase;
-    moduleinfo.addrhigh = (SIZE_T)(modulebase + modulesize) - 1;
-    moduleinfo.flags    = 0x0;
-    moduleinfo.name     = modulenamea;
-    moduleinfo.path     = modulepatha;
-    newmodules->insert(moduleinfo);
-
-    return TRUE;
-}
-
-// attachtoloadedmodules - Attaches VLD to all modules contained in the provided
-//   ModuleSet. Not all modules are in the ModuleSet will actually be included
-//   in leak detection. Only modules that import the global VisualLeakDetector
-//   class object, or those that are otherwise explicitly included in leak
-//   detection, will be checked for memory leaks.
-//
-//   When VLD attaches to a module, it means that any of the imports listed in
-//   the import patch table which are imported by the module, will be redirected
-//   to VLD's designated replacements.
-//
-//  - newmodules (IN): Pointer to a ModuleSet containing information about any
-//      loaded modules that need to be attached.
-//
-//  Return Value:
-//
-//    None.
-//
-VOID VisualLeakDetector::attachtoloadedmodules (ModuleSet *newmodules)
-{
-    size_t                count;
-    DWORD64               modulebase;
-    UINT32                moduleflags;
-    IMAGEHLP_MODULE64     moduleimageinfo;
-    LPCSTR                modulename;
-#define MAXMODULENAME (_MAX_FNAME + _MAX_EXT)
-    WCHAR                 modulenamew [MAXMODULENAME];
-    LPCSTR                modulepath;
-    DWORD                 modulesize;
-    ModuleSet::Iterator   newit;
-    ModuleSet::Iterator   oldit;
-    ModuleSet            *oldmodules;
-    BOOL                  refresh;
-    UINT                  tablesize = sizeof(m_patchtable) / sizeof(patchentry_t);
-    ModuleSet::Muterator  updateit;
-
-    // Iterate through the supplied set, until all modules have been attached.
-    for (newit = newmodules->begin(); newit != newmodules->end(); ++newit) {
-        modulebase  = (DWORD64)(*newit).addrlow;
-        moduleflags = 0x0;
-        modulename  = (*newit).name;
-        modulepath  = (*newit).path;
-        modulesize  = (DWORD)((*newit).addrhigh - (*newit).addrlow) + 1;
-
-        refresh = FALSE;
-        EnterCriticalSection(&m_moduleslock);
-        oldmodules = m_loadedmodules;
-        if (oldmodules != NULL) {
-            // This is not the first time we have been called to attach to the
-            // currently loaded modules.
-            oldit = oldmodules->find(*newit);
-            if (oldit != oldmodules->end()) {
-                // We've seen this "new" module loaded in the process before.
-                moduleflags = (*oldit).flags;
-                LeaveCriticalSection(&m_moduleslock);
-                if (moduleispatched((HMODULE)modulebase, m_patchtable, tablesize)) {
-                    // This module is already attached. Just update the module's
-                    // flags, nothing more.
-                    updateit = newit;
-                    (*updateit).flags = moduleflags;
-                    continue;
-                }
-                else {
-                    // This module may have been attached before and has been
-                    // detached. We'll need to try reattaching to it in case it
-                    // was unloaded and then subsequently reloaded.
-                    refresh = TRUE;
-                }
-            }
-            else {
-                LeaveCriticalSection(&m_moduleslock);
-            }
-        }
-        else {
-            LeaveCriticalSection(&m_moduleslock);
-        }
-
-        EnterCriticalSection(&symbollock);
-        if ((refresh == TRUE) && (moduleflags & VLD_MODULE_SYMBOLSLOADED)) {
-            // Discard the previously loaded symbols, so we can refresh them.
-            if (SymUnloadModule64(currentprocess, modulebase) == FALSE) {
-                report(L"WARNING: Visual Leak Detector: Failed to unload the symbols for %s. Function names and line"
-                       L" numbers shown in the memory leak report for %s may be inaccurate.", modulename, modulename);
-            }
-        }
-
-        // Try to load the module's symbols. This ensures that we have loaded
-        // the symbols for every module that has ever been loaded into the
-        // process, guaranteeing the symbols' availability when generating the
-        // leak report.
-        moduleimageinfo.SizeOfStruct = sizeof(IMAGEHLP_MODULE64);
-        if ((SymGetModuleInfoW64(currentprocess, (DWORD64)modulebase, &moduleimageinfo) == TRUE) ||
-            ((SymLoadModule64(currentprocess, NULL, modulepath, NULL, modulebase, modulesize) == modulebase) &&
-            (SymGetModuleInfoW64(currentprocess, modulebase, &moduleimageinfo) == TRUE))) {
-            moduleflags |= VLD_MODULE_SYMBOLSLOADED;
-        }
-        LeaveCriticalSection(&symbollock);
-
-        if (_stricmp("vld.dll", modulename) == 0) {
-            // What happens when a module goes through it's own portal? Bad things.
-            // Like infinite recursion. And ugly bald men wearing dresses. VLD
-            // should not, therefore, attach to itself.
-            continue;
-        }
-
-        mbstowcs_s(&count, modulenamew, MAXMODULENAME, modulename, _TRUNCATE);
-        if ((findimport((HMODULE)modulebase, m_vldbase, "vld.dll", "?vld@@3VVisualLeakDetector@@A") == FALSE) &&
-            (wcsstr(vld.m_forcedmodulelist, modulenamew) == NULL)) {
-            // This module does not import VLD. This means that none of the module's
-            // sources #included vld.h. Exclude this module from leak detection.
-            moduleflags |= VLD_MODULE_EXCLUDED;
-        }
-        else if (!(moduleflags & VLD_MODULE_SYMBOLSLOADED) || (moduleimageinfo.SymType == SymExport)) {
-            // This module is going to be included in leak detection, but complete
-            // symbols for this module couldn't be loaded. This means that any stack
-            // traces through this module may lack information, like line numbers
-            // and function names.
-            report(L"WARNING: Visual Leak Detector: A module, %s, included in memory leak detection\n"
-                   L"  does not have any debugging symbols available, or they could not be located.\n"
-                   L"  Function names and/or line numbers for this module may not be available.\n", modulename);
-        }
-
-        // Update the module's flags in the "new modules" set.
-        updateit = newit;
-        (*updateit).flags = moduleflags;
-
-        // Attach to the module.
-        patchmodule((HMODULE)modulebase, m_patchtable, tablesize);
-    }
-}
-
-// buildsymbolsearchpath - Builds the symbol search path for the symbol handler.
-//   This helps the symbol handler find the symbols for the application being
-//   debugged.
-//
-//  Return Value:
-//
-//    Returns a string containing the search path. The caller is responsible for
-//    freeing the string.
-//
-LPWSTR VisualLeakDetector::buildsymbolsearchpath ()
-{
-    WCHAR   directory [_MAX_DIR];
-    WCHAR   drive [_MAX_DRIVE];
-    LPWSTR  env;
-    DWORD   envlen;
-    SIZE_T  index;
-    SIZE_T  length;
-    HMODULE module;
-    LPWSTR  path = new WCHAR [MAX_PATH];
-    SIZE_T  pos = 0;
-    WCHAR   system [MAX_PATH];
-    WCHAR   windows [MAX_PATH];
-
-    // Oddly, the symbol handler ignores the link to the PDB embedded in the
-    // executable image. So, we'll manually add the location of the executable
-    // to the search path since that is often where the PDB will be located.
-    path[0] = L'\0';
-    module = GetModuleHandle(NULL);
-    GetModuleFileName(module, path, MAX_PATH);
-    _wsplitpath_s(path, drive, _MAX_DRIVE, directory, _MAX_DIR, NULL, 0, NULL, 0);
-    wcsncpy_s(path, MAX_PATH, drive, _TRUNCATE);
-    strapp(&path, directory);
-
-    // When the symbol handler is given a custom symbol search path, it will no
-    // longer search the default directories (working directory, system root,
-    // etc). But we'd like it to still search those directories, so we'll add
-    // them to our custom search path.
-    //
-    // Append the working directory.
-    strapp(&path, L";.\\");
-
-    // Append the Windows directory.
-    if (GetWindowsDirectory(windows, MAX_PATH) != 0) {
-        strapp(&path, L";");
-        strapp(&path, windows);
-    }
-
-    // Append the system directory.
-    if (GetSystemDirectory(system, MAX_PATH) != 0) {
-        strapp(&path, L";");
-        strapp(&path, system);
-    }
-
-    // Append %_NT_SYMBOL_PATH%.
-    envlen = GetEnvironmentVariable(L"_NT_SYMBOL_PATH", NULL, 0);
-    if (envlen != 0) {
-        env = new WCHAR [envlen];
-        if (GetEnvironmentVariable(L"_NT_SYMBOL_PATH", env, envlen) != 0) {
-            strapp(&path, L";");
-            strapp(&path, env);
-        }
-        delete [] env;
-    }
-
-    //  Append %_NT_ALT_SYMBOL_PATH%.
-    envlen = GetEnvironmentVariable(L"_NT_ALT_SYMBOL_PATH", NULL, 0);
-    if (envlen != 0) {
-        env = new WCHAR [envlen];
-        if (GetEnvironmentVariable(L"_NT_ALT_SYMBOL_PATH", env, envlen) != 0) {
-            strapp(&path, L";");
-            strapp(&path, env);
-        }
-        delete [] env;
-    }
-
-    // Remove any quotes from the path. The symbol handler doesn't like them.
-    pos = 0;
-    length = wcslen(path);
-    while (pos < length) {
-        if (path[pos] == L'\"') {
-            for (index = pos; index < length; index++) {
-                path[index] = path[index + 1];
-            }
-        }
-        pos++;
-    }
-
-    return path;
-}
-
-// configure - Configures VLD using values read from the vld.ini file.
-//
-//  Return Value:
-//
-//    None.
-//
-VOID VisualLeakDetector::configure ()
-{
-#define BSIZE 64
-    WCHAR        buffer [BSIZE];
-    WCHAR        filename [MAX_PATH];
-    WCHAR        inipath [MAX_PATH];
-    BOOL         keyopen = FALSE;
-    DWORD        length;
-    HKEY         productkey;
-    LONG         regstatus;
-    struct _stat s;
-    DWORD        valuetype;
-
-    if (_wstat(L".\\vld.ini", &s) == 0) {
-        // Found a copy of vld.ini in the working directory. Use it.
-        wcsncpy_s(inipath, MAX_PATH, L".\\vld.ini", _TRUNCATE);
-    }
-    else {
-        // Get the location of the vld.ini file from the registry.
-        regstatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE, VLDREGKEYPRODUCT, 0, KEY_QUERY_VALUE, &productkey);
-        if (regstatus == ERROR_SUCCESS) {
-            keyopen = TRUE;
-            regstatus = RegQueryValueEx(productkey, L"IniFile", NULL, &valuetype, (LPBYTE)&inipath, &length);
-        }
-        if (keyopen) {
-            RegCloseKey(productkey);
-        }
-        if ((regstatus != ERROR_SUCCESS) || (_wstat(inipath, &s) != 0)) {
-            // The location of vld.ini could not be read from the registry. As a
-            // last resort, look in the Windows directory.
-            wcsncpy_s(inipath, MAX_PATH, L"vld.ini", _TRUNCATE);
-        }
-    }
-
-    // Read the boolean options.
-    GetPrivateProfileString(L"Options", L"VLD", L"on", buffer, BSIZE, inipath);
-    if (strtobool(buffer) == FALSE) {
-        m_options |= VLD_OPT_VLDOFF;
-        return;
-    }
-
-    GetPrivateProfileString(L"Options", L"AggregateDuplicates", L"", buffer, BSIZE, inipath);
-    if (strtobool(buffer) == TRUE) {
-        m_options |= VLD_OPT_AGGREGATE_DUPLICATES;
-    }
-
-    GetPrivateProfileString(L"Options", L"SelfTest", L"", buffer, BSIZE, inipath);
-    if (strtobool(buffer) == TRUE) {
-        m_options |= VLD_OPT_SELF_TEST;
-    }
-
-    GetPrivateProfileString(L"Options", L"SlowDebuggerDump", L"", buffer, BSIZE, inipath);
-    if (strtobool(buffer) == TRUE) {
-        m_options |= VLD_OPT_SLOW_DEBUGGER_DUMP;
+        else {
+            if (strcmp(entry->importname, procname) == 0) {
+                return (FARPROC)entry->replacement;
+            }
+        }
     }
 
-    GetPrivateProfileString(L"Options", L"StartDisabled", L"", buffer, BSIZE, inipath);
-    if (strtobool(buffer) == TRUE) {
-        m_options |= VLD_OPT_START_DISABLED;
-    }
+    // The requested function is not a patched function. Just return the real
+    // address of the requested function.
+    return GetProcAddress(module, procname);
+}
 
-    GetPrivateProfileString(L"Options", L"TraceInternalFrames", L"", buffer, BSIZE, inipath);
-    if (strtobool(buffer) == TRUE) {
-        m_options |= VLD_OPT_TRACE_INTERNAL_FRAMES;
-    }
+// _HeapCreate - Calls to HeapCreate are patched through to this function. This
+//   function is just a wrapper around the real HeapCreate that calls VLD's heap
+//   creation tracking function after the heap has been created.
+//
+//  - options (IN): Heap options.
+//
+//  - initsize (IN): Initial size of the heap.
+//
+//  - maxsize (IN): Maximum size of the heap.
+//
+//  Return Value:
+//
+//    Returns the value returned by HeapCreate.
+//
+HANDLE VisualLeakDetector::_HeapCreate (DWORD options, SIZE_T initsize, SIZE_T maxsize)
+{
+    DWORD64            displacement;
+    SIZE_T             fp;
+    SYMBOL_INFO       *functioninfo;
+    HANDLE             heap;
+    HeapMap::Iterator  heapit;
+    SIZE_T             ra;
+    BYTE               symbolbuffer [sizeof(SYMBOL_INFO) + (MAXSYMBOLNAMELENGTH * sizeof(WCHAR)) - 1] = { 0 };
+    BOOL               symfound;
 
-    // Read the integer configuration options.
-    m_maxdatadump = GetPrivateProfileInt(L"Options", L"MaxDataDump", VLD_DEFAULT_MAX_DATA_DUMP, inipath);
-    m_maxtraceframes = GetPrivateProfileInt(L"Options", L"MaxTraceFrames", VLD_DEFAULT_MAX_TRACE_FRAMES, inipath);
-    if (m_maxtraceframes < 1) {
-        m_maxtraceframes = VLD_DEFAULT_MAX_TRACE_FRAMES;
-    }
+    // Get the return address within the calling function.
+    FRAMEPOINTER(fp);
+    ra = *((SIZE_T*)fp + 1);
 
-    // Read the force-include module list.
-    GetPrivateProfileString(L"Options", L"ForceIncludeModules", L"", m_forcedmodulelist, MAXMODULELISTLENGTH, inipath);
-    _wcslwr_s(m_forcedmodulelist, MAXMODULELISTLENGTH);
+    // Create the heap.
+    heap = HeapCreate(options, initsize, maxsize);
 
-    // Read the report destination (debugger, file, or both).
-    GetPrivateProfileString(L"Options", L"ReportFile", L"", filename, MAX_PATH, inipath);
-    if (wcslen(filename) == 0) {
-        wcsncpy_s(filename, MAX_PATH, VLD_DEFAULT_REPORT_FILE_NAME, _TRUNCATE);
-    }
-    _wfullpath(m_reportfilepath, filename, MAX_PATH);
-    GetPrivateProfileString(L"Options", L"ReportTo", L"", buffer, BSIZE, inipath);
-    if (_wcsicmp(buffer, L"both") == 0) {
-        m_options |= (VLD_OPT_REPORT_TO_DEBUGGER | VLD_OPT_REPORT_TO_FILE);
-    }
-    else if (_wcsicmp(buffer, L"file") == 0) {
-        m_options |= VLD_OPT_REPORT_TO_FILE;
-    }
-    else {
-        m_options |= VLD_OPT_REPORT_TO_DEBUGGER;
-    }
+    // Map the created heap handle to a new block map.
+    vld.mapheap(heap);
 
-    // Read the report file encoding (ascii or unicode).
-    GetPrivateProfileString(L"Options", L"ReportEncoding", L"", buffer, BSIZE, inipath);
-    if (_wcsicmp(buffer, L"unicode") == 0) {
-        m_options |= VLD_OPT_UNICODE_REPORT;
-    }
-    if ((m_options & VLD_OPT_UNICODE_REPORT) && !(m_options & VLD_OPT_REPORT_TO_FILE)) {
-        // If Unicode report encoding is enabled, then the report needs to be
-        // sent to a file because the debugger will not display Unicode
-        // characters, it will display question marks in their place instead.
-        m_options |= VLD_OPT_REPORT_TO_FILE;
-        m_status |= VLD_STATUS_FORCE_REPORT_TO_FILE;
+    // Try to get the name of the function containing the return address.
+    functioninfo = (SYMBOL_INFO*)&symbolbuffer;
+    functioninfo->SizeOfStruct = sizeof(SYMBOL_INFO);
+    functioninfo->MaxNameLen = MAXSYMBOLNAMELENGTH;
+    EnterCriticalSection(&symbollock);
+    symfound = SymFromAddrW(currentprocess, ra, &displacement, functioninfo);
+    LeaveCriticalSection(&symbollock);
+    if (symfound == TRUE) {
+        if (wcscmp(L"_heap_init", functioninfo->Name) == 0) {
+            // HeapCreate was called by _heap_init. This is a static CRT heap.
+            EnterCriticalSection(&vld.m_maplock);
+            heapit = vld.m_heapmap->find(heap);
+            assert(heapit != vld.m_heapmap->end());
+            (*heapit).second->flags |= VLD_HEAP_CRT;
+            LeaveCriticalSection(&vld.m_maplock);
+        }
     }
 
-    // Read the stack walking method.
-    GetPrivateProfileString(L"Options", L"StackWalkMethod", L"", buffer, BSIZE, inipath);
-    if (_wcsicmp(buffer, L"safe") == 0) {
-        m_options |= VLD_OPT_SAFE_STACK_WALK;
-    }
+    return heap;
 }
 
-// detachfrommodule - Callback function for EnumerateLoadedModules64 that
-//   detaches Visual Leak Detector from the specified module. If the specified
-//   module has not previously been attached to, then calling this function will
-//   not actually result in any changes.
-//
-//  - modulepath (IN): String containing the name, which may inlcude a path, of
-//      the module to detach from (ignored).
-//
-//  - modulebase (IN): Base address of the module.
-//
-//  - modulesize (IN): Total size of the module (ignored).
+// _HeapDestroy - Calls to HeapDestroy are patched through to this function.
+//   This function is just a wrapper around the real HeapDestroy that calls
+//   VLD's heap destruction tracking function after the heap has been destroyed.
 //
-//  - context (IN): User-supplied context (ignored).
+//  - heap (IN): Handle to the heap to be destroyed.
 //
 //  Return Value:
 //
-//    Always returns TRUE.
+//    Returns the valued returned by HeapDestroy.
 //
-BOOL VisualLeakDetector::detachfrommodule (PCWSTR /*modulepath*/, DWORD64 modulebase, ULONG /*modulesize*/,
-                                           PVOID /*context*/)
+BOOL VisualLeakDetector::_HeapDestroy (HANDLE heap)
 {
-    UINT tablesize = sizeof(m_patchtable) / sizeof(patchentry_t);
+    // After this heap is destroyed, the heap's address space will be unmapped
+    // from the process's address space. So, we'd better generate a leak report
+    // for this heap now, while we can still read from the memory blocks
+    // allocated to it.
+    vld.reportleaks(heap);
 
-    restoremodule((HMODULE)modulebase, m_patchtable, tablesize);
+    vld.unmapheap(heap);
 
-    return TRUE;
+    return HeapDestroy(heap);
 }
 
-// DidAlloc - Calls to IMalloc::DidAlloc will end up here. This function is just
-//   a wrapper around the system implementation of IMalloc::DidAlloc.
+// _LdrLoadDll - Calls to LdrLoadDll are patched through to this function. This
+//   function invokes the real LdrLoadDll and then re-attaches VLD to all
+//   modules loaded in the process after loading of the new DLL is complete.
+//   All modules must be re-enumerated because the explicit load of the
+//   specified module may result in the implicit load of one or more additional
+//   modules which are dependencies of the specified module.
 //
-//  - mem (IN): Pointer to a memory block to inquire about.
+//  - searchpath (IN): The path to use for searching for the specified module to
+//      be loaded.
+//
+//  - flags (IN): Pointer to action flags.
+//
+//  - modulename (IN): Pointer to a unicodestring_t structure specifying the
+//      name of the module to be loaded.
+//
+//  - modulehandle (OUT): Address of a HANDLE to receive the newly loaded
+//      module's handle.
 //
 //  Return Value:
 //
-//    Returns the value returned by the system implementation of
-//    IMalloc::DidAlloc.
+//    Returns the value returned by LdrLoadDll.
 //
-INT VisualLeakDetector::DidAlloc (LPVOID mem)
+NTSTATUS VisualLeakDetector::_LdrLoadDll (LPWSTR searchpath, PDWORD flags, unicodestring_t *modulename,
+                                          PHANDLE modulehandle)
 {
-    assert(m_imalloc != NULL);
-    return m_imalloc->DidAlloc(mem);
+    ModuleSet::Iterator  moduleit;
+    ModuleSet           *newmodules;
+    ModuleSet           *oldmodules;
+    NTSTATUS             status;
+
+    EnterCriticalSection(&vld.m_loaderlock);
+
+    // Load the DLL.
+    status = LdrLoadDll(searchpath, flags, modulename, modulehandle);
+    
+    if (STATUS_SUCCESS == status) {
+        // Create a new set of all loaded modules, including any newly loaded
+        // modules.
+        newmodules = new ModuleSet;
+        newmodules->reserve(MODULESETRESERVE);
+        EnumerateLoadedModulesW64(currentprocess, addloadedmodule, newmodules);
+
+        // Attach to all modules included in the set.
+        vld.attachtoloadedmodules(newmodules);
+
+        // Start using the new set of loaded modules.
+        EnterCriticalSection(&vld.m_moduleslock);
+        oldmodules = vld.m_loadedmodules;
+        vld.m_loadedmodules = newmodules;
+        LeaveCriticalSection(&vld.m_moduleslock);
+
+        // Free resources used by the old module list.
+        for (moduleit = oldmodules->begin(); moduleit != oldmodules->end(); ++moduleit) {
+            delete (*moduleit).name;
+            delete (*moduleit).path;
+        }
+        delete oldmodules;
+    }
+
+    LeaveCriticalSection(&vld.m_loaderlock);
+
+    return status;
 }
 
-// enabled - Determines if memory leak detection is enabled for the current
-//   thread.
+// _RtlAllocateHeap - Calls to RtlAllocateHeap are patched through to this
+//   function. This function invokes the real RtlAllocateHeap and then calls
+//   VLD's allocation tracking function. Pretty much all memory allocations
+//   will eventually result in a call to RtlAllocateHeap, so this is where we
+//   finally map the allocated block.
+//
+//  - heap (IN): Handle to the heap from which to allocate memory.
+//
+//  - flags (IN): Heap allocation control flags.
+//
+//  - size (IN): Size, in bytes, of the block to allocate.
 //
 //  Return Value:
 //
-//    Returns true if Visual Leak Detector is enabled for the current thread.
-//    Otherwise, returns false.
+//    Returns the return value from RtlAllocateHeap.
 //
-BOOL VisualLeakDetector::enabled ()
+LPVOID VisualLeakDetector::_RtlAllocateHeap (HANDLE heap, DWORD flags, SIZE_T size)
 {
-    tls_t *tls = vld.gettls();
+    BOOL                 crtalloc;
+    BOOL                 excluded = FALSE;
+    SIZE_T               fp;
+    LPVOID               block;
+    moduleinfo_t         moduleinfo;
+    ModuleSet::Iterator  moduleit;
+    SIZE_T               returnaddress;
+    tls_t               *tls = vld.gettls();
 
-    if (!(m_status & VLD_STATUS_INSTALLED)) {
-        // Memory leak detection is not yet enabled because VLD is still
-        // initializing.
-        return FALSE;
-    }
+    // Allocate the block.
+    block = RtlAllocateHeap(heap, flags, size);
+    if ((block != NULL) && vld.enabled()) {
+        if (tls->addrfp == 0x0) {
+            // This is the first call to enter VLD for the current allocation.
+            // Record the current frame pointer.
+            FRAMEPOINTER(fp);
+        }
+        else {
+            fp = tls->addrfp;
+        }
+        crtalloc = (tls->flags & VLD_TLS_CRTALLOC) ? TRUE : FALSE;
 
-    if (!(tls->flags & VLD_TLS_DISABLED) && !(tls->flags & VLD_TLS_ENABLED)) {
-        // The enabled/disabled state for the current thread has not been 
-        // initialized yet. Use the default state.
-        if (m_options & VLD_OPT_START_DISABLED) {
-            tls->flags |= VLD_TLS_DISABLED;
+        // Reset thread local flags and variables, in case any libraries called
+        // into while mapping the block allocate some memory.
+        tls->addrfp = 0x0;
+        tls->flags &=~VLD_TLS_CRTALLOC;
+
+        // Find the information for the module that initiated this allocation.
+        returnaddress = *((SIZE_T*)fp + 1);
+        moduleinfo.addrhigh = returnaddress;
+        moduleinfo.addrlow  = returnaddress;
+        EnterCriticalSection(&vld.m_moduleslock);
+        moduleit = vld.m_loadedmodules->find(moduleinfo);
+        if (moduleit != vld.m_loadedmodules->end()) {
+            excluded = (*moduleit).flags & VLD_MODULE_EXCLUDED ? TRUE : FALSE;
         }
-        else {
-            tls->flags |= VLD_TLS_ENABLED;
+        LeaveCriticalSection(&vld.m_moduleslock);
+        if (!excluded) {
+            // The module that initiated this allocation is included in leak
+            // detection. Map this block to the specified heap.
+            vld.mapblock(heap, block, size, fp, crtalloc);
         }
     }
 
-    return ((tls->flags & VLD_TLS_ENABLED) != 0);
+    // Reset thread local flags and variables for the next allocation.
+    tls->addrfp = 0x0;
+    tls->flags &= ~VLD_TLS_CRTALLOC;
+
+    return block;
 }
 
-// eraseduplicates - Erases, from the block maps, blocks that appear to be
-//   duplicate leaks of an already identified leak.
+// _RtlFreeHeap - Calls to RtlFreeHeap are patched through to this function.
+//   This function calls VLD's free tracking function and then invokes the real
+//   RtlFreeHeap. Pretty much all memory frees will eventually result in a call
+//   to RtlFreeHeap, so this is where we finally unmap the freed block.
 //
-//  - element (IN): BlockMap Iterator referencing the block of which to search
-//      for duplicates.
+//  - heap (IN): Handle to the heap to which the block being freed belongs.
+//
+//  - flags (IN): Heap control flags.
+//
+//  - mem (IN): Pointer to the memory block being freed.
 //
 //  Return Value:
 //
-//    Returns the number of duplicate blocks erased from the block map.
+//    Returns the value returned by RtlFreeHeap.
 //
-SIZE_T VisualLeakDetector::eraseduplicates (const BlockMap::Iterator &element)
+BOOL VisualLeakDetector::_RtlFreeHeap (HANDLE heap, DWORD flags, LPVOID mem)
 {
-    BlockMap::Iterator  blockit;
-    BlockMap           *blockmap;
-    blockinfo_t        *elementinfo;
-    SIZE_T              erased = 0;
-    HeapMap::Iterator   heapit;
-    blockinfo_t        *info;
-    BlockMap::Iterator  previt;
+    BOOL status;
 
-    elementinfo = (*element).second;
+    // Unmap the block from the specified heap.
+    vld.unmapblock(heap, mem);
 
-    // Iteratate through all block maps, looking for blocks with the same size
-    // and callstack as the specified element.
-    for (heapit = m_heapmap->begin(); heapit != m_heapmap->end(); ++heapit) {
-        blockmap = &(*heapit).second->blockmap;
-        for (blockit = blockmap->begin(); blockit != blockmap->end(); ++blockit) {
-            if (blockit == element) {
-                // Don't delete the element of which we are searching for
-                // duplicates.
-                continue;
-            }
-            info = (*blockit).second;
-            if ((info->size == elementinfo->size) && (*(info->callstack) == *(elementinfo->callstack))) {
-                // Found a duplicate. Erase it.
-                delete info->callstack;
-                delete info;
-                previt = blockit - 1;
-                blockmap->erase(blockit);
-                blockit = previt;
-                erased++;
-            }
-        }
-    }
+    status = RtlFreeHeap(heap, flags, mem);
 
-    return erased;
+    return status;
 }
 
-// Free - Calls to IMalloc::Free will end up here. This function is just a
-//   wrapper around the real IMalloc::Free implementation.
-//
-//  - mem (IN): Pointer to the memory block to be freed.
+// _RtlReAllocateHeap - Calls to RtlReAllocateHeap are patched through to this
+//   function. This function invokes the real RtlReAllocateHeap and then calls
+//   VLD's reallocation tracking function. All arguments passed to this function
+//   are passed on to the real RtlReAllocateHeap without modification. Pretty
+//   much all memory re-allocations will eventually result in a call to
+//   RtlReAllocateHeap, so this is where we finally remap the reallocated block.
 //
-//  Return Value:
+//  - heap (IN): Handle to the heap to reallocate memory from.
 //
-//    None.
+//  - flags (IN): Heap control flags.
 //
-VOID VisualLeakDetector::Free (LPVOID mem)
-{
-    assert(m_imalloc != NULL);
-    m_imalloc->Free(mem);
-}
-
-// GetSize - Calls to IMalloc::GetSize will end up here. This function is just a
-//   wrapper around the real IMalloc::GetSize implementation.
+//  - mem (IN): Pointer to the currently allocated block which is to be
+//      reallocated.
 //
-//  - mem (IN): Pointer to the memory block to inquire about.
+//  - size (IN): Size, in bytes, of the block to reallocate.
 //
 //  Return Value:
 //
-//    Returns the value returned by the system implementation of
-//    IMalloc::GetSize.
+//    Returns the value returned by RtlReAllocateHeap.
 //
-ULONG VisualLeakDetector::GetSize (LPVOID mem)
+LPVOID VisualLeakDetector::_RtlReAllocateHeap (HANDLE heap, DWORD flags, LPVOID mem, SIZE_T size)
 {
-    assert(m_imalloc != NULL);
-    return m_imalloc->GetSize(mem);
-}
+    BOOL                 crtalloc;
+    BOOL                 excluded = FALSE;
+    SIZE_T               fp;
+    moduleinfo_t         moduleinfo;
+    ModuleSet::Iterator  moduleit;
+    LPVOID               newmem;
+    SIZE_T               returnaddress;
+    tls_t               *tls = vld.gettls();
 
-// gettls - Obtains the thread local strorage structure for the calling thread.
-//
-//  Return Value:
-//
-//    Returns a pointer to the thread local storage structure. (This function
-//    always succeeds).
-//
-tls_t* VisualLeakDetector::gettls ()
-{
-    tls_t *tls;
-    
-    // Get the pointer to this thread's thread local storage structure.
-    tls = (tls_t*)TlsGetValue(m_tlsindex);
-    assert(GetLastError() == ERROR_SUCCESS);
+    // Reallocate the block.
+    newmem = RtlReAllocateHeap(heap, flags, mem, size);
 
-    if (tls == NULL) {
-        // This thread's thread local storage structure has not been allocated.
-        tls = new tls_t;
-        TlsSetValue(m_tlsindex, tls);
+    if (newmem != NULL) {
+        if (tls->addrfp == 0x0) {
+            // This is the first call to enter VLD for the current allocation.
+            // Record the current frame pointer.
+            FRAMEPOINTER(fp);
+        }
+        else {
+            fp = tls->addrfp;
+        }
+        crtalloc = (tls->flags & VLD_TLS_CRTALLOC) ? TRUE : FALSE;
+
+        // Reset thread local flags and variables, in case any libraries called
+        // into while remapping the block allocate some memory.
         tls->addrfp = 0x0;
-        tls->flags = 0x0;
-        tls->threadid = GetCurrentThreadId();
+        tls->flags &= ~VLD_TLS_CRTALLOC;
 
-        // Add this thread's TLS to the TlsSet.
-        EnterCriticalSection(&m_tlslock);
-        m_tlsset->insert(tls);
-        LeaveCriticalSection(&m_tlslock);
+        // Find the information for the module that initiated this reallocation.
+        returnaddress = *((SIZE_T*)fp + 1);
+        moduleinfo.addrhigh = returnaddress;
+        moduleinfo.addrlow  = returnaddress;
+        EnterCriticalSection(&vld.m_moduleslock);
+        moduleit = vld.m_loadedmodules->find(moduleinfo);
+        if (moduleit != vld.m_loadedmodules->end()) {
+            excluded = (*moduleit).flags & VLD_MODULE_EXCLUDED ? TRUE : FALSE;
+        }
+        LeaveCriticalSection(&vld.m_moduleslock);
+        if (!excluded) {
+            // The module that initiated this allocation is included in leak
+            // detection. Remap the block.
+            vld.remapblock(heap, mem, newmem, size, fp, crtalloc);
+        }
     }
 
-    return tls;
-}
+    // Reset thread local flags and variables for the next allocation.
+    tls->addrfp = 0x0;
+    tls->flags &= ~VLD_TLS_CRTALLOC;
 
-// HeapMinimize - Calls to IMalloc::HeapMinimize will end up here. This function
-//   is just a wrapper around the real IMalloc::HeapMinimize implementation.
-//
-//  Return Value:
-//
-//    None.
-//
-VOID VisualLeakDetector::HeapMinimize ()
-{
-    assert(m_imalloc != NULL);
-    m_imalloc->HeapMinimize();
+    return newmem;
 }
 
-// mapblock - Tracks memory allocations. Information about allocated blocks is
-//   collected and then the block is mapped to this information.
-//
-//  - heap (IN): Handle to the heap from which the block has been allocated.
+////////////////////////////////////////////////////////////////////////////////
 //
-//  - mem (IN): Pointer to the memory block being allocated.
+// COM IAT Replacement Functions
 //
-//  - size (IN): Size, in bytes, of the memory block being allocated.
+////////////////////////////////////////////////////////////////////////////////
+
+// _CoGetMalloc - Calls to CoGetMalloc are patched through to this function.
+//   This function returns a pointer to Visual Leak Detector's implementation
+//   of the IMalloc interface, instead of returning a pointer to the system
+//   implementation. This allows VLD's implementation of the IMalloc interface
+//   (which is basically a thin wrapper around the system implementation) to be
+//   invoked in place of the system implementation.
 //
-//  - framepointer (IN): Framepointer at the time this allocation first entered
-//      VLD's code. This is used from determining the starting point for the
-//      stack trace.
+//  - context (IN): Reserved; value must be 1.
 //
-//  - crtalloc (IN): Should be set to TRUE if this allocation is a CRT memory
-//      block. Otherwise should be FALSE.
+//  - imalloc (IN): Address of a pointer to receive the address of VLD's
+//      implementation of the IMalloc interface.
 //
 //  Return Value:
 //
-//    None.
+//    Always returns S_OK.
 //
-VOID VisualLeakDetector::mapblock (HANDLE heap, LPCVOID mem, SIZE_T size, SIZE_T framepointer, BOOL crtalloc)
+HRESULT VisualLeakDetector::_CoGetMalloc (DWORD context, LPMALLOC *imalloc)
 {
-    blockinfo_t        *blockinfo;
-    BlockMap::Iterator  blockit;
-    BlockMap           *blockmap;
-    HeapMap::Iterator   heapit;
-    static SIZE_T       serialnumber = 0;
+    static CoGetMalloc_t pCoGetMalloc = NULL;
 
-    // Record the block's information.
-    blockinfo = new blockinfo_t;
-    if (m_options & VLD_OPT_SAFE_STACK_WALK) {
-        blockinfo->callstack = new SafeCallStack;
-    }
-    else {
-        blockinfo->callstack = new FastCallStack;
-    }
-    if (m_options & VLD_OPT_TRACE_INTERNAL_FRAMES) {
-        // Passing NULL for the frame pointer argument will force the stack
-        // trace to begin at the current frame.
-        blockinfo->callstack->getstacktrace(m_maxtraceframes, NULL);
-    }
-    else {
-        // Start the stack trace at the call that first entered VLD's code.
-        blockinfo->callstack->getstacktrace(m_maxtraceframes, (SIZE_T*)framepointer);
+    HMODULE ole32;
+
+    *imalloc = (LPMALLOC)&vld;
+
+    if (pCoGetMalloc == NULL) {
+        // This is the first call to this function. Link to the real
+        // CoGetMalloc and get a pointer to the system implementation of the
+        // IMalloc interface.
+        ole32 = GetModuleHandle(L"ole32.dll");
+        pCoGetMalloc = (CoGetMalloc_t)GetProcAddress(ole32, "CoGetMalloc");
+        pCoGetMalloc(context, &vld.m_imalloc);
     }
-    blockinfo->serialnumber = serialnumber++;
-    blockinfo->size = size;
 
-    // Insert the block's information into the block map.
-    EnterCriticalSection(&m_maplock);
-    heapit = m_heapmap->find(heap);
-    if (heapit == m_heapmap->end()) {
-        // We haven't mapped this heap to a block map yet. Do it now.
-        mapheap(heap);
-        heapit = m_heapmap->find(heap);
-        assert(heapit != m_heapmap->end());
-    }
-    if (crtalloc == TRUE) {
-        // The heap that this block was allocated from is a CRT heap.
-        (*heapit).second->flags |= VLD_HEAP_CRT;
+    return S_OK;
+}
+
+// _CoTaskMemAlloc - Calls to CoTaskMemAlloc are patched through to this
+//   function. This function is just a wrapper around the real CoTaskMemAlloc
+//   that sets appropriate flags to be consulted when the memory is actually
+//   allocated by RtlAllocateHeap.
+//
+//  - size (IN): Size of the memory block to allocate.
+//
+//  Return Value:
+//
+//    Returns the value returned from CoTaskMemAlloc.
+//
+LPVOID VisualLeakDetector::_CoTaskMemAlloc (ULONG size)
+{
+    static CoTaskMemAlloc_t pCoTaskMemAlloc = NULL;
+
+    LPVOID   block;
+    SIZE_T   fp;
+    HMODULE  ole32;
+    tls_t   *tls = vld.gettls();
+
+    if (tls->addrfp == 0x0) {
+        // This is the first call to enter VLD for the current allocation.
+        // Record the current frame pointer.
+        FRAMEPOINTER(fp);
+        tls->addrfp = fp;
     }
-    blockmap = &(*heapit).second->blockmap;
-    blockit = blockmap->insert(mem, blockinfo);
-    if (blockit == blockmap->end()) {
-        // A block with this address has already been allocated. The
-        // previously allocated block must have been freed (probably by some
-        // mechanism unknown to VLD), or the heap wouldn't have allocated it
-        // again. Replace the previously allocated info with the new info.
-        blockit = blockmap->find(mem);
-        delete (*blockit).second->callstack;
-        delete (*blockit).second;
-        blockmap->erase(blockit);
-        blockmap->insert(mem, blockinfo);
+
+    if (pCoTaskMemAlloc == NULL) {
+        // This is the first call to this function. Link to the real
+        // CoTaskMemAlloc.
+        ole32 = GetModuleHandle(L"ole32.dll");
+        pCoTaskMemAlloc = (CoTaskMemAlloc_t)GetProcAddress(ole32, "CoTaskMemAlloc");
     }
-    LeaveCriticalSection(&m_maplock);
+
+    // Do the allocation. The block will be mapped by _RtlAllocateHeap.
+    block = pCoTaskMemAlloc(size);
+
+    // Reset thread local flags and variables for the next allocation.
+    tls->addrfp = 0x0;
+    tls->flags &= ~VLD_TLS_CRTALLOC;
+    
+    return block;
 }
 
-// mapheap - Tracks heap creation. Creates a block map for tracking individual
-//   allocations from the newly created heap and then maps the heap to this
-//   block map.
+// _CoTaskMemRealloc - Calls to CoTaskMemRealloc are patched through to this
+//   function. This function is just a wrapper around the real CoTaskMemRealloc
+//   that sets appropriate flags to be consulted when the memory is actually
+//   allocated by RtlAllocateHeap.
 //
-//  - heap (IN): Handle to the newly created heap.
+//  - mem (IN): Pointer to the memory block to reallocate.
+//
+//  - size (IN): Size, in bytes, of the block to reallocate.
 //
 //  Return Value:
 //
-//    None.
+//    Returns the value returned from CoTaskMemRealloc.
 //
-VOID VisualLeakDetector::mapheap (HANDLE heap)
+LPVOID VisualLeakDetector::_CoTaskMemRealloc (LPVOID mem, ULONG size)
 {
-    heapinfo_t        *heapinfo;
-    HeapMap::Iterator  heapit;
+    static CoTaskMemRealloc_t pCoTaskMemRealloc = NULL;
 
-    // Create a new block map for this heap and insert it into the heap map.
-    heapinfo = new heapinfo_t;
-    heapinfo->blockmap.reserve(BLOCKMAPRESERVE);
-    heapinfo->flags = 0x0;
-    EnterCriticalSection(&m_maplock);
-    heapit = m_heapmap->insert(heap, heapinfo);
-    if (heapit == m_heapmap->end()) {
-        // Somehow this heap has been created twice without being destroyed,
-        // or at least it was destroyed without VLD's knowledge. Unmap the heap
-        // from the existing heapinfo, and remap it to the new one.
-        report(L"WARNING: Visual Leak Detector detected a duplicate heap (" ADDRESSFORMAT L").\n", heap);
-        heapit = m_heapmap->find(heap);
-        unmapheap((*heapit).first);
-        m_heapmap->insert(heap, heapinfo);
+    LPVOID   block;
+    SIZE_T   fp;
+    HMODULE  ole32;
+    tls_t   *tls = vld.gettls();
+
+    if (tls->addrfp == 0x0) {
+        // This is the first call to enter VLD for the current allocation.
+        // Record the current frame pointer.
+        FRAMEPOINTER(fp);
+        tls->addrfp = fp;
     }
-    LeaveCriticalSection(&m_maplock);
+
+    if (pCoTaskMemRealloc == NULL) {
+        // This is the first call to this function. Link to the real
+        // CoTaskMemRealloc.
+        ole32 = GetModuleHandle(L"ole32.dll");
+        pCoTaskMemRealloc = (CoTaskMemRealloc_t)GetProcAddress(ole32, "CoTaskMemRealloc");
+    }
+
+    // Do the allocation. The block will be mapped by _RtlReAllocateHeap.
+    block = pCoTaskMemRealloc(mem, size);
+
+    // Reset thread local flags and variables for the next allocation.
+    tls->addrfp = 0x0;
+    tls->flags &= ~VLD_TLS_CRTALLOC;
+
+    return block;
 }
 
-// QueryInterface - Calls to IMalloc::QueryInterface will end up here. This
-//   function is just a wrapper around the real IMalloc::QueryInterface
-//   implementation.
+////////////////////////////////////////////////////////////////////////////////
 //
-//  - iid (IN): COM interface ID to query about.
+// Public COM IMalloc Implementation Functions
 //
-//  - object (IN): Address of a pointer to receive the requested interface
-//      pointer.
+////////////////////////////////////////////////////////////////////////////////
+
+// AddRef - Calls to IMalloc::AddRef end up here. This function is just a
+//   wrapper around the real IMalloc::AddRef implementation.
 //
 //  Return Value:
 //
 //    Returns the value returned by the system implementation of
-//    IMalloc::QueryInterface.
+//    IMalloc::AddRef.
 //
-HRESULT VisualLeakDetector::QueryInterface (REFIID iid, LPVOID *object)
+ULONG VisualLeakDetector::AddRef ()
 {
     assert(m_imalloc != NULL);
-    return m_imalloc->QueryInterface(iid, object);
+    return m_imalloc->AddRef();
 }
 
-// Realloc - Calls to IMalloc::Realloc will end up here. This function is just a
-//   wrapper around the real IMalloc::Realloc implementation that sets
-//   appropriate flags to be consulted when the memory is actually allocated by
-//   RtlAllocateHeap.
-//
-//  - mem (IN): Pointer to the memory block to reallocate.
+// Alloc - Calls to IMalloc::Alloc end up here. This function is just a wrapper
+//   around the real IMalloc::Alloc implementation that sets appropriate flags
+//   to be consulted when the memory is actually allocated by RtlAllocateHeap.
 //
-//  - size (IN): Size, in bytes, of the memory block to reallocate.
+//  - size (IN): The size of the memory block to allocate.
 //
 //  Return Value:
 //
-//    Returns the value returned by the system implementation of
-//    IMalloc::Realloc.
+//    Returns the value returned by the system's IMalloc::Alloc implementation.
 //
-LPVOID VisualLeakDetector::Realloc (LPVOID mem, ULONG size)
+LPVOID VisualLeakDetector::Alloc (ULONG size)
 {
     LPVOID  block;
     SIZE_T  fp;
@@ -2988,351 +2604,145 @@ LPVOID VisualLeakDetector::Realloc (LPVOID mem, ULONG size)
         tls->addrfp = fp;
     }
 
-    // Do the allocation. The block will be mapped by _RtlReAllocateHeap.
+    // Do the allocation. The block will be mapped by _RtlAllocateHeap.
     assert(m_imalloc != NULL);
-    block = m_imalloc->Realloc(mem, size);
+    block = m_imalloc->Alloc(size);
 
     // Reset thread local flags and variables for the next allocation.
     tls->addrfp = 0x0;
     tls->flags &= ~VLD_TLS_CRTALLOC;
-    
+
     return block;
 }
 
-// Release - Calls to IMalloc::Release will end up here. This function is just
-//   a wrapper around the real IMalloc::Release implementation.
+// DidAlloc - Calls to IMalloc::DidAlloc will end up here. This function is just
+//   a wrapper around the system implementation of IMalloc::DidAlloc.
+//
+//  - mem (IN): Pointer to a memory block to inquire about.
 //
 //  Return Value:
 //
 //    Returns the value returned by the system implementation of
-//    IMalloc::Release.
+//    IMalloc::DidAlloc.
 //
-ULONG VisualLeakDetector::Release ()
+INT VisualLeakDetector::DidAlloc (LPVOID mem)
 {
     assert(m_imalloc != NULL);
-    return m_imalloc->Release();
+    return m_imalloc->DidAlloc(mem);
 }
 
-// remapblock - Tracks reallocations. Unmaps a block from its previously
-//   collected information and remaps it to updated information.
-//
-//  Note: If the block itself remains at the same address, then the block's
-//   information can simply be updated rather than having to actually erase and
-//   reinsert the block.
-//
-//  - heap (IN): Handle to the heap from which the memory is being reallocated.
-//
-//  - mem (IN): Pointer to the memory block being reallocated.
-//
-//  - newmem (IN): Pointer to the memory block being returned to the caller
-//      that requested the reallocation. This pointer may or may not be the same
-//      as the original memory block (as pointed to by "mem").
-//
-//  - size (IN): Size, in bytes, of the new memory block.
-//
-//  - framepointer (IN): The frame pointer at which this reallocation entered
-//      VLD's code. Used for determining the starting point of the stack trace.
+// Free - Calls to IMalloc::Free will end up here. This function is just a
+//   wrapper around the real IMalloc::Free implementation.
 //
-//  - crtalloc (IN): Should be set to TRUE if this reallocation is for a CRT
-//      memory block. Otherwise should be set to FALSE.
+//  - mem (IN): Pointer to the memory block to be freed.
 //
 //  Return Value:
 //
 //    None.
 //
-VOID VisualLeakDetector::remapblock (HANDLE heap, LPCVOID mem, LPCVOID newmem, SIZE_T size, SIZE_T framepointer,
-                                     BOOL crtalloc)
+VOID VisualLeakDetector::Free (LPVOID mem)
 {
-    BlockMap::Iterator   blockit;
-    BlockMap            *blockmap;
-    HeapMap::Iterator    heapit;
-    blockinfo_t         *info;
-
-    if (newmem != mem) {
-        // The block was not reallocated in-place. Instead the old block was
-        // freed and a new block allocated to satisfy the new size.
-        unmapblock(heap, mem);
-        mapblock(heap, newmem, size, framepointer, crtalloc);
-        return;
-    }
-
-    // The block was reallocated in-place. Find the existing blockinfo_t
-    // entry in the block map and update it with the new callstack and size.
-    EnterCriticalSection(&m_maplock);
-    heapit = m_heapmap->find(heap);
-    if (heapit == m_heapmap->end()) {
-        // We haven't mapped this heap to a block map yet. Obviously the
-        // block has also not been mapped to a blockinfo_t entry yet either,
-        // so treat this reallocation as a brand-new allocation (this will
-        // also map the heap to a new block map).
-        mapblock(heap, newmem, size, framepointer, crtalloc);
-        LeaveCriticalSection(&m_maplock);
-        return;
-    }
-
-    // Find the block's blockinfo_t structure so that we can update it.
-    blockmap = &(*heapit).second->blockmap;
-    blockit = blockmap->find(mem);
-    if (blockit == blockmap->end()) {
-        // The block hasn't been mapped to a blockinfo_t entry yet.
-        // Treat this reallocation as a new allocation.
-        mapblock(heap, newmem, size, framepointer, crtalloc);
-        LeaveCriticalSection(&m_maplock);
-        return;
-    }
-
-    // Found the blockinfo_t entry for this block. Update it with
-    // a new callstack and new size.
-    info = (*blockit).second;
-    info->callstack->clear();
-    if (crtalloc) {
-        // The heap that this block was allocated from is a CRT heap.
-        (*heapit).second->flags |= VLD_HEAP_CRT;
-    }
-    LeaveCriticalSection(&m_maplock);
+    assert(m_imalloc != NULL);
+    m_imalloc->Free(mem);
+}
 
-    // Update the block's callstack and size.
-    if (m_options & VLD_OPT_TRACE_INTERNAL_FRAMES) {
-        // Passing NULL for the frame pointer argument will force
-        // the stack trace to begin at the current frame.
-        info->callstack->getstacktrace(m_maxtraceframes, NULL);
-    }
-    else {
-        // Start the stack trace at the call that first entered
-        // VLD's code.
-        info->callstack->getstacktrace(m_maxtraceframes, (SIZE_T*)framepointer);
-    }
-    info->size = size;
+// GetSize - Calls to IMalloc::GetSize will end up here. This function is just a
+//   wrapper around the real IMalloc::GetSize implementation.
+//
+//  - mem (IN): Pointer to the memory block to inquire about.
+//
+//  Return Value:
+//
+//    Returns the value returned by the system implementation of
+//    IMalloc::GetSize.
+//
+ULONG VisualLeakDetector::GetSize (LPVOID mem)
+{
+    assert(m_imalloc != NULL);
+    return m_imalloc->GetSize(mem);
 }
 
-// reportconfig - Generates a brief report summarizing Visual Leak Detector's
-//   configuration, as loaded from the vld.ini file.
+// HeapMinimize - Calls to IMalloc::HeapMinimize will end up here. This function
+//   is just a wrapper around the real IMalloc::HeapMinimize implementation.
 //
 //  Return Value:
 //
 //    None.
 //
-VOID VisualLeakDetector::reportconfig ()
+VOID VisualLeakDetector::HeapMinimize ()
 {
-    if (m_options & VLD_OPT_AGGREGATE_DUPLICATES) {
-        report(L"    Aggregating duplicate leaks.\n");
-    }
-    if (wcslen(m_forcedmodulelist) != 0) {
-        report(L"    Forcing inclusion of these modules in leak detection: %s\n", m_forcedmodulelist);
-    }
-    if (m_maxdatadump != VLD_DEFAULT_MAX_DATA_DUMP) {
-        if (m_maxdatadump == 0) {
-            report(L"    Suppressing data dumps.\n");
-        }
-        else {
-            report(L"    Limiting data dumps to %lu bytes.\n", m_maxdatadump);
-        }
-    }
-    if (m_maxtraceframes != VLD_DEFAULT_MAX_TRACE_FRAMES) {
-        report(L"    Limiting stack traces to %u frames.\n", m_maxtraceframes);
-    }
-    if (m_options & VLD_OPT_UNICODE_REPORT) {
-        report(L"    Generating a Unicode (UTF-16) encoded report.\n");
-    }
-    if (m_options & VLD_OPT_REPORT_TO_FILE) {
-        if (m_options & VLD_OPT_REPORT_TO_DEBUGGER) {
-            report(L"    Outputting the report to the debugger and to %s\n", m_reportfilepath);
-        }
-        else {
-            report(L"    Outputting the report to %s\n", m_reportfilepath);
-        }
-    }
-    if (m_options & VLD_OPT_SLOW_DEBUGGER_DUMP) {
-        report(L"    Outputting the report to the debugger at a slower rate.\n");
-    }
-    if (m_options & VLD_OPT_SAFE_STACK_WALK) {
-        report(L"    Using the \"safe\" (but slow) stack walking method.\n");
-    }
-    if (m_options & VLD_OPT_SELF_TEST) {
-        report(L"    Perfoming a memory leak self-test.\n");
-    }
-    if (m_options & VLD_OPT_START_DISABLED) {
-        report(L"    Starting with memory leak detection disabled.\n");
-    }
-    if (m_options & VLD_OPT_TRACE_INTERNAL_FRAMES) {
-        report(L"    Including heap and VLD internal frames in stack traces.\n");
-    }
+    assert(m_imalloc != NULL);
+    m_imalloc->HeapMinimize();
 }
 
-// reportleaks - Generates a memory leak report for the specified heap.
+// QueryInterface - Calls to IMalloc::QueryInterface will end up here. This
+//   function is just a wrapper around the real IMalloc::QueryInterface
+//   implementation.
 //
-//  - heap (IN): Handle to the heap for which to generate a memory leak
-//      report.
+//  - iid (IN): COM interface ID to query about.
+//
+//  - object (IN): Address of a pointer to receive the requested interface
+//      pointer.
 //
 //  Return Value:
 //
-//    None.
+//    Returns the value returned by the system implementation of
+//    IMalloc::QueryInterface.
 //
-VOID VisualLeakDetector::reportleaks (HANDLE heap)
+HRESULT VisualLeakDetector::QueryInterface (REFIID iid, LPVOID *object)
 {
-    LPCVOID              address;
-    LPCVOID              block;
-    BlockMap::Iterator   blockit;
-    BlockMap            *blockmap;
-    crtdbgblockheader_t *crtheader;
-    SIZE_T               duplicates;
-    heapinfo_t          *heapinfo;
-    HeapMap::Iterator    heapit;
-    blockinfo_t         *info;
-    SIZE_T               size;
-
-    // Find the heap's information (blockmap, etc).
-    EnterCriticalSection(&m_maplock);
-    heapit = m_heapmap->find(heap);
-    if (heapit == m_heapmap->end()) {
-        // Nothing is allocated from this heap. No leaks.
-        LeaveCriticalSection(&m_maplock);
-        return;
-    }
-
-    heapinfo = (*heapit).second;
-    blockmap = &heapinfo->blockmap;
-    for (blockit = blockmap->begin(); blockit != blockmap->end(); ++blockit) {
-        // Found a block which is still in the BlockMap. We've identified a
-        // potential memory leak.
-        block = (*blockit).first;
-        info = (*blockit).second;
-        address = block;
-        size = info->size;
-        if (heapinfo->flags & VLD_HEAP_CRT) {
-            // This block is allocated to a CRT heap, so the block has a CRT
-            // memory block header prepended to it.
-            crtheader = (crtdbgblockheader_t*)block;
-            if (CRT_USE_TYPE(crtheader->use) == CRT_USE_INTERNAL) {
-                // This block is marked as being used internally by the CRT.
-                // The CRT will free the block after VLD is destroyed.
-                continue;
-            }
-            // The CRT header is more or less transparent to the user, so
-            // the information about the contained block will probably be
-            // more useful to the user. Accordingly, that's the information
-            // we'll include in the report.
-            address = CRTDBGBLOCKDATA(block);
-            size = crtheader->size;
-        }
-        // It looks like a real memory leak.
-        if (m_leaksfound == 0) {
-            report(L"WARNING: Visual Leak Detector detected memory leaks!\n");
-        }
-        m_leaksfound++;
-        report(L"---------- Block %ld at " ADDRESSFORMAT L": %u bytes ----------\n", info->serialnumber, address, size);
-        if (m_options & VLD_OPT_AGGREGATE_DUPLICATES) {
-            // Aggregate all other leaks which are duplicates of this one
-            // under this same heading, to cut down on clutter.
-            duplicates = eraseduplicates(blockit);
-            if (duplicates) {
-                report(L"A total of %lu leaks match this size and call stack. Showing only the first one.\n",
-                       duplicates + 1);
-                m_leaksfound += duplicates;
-            }
-        }
-        // Dump the call stack.
-        report(L"  Call Stack:\n");
-        info->callstack->dump(m_options & VLD_OPT_TRACE_INTERNAL_FRAMES);
-        // Dump the data in the user data section of the memory block.
-        if (m_maxdatadump != 0) {
-            report(L"  Data:\n");
-            if (m_options & VLD_OPT_UNICODE_REPORT) {
-                dumpmemoryw(address, (m_maxdatadump < size) ? m_maxdatadump : size);
-            }
-            else {
-                dumpmemorya(address, (m_maxdatadump < size) ? m_maxdatadump : size);
-            }
-        }
-        report(L"\n");
-    }
-
-    LeaveCriticalSection(&m_maplock);
+    assert(m_imalloc != NULL);
+    return m_imalloc->QueryInterface(iid, object);
 }
 
-// unmapblock - Tracks memory blocks that are freed. Unmaps the specified block
-//   from the block's information, relinquishing internally allocated resources.
+// Realloc - Calls to IMalloc::Realloc will end up here. This function is just a
+//   wrapper around the real IMalloc::Realloc implementation that sets
+//   appropriate flags to be consulted when the memory is actually allocated by
+//   RtlAllocateHeap.
 //
-//  - heap (IN): Handle to the heap to which this block is being freed.
+//  - mem (IN): Pointer to the memory block to reallocate.
 //
-//  - mem (IN): Pointer to the memory block being freed.
+//  - size (IN): Size, in bytes, of the memory block to reallocate.
 //
 //  Return Value:
 //
-//    None.
+//    Returns the value returned by the system implementation of
+//    IMalloc::Realloc.
 //
-VOID VisualLeakDetector::unmapblock (HANDLE heap, LPCVOID mem)
+LPVOID VisualLeakDetector::Realloc (LPVOID mem, ULONG size)
 {
-    BlockMap::Iterator  blockit;
-    BlockMap           *blockmap;
-    HeapMap::Iterator   heapit;
-    blockinfo_t        *info;
+    LPVOID  block;
+    SIZE_T  fp;
+    tls_t  *tls = vld.gettls();
 
-    // Find this heap's block map.
-    EnterCriticalSection(&m_maplock);
-    heapit = m_heapmap->find(heap);
-    if (heapit == m_heapmap->end()) {
-        // We don't have a block map for this heap. We must not have monitored
-        // this allocation (probably happened before VLD was initialized).
-        LeaveCriticalSection(&m_maplock);
-        return;
+    if (tls->addrfp == 0x0) {
+        // This is the first call to enter VLD for the current allocation.
+        // Record the current frame pointer.
+        FRAMEPOINTER(fp);
+        tls->addrfp = fp;
     }
 
-    // Find this block in the block map.
-    blockmap = &(*heapit).second->blockmap;
-    blockit = blockmap->find(mem);
-    if (blockit == blockmap->end()) {
-        // This block is not in the block map. We must not have monitored this
-        // allocation (probably happened before VLD was initialized).
-        LeaveCriticalSection(&m_maplock);
-        return;
-    }
+    // Do the allocation. The block will be mapped by _RtlReAllocateHeap.
+    assert(m_imalloc != NULL);
+    block = m_imalloc->Realloc(mem, size);
 
-    // Free the blockinfo_t structure and erase it from the block map.
-    info = (*blockit).second;
-    delete info->callstack;
-    delete info;
-    blockmap->erase(blockit);
-    LeaveCriticalSection(&m_maplock);
+    // Reset thread local flags and variables for the next allocation.
+    tls->addrfp = 0x0;
+    tls->flags &= ~VLD_TLS_CRTALLOC;
+    
+    return block;
 }
 
-// unmapheap - Tracks heap destruction. Unmaps the specified heap from its block
-//   map. The block map is cleared and deleted, relinquishing internally
-//   allocated resources.
-//
-//  - heap (IN): Handle to the heap which is being destroyed.
+// Release - Calls to IMalloc::Release will end up here. This function is just
+//   a wrapper around the real IMalloc::Release implementation.
 //
 //  Return Value:
 //
-//    None.
+//    Returns the value returned by the system implementation of
+//    IMalloc::Release.
 //
-VOID VisualLeakDetector::unmapheap (HANDLE heap)
+ULONG VisualLeakDetector::Release ()
 {
-    BlockMap::Iterator  blockit;
-    BlockMap           *blockmap;
-    heapinfo_t         *heapinfo;
-    HeapMap::Iterator   heapit;
-
-    // Find this heap's block map.
-    EnterCriticalSection(&m_maplock);
-    heapit = m_heapmap->find(heap);
-    if (heapit == m_heapmap->end()) {
-        // This heap hasn't been mapped. We must not have monitored this heap's
-        // creation (probably happened before VLD was initialized).
-        LeaveCriticalSection(&m_maplock);
-        return;
-    }
-
-    // Free all of the blockinfo_t structures stored in the block map.
-    heapinfo = (*heapit).second;
-    blockmap = &heapinfo->blockmap;
-    for (blockit = blockmap->begin(); blockit != blockmap->end(); ++blockit) {
-        delete (*blockit).second->callstack;
-        delete (*blockit).second;
-    }
-    delete heapinfo;
-
-    // Remove this heap's block map from the heap map.
-    m_heapmap->erase(heapit);
-    LeaveCriticalSection(&m_maplock);
+    assert(m_imalloc != NULL);
+    return m_imalloc->Release();
 }