home *** CD-ROM | disk | FTP | other *** search
/ io Programmo 40 / IOPROG_40.ISO / SOFT / NETFrameworkSDK.exe / comsdk.cab / samples1.exe / Debugger / DebuggerUtil.h < prev    next >
Encoding:
C/C++ Source or Header  |  2000-06-23  |  22.5 KB  |  636 lines

  1. #ifndef __DEBUGGERUTIL_H__
  2. #define __DEBUGGERUTIL_H__
  3.  
  4. #include "stdlib.h"
  5.  
  6. static inline void * __cdecl operator new(size_t n) { return LocalAlloc(LMEM_FIXED, n); }
  7. static inline void * __cdecl operator new[](size_t n) { return LocalAlloc(LMEM_FIXED, n); };
  8. static inline void __cdecl operator delete(void *p) { LocalFree(p); }
  9. static inline void __cdecl operator delete[](void *p) { LocalFree(p); }
  10.  
  11. /* ------------------------------------------------------------------------- *
  12.  * Utility methods used by the debugger sample.
  13.  * ------------------------------------------------------------------------- */
  14.  
  15. #define     CQUICKBYTES_BASE_SIZE           512
  16. #define     CQUICKBYTES_INCREMENTAL_SIZE    128
  17.  
  18. //*****************************************************************************
  19. //
  20. // **** CQuickBytes
  21. // This helper class is useful for cases where 90% of the time you allocate 512
  22. // or less bytes for a data structure.  This class contains a 512 byte buffer.
  23. // Alloc() will return a pointer to this buffer if your allocation is small
  24. // enough, otherwise it asks the heap for a larger buffer which is freed for
  25. // you.  No mutex locking is required for the small allocation case, making the
  26. // code run faster, less heap fragmentation, etc...  Each instance will allocate
  27. // 520 bytes, so use accordinly.
  28. //
  29. //*****************************************************************************
  30. class CQuickBytes
  31. {
  32. public:
  33.     CQuickBytes() :
  34.         pbBuff(0),
  35.         iSize(0),
  36.         cbTotal(CQUICKBYTES_BASE_SIZE)
  37.     { }
  38.  
  39.     ~CQuickBytes()
  40.     {
  41.         if (pbBuff)
  42.             free(pbBuff);
  43.     }
  44.  
  45.     void *Alloc(int iItems)
  46.     {
  47.         iSize = iItems;
  48.         if (iItems <= CQUICKBYTES_BASE_SIZE)
  49.             return (&rgData[0]);
  50.         else
  51.         {
  52.             pbBuff = malloc(iItems);
  53.             return (pbBuff);
  54.         }
  55.     }
  56.  
  57.     HRESULT ReSize(int iItems)
  58.     {
  59.         void *pbBuffNew;
  60.         if (iItems <= cbTotal)
  61.         {
  62.             iSize = iItems;
  63.             return NOERROR;
  64.         }
  65.  
  66.         pbBuffNew = malloc(iItems + CQUICKBYTES_INCREMENTAL_SIZE);
  67.         if (!pbBuffNew)
  68.             return E_OUTOFMEMORY;
  69.         if (pbBuff) 
  70.         {
  71.             memcpy(pbBuffNew, pbBuff, cbTotal);
  72.             free(pbBuff);
  73.         }
  74.         else
  75.         {
  76.             _ASSERTE(cbTotal == CQUICKBYTES_BASE_SIZE);
  77.             memcpy(pbBuffNew, rgData, cbTotal);
  78.         }
  79.         cbTotal = iItems + CQUICKBYTES_INCREMENTAL_SIZE;
  80.         iSize = iItems;
  81.         pbBuff = pbBuffNew;
  82.         return NOERROR;
  83.         
  84.     }
  85.     operator PVOID()
  86.     { return ((pbBuff) ? pbBuff : &rgData[0]); }
  87.  
  88.     void *Ptr()
  89.     { return ((pbBuff) ? pbBuff : &rgData[0]); }
  90.  
  91.     int Size()
  92.     { return (iSize); }
  93.  
  94.     void        *pbBuff;
  95.     int         iSize;              // number of bytes used
  96.     int         cbTotal;            // total bytes allocated in the buffer
  97.     BYTE        rgData[512];
  98. };
  99.  
  100. //*****************************************************************************
  101. // The information that the hash table implementation stores at the beginning
  102. // of every record that can be but in the hash table.
  103. //*****************************************************************************
  104. struct HASHENTRY
  105. {
  106.     USHORT      iPrev;                  // Previous bucket in the chain.
  107.     USHORT      iNext;                  // Next bucket in the chain.
  108. };
  109.  
  110. struct FREEHASHENTRY : HASHENTRY
  111. {
  112.     USHORT      iFree;
  113. };
  114.  
  115. //*****************************************************************************
  116. // Used by the FindFirst/FindNextEntry functions.  These api's allow you to
  117. // do a sequential scan of all entries.
  118. //*****************************************************************************
  119. struct HASHFIND
  120. {
  121.     USHORT      iBucket;            // The next bucket to look in.
  122.     USHORT      iNext;
  123. };
  124.  
  125.  
  126. //*****************************************************************************
  127. // This is a class that implements a chain and bucket hash table.  The table
  128. // is actually supplied as an array of structures by the user of this class
  129. // and this maintains the chains in a HASHENTRY structure that must be at the
  130. // beginning of every structure placed in the hash table.  Immediately
  131. // following the HASHENTRY must be the key used to hash the structure.
  132. //*****************************************************************************
  133. class CHashTable
  134. {
  135. protected:
  136.     BYTE        *m_pcEntries;           // Pointer to the array of structs.
  137.     USHORT      m_iEntrySize;           // Size of the structs.
  138.     USHORT      m_iBuckets;             // # of chains we are hashing into.
  139.     USHORT      *m_piBuckets;           // Ptr to the array of bucket chains.
  140.  
  141.     HASHENTRY *EntryPtr(USHORT iEntry)
  142.     { return ((HASHENTRY *) (m_pcEntries + (iEntry * m_iEntrySize))); }
  143.  
  144.     USHORT     ItemIndex(HASHENTRY *p)
  145.     {
  146.         //
  147.         // The following Index calculation is not safe on 64-bit platforms,
  148.         // so we'll assert a range check in debug, which will catch SOME
  149.         // offensive usages.  It also seems, to my eye, not to be safe on 
  150.         // 32-bit platforms, but the 32-bit compilers don't seem to complain
  151.         // about it.  Perhaps our warning levels are set too low? 
  152.         //
  153.         // [[@TODO: brianbec]]
  154.         //
  155.         
  156. #       pragma warning(disable:4244)
  157.  
  158.         _ASSERTE( (( ( ((BYTE*)p) - m_pcEntries ) / m_iEntrySize ) & (~0xFFFF)) == 0 ) ;
  159.  
  160.         return (((BYTE *) p - m_pcEntries) / m_iEntrySize);
  161.  
  162. #       pragma warning(default:4244)
  163.     }
  164.     
  165.  
  166. public:
  167.     CHashTable(
  168.         USHORT      iBuckets) :         // # of chains we are hashing into.
  169.         m_iBuckets(iBuckets),
  170.         m_piBuckets(NULL),
  171.         m_pcEntries(NULL)
  172.     {
  173.         _ASSERTE(iBuckets < 0xffff);
  174.     }
  175.     ~CHashTable()
  176.     {
  177.         if (m_piBuckets != NULL)
  178.         {
  179.             delete [] m_piBuckets;
  180.             m_piBuckets = NULL;
  181.         }
  182.     }
  183.  
  184. //*****************************************************************************
  185. // This is the second part of construction where we do all of the work that
  186. // can fail.  We also take the array of structs here because the calling class
  187. // presumably needs to allocate it in its NewInit.
  188. //*****************************************************************************
  189.     HRESULT NewInit(                    // Return status.
  190.         BYTE        *pcEntries,         // Array of structs we are managing.
  191.         USHORT      iEntrySize);        // Size of the entries.
  192.  
  193. //*****************************************************************************
  194. // Return a boolean indicating whether or not this hash table has been inited.
  195. //*****************************************************************************
  196.     int IsInited()
  197.     { return (m_piBuckets != NULL); }
  198.  
  199. //*****************************************************************************
  200. // This can be called to change the pointer to the table that the hash table
  201. // is managing.  You might call this if (for example) you realloc the size
  202. // of the table and its pointer is different.
  203. //*****************************************************************************
  204.     void SetTable(
  205.         BYTE        *pcEntries)         // Array of structs we are managing.
  206.     {
  207.         m_pcEntries = pcEntries;
  208.     }
  209.  
  210. //*****************************************************************************
  211. // Clear the hash table as if there were nothing in it.
  212. //*****************************************************************************
  213.     void Clear()
  214.     {
  215.         _ASSERTE(m_piBuckets != NULL);
  216.         memset(m_piBuckets, 0xff, m_iBuckets * sizeof(USHORT));
  217.     }
  218.  
  219. //*****************************************************************************
  220. // Add the struct at the specified index in m_pcEntries to the hash chains.
  221. //*****************************************************************************
  222.     BYTE *Add(                          // New entry.
  223.         USHORT      iHash,              // Hash value of entry to add.
  224.         USHORT      iIndex);            // Index of struct in m_pcEntries.
  225.  
  226. //*****************************************************************************
  227. // Delete the struct at the specified index in m_pcEntries from the hash chains.
  228. //*****************************************************************************
  229.     void Delete(
  230.         USHORT      iHash,              // Hash value of entry to delete.
  231.         USHORT      iIndex);            // Index of struct in m_pcEntries.
  232.  
  233.     void Delete(
  234.         USHORT      iHash,              // Hash value of entry to delete.
  235.         HASHENTRY   *psEntry);          // The struct to delete.
  236.  
  237. //*****************************************************************************
  238. // The item at the specified index has been moved, update the previous and
  239. // next item.
  240. //*****************************************************************************
  241.     void Move(
  242.         USHORT      iHash,              // Hash value for the item.
  243.         USHORT      iNew);              // New location.
  244.  
  245. //*****************************************************************************
  246. // Search the hash table for an entry with the specified key value.
  247. //*****************************************************************************
  248.     BYTE *Find(                         // Index of struct in m_pcEntries.
  249.         USHORT      iHash,              // Hash value of the item.
  250.         BYTE        *pcKey);            // The key to match.
  251.  
  252. //*****************************************************************************
  253. // Search the hash table for the next entry with the specified key value.
  254. //*****************************************************************************
  255.     USHORT FindNext(                    // Index of struct in m_pcEntries.
  256.         BYTE        *pcKey,             // The key to match.
  257.         USHORT      iIndex);            // Index of previous match.
  258.  
  259. //*****************************************************************************
  260. // Returns the first entry in the first hash bucket and inits the search
  261. // struct.  Use the FindNextEntry function to continue walking the list.  The
  262. // return order is not gauranteed.
  263. //*****************************************************************************
  264.     BYTE *FindFirstEntry(               // First entry found, or 0.
  265.         HASHFIND    *psSrch)            // Search object.
  266.     {
  267.         if (m_piBuckets == 0)
  268.             return (0);
  269.         psSrch->iBucket = 1;
  270.         psSrch->iNext = m_piBuckets[0];
  271.         return (FindNextEntry(psSrch));
  272.     }
  273.  
  274. //*****************************************************************************
  275. // Returns the next entry in the list.
  276. //*****************************************************************************
  277.     BYTE *FindNextEntry(                // The next entry, or0 for end of list.
  278.         HASHFIND    *psSrch);           // Search object.
  279.  
  280. protected:
  281.     virtual inline BOOL Cmp(const BYTE *pc1, const HASHENTRY *pc2) = 0;
  282. };
  283.  
  284.  
  285. //*****************************************************************************
  286. // Allocater classes for the CHashTableAndData class.  One is for VirtualAlloc
  287. // and the other for malloc.
  288. //*****************************************************************************
  289. class CVMemData
  290. {
  291. public:
  292.     static BYTE *Alloc(int iSize, int iMaxSize)
  293.     {
  294.         BYTE        *pPtr;
  295.  
  296.         _ASSERTE((iSize & 4095) == 0);
  297.         _ASSERTE((iMaxSize & 4095) == 0);
  298.         if ((pPtr = (BYTE *) VirtualAlloc(NULL, iMaxSize,
  299.                                         MEM_RESERVE, PAGE_NOACCESS)) == NULL ||
  300.             VirtualAlloc(pPtr, iSize, MEM_COMMIT, PAGE_READWRITE) == NULL)
  301.         {
  302.             VirtualFree(pPtr, 0, MEM_RELEASE);
  303.             return (NULL);
  304.         }
  305.         return (pPtr);
  306.     }
  307.     static void Free(BYTE *pPtr, int iSize)
  308.     {
  309.         _ASSERTE((iSize & 4095) == 0);
  310.         VirtualFree(pPtr, iSize, MEM_DECOMMIT);
  311.         VirtualFree(pPtr, 0, MEM_RELEASE);
  312.     }
  313.     static BYTE *Grow(BYTE *pPtr, int iCurSize)
  314.     {
  315.         _ASSERTE((iCurSize & 4095) == 0);
  316.         return ((BYTE *) VirtualAlloc(pPtr + iCurSize, GrowSize(), MEM_COMMIT, PAGE_READWRITE));
  317.     }
  318.     static int RoundSize(int iSize)
  319.     {
  320.         return ((iSize + 4095) & ~4095);
  321.     }
  322.     static int GrowSize()
  323.     {
  324.         return (4096);
  325.     }
  326. };
  327.  
  328. class CNewData
  329. {
  330. public:
  331.     static BYTE *Alloc(int iSize, int iMaxSize)
  332.     {
  333.         return ((BYTE *) malloc(iSize));
  334.     }
  335.     static void Free(BYTE *pPtr, int iSize)
  336.     {
  337.         free(pPtr);
  338.     }
  339.     static BYTE *Grow(BYTE *&pPtr, int iCurSize)
  340.     {
  341.         void *p = realloc(pPtr, iCurSize + GrowSize());
  342.         if (p == 0) return (0);
  343.         return (pPtr = (BYTE *) p);
  344.     }
  345.     static int RoundSize(int iSize)
  346.     {
  347.         return (iSize);
  348.     }
  349.     static int GrowSize()
  350.     {
  351.         return (256);
  352.     }
  353. };
  354.  
  355.  
  356. //*****************************************************************************
  357. // This simple code handles a contiguous piece of memory.  Growth is done via
  358. // realloc, so pointers can move.  This class just cleans up the amount of code
  359. // required in every function that uses this type of data structure.
  360. //*****************************************************************************
  361. class CMemChunk
  362. {
  363. public:
  364.     CMemChunk() : m_pbData(0), m_cbSize(0), m_cbNext(0) { }
  365.     ~CMemChunk()
  366.     {
  367.         Clear();
  368.     }
  369.  
  370.     BYTE *GetChunk(int cbSize)
  371.     {
  372.         BYTE *p;
  373.         if (m_cbSize - m_cbNext < cbSize)
  374.         {
  375.             int cbNew = max(cbSize, 512);
  376.             p = (BYTE *) realloc(m_pbData, m_cbSize + cbNew);
  377.             if (!p) return (0);
  378.             m_pbData = p;
  379.             m_cbSize += cbNew;
  380.         }
  381.         p = m_pbData + m_cbNext;
  382.         m_cbNext += cbSize;
  383.         return (p);
  384.     }
  385.  
  386.     // Can only delete the last unused chunk.  no free list.
  387.     void DelChunk(BYTE *p, int cbSize)
  388.     {
  389.         _ASSERTE(p >= m_pbData && p < m_pbData + m_cbNext);
  390.         if (p + cbSize  == m_pbData + m_cbNext)
  391.             m_cbNext -= cbSize;
  392.     }
  393.  
  394.     int Size()
  395.     { return (m_cbSize); }
  396.  
  397.     int Offset()
  398.     { return (m_cbNext); }
  399.  
  400.     BYTE *Ptr(int cbOffset = 0)
  401.     {
  402.         _ASSERTE(m_pbData && m_cbSize);
  403.         _ASSERTE(cbOffset < m_cbSize);
  404.         return (m_pbData + cbOffset);
  405.     }
  406.  
  407.     void Clear()
  408.     {
  409.         if (m_pbData)
  410.             free(m_pbData);
  411.         m_pbData = 0;
  412.         m_cbSize = m_cbNext = 0;
  413.     }
  414.  
  415. private:
  416.     BYTE        *m_pbData;              // Data pointer.
  417.     int         m_cbSize;               // Size of current data.
  418.     int         m_cbNext;               // Next place to write.
  419. };
  420.  
  421.  
  422. //*****************************************************************************
  423. // This implements a hash table and the allocation and management of the
  424. // records that are being hashed.
  425. //*****************************************************************************
  426. template <class M>
  427. class CHashTableAndData : protected CHashTable
  428. {
  429.     USHORT      m_iFree;
  430.     USHORT      m_iEntries;
  431.  
  432. public:
  433.     CHashTableAndData(
  434.         USHORT      iBuckets) :         // # of chains we are hashing into.
  435.         CHashTable(iBuckets)
  436.     {
  437.         m_iFree = m_iEntries = 0;
  438.     }
  439.     ~CHashTableAndData()
  440.     {
  441.         if (m_pcEntries != NULL)
  442.             M::Free(m_pcEntries, M::RoundSize(m_iEntries * m_iEntrySize));
  443.     }
  444.  
  445. //*****************************************************************************
  446. // This is the second part of construction where we do all of the work that
  447. // can fail.  We also take the array of structs here because the calling class
  448. // presumably needs to allocate it in its NewInit.
  449. //*****************************************************************************
  450.     HRESULT NewInit(                    // Return status.
  451.         USHORT      iEntries,           // # of entries.
  452.         USHORT      iEntrySize,         // Size of the entries.
  453.         int         iMaxSize);          // Max size of data.
  454.  
  455. //*****************************************************************************
  456. // Clear the hash table as if there were nothing in it.
  457. //*****************************************************************************
  458.     void Clear()
  459.     {
  460.         m_iFree = 0;
  461.  
  462.         if (m_iEntries > 0)
  463.         {
  464.             InitFreeChain(0, m_iEntries);
  465.             CHashTable::Clear();
  466.         }
  467.     }
  468.  
  469. //*****************************************************************************
  470. //*****************************************************************************
  471.     BYTE *Add(
  472.         USHORT      iHash)              // Hash value of entry to add.
  473.     {
  474.         FREEHASHENTRY *psEntry;
  475.  
  476.         // Make the table bigger if necessary.
  477.         if (m_iFree == 0xffff && !Grow())
  478.             return (NULL);
  479.  
  480.         // Add the first entry from the free list to the hash chain.
  481.         psEntry = (FREEHASHENTRY *) CHashTable::Add(iHash, m_iFree);
  482.         m_iFree = psEntry->iFree;
  483.         return ((BYTE *) psEntry);
  484.     }
  485.  
  486. //*****************************************************************************
  487. // Delete the struct at the specified index in m_pcEntries from the hash chains.
  488. //*****************************************************************************
  489.     void Delete(
  490.         USHORT      iHash,              // Hash value of entry to delete.
  491.         USHORT      iIndex)             // Index of struct in m_pcEntries.
  492.     {
  493.         CHashTable::Delete(iHash, iIndex);
  494.         ((FREEHASHENTRY *) EntryPtr(iIndex))->iFree = m_iFree;
  495.         m_iFree = iIndex;
  496.     }
  497.  
  498.     void Delete(
  499.         USHORT      iHash,              // Hash value of entry to delete.
  500.         HASHENTRY   *psEntry)           // The struct to delete.
  501.     {
  502.         CHashTable::Delete(iHash, psEntry);
  503.         ((FREEHASHENTRY *) psEntry)->iFree = m_iFree;
  504.         m_iFree = ItemIndex(psEntry);
  505.     }
  506.  
  507. private:
  508.     void InitFreeChain(USHORT iStart,USHORT iEnd);
  509.     int Grow();
  510. };
  511.  
  512.  
  513. //*****************************************************************************
  514. // This is the second part of construction where we do all of the work that
  515. // can fail.  We also take the array of structs here because the calling class
  516. // presumably needs to allocate it in its NewInit.
  517. //*****************************************************************************
  518. template<class M>
  519. HRESULT CHashTableAndData<M>::NewInit(// Return status.
  520.     USHORT      iEntries,               // # of entries.
  521.     USHORT      iEntrySize,             // Size of the entries.
  522.     int         iMaxSize)               // Max size of data.
  523. {
  524.     BYTE        *pcEntries;
  525.     HRESULT     hr;
  526.  
  527.     // Allocate the memory for the entries.
  528.     if ((pcEntries = M::Alloc(M::RoundSize(iEntries * iEntrySize),
  529.                                 M::RoundSize(iMaxSize))) == 0)
  530.         return (E_OUTOFMEMORY);
  531.     m_iEntries = iEntries;
  532.  
  533.     // Init the base table.
  534.     if (FAILED(hr = CHashTable::NewInit(pcEntries, iEntrySize)))
  535.         M::Free(pcEntries, M::RoundSize(iEntries * iEntrySize));
  536.     else
  537.     {
  538.         // Init the free chain.
  539.         m_iFree = 0;
  540.         InitFreeChain(0, iEntries);
  541.     }
  542.     return (hr);
  543. }
  544.  
  545. //*****************************************************************************
  546. // Initialize a range of records such that they are linked together to be put
  547. // on the free chain.
  548. //*****************************************************************************
  549. template<class M>
  550. void CHashTableAndData<M>::InitFreeChain(
  551.     USHORT      iStart,                 // Index to start initializing.
  552.     USHORT      iEnd)                   // Index to stop initializing
  553. {
  554.     BYTE        *pcPtr;
  555.     _ASSERTE(iEnd > iStart);
  556.  
  557.     pcPtr = m_pcEntries + iStart * m_iEntrySize;
  558.     for (++iStart; iStart < iEnd; ++iStart)
  559.     {
  560.         ((FREEHASHENTRY *) pcPtr)->iFree = iStart;
  561.         pcPtr += m_iEntrySize;
  562.     }
  563.     ((FREEHASHENTRY *) pcPtr)->iFree = 0xffff;
  564. }
  565.  
  566. //*****************************************************************************
  567. // Attempt to increase the amount of space available for the record heap.
  568. //*****************************************************************************
  569. template<class M>
  570. int CHashTableAndData<M>::Grow()        // 1 if successful, 0 if not.
  571. {
  572.     int         iCurSize;               // Current size in bytes.
  573.     int         iEntries;               // New # of entries.
  574.  
  575.     _ASSERTE(m_pcEntries != NULL);
  576.     _ASSERTE(m_iFree == 0xffff);
  577.  
  578.     // Compute the current size and new # of entries.
  579.     iCurSize = M::RoundSize(m_iEntries * m_iEntrySize);
  580.     iEntries = (iCurSize + M::GrowSize()) / m_iEntrySize;
  581.  
  582.     // Make sure we stay below 0xffff.
  583.     if (iEntries >= 0xffff) return (0);
  584.  
  585.     // Try to expand the array.
  586.     if (M::Grow(m_pcEntries, iCurSize) == 0)
  587.         return (0);
  588.  
  589.     // Init the newly allocated space.
  590.     InitFreeChain(m_iEntries, iEntries);
  591.     m_iFree = m_iEntries;
  592.     m_iEntries = iEntries;
  593.     return (1);
  594. }
  595.  
  596. #define MAKE_ANSIPTR_FROMWIDE(ptrname, widestr) \
  597.     long __l##ptrname = (wcslen(widestr) + 1) * 2 * sizeof(char); \
  598.     CQuickBytes __CQuickBytes##ptrname; \
  599.     __CQuickBytes##ptrname.Alloc(__l##ptrname); \
  600.     WideCharToMultiByte(CP_ACP, 0, widestr, -1, (LPSTR)__CQuickBytes##ptrname.Ptr(), __l##ptrname, NULL, NULL); \
  601.     LPSTR ptrname = (LPSTR)__CQuickBytes##ptrname.Ptr()
  602.  
  603. #define MAKE_UTF8PTR_FROMWIDE(ptrname, widestr) \
  604.     long __l##ptrname = (long)((wcslen(widestr) + 1) * 2 * sizeof(char)); \
  605.     LPSTR ptrname = (LPSTR)alloca(__l##ptrname); \
  606.     WideCharToMultiByte(CP_ACP, 0, widestr, -1, ptrname, __l##ptrname, NULL, NULL);
  607.  
  608. // NOTE: CP_ACP is not correct, but Win95 does not support CP_UTF8.  For this
  609. //  particular application, CP_ACP is "close enough".
  610. #define MAKE_WIDEPTR_FROMUTF8(ptrname, utf8str) \
  611.     long __l##ptrname; \
  612.     LPWSTR ptrname;    \
  613.     __l##ptrname = MultiByteToWideChar(CP_ACP, 0, utf8str, -1, 0, 0); \
  614.     ptrname = (LPWSTR) alloca(__l##ptrname*sizeof(WCHAR));    \
  615.     MultiByteToWideChar(CP_ACP, 0, utf8str, -1, ptrname, __l##ptrname);
  616.  
  617.  
  618. #define TESTANDRETURN(test, hrVal)              \
  619.     _ASSERTE(test);                             \
  620.     if (! (test))                               \
  621.         return hrVal;
  622.  
  623. #define TESTANDRETURNPOINTER(pointer)           \
  624.     TESTANDRETURN(pointer!=NULL, E_POINTER)
  625.  
  626. #define TESTANDRETURNMEMORY(pointer)            \
  627.     TESTANDRETURN(pointer!=NULL, E_OUTOFMEMORY)
  628.  
  629. #define TESTANDRETURNHR(hr)                     \
  630.     TESTANDRETURN(SUCCEEDED(hr), hr)
  631.  
  632. #define TESTANDRETURNARG(argtest)               \
  633.     TESTANDRETURN(argtest, E_INVALIDARG)
  634.  
  635. #endif // __DEBUGGERUTIL_H__
  636.