debug.c
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 55k
Category:

Windows Kernel

Development Platform:

Visual C++

  1. //
  2. // Debug squirty functions
  3. //
  4. #ifdef UNIX
  5. // Define some things for debug.h
  6. //
  7. #define SZ_DEBUGINI         "ccshell.ini"
  8. #define SZ_DEBUGSECTION     "shellib"
  9. #define SZ_MODULE           "SHELLIB"
  10. #endif
  11. #include "proj.h"
  12. #pragma  hdrstop
  13. #include "shellp.h"
  14. #include <platform.h> // LINE_SEPARATOR_STR and friends
  15. #include <winbase.h> // for GetModuleFileNameA
  16. #define DM_DEBUG              0
  17. BOOL UnicodeFromAnsi(LPWSTR *, LPCSTR, LPWSTR, int);
  18. #if defined(DEBUG) || defined(PRODUCT_PROF)
  19. // (c_szCcshellIniFile and c_szCcshellIniSecDebug are declared in debug.h)
  20. extern CHAR const FAR c_szCcshellIniFile[];
  21. extern CHAR const FAR c_szCcshellIniSecDebug[];
  22. HANDLE g_hDebugOutputFile = INVALID_HANDLE_VALUE;
  23. void ShellDebugAppendToDebugFileA(LPCSTR pszOutputString)
  24. {
  25.     if (g_hDebugOutputFile != INVALID_HANDLE_VALUE)
  26.     {
  27.         DWORD cbWrite = lstrlenA(pszOutputString);
  28.         WriteFile(g_hDebugOutputFile, pszOutputString, cbWrite, &cbWrite, NULL);
  29.     }
  30. }
  31. void ShellDebugAppendToDebugFileW(LPCWSTR pszOutputString)
  32. {
  33.     if (g_hDebugOutputFile != INVALID_HANDLE_VALUE)
  34.     {
  35.         char szBuf[500];
  36.         DWORD cbWrite = WideCharToMultiByte(CP_ACP, 0, pszOutputString, -1, szBuf, ARRAYSIZE(szBuf), NULL, NULL);
  37.         WriteFile(g_hDebugOutputFile, szBuf, cbWrite, &cbWrite, NULL);
  38.     }
  39. }
  40. #if 1 // Looking at the assertW stuff, it delegates already to assertA -- I'm not sure
  41.       // why I really need these wrappers!  (What was broken on my build?  I don't know,
  42.       // but obviously the stuff below was half baked -- there are still problems.)
  43.       // So I'm removing this for now so as to not bother anyone else...  [mikesh]
  44.       //
  45.       // Fixed a few problems and it worked for me. (edwardp)
  46.       //
  47. //
  48. // We cannot link to shlwapi, because comctl32 cannot link to shlwapi.
  49. // Duplicate some functions here so unicode stuff can run on Win95 platforms.
  50. //
  51. VOID MyOutputDebugStringWrapW(LPCWSTR lpOutputString)
  52. {
  53.     if (staticIsOS(OS_NT))
  54.     {
  55.         OutputDebugStringW(lpOutputString);
  56.         ShellDebugAppendToDebugFileW(lpOutputString);
  57.     }
  58.     else
  59.     {
  60.         char szBuf[500];
  61.         WideCharToMultiByte(CP_ACP, 0, lpOutputString, -1, szBuf, ARRAYSIZE(szBuf), NULL, NULL);
  62.         OutputDebugStringA(szBuf);
  63.         ShellDebugAppendToDebugFileA(szBuf);
  64.     }
  65. }
  66. #define OutputDebugStringW MyOutputDebugStringWrapW
  67. VOID MyOutputDebugStringWrapA(LPCSTR lpOutputString)
  68. {
  69.     OutputDebugStringA(lpOutputString);
  70.     ShellDebugAppendToDebugFileA(lpOutputString);
  71. }
  72. #define OutputDebugStringA MyOutputDebugStringWrapA
  73. LPWSTR MyCharPrevWrapW(LPCWSTR lpszStart, LPCWSTR lpszCurrent)
  74. {
  75.     if (lpszCurrent == lpszStart)
  76.     {
  77.         return (LPWSTR) lpszStart;
  78.     }
  79.     else
  80.     {
  81.         return (LPWSTR) lpszCurrent - 1;
  82.     }
  83. }
  84. #define CharPrevW MyCharPrevWrapW
  85. int MywvsprintfWrapW(LPWSTR pwszOut, LPCWSTR pwszFormat, va_list arglist)
  86. {
  87.     if (staticIsOS(OS_NT))
  88.     {
  89.         return wvsprintfW(pwszOut, pwszFormat, arglist);
  90.     }
  91.     else
  92.     {
  93.         char szFormat[500];
  94.         char szOut[1024+40]; // this is how big our ach buffers are
  95.         int iRet;
  96.         WideCharToMultiByte(CP_ACP, 0, pwszFormat, -1, szFormat, ARRAYSIZE(szFormat), NULL, NULL);
  97.         iRet = wvsprintfA(szOut, szFormat, arglist);
  98.         MultiByteToWideChar(CP_ACP, 0, szOut, -1, pwszOut, 1024+40);
  99.         return iRet;
  100.     }
  101. }
  102. #define wvsprintfW MywvsprintfWrapW
  103. int MywsprintfWrapW(LPWSTR pwszOut, LPCWSTR pwszFormat, ...)
  104. {
  105.     int iRet;
  106.     
  107.     va_list ArgList;
  108.     va_start(ArgList, pwszFormat);
  109.     iRet = MywvsprintfWrapW(pwszOut, pwszFormat, ArgList);
  110.     va_end(ArgList);
  111.     return iRet;
  112. }
  113. #define wsprintfW MywsprintfWrapW
  114. LPWSTR lstrcpyWrapW(LPWSTR pszDst, LPCWSTR pszSrc)
  115. {
  116.     while((*pszDst++ = *pszSrc++));
  117.     return pszDst;
  118. }
  119. #define lstrcpyW lstrcpyWrapW
  120. LPWSTR lstrcatWrapW(LPWSTR pszDst, LPCWSTR pszSrc)
  121. {
  122.     return lstrcpyWrapW(pszDst + lstrlenW(pszDst), pszSrc);
  123. }
  124. #define lstrcatW lstrcatWrapW
  125. #endif 
  126. /*----------------------------------------------------------
  127. Purpose: Special verion of atoi.  Supports hexadecimal too.
  128.          If this function returns FALSE, *piRet is set to 0.
  129. Returns: TRUE if the string is a number, or contains a partial number
  130.          FALSE if the string is not a number
  131. Cond:    --
  132. */
  133. static
  134. BOOL
  135. MyStrToIntExA(
  136.     LPCSTR    pszString,
  137.     DWORD     dwFlags,          // STIF_ bitfield
  138.     int FAR * piRet)
  139.     {
  140.     #define IS_DIGIT(ch)    InRange(ch, '0', '9')
  141.     BOOL bRet;
  142.     int n;
  143.     BOOL bNeg = FALSE;
  144.     LPCSTR psz;
  145.     LPCSTR pszAdj;
  146.     // Skip leading whitespace
  147.     //
  148.     for (psz = pszString; *psz == ' ' || *psz == 'n' || *psz == 't'; psz = CharNextA(psz))
  149.         ;
  150.     // Determine possible explicit signage
  151.     //
  152.     if (*psz == '+' || *psz == '-')
  153.         {
  154.         bNeg = (*psz == '+') ? FALSE : TRUE;
  155.         psz++;
  156.         }
  157.     // Or is this hexadecimal?
  158.     //
  159.     pszAdj = CharNextA(psz);
  160.     if ((STIF_SUPPORT_HEX & dwFlags) &&
  161.         *psz == '0' && (*pszAdj == 'x' || *pszAdj == 'X'))
  162.         {
  163.         // Yes
  164.         // (Never allow negative sign with hexadecimal numbers)
  165.         bNeg = FALSE;
  166.         psz = CharNextA(pszAdj);
  167.         pszAdj = psz;
  168.         // Do the conversion
  169.         //
  170.         for (n = 0; ; psz = CharNextA(psz))
  171.             {
  172.             if (IS_DIGIT(*psz))
  173.                 n = 0x10 * n + *psz - '0';
  174.             else
  175.                 {
  176.                 CHAR ch = *psz;
  177.                 int n2;
  178.                 if (ch >= 'a')
  179.                     ch -= 'a' - 'A';
  180.                 n2 = ch - 'A' + 0xA;
  181.                 if (n2 >= 0xA && n2 <= 0xF)
  182.                     n = 0x10 * n + n2;
  183.                 else
  184.                     break;
  185.                 }
  186.             }
  187.         // Return TRUE if there was at least one digit
  188.         bRet = (psz != pszAdj);
  189.         }
  190.     else
  191.         {
  192.         // No
  193.         pszAdj = psz;
  194.         // Do the conversion
  195.         for (n = 0; IS_DIGIT(*psz); psz = CharNextA(psz))
  196.             n = 10 * n + *psz - '0';
  197.         // Return TRUE if there was at least one digit
  198.         bRet = (psz != pszAdj);
  199.         }
  200.     *piRet = bNeg ? -n : n;
  201.     return bRet;
  202.     }
  203. #endif
  204. #ifdef DEBUG
  205. EXTERN_C g_bUseNewLeakDetection = FALSE;
  206. DWORD g_dwDumpFlags     = 0;        // DF_*
  207. #ifdef FULL_DEBUG
  208. DWORD g_dwTraceFlags    = TF_ERROR | TF_WARNING;     // TF_*
  209. #ifndef BREAK_ON_ASSERTS
  210. #define BREAK_ON_ASSERTS
  211. #endif
  212. #else
  213. DWORD g_dwTraceFlags    = TF_ERROR;  // TF_*
  214. #endif
  215. #ifdef BREAK_ON_ASSERTS
  216. DWORD g_dwBreakFlags    = BF_ASSERT;// BF_*
  217. #else
  218. DWORD g_dwBreakFlags    = 0;        // BF_*
  219. #endif
  220. DWORD g_dwPrototype     = 0;        
  221. DWORD g_dwFuncTraceFlags = 0;       // FTF_*
  222. // TLS slot used to store depth for CcshellFuncMsg indentation
  223. static DWORD g_tlsStackDepth = TLS_OUT_OF_INDEXES;
  224. // Hack stack depth counter used when g_tlsStackDepth is not available
  225. static DWORD g_dwHackStackDepth = 0;
  226. static char g_szIndentLeader[] = "                                                                                ";
  227. static WCHAR g_wszIndentLeader[] = L"                                                                                ";
  228. static CHAR const FAR c_szNewline[] = LINE_SEPARATOR_STR;   // (Deliberately CHAR)
  229. static WCHAR const FAR c_wszNewline[] = TEXTW(LINE_SEPARATOR_STR);
  230. extern CHAR const FAR c_szTrace[];              // (Deliberately CHAR)
  231. extern CHAR const FAR c_szErrorDbg[];           // (Deliberately CHAR)
  232. extern CHAR const FAR c_szWarningDbg[];         // (Deliberately CHAR)
  233. extern WCHAR const FAR c_wszTrace[];
  234. extern WCHAR const FAR c_wszErrorDbg[]; 
  235. extern WCHAR const FAR c_wszWarningDbg[];
  236. extern const CHAR  FAR c_szAssertMsg[];
  237. extern CHAR const FAR c_szAssertFailed[];
  238. extern const WCHAR  FAR c_wszAssertMsg[];
  239. extern WCHAR const FAR c_wszAssertFailed[];
  240. extern CHAR const FAR c_szRip[];
  241. extern CHAR const FAR c_szRipNoFn[];
  242. extern CHAR const FAR c_szRipMsg[];
  243. extern WCHAR const FAR c_wszRip[];
  244. extern WCHAR const FAR c_wszRipNoFn[];
  245. /*-------------------------------------------------------------------------
  246. Purpose: Adds one of the following prefix strings to pszBuf:
  247.            "t   MODULE  "
  248.            "err MODULE  "
  249.            "wrn MODULE  "
  250.          Returns the count of characters written.
  251. */
  252. int
  253. SetPrefixStringA(
  254.     OUT LPSTR pszBuf,
  255.     IN  DWORD dwFlags)
  256. {
  257.     if (TF_ALWAYS == dwFlags)
  258.         lstrcpyA(pszBuf, c_szTrace);
  259.     else if (IsFlagSet(dwFlags, TF_WARNING))
  260.         lstrcpyA(pszBuf, c_szWarningDbg);
  261.     else if (IsFlagSet(dwFlags, TF_ERROR))
  262.         lstrcpyA(pszBuf, c_szErrorDbg);
  263.     else
  264.         lstrcpyA(pszBuf, c_szTrace);
  265.     return lstrlenA(pszBuf);
  266. }
  267. int
  268. SetPrefixStringW(
  269.     OUT LPWSTR pszBuf,
  270.     IN  DWORD  dwFlags)
  271. {
  272.     if (TF_ALWAYS == dwFlags)
  273.         lstrcpyW(pszBuf, c_wszTrace);
  274.     else if (IsFlagSet(dwFlags, TF_WARNING))
  275.         lstrcpyW(pszBuf, c_wszWarningDbg);
  276.     else if (IsFlagSet(dwFlags, TF_ERROR))
  277.         lstrcpyW(pszBuf, c_wszErrorDbg);
  278.     else
  279.         lstrcpyW(pszBuf, c_wszTrace);
  280.     return lstrlenW(pszBuf);
  281. }
  282. static
  283. LPCSTR
  284. _PathFindFileNameA(
  285.     LPCSTR pPath)
  286. {
  287.     LPCSTR pT;
  288.     for (pT = pPath; *pPath; pPath = CharNextA(pPath)) {
  289.         if ((pPath[0] == '\' || pPath[0] == ':' || pPath[0] == '/')
  290.             && pPath[1] &&  pPath[1] != '\'  &&   pPath[1] != '/')
  291.             pT = pPath + 1;
  292.     }
  293.     return pT;
  294. }
  295. static
  296. LPCWSTR
  297. _PathFindFileNameW(
  298.     LPCWSTR pPath)
  299. {
  300.     LPCWSTR pT;
  301.     for (pT = pPath; *pPath; pPath++) {
  302.         if ((pPath[0] == TEXTW('\') || pPath[0] == TEXTW(':') || pPath[0] == TEXTW('/'))
  303.             && pPath[1] &&  pPath[1] != TEXTW('\')  &&   pPath[1] != TEXTW('/'))
  304.             pT = pPath + 1;
  305.     }
  306.     return pT;
  307. }
  308. /*-------------------------------------------------------------------------
  309. Purpose: Returns TRUE if this process is a primary shell process.
  310. */
  311. BOOL _IsShellProcess()
  312. {
  313.     CHAR szModuleName[MAX_PATH];
  314.     
  315.     if (GetModuleFileNameA(NULL, szModuleName, sizeof(CHAR) * MAX_PATH) > 0 )
  316.     {                      
  317.         if (StrStrIA(szModuleName, "explorer.exe") || 
  318.             StrStrIA(szModuleName, "iexplore.exe") ||
  319.             StrStrIA(szModuleName, "rundll32.exe") || 
  320.             StrStrIA(szModuleName, "welcome.exe") ||
  321.             StrStrIA(szModuleName, "mshtmpad.exe"))
  322.         {
  323.             // yes, the exe is a shell one
  324.             return TRUE;
  325.         }
  326.     }
  327.     // not a normal shell executable
  328.     return FALSE;
  329. }
  330. // BUGBUG (scotth): Use the Ccshell functions.  _AssertMsg and
  331. // _DebugMsg are obsolete.  They will be removed once all the 
  332. // components don't have TEXT() wrapping their debug strings anymore.
  333. void 
  334. WINCAPI 
  335. _AssertMsgA(
  336.     BOOL f, 
  337.     LPCSTR pszMsg, ...)
  338. {
  339.     CHAR ach[1024+40];
  340.     va_list vArgs;
  341.     if (!f)
  342.     {
  343.         int cch;
  344.         lstrcpyA(ach, c_szAssertMsg);
  345.         cch = lstrlenA(ach);
  346.         va_start(vArgs, pszMsg);
  347.         wvsprintfA(&ach[cch], pszMsg, vArgs);
  348.         va_end(vArgs);
  349.         OutputDebugStringA(ach);
  350.         OutputDebugStringA(c_szNewline);
  351.         if (IsFlagSet(g_dwBreakFlags, BF_ASSERT))
  352.         {
  353.             // MSDEV USERS:  This is not the real assert.  Hit 
  354.             //               Shift-F11 to jump back to the caller.
  355.             DEBUG_BREAK;                                                            // ASSERT
  356.         }
  357.     }
  358. }
  359. void 
  360. WINCAPI 
  361. _AssertMsgW(
  362.     BOOL f, 
  363.     LPCWSTR pszMsg, ...)
  364. {
  365.     WCHAR ach[1024+40];
  366.     va_list vArgs;
  367.     if (!f)
  368.     {
  369.         int cch;
  370.         lstrcpyW(ach, c_wszAssertMsg);
  371.         cch = lstrlenW(ach);
  372.         va_start(vArgs, pszMsg);
  373.         wvsprintfW(&ach[cch], pszMsg, vArgs);
  374.         va_end(vArgs);
  375.         OutputDebugStringW(ach);
  376.         OutputDebugStringW(c_wszNewline);
  377.         if (IsFlagSet(g_dwBreakFlags, BF_ASSERT))
  378.         {
  379.             // MSDEV USERS:  This is not the real assert.  Hit 
  380.             //               Shift-F11 to jump back to the caller.
  381.             DEBUG_BREAK;                                                            // ASSERT
  382.         }
  383.     }
  384. }
  385. void 
  386. _AssertStrLenW(
  387.     LPCWSTR pszStr, 
  388.     int iLen)
  389. {
  390.     if (pszStr && iLen < lstrlenW(pszStr))
  391.     {                                           
  392.         // MSDEV USERS:  This is not the real assert.  Hit 
  393.         //               Shift-F11 to jump back to the caller.
  394.         DEBUG_BREAK;                                                            // ASSERT
  395.     }
  396. }
  397. void 
  398. _AssertStrLenA(
  399.     LPCSTR pszStr, 
  400.     int iLen)
  401. {
  402.     if (pszStr && iLen < lstrlenA(pszStr))
  403.     {                                           
  404.         // MSDEV USERS:  This is not the real assert.  Hit 
  405.         //               Shift-F11 to jump back to the caller.
  406.         DEBUG_BREAK;                                                            // ASSERT
  407.     }
  408. }
  409. void 
  410. WINCAPI 
  411. _DebugMsgA(
  412.     DWORD flag, 
  413.     LPCSTR pszMsg, ...)
  414. {
  415.     CHAR ach[5*MAX_PATH+40];  // Handles 5*largest path + slop for message
  416.     va_list vArgs;
  417.     if (TF_ALWAYS == flag || (IsFlagSet(g_dwTraceFlags, flag) && flag))
  418.     {
  419.         int cch;
  420.         cch = SetPrefixStringA(ach, flag);
  421.         va_start(vArgs, pszMsg);
  422.         try
  423.         {
  424.             wvsprintfA(&ach[cch], pszMsg, vArgs);
  425.         }
  426.         except(EXCEPTION_EXECUTE_HANDLER)
  427.         {
  428.             OutputDebugString(TEXT("CCSHELL: DebugMsg exception: "));
  429.             OutputDebugStringA(pszMsg);
  430.         }
  431.         __endexcept
  432.         va_end(vArgs);
  433.         OutputDebugStringA(ach);
  434.         OutputDebugStringA(c_szNewline);
  435.         if (TF_ALWAYS != flag &&
  436.             ((flag & TF_ERROR) && IsFlagSet(g_dwBreakFlags, BF_ONERRORMSG) ||
  437.              (flag & TF_WARNING) && IsFlagSet(g_dwBreakFlags, BF_ONWARNMSG)))
  438.         {
  439.             // MSDEV USERS:  This is not the real assert.  Hit 
  440.             //               Shift-F11 to jump back to the caller.
  441.             DEBUG_BREAK;                                                            // ASSERT
  442.         }
  443.     }
  444. }
  445. void 
  446. WINCAPI 
  447. _DebugMsgW(
  448.     DWORD flag, 
  449.     LPCWSTR pszMsg, ...)
  450. {
  451.     WCHAR ach[5*MAX_PATH+40];  // Handles 5*largest path + slop for message
  452.     va_list vArgs;
  453.     if (TF_ALWAYS == flag || (IsFlagSet(g_dwTraceFlags, flag) && flag))
  454.     {
  455.         int cch;
  456.         SetPrefixStringW(ach, flag);
  457.         cch = lstrlenW(ach);
  458.         va_start(vArgs, pszMsg);
  459.         try
  460.         {
  461.             wvsprintfW(&ach[cch], pszMsg, vArgs);
  462.         }
  463.         except(EXCEPTION_EXECUTE_HANDLER)
  464.         {
  465.             OutputDebugString(TEXT("CCSHELL: DebugMsg exception: "));
  466.             OutputDebugStringW(pszMsg);
  467.         }
  468.         __endexcept
  469.         va_end(vArgs);
  470.         OutputDebugStringW(ach);
  471.         OutputDebugStringW(c_wszNewline);
  472.         if (TF_ALWAYS != flag &&
  473.             ((flag & TF_ERROR) && IsFlagSet(g_dwBreakFlags, BF_ONERRORMSG) ||
  474.              (flag & TF_WARNING) && IsFlagSet(g_dwBreakFlags, BF_ONWARNMSG)))
  475.         {
  476.             // MSDEV USERS:  This is not the real assert.  Hit 
  477.             //               Shift-F11 to jump back to the caller.
  478.             DEBUG_BREAK;                                                        // ASSERT
  479.         }
  480.     }
  481. }
  482. //
  483. //  Smart debug functions
  484. //
  485. /*----------------------------------------------------------
  486. Purpose: Displays assertion string.
  487. Returns: TRUE to debugbreak
  488. */
  489. BOOL
  490. CcshellAssertFailedA(
  491.     LPCSTR pszFile,
  492.     int line,
  493.     LPCSTR pszEval,
  494.     BOOL bBreakInside)
  495. {
  496.     BOOL bRet = FALSE;
  497.     LPCSTR psz;
  498.     CHAR ach[256];
  499.     psz = _PathFindFileNameA(pszFile);
  500.     wsprintfA(ach, c_szAssertFailed, psz, line, pszEval);
  501.     OutputDebugStringA(ach);
  502.     if (IsFlagSet(g_dwBreakFlags, BF_ASSERT))
  503.     {
  504.         if (bBreakInside)
  505.         {
  506.             // !!!  ASSERT  !!!!  ASSERT  !!!!  ASSERT !!!
  507.             // MSDEV USERS:  This is not the real assert.  Hit 
  508.             //               Shift-F11 to jump back to the caller.
  509.             DEBUG_BREAK;                                                // ASSERT
  510.             // !!!  ASSERT  !!!!  ASSERT  !!!!  ASSERT !!!
  511.         }
  512.         else
  513.             bRet = TRUE;
  514.     }
  515.     return bRet;
  516. }
  517. /*----------------------------------------------------------
  518. Purpose: Displays assertion string.
  519. */
  520. BOOL
  521. CcshellAssertFailedW(
  522.     LPCWSTR pszFile,
  523.     int line,
  524.     LPCWSTR pszEval,
  525.     BOOL bBreakInside)
  526. {
  527.     BOOL bRet = FALSE;
  528.     LPCWSTR psz;
  529.     WCHAR ach[1024];    // Some callers use more than 256
  530.     psz = _PathFindFileNameW(pszFile);
  531.     // If psz == NULL, CharPrevW failed which implies we are running on Win95.  We can get this
  532.     // if we get an assert in some of the W functions in shlwapi...  Call the A version of assert...
  533.     if (!psz)
  534.     {
  535.         char szFile[MAX_PATH];
  536.         char szEval[256];   // since the total output is thhis size should be enough...
  537.         WideCharToMultiByte(CP_ACP, 0, pszFile, -1, szFile, ARRAYSIZE(szFile), NULL, NULL);
  538.         WideCharToMultiByte(CP_ACP, 0, pszEval, -1, szEval, ARRAYSIZE(szEval), NULL, NULL);
  539.         return CcshellAssertFailedA(szFile, line, szEval, bBreakInside);
  540.     }
  541.     wsprintfW(ach, c_wszAssertFailed, psz, line, pszEval);
  542.     OutputDebugStringW(ach);
  543.     if (IsFlagSet(g_dwBreakFlags, BF_ASSERT))
  544.     {
  545.         if (bBreakInside)
  546.         {
  547.             // !!!  ASSERT  !!!!  ASSERT  !!!!  ASSERT !!!
  548.             
  549.             // MSDEV USERS:  This is not the real assert.  Hit 
  550.             //               Shift-F11 to jump back to the caller.
  551.             DEBUG_BREAK;                                                // ASSERT
  552.             // !!!  ASSERT  !!!!  ASSERT  !!!!  ASSERT !!!
  553.         }
  554.         else
  555.             bRet = TRUE;
  556.     }
  557.     return bRet;
  558. }
  559. /*----------------------------------------------------------
  560. Purpose: Displays a RIP string.
  561. Returns: TRUE to debugbreak
  562. */
  563. BOOL
  564. CcshellRipA(
  565.     LPCSTR pszFile,
  566.     int line,
  567.     LPCSTR pszEval,
  568.     BOOL bBreakInside)
  569. {
  570.     BOOL bRet = FALSE;
  571.     LPCSTR psz;
  572.     CHAR ach[256];
  573.     psz = _PathFindFileNameA(pszFile);
  574.     wsprintfA(ach, c_szRipNoFn, psz, line, pszEval);
  575.     OutputDebugStringA(ach);
  576.     if (_IsShellProcess() || IsFlagSet(g_dwBreakFlags, BF_RIP))
  577.     {
  578.         if (bBreakInside)
  579.         {
  580.             // !!!  RIP  !!!!  RIP  !!!!  RIP !!!
  581.             
  582.             // MSDEV USERS:  This is not the real RIP.  Hit 
  583.             //               Shift-F11 to jump back to the caller.
  584.             DEBUG_BREAK;                                                // ASSERT
  585.             // !!!  RIP  !!!!  RIP  !!!!  RIP !!!
  586.         }
  587.         else
  588.             bRet = TRUE;
  589.     }
  590.     return bRet;
  591. }
  592. /*----------------------------------------------------------
  593. Purpose: Displays a RIP string.
  594. */
  595. BOOL
  596. CcshellRipW(
  597.     LPCWSTR pszFile,
  598.     int line,
  599.     LPCWSTR pszEval,
  600.     BOOL bBreakInside)
  601. {
  602.     BOOL bRet = FALSE;
  603.     LPCWSTR psz;
  604.     WCHAR ach[256];
  605.     psz = _PathFindFileNameW(pszFile);
  606.     // If psz == NULL, CharPrevW failed which implies we are running on Win95.  
  607.     // We can get this if we get an assert in some of the W functions in 
  608.     // shlwapi...  Call the A version of assert...
  609.     if (!psz)
  610.     {
  611.         char szFile[MAX_PATH];
  612.         char szEval[256];   // since the total output is thhis size should be enough...
  613.         WideCharToMultiByte(CP_ACP, 0, pszFile, -1, szFile, ARRAYSIZE(szFile), NULL, NULL);
  614.         WideCharToMultiByte(CP_ACP, 0, pszEval, -1, szEval, ARRAYSIZE(szEval), NULL, NULL);
  615.         return CcshellRipA(szFile, line, szEval, bBreakInside);
  616.     }
  617.     wsprintfW(ach, c_wszRipNoFn, psz, line, pszEval);
  618.     OutputDebugStringW(ach);
  619.     if (_IsShellProcess() || IsFlagSet(g_dwBreakFlags, BF_RIP))
  620.     {
  621.         if (bBreakInside)
  622.         {
  623.             // !!!  RIP  !!!!  RIP  !!!!  RIP !!!
  624.             // MSDEV USERS:  This is not the real assert.  Hit 
  625.             //               Shift-F11 to jump back to the caller.
  626.             DEBUG_BREAK;                                                // ASSERT
  627.             // !!!  RIP  !!!!  RIP  !!!!  RIP !!!
  628.         }
  629.         else
  630.             bRet = TRUE;
  631.     }
  632.     return bRet;
  633. }
  634. BOOL
  635. WINCAPI 
  636. CcshellRipMsgA(
  637.     BOOL f, 
  638.     LPCSTR pszMsg, ...)
  639. {
  640.     CHAR ach[1024+40];
  641.     va_list vArgs;
  642.     if (!f)
  643.     {
  644.         OutputDebugStringA(c_szRipMsg);
  645.         va_start(vArgs, pszMsg);
  646.         wvsprintfA(ach, pszMsg, vArgs);
  647.         va_end(vArgs);
  648.         OutputDebugStringA(ach);
  649.         OutputDebugStringA(c_szNewline);
  650.         if (_IsShellProcess() || IsFlagSet(g_dwBreakFlags, BF_RIP))
  651.         {
  652.             // MSDEV USERS:  This is not the real assert.  Hit 
  653.             //               Shift-F11 to jump back to the caller.
  654.             DEBUG_BREAK;                                                            // ASSERT
  655.         }
  656.     }
  657.     return FALSE;
  658. }
  659. BOOL
  660. WINCAPI 
  661. CcshellRipMsgW(
  662.     BOOL f, 
  663.     LPCSTR pszMsg, ...)         // (this is deliberately CHAR)
  664. {
  665.     WCHAR ach[1024+40];
  666.     va_list vArgs;
  667.     if (!f)
  668.     {
  669.         LPWSTR pwsz;
  670.         WCHAR wszBuf[128];
  671.         OutputDebugStringA(c_szRipMsg);
  672.         // (We convert the string, rather than simply input an
  673.         // LPCWSTR parameter, so the caller doesn't have to wrap
  674.         // all the string constants with the TEXT() macro.)
  675.         ach[0] = L'';     // In case this fails
  676.         if (UnicodeFromAnsi(&pwsz, pszMsg, wszBuf, SIZECHARS(wszBuf)))
  677.         {
  678.             va_start(vArgs, pszMsg);
  679.             wvsprintfW(ach, pwsz, vArgs);
  680.             va_end(vArgs);
  681.             UnicodeFromAnsi(&pwsz, NULL, wszBuf, 0);
  682.         }
  683.         OutputDebugStringW(ach);
  684.         OutputDebugStringA(c_szNewline);
  685.         if (_IsShellProcess() || IsFlagSet(g_dwBreakFlags, BF_RIP))
  686.         {
  687.             // MSDEV USERS:  This is not the real assert.  Hit 
  688.             //               Shift-F11 to jump back to the caller.
  689.             DEBUG_BREAK;                                                            // ASSERT
  690.         }
  691.     }
  692.     return FALSE;
  693. }
  694. /*----------------------------------------------------------
  695. Purpose: Keep track of the stack depth for function call trace
  696.          messages.
  697. */
  698. void
  699. CcshellStackEnter(void)
  700.     {
  701.     if (TLS_OUT_OF_INDEXES != g_tlsStackDepth)
  702.         {
  703.         DWORD dwDepth;
  704.         dwDepth = PtrToUlong(TlsGetValue(g_tlsStackDepth));
  705.         TlsSetValue(g_tlsStackDepth, (LPVOID)(ULONG_PTR)(dwDepth + 1));
  706.         }
  707.     else
  708.         {
  709.         g_dwHackStackDepth++;
  710.         }
  711.     }
  712. /*----------------------------------------------------------
  713. Purpose: Keep track of the stack depth for functionc all trace
  714.          messages.
  715. */
  716. void
  717. CcshellStackLeave(void)
  718.     {
  719.     if (TLS_OUT_OF_INDEXES != g_tlsStackDepth)
  720.         {
  721.         DWORD dwDepth;
  722.         dwDepth = PtrToUlong(TlsGetValue(g_tlsStackDepth));
  723.         if (EVAL(0 < dwDepth))
  724.             {
  725.             EVAL(TlsSetValue(g_tlsStackDepth, (LPVOID)(ULONG_PTR)(dwDepth - 1)));
  726.             }
  727.         }
  728.     else
  729.         {
  730.         if (EVAL(0 < g_dwHackStackDepth))
  731.             {
  732.             g_dwHackStackDepth--;
  733.             }
  734.         }
  735.     }
  736. /*----------------------------------------------------------
  737. Purpose: Return the stack depth.
  738. */
  739. static
  740. DWORD
  741. CcshellGetStackDepth(void)
  742.     {
  743.     DWORD dwDepth;
  744.     if (TLS_OUT_OF_INDEXES != g_tlsStackDepth)
  745.         {
  746.         dwDepth = PtrToUlong(TlsGetValue(g_tlsStackDepth));
  747.         }
  748.     else
  749.         {
  750.         dwDepth = g_dwHackStackDepth;
  751.         }
  752.     return dwDepth;
  753.     }
  754. /*----------------------------------------------------------
  755. Purpose: This function converts a multi-byte string to a
  756.          wide-char string.
  757.          If pszBuf is non-NULL and the converted string can fit in
  758.          pszBuf, then *ppszWide will point to the given buffer.
  759.          Otherwise, this function will allocate a buffer that can
  760.          hold the converted string.
  761.          If pszAnsi is NULL, then *ppszWide will be freed.  Note
  762.          that pszBuf must be the same pointer between the call
  763.          that converted the string and the call that frees the
  764.          string.
  765. Returns: TRUE
  766.          FALSE (if out of memory)
  767. */
  768. BOOL
  769. UnicodeFromAnsi(
  770.     LPWSTR * ppwszWide,
  771.     LPCSTR pszAnsi,           // NULL to clean up
  772.     LPWSTR pwszBuf,
  773.     int cchBuf)
  774.     {
  775.     BOOL bRet;
  776.     // Convert the string?
  777.     if (pszAnsi)
  778.         {
  779.         // Yes; determine the converted string length
  780.         int cch;
  781.         LPWSTR pwsz;
  782.         int cchAnsi = lstrlenA(pszAnsi)+1;
  783.         cch = MultiByteToWideChar(CP_ACP, 0, pszAnsi, cchAnsi, NULL, 0);
  784.         // String too big, or is there no buffer?
  785.         if (cch > cchBuf || NULL == pwszBuf)
  786.             {
  787.             // Yes; allocate space
  788.             cchBuf = cch + 1;
  789.             pwsz = (LPWSTR)LocalAlloc(LPTR, CbFromCchW(cchBuf));
  790.             }
  791.         else
  792.             {
  793.             // No; use the provided buffer
  794.             pwsz = pwszBuf;
  795.             }
  796.         if (pwsz)
  797.             {
  798.             // Convert the string
  799.             cch = MultiByteToWideChar(CP_ACP, 0, pszAnsi, cchAnsi, pwsz, cchBuf);
  800.             bRet = (0 < cch);
  801.             }
  802.         else
  803.             {
  804.             bRet = FALSE;
  805.             }
  806.         *ppwszWide = pwsz;
  807.         }
  808.     else
  809.         {
  810.         // No; was this buffer allocated?
  811.         if (*ppwszWide && pwszBuf != *ppwszWide)
  812.             {
  813.             // Yes; clean up
  814.             LocalFree((HLOCAL)*ppwszWide);
  815.             *ppwszWide = NULL;
  816.             }
  817.         bRet = TRUE;
  818.         }
  819.     return bRet;
  820.     }
  821. /*----------------------------------------------------------
  822. Purpose: Wide-char version of CcshellAssertMsgA
  823. */
  824. void
  825. CDECL
  826. CcshellAssertMsgW(
  827.     BOOL f,
  828.     LPCSTR pszMsg, ...)
  829. {
  830.     WCHAR ach[1024+40];    // Largest path plus extra
  831.     va_list vArgs;
  832.     if (!f)
  833.         {
  834.         int cch;
  835.         WCHAR wszBuf[1024];
  836.         LPWSTR pwsz;
  837.         lstrcpyW(ach, c_wszAssertMsg);
  838.         cch = lstrlenW(ach);
  839.         va_start(vArgs, pszMsg);
  840.         // (We convert the string, rather than simply input an
  841.         // LPCWSTR parameter, so the caller doesn't have to wrap
  842.         // all the string constants with the TEXT() macro.)
  843.         if (UnicodeFromAnsi(&pwsz, pszMsg, wszBuf, SIZECHARS(wszBuf)))
  844.             {
  845.             wvsprintfW(&ach[cch], pwsz, vArgs);
  846.             UnicodeFromAnsi(&pwsz, NULL, wszBuf, 0);
  847.             }
  848.         va_end(vArgs);
  849.         OutputDebugStringW(ach);
  850.         OutputDebugStringW(c_wszNewline);
  851.         if (IsFlagSet(g_dwBreakFlags, BF_ASSERT))
  852.         {
  853.             // !!!  ASSERT  !!!!  ASSERT  !!!!  ASSERT !!!
  854.             
  855.             // MSDEV USERS:  This is not the real assert.  Hit 
  856.             //               Shift-F11 to jump back to the caller.
  857.             DEBUG_BREAK;                                                // ASSERT
  858.             // !!!  ASSERT  !!!!  ASSERT  !!!!  ASSERT !!!
  859.         }
  860.     }
  861. }
  862. /*----------------------------------------------------------
  863. Purpose: Wide-char version of CcshellDebugMsgA.  Note this
  864.          function deliberately takes an ANSI format string
  865.          so our trace messages don't all need to be wrapped
  866.          in TEXT().
  867. */
  868. void
  869. CDECL
  870. CcshellDebugMsgW(
  871.     DWORD flag,
  872.     LPCSTR pszMsg, ...)         // (this is deliberately CHAR)
  873. {
  874.     WCHAR ach[1024+40];    // Largest path plus extra
  875.     va_list vArgs;
  876.     if (TF_ALWAYS == flag || (IsFlagSet(g_dwTraceFlags, flag) && flag))
  877.     {
  878.         int cch;
  879.         WCHAR wszBuf[1024];
  880.         LPWSTR pwsz;
  881.         SetPrefixStringW(ach, flag);
  882.         cch = lstrlenW(ach);
  883.         va_start(vArgs, pszMsg);
  884.         // (We convert the string, rather than simply input an
  885.         // LPCWSTR parameter, so the caller doesn't have to wrap
  886.         // all the string constants with the TEXT() macro.)
  887.         if (UnicodeFromAnsi(&pwsz, pszMsg, wszBuf, SIZECHARS(wszBuf)))
  888.         {
  889.             wvsprintfW(&ach[cch], pwsz, vArgs);
  890.             UnicodeFromAnsi(&pwsz, NULL, wszBuf, 0);
  891.         }
  892.         va_end(vArgs);
  893.         OutputDebugStringW(ach);
  894.         OutputDebugStringW(c_wszNewline);
  895.         if (TF_ALWAYS != flag &&
  896.             ((flag & TF_ERROR) && IsFlagSet(g_dwBreakFlags, BF_ONERRORMSG) ||
  897.              (flag & TF_WARNING) && IsFlagSet(g_dwBreakFlags, BF_ONWARNMSG)))
  898.         {
  899.             // MSDEV USERS:  This is not the real assert.  Hit 
  900.             //               Shift-F11 to jump back to the caller.
  901.             DEBUG_BREAK;                                                // ASSERT
  902.         }
  903.     }
  904. }
  905. /*-------------------------------------------------------------------------
  906. Purpose: Since the ATL code does not pass in a flag parameter,
  907.          we'll hardcode and check for TF_ATL.
  908. */
  909. void CDECL ShellAtlTraceW(LPCWSTR pszMsg, ...)
  910. {
  911.     WCHAR ach[1024+40];    // Largest path plus extra
  912.     va_list vArgs;
  913.     if (g_dwTraceFlags & TF_ATL)
  914.     {
  915.         int cch;
  916.         SetPrefixStringW(ach, TF_ATL);
  917.         lstrcatW(ach, L"(ATL) ");
  918.         cch = lstrlenW(ach);
  919.         va_start(vArgs, pszMsg);
  920.         wvsprintfW(&ach[cch], pszMsg, vArgs);
  921.         va_end(vArgs);
  922.         OutputDebugStringW(ach);
  923.     }
  924. }
  925. /*----------------------------------------------------------
  926. Purpose: Wide-char version of CcshellFuncMsgA.  Note this
  927.          function deliberately takes an ANSI format string
  928.          so our trace messages don't all need to be wrapped
  929.          in TEXT().
  930. */
  931. void
  932. CDECL
  933. CcshellFuncMsgW(
  934.     DWORD flag,
  935.     LPCSTR pszMsg, ...)         // (this is deliberately CHAR)
  936.     {
  937.     WCHAR ach[1024+40];    // Largest path plus extra
  938.     va_list vArgs;
  939.     if (IsFlagSet(g_dwTraceFlags, TF_FUNC) &&
  940.         IsFlagSet(g_dwFuncTraceFlags, flag))
  941.         {
  942.         int cch;
  943.         WCHAR wszBuf[1024];
  944.         LPWSTR pwsz;
  945.         DWORD dwStackDepth;
  946.         LPWSTR pszLeaderEnd;
  947.         WCHAR chSave;
  948.         // Determine the indentation for trace message based on
  949.         // stack depth.
  950.         dwStackDepth = CcshellGetStackDepth();
  951.         if (dwStackDepth < SIZECHARS(g_szIndentLeader))
  952.             {
  953.             pszLeaderEnd = &g_wszIndentLeader[dwStackDepth];
  954.             }
  955.         else
  956.             {
  957.             pszLeaderEnd = &g_wszIndentLeader[SIZECHARS(g_wszIndentLeader)-1];
  958.             }
  959.         chSave = *pszLeaderEnd;
  960.         *pszLeaderEnd = '';
  961.         wsprintfW(ach, L"%s %s", c_wszTrace, g_wszIndentLeader);
  962.         *pszLeaderEnd = chSave;
  963.         // Compose remaining string
  964.         cch = lstrlenW(ach);
  965.         va_start(vArgs, pszMsg);
  966.         // (We convert the string, rather than simply input an
  967.         // LPCWSTR parameter, so the caller doesn't have to wrap
  968.         // all the string constants with the TEXT() macro.)
  969.         if (UnicodeFromAnsi(&pwsz, pszMsg, wszBuf, SIZECHARS(wszBuf)))
  970.             {
  971.             wvsprintfW(&ach[cch], pwsz, vArgs);
  972.             UnicodeFromAnsi(&pwsz, NULL, wszBuf, 0);
  973.             }
  974.         va_end(vArgs);
  975.         OutputDebugStringW(ach);
  976.         OutputDebugStringW(c_wszNewline);
  977.         }
  978.     }
  979. /*----------------------------------------------------------
  980. Purpose: Assert failed message only
  981. */
  982. void
  983. CDECL
  984. CcshellAssertMsgA(
  985.     BOOL f,
  986.     LPCSTR pszMsg, ...)
  987. {
  988.     CHAR ach[1024+40];    // Largest path plus extra
  989.     va_list vArgs;
  990.     if (!f)
  991.     {
  992.         int cch;
  993.         lstrcpyA(ach, c_szAssertMsg);
  994.         cch = lstrlenA(ach);
  995.         va_start(vArgs, pszMsg);
  996.         wvsprintfA(&ach[cch], pszMsg, vArgs);
  997.         va_end(vArgs);
  998.         OutputDebugStringA(ach);
  999.         OutputDebugStringA(c_szNewline);
  1000.         if (IsFlagSet(g_dwBreakFlags, BF_ASSERT))
  1001.         {
  1002.             // !!!  ASSERT  !!!!  ASSERT  !!!!  ASSERT !!!
  1003.             
  1004.             // MSDEV USERS:  This is not the real assert.  Hit 
  1005.             //               Shift-F11 to jump back to the caller.
  1006.             DEBUG_BREAK;                                                // ASSERT
  1007.             // !!!  ASSERT  !!!!  ASSERT  !!!!  ASSERT !!!
  1008.         }
  1009.     }
  1010. }
  1011. /*----------------------------------------------------------
  1012. Purpose: Debug spew
  1013. */
  1014. void
  1015. CDECL
  1016. CcshellDebugMsgA(
  1017.     DWORD flag,
  1018.     LPCSTR pszMsg, ...)
  1019. {
  1020.     CHAR ach[1024+40];    // Largest path plus extra
  1021.     va_list vArgs;
  1022.     if (TF_ALWAYS == flag || (IsFlagSet(g_dwTraceFlags, flag) && flag))
  1023.     {
  1024.         int cch;
  1025.         cch = SetPrefixStringA(ach, flag);
  1026.         va_start(vArgs, pszMsg);
  1027.         wvsprintfA(&ach[cch], pszMsg, vArgs);
  1028.         va_end(vArgs);
  1029.         OutputDebugStringA(ach);
  1030.         OutputDebugStringA(c_szNewline);
  1031.         if (TF_ALWAYS != flag &&
  1032.             ((flag & TF_ERROR) && IsFlagSet(g_dwBreakFlags, BF_ONERRORMSG) ||
  1033.              (flag & TF_WARNING) && IsFlagSet(g_dwBreakFlags, BF_ONWARNMSG)))
  1034.         {
  1035.             // MSDEV USERS:  This is not the real assert.  Hit 
  1036.             //               Shift-F11 to jump back to the caller.
  1037.             DEBUG_BREAK;                                                // ASSERT
  1038.         }
  1039.     }
  1040. }
  1041. /*-------------------------------------------------------------------------
  1042. Purpose: Since the ATL code does not pass in a flag parameter,
  1043.          we'll hardcode and check for TF_ATL.
  1044. */
  1045. void CDECL ShellAtlTraceA(LPCSTR pszMsg, ...)
  1046. {
  1047.     CHAR ach[1024+40];    // Largest path plus extra
  1048.     va_list vArgs;
  1049.     if (g_dwTraceFlags & TF_ATL)
  1050.     {
  1051.         int cch;
  1052.         SetPrefixStringA(ach, TF_ATL);
  1053.         lstrcatA(ach, "(ATL) ");
  1054.         cch = lstrlenA(ach);
  1055.         va_start(vArgs, pszMsg);
  1056.         wvsprintfA(&ach[cch], pszMsg, vArgs);
  1057.         va_end(vArgs);
  1058.         OutputDebugStringA(ach);
  1059.     }
  1060. }
  1061. /*----------------------------------------------------------
  1062. Purpose: Debug spew for function trace calls
  1063. */
  1064. void
  1065. CDECL
  1066. CcshellFuncMsgA(
  1067.     DWORD flag,
  1068.     LPCSTR pszMsg, ...)
  1069.     {
  1070.     CHAR ach[1024+40];    // Largest path plus extra
  1071.     va_list vArgs;
  1072.     if (IsFlagSet(g_dwTraceFlags, TF_FUNC) &&
  1073.         IsFlagSet(g_dwFuncTraceFlags, flag))
  1074.         {
  1075.         int cch;
  1076.         DWORD dwStackDepth;
  1077.         LPSTR pszLeaderEnd;
  1078.         CHAR chSave;
  1079.         // Determine the indentation for trace message based on
  1080.         // stack depth.
  1081.         dwStackDepth = CcshellGetStackDepth();
  1082.         if (dwStackDepth < sizeof(g_szIndentLeader))
  1083.             {
  1084.             pszLeaderEnd = &g_szIndentLeader[dwStackDepth];
  1085.             }
  1086.         else
  1087.             {
  1088.             pszLeaderEnd = &g_szIndentLeader[sizeof(g_szIndentLeader)-1];
  1089.             }
  1090.         chSave = *pszLeaderEnd;
  1091.         *pszLeaderEnd = '';
  1092.         wsprintfA(ach, "%s %s", c_szTrace, g_szIndentLeader);
  1093.         *pszLeaderEnd = chSave;
  1094.         // Compose remaining string
  1095.         cch = lstrlenA(ach);
  1096.         va_start(vArgs, pszMsg);
  1097.         wvsprintfA(&ach[cch], pszMsg, vArgs);
  1098.         va_end(vArgs);
  1099.         OutputDebugStringA(ach);
  1100.         OutputDebugStringA(c_szNewline);
  1101.         }
  1102.     }
  1103. /*-------------------------------------------------------------------------
  1104. Purpose: Spews a trace message if hrTest is a failure code.
  1105. */
  1106. HRESULT 
  1107. TraceHR(
  1108.     HRESULT hrTest, 
  1109.     LPCSTR pszExpr, 
  1110.     LPCSTR pszFile, 
  1111.     int iLine)
  1112. {
  1113.     CHAR ach[1024+40];    // Largest path plus extra
  1114.     if (g_dwTraceFlags & TF_WARNING &&
  1115.         FAILED(hrTest))
  1116.     {
  1117.         int cch;
  1118.         cch = SetPrefixStringA(ach, TF_WARNING);
  1119.         wsprintfA(&ach[cch], "THR: Failure of "%s" at %s, line %d (%#08lx)", 
  1120.                    pszExpr, _PathFindFileNameA(pszFile), iLine, hrTest);
  1121.         OutputDebugStringA(ach);
  1122.         OutputDebugStringA(c_szNewline);
  1123.         if (IsFlagSet(g_dwBreakFlags, BF_THR))
  1124.         {
  1125.             // !!!  THR  !!!!  THR  !!!!  THR !!!
  1126.             // MSDEV USERS:  This is not the real assert.  Hit 
  1127.             //               Shift-F11 to jump back to the caller.
  1128.             DEBUG_BREAK;                                                // ASSERT
  1129.             // !!!  THR  !!!!  THR  !!!!  THR !!!
  1130.         }
  1131.     }
  1132.     return hrTest;
  1133. }
  1134. /*-------------------------------------------------------------------------
  1135. Purpose: Spews a trace message if bTest is false.
  1136. */
  1137. BOOL 
  1138. TraceBool(
  1139.     BOOL bTest, 
  1140.     LPCSTR pszExpr, 
  1141.     LPCSTR pszFile, 
  1142.     int iLine)
  1143. {
  1144.     CHAR ach[1024+40];    // Largest path plus extra
  1145.     if (g_dwTraceFlags & TF_WARNING && !bTest)
  1146.     {
  1147.         int cch;
  1148.         cch = SetPrefixStringA(ach, TF_WARNING);
  1149.         wsprintfA(&ach[cch], "TBOOL: Failure of "%s" at %s, line %d", 
  1150.                    pszExpr, _PathFindFileNameA(pszFile), iLine);
  1151.         OutputDebugStringA(ach);
  1152.         OutputDebugStringA(c_szNewline);
  1153.         if (IsFlagSet(g_dwBreakFlags, BF_THR))
  1154.         {
  1155.             // !!!  TBOOL  !!!!  TBOOL  !!!!  TBOOL !!!
  1156.             // MSDEV USERS:  This is not the real assert.  Hit 
  1157.             //               Shift-F11 to jump back to the caller.
  1158.             DEBUG_BREAK;                                                // ASSERT
  1159.             // !!!  TBOOL  !!!!  TBOOL  !!!!  TBOOL !!!
  1160.         }
  1161.     }
  1162.     return bTest;
  1163. }
  1164. /*-------------------------------------------------------------------------
  1165. Purpose: Spews a trace message if iTest is -1.
  1166. */
  1167. int 
  1168. TraceInt(
  1169.     int iTest, 
  1170.     LPCSTR pszExpr, 
  1171.     LPCSTR pszFile, 
  1172.     int iLine)
  1173. {
  1174.     CHAR ach[1024+40];    // Largest path plus extra
  1175.     if (g_dwTraceFlags & TF_WARNING && -1 == iTest)
  1176.     {
  1177.         int cch;
  1178.         cch = SetPrefixStringA(ach, TF_WARNING);
  1179.         wsprintfA(&ach[cch], "TINT: Failure of "%s" at %s, line %d", 
  1180.                    pszExpr, _PathFindFileNameA(pszFile), iLine);
  1181.         OutputDebugStringA(ach);
  1182.         OutputDebugStringA(c_szNewline);
  1183.         if (IsFlagSet(g_dwBreakFlags, BF_THR))
  1184.         {
  1185.             // !!!  TINT  !!!!  TINT  !!!!  TINT !!!
  1186.             // MSDEV USERS:  This is not the real assert.  Hit 
  1187.             //               Shift-F11 to jump back to the caller.
  1188.             DEBUG_BREAK;                                                // ASSERT
  1189.             // !!!  TINT  !!!!  TINT  !!!!  TINT !!!
  1190.         }
  1191.     }
  1192.     return iTest;
  1193. }
  1194. /*-------------------------------------------------------------------------
  1195. Purpose: Spews a trace message if pvTest is NULL.
  1196. */
  1197. LPVOID 
  1198. TracePtr(
  1199.     LPVOID pvTest, 
  1200.     LPCSTR pszExpr, 
  1201.     LPCSTR pszFile, 
  1202.     int iLine)
  1203. {
  1204.     CHAR ach[1024+40];    // Largest path plus extra
  1205.     if (g_dwTraceFlags & TF_WARNING && NULL == pvTest)
  1206.     {
  1207.         int cch;
  1208.         cch = SetPrefixStringA(ach, TF_WARNING);
  1209.         wsprintfA(&ach[cch], "TPTR: Failure of "%s" at %s, line %d", 
  1210.                    pszExpr, _PathFindFileNameA(pszFile), iLine);
  1211.         OutputDebugStringA(ach);
  1212.         OutputDebugStringA(c_szNewline);
  1213.         if (IsFlagSet(g_dwBreakFlags, BF_THR))
  1214.         {
  1215.             // !!!  TPTR  !!!!  TPTR  !!!!  TPTR !!!
  1216.             // MSDEV USERS:  This is not the real assert.  Hit 
  1217.             //               Shift-F11 to jump back to the caller.
  1218.             DEBUG_BREAK;                                                // ASSERT
  1219.             // !!!  TPTR  !!!!  TPTR  !!!!  TPTR !!!
  1220.         }
  1221.     }
  1222.     return pvTest;
  1223. }
  1224. /*-------------------------------------------------------------------------
  1225. Purpose: Spews a trace message if dwTest is a Win32 failure code.
  1226. */
  1227. DWORD  
  1228. TraceWin32(
  1229.     DWORD dwTest, 
  1230.     LPCSTR pszExpr, 
  1231.     LPCSTR pszFile, 
  1232.     int iLine)
  1233. {
  1234.     CHAR ach[1024+40];    // Largest path plus extra
  1235.     if (g_dwTraceFlags & TF_WARNING &&
  1236.         ERROR_SUCCESS != dwTest)
  1237.     {
  1238.         int cch;
  1239.         cch = SetPrefixStringA(ach, TF_WARNING);
  1240.         wsprintfA(&ach[cch], "TW32: Failure of "%s" at %s, line %d (%#08lx)", 
  1241.                    pszExpr, _PathFindFileNameA(pszFile), iLine, dwTest);
  1242.         OutputDebugStringA(ach);
  1243.         OutputDebugStringA(c_szNewline);
  1244.         if (IsFlagSet(g_dwBreakFlags, BF_THR))
  1245.         {
  1246.             // !!!  THR  !!!!  THR  !!!!  THR !!!
  1247.             // MSDEV USERS:  This is not the real assert.  Hit 
  1248.             //               Shift-F11 to jump back to the caller.
  1249.             DEBUG_BREAK;                                                // ASSERT
  1250.             // !!!  THR  !!!!  THR  !!!!  THR !!!
  1251.         }
  1252.     }
  1253.     return dwTest;
  1254. }
  1255. //
  1256. //  Debug .ini functions
  1257. //
  1258. #pragma data_seg(DATASEG_READONLY)
  1259. // (These are deliberately CHAR)
  1260. CHAR const FAR c_szNull[] = "";
  1261. CHAR const FAR c_szZero[] = "0";
  1262. CHAR const FAR c_szIniKeyBreakFlags[] = "BreakFlags";
  1263. CHAR const FAR c_szIniKeyTraceFlags[] = "TraceFlags";
  1264. CHAR const FAR c_szIniKeyFuncTraceFlags[] = "FuncTraceFlags";
  1265. CHAR const FAR c_szIniKeyDumpFlags[] = "DumpFlags";
  1266. CHAR const FAR c_szIniKeyProtoFlags[] = "Prototype";
  1267. #pragma data_seg()
  1268. // Some of the .ini processing code was pimped from the sync engine.
  1269. //
  1270. typedef struct _INIKEYHEADER
  1271.     {
  1272.     LPCTSTR pszSectionName;
  1273.     LPCTSTR pszKeyName;
  1274.     LPCTSTR pszDefaultRHS;
  1275.     } INIKEYHEADER;
  1276. typedef struct _BOOLINIKEY
  1277.     {
  1278.     INIKEYHEADER ikh;
  1279.     LPDWORD puStorage;
  1280.     DWORD dwFlag;
  1281.     } BOOLINIKEY;
  1282. typedef struct _INTINIKEY
  1283.     {
  1284.     INIKEYHEADER ikh;
  1285.     LPDWORD puStorage;
  1286.     } INTINIKEY;
  1287. #define PutIniIntCmp(idsSection, idsKey, nNewValue, nSave) 
  1288.     if ((nNewValue) != (nSave)) PutIniInt(idsSection, idsKey, nNewValue)
  1289. #define WritePrivateProfileInt(szApp, szKey, i, lpFileName) 
  1290.     {CHAR sz[7]; 
  1291.     WritePrivateProfileString(szApp, szKey, SzFromInt(sz, i), lpFileName);}
  1292. #ifdef BOOL_INI_VALUES
  1293. /* Boolean TRUE strings used by IsIniYes() (comparison is case-insensitive) */
  1294. static LPCTSTR s_rgpszTrue[] =
  1295.     {
  1296.     TEXT("1"),
  1297.     TEXT("On"),
  1298.     TEXT("True"),
  1299.     TEXT("Y"),
  1300.     TEXT("Yes")
  1301.     };
  1302. /* Boolean FALSE strings used by IsIniYes() (comparison is case-insensitive) */
  1303. static LPCTSTR s_rgpszFalse[] =
  1304.     {
  1305.     TEXT("0"),
  1306.     TEXT("Off"),
  1307.     TEXT("False"),
  1308.     TEXT("N"),
  1309.     TEXT("No")
  1310.     };
  1311. #endif
  1312. #ifdef BOOL_INI_VALUES
  1313. /*----------------------------------------------------------
  1314. Purpose: Determines whether a string corresponds to a boolean
  1315.           TRUE value.
  1316. Returns: The boolean value (TRUE or FALSE)
  1317. */
  1318. BOOL
  1319. PRIVATE
  1320. IsIniYes(
  1321.     LPCTSTR psz)
  1322.     {
  1323.     int i;
  1324.     BOOL bNotFound = TRUE;
  1325.     BOOL bResult;
  1326.     Assert(psz);
  1327.     /* Is the value TRUE? */
  1328.     for (i = 0; i < ARRAYSIZE(s_rgpszTrue); i++)
  1329.         {
  1330.         if (IsSzEqual(psz, s_rgpszTrue[i]))
  1331.             {
  1332.             bResult = TRUE;
  1333.             bNotFound = FALSE;
  1334.             break;
  1335.             }
  1336.         }
  1337.     /* Is the value FALSE? */
  1338.     if (bNotFound)
  1339.         {
  1340.         for (i = 0; i < ARRAYSIZE(s_rgpszFalse); i++)
  1341.             {
  1342.             if (IsSzEqual(psz, s_rgpszFalse[i]))
  1343.                 {
  1344.                 bResult = FALSE;
  1345.                 bNotFound = FALSE;
  1346.                 break;
  1347.                 }
  1348.             }
  1349.         /* Is the value a known string? */
  1350.         if (bNotFound)
  1351.             {
  1352.             /* No.  Whine about it. */
  1353.             TraceMsg(TF_WARNING, "IsIniYes() called on unknown Boolean RHS '%s'.", psz);
  1354.             bResult = FALSE;
  1355.             }
  1356.         }
  1357.     return bResult;
  1358.     }
  1359. /*----------------------------------------------------------
  1360. Purpose: Process keys with boolean RHSs.
  1361. */
  1362. void
  1363. PRIVATE
  1364. ProcessBooleans(void)
  1365.     {
  1366.     int i;
  1367.     for (i = 0; i < ARRAYSIZE(s_rgbik); i++)
  1368.         {
  1369.         DWORD dwcbKeyLen;
  1370.         TCHAR szRHS[MAX_BUF];
  1371.         BOOLINIKEY * pbik = &(s_rgbik[i]);
  1372.         LPCTSTR lpcszRHS;
  1373.         /* Look for key. */
  1374.         dwcbKeyLen = GetPrivateProfileString(pbik->ikh.pszSectionName,
  1375.                                    pbik->ikh.pszKeyName, TEXT(""), szRHS,
  1376.                                    SIZECHARS(szRHS), c_szCcshellIniFile);
  1377.         if (dwcbKeyLen)
  1378.             lpcszRHS = szRHS;
  1379.         else
  1380.             lpcszRHS = pbik->ikh.pszDefaultRHS;
  1381.         if (IsIniYes(lpcszRHS))
  1382.             {
  1383.             if (IsFlagClear(*(pbik->puStorage), pbik->dwFlag))
  1384.                 TraceMsg(TF_GENERAL, "ProcessIniFile(): %s set in %s![%s].",
  1385.                          pbik->ikh.pszKeyName,
  1386.                          c_szCcshellIniFile,
  1387.                          pbik->ikh.pszSectionName);
  1388.             SetFlag(*(pbik->puStorage), pbik->dwFlag);
  1389.             }
  1390.         else
  1391.             {
  1392.             if (IsFlagSet(*(pbik->puStorage), pbik->dwFlag))
  1393.                 TraceMsg(TF_GENERAL, "ProcessIniFile(): %s cleared in %s![%s].",
  1394.                          pbik->ikh.pszKeyName,
  1395.                          c_szCcshellIniFile,
  1396.                          pbik->ikh.pszSectionName);
  1397.             ClearFlag(*(pbik->puStorage), pbik->dwFlag);
  1398.             }
  1399.         }
  1400.     }
  1401. #endif
  1402. #ifdef UNICODE
  1403. /*----------------------------------------------------------
  1404. Purpose: This function converts a wide-char string to a multi-byte
  1405.          string.
  1406.          If pszBuf is non-NULL and the converted string can fit in
  1407.          pszBuf, then *ppszAnsi will point to the given buffer.
  1408.          Otherwise, this function will allocate a buffer that can
  1409.          hold the converted string.
  1410.          If pszWide is NULL, then *ppszAnsi will be freed.  Note
  1411.          that pszBuf must be the same pointer between the call
  1412.          that converted the string and the call that frees the
  1413.          string.
  1414. Returns: TRUE
  1415.          FALSE (if out of memory)
  1416. */
  1417. static
  1418. BOOL
  1419. MyAnsiFromUnicode(
  1420.     LPSTR * ppszAnsi,
  1421.     LPCWSTR pwszWide,        // NULL to clean up
  1422.     LPSTR pszBuf,
  1423.     int cchBuf)
  1424.     {
  1425.     BOOL bRet;
  1426.     // Convert the string?
  1427.     if (pwszWide)
  1428.         {
  1429.         // Yes; determine the converted string length
  1430.         int cch;
  1431.         LPSTR psz;
  1432.         cch = WideCharToMultiByte(CP_ACP, 0, pwszWide, -1, NULL, 0, NULL, NULL);
  1433.         // String too big, or is there no buffer?
  1434.         if (cch > cchBuf || NULL == pszBuf)
  1435.             {
  1436.             // Yes; allocate space
  1437.             cchBuf = cch + 1;
  1438.             psz = (LPSTR)LocalAlloc(LPTR, CbFromCchA(cchBuf));
  1439.             }
  1440.         else
  1441.             {
  1442.             // No; use the provided buffer
  1443.             Assert(pszBuf);
  1444.             psz = pszBuf;
  1445.             }
  1446.         if (psz)
  1447.             {
  1448.             // Convert the string
  1449.             cch = WideCharToMultiByte(CP_ACP, 0, pwszWide, -1, psz, cchBuf, NULL, NULL);
  1450.             bRet = (0 < cch);
  1451.             }
  1452.         else
  1453.             {
  1454.             bRet = FALSE;
  1455.             }
  1456.         *ppszAnsi = psz;
  1457.         }
  1458.     else
  1459.         {
  1460.         // No; was this buffer allocated?
  1461.         if (*ppszAnsi && pszBuf != *ppszAnsi)
  1462.             {
  1463.             // Yes; clean up
  1464.             LocalFree((HLOCAL)*ppszAnsi);
  1465.             *ppszAnsi = NULL;
  1466.             }
  1467.         bRet = TRUE;
  1468.         }
  1469.     return bRet;
  1470.     }
  1471. /*----------------------------------------------------------
  1472. Purpose: Wide-char wrapper for StrToIntExA.
  1473. Returns: see StrToIntExA
  1474. */
  1475. static
  1476. BOOL
  1477. MyStrToIntExW(
  1478.     LPCWSTR   pwszString,
  1479.     DWORD     dwFlags,          // STIF_ bitfield
  1480.     int FAR * piRet)
  1481.     {
  1482.     // Most strings will simply use this temporary buffer, but AnsiFromUnicode
  1483.     // will allocate a buffer if the supplied string is bigger.
  1484.     CHAR szBuf[MAX_PATH];
  1485.     LPSTR pszString;
  1486.     BOOL bRet = MyAnsiFromUnicode(&pszString, pwszString, szBuf, SIZECHARS(szBuf));
  1487.     if (bRet)
  1488.         {
  1489.         bRet = MyStrToIntExA(pszString, dwFlags, piRet);
  1490.         MyAnsiFromUnicode(&pszString, NULL, szBuf, 0);
  1491.         }
  1492.     return bRet;
  1493.     }
  1494. #endif // UNICODE
  1495. #ifdef UNICODE
  1496. #define MyStrToIntEx        MyStrToIntExW
  1497. #else
  1498. #define MyStrToIntEx        MyStrToIntExA
  1499. #endif
  1500. /*----------------------------------------------------------
  1501. Purpose: This function reads a .ini file to determine the debug
  1502.          flags to set.  The .ini file and section are specified
  1503.          by the following manifest constants:
  1504.                 SZ_DEBUGINI
  1505.                 SZ_DEBUGSECTION
  1506.          The debug variables that are set by this function are
  1507.          g_dwDumpFlags, g_dwTraceFlags, g_dwBreakFlags, and
  1508.          g_dwFuncTraceFlags, g_dwPrototype.
  1509. Returns: TRUE if initialization is successful
  1510. */
  1511. BOOL
  1512. PUBLIC
  1513. CcshellGetDebugFlags(void)
  1514.     {
  1515.     CHAR szRHS[MAX_PATH];
  1516.     int val;
  1517.     // BUGBUG (scotth): Yes, COMCTL32 exports StrToIntEx, but I
  1518.     //  don't want to cause a dependency delta and force everyone
  1519.     //  to get a new comctl32 just because they built debug.
  1520.     //  So use a local version of StrToIntEx.
  1521.     // Trace Flags
  1522.     GetPrivateProfileStringA(c_szCcshellIniSecDebug,
  1523.                             c_szIniKeyTraceFlags,
  1524.                             c_szNull,
  1525.                             szRHS,
  1526.                             SIZECHARS(szRHS),
  1527.                             c_szCcshellIniFile);
  1528.     if (MyStrToIntExA(szRHS, STIF_SUPPORT_HEX, &val))
  1529.         g_dwTraceFlags = (DWORD)val;
  1530. #ifdef FULL_DEBUG
  1531.     else
  1532.         g_dwTraceFlags = 3; // default to TF_ERROR and TF_WARNING trace messages
  1533. #endif
  1534.     TraceMsgA(DM_DEBUG, "CcshellGetDebugFlags(): %s set to %#08x.",
  1535.              c_szIniKeyTraceFlags, g_dwTraceFlags);
  1536.     // Function trace Flags
  1537.     GetPrivateProfileStringA(c_szCcshellIniSecDebug,
  1538.                             c_szIniKeyFuncTraceFlags,
  1539.                             c_szNull,
  1540.                             szRHS,
  1541.                             SIZECHARS(szRHS),
  1542.                             c_szCcshellIniFile);
  1543.     if (MyStrToIntExA(szRHS, STIF_SUPPORT_HEX, &val))
  1544.         g_dwFuncTraceFlags = (DWORD)val;
  1545.     TraceMsgA(DM_DEBUG, "CcshellGetDebugFlags(): %s set to %#08x.",
  1546.              c_szIniKeyFuncTraceFlags, g_dwFuncTraceFlags);
  1547.     // Dump Flags
  1548.     GetPrivateProfileStringA(c_szCcshellIniSecDebug,
  1549.                             c_szIniKeyDumpFlags,
  1550.                             c_szNull,
  1551.                             szRHS,
  1552.                             SIZECHARS(szRHS),
  1553.                             c_szCcshellIniFile);
  1554.     if (MyStrToIntExA(szRHS, STIF_SUPPORT_HEX, &val))
  1555.         g_dwDumpFlags = (DWORD)val;
  1556.     TraceMsgA(DM_DEBUG, "CcshellGetDebugFlags(): %s set to %#08x.",
  1557.              c_szIniKeyDumpFlags, g_dwDumpFlags);
  1558.     // Break Flags
  1559.     GetPrivateProfileStringA(c_szCcshellIniSecDebug,
  1560.                             c_szIniKeyBreakFlags,
  1561.                             c_szNull,
  1562.                             szRHS,
  1563.                             SIZECHARS(szRHS),
  1564.                             c_szCcshellIniFile);
  1565.     if (MyStrToIntExA(szRHS, STIF_SUPPORT_HEX, &val))
  1566.         g_dwBreakFlags = (DWORD)val;
  1567. #ifdef FULL_DEBUG
  1568.     else
  1569.         g_dwBreakFlags = 5; // default to break on ASSERT and TF_ERROR
  1570. #endif
  1571.     TraceMsgA(DM_DEBUG, "CcshellGetDebugFlags(): %s set to %#08x.",
  1572.              c_szIniKeyBreakFlags, g_dwBreakFlags);
  1573.     // Prototype Flags
  1574.     GetPrivateProfileStringA(c_szCcshellIniSecDebug,
  1575.                             c_szIniKeyProtoFlags,
  1576.                             c_szNull,
  1577.                             szRHS,
  1578.                             SIZECHARS(szRHS),
  1579.                             c_szCcshellIniFile);
  1580.     if (MyStrToIntExA(szRHS, STIF_SUPPORT_HEX, &val))
  1581.         g_dwPrototype = (DWORD)val;
  1582.     // Are we using the new leak detection from shelldbg.dll?
  1583.     GetPrivateProfileStringA("ShellDbg",
  1584.                             "NewLeakDetection",
  1585.                             c_szNull,
  1586.                             szRHS,
  1587.                             SIZECHARS(szRHS),
  1588.                             c_szCcshellIniFile);
  1589.     if (MyStrToIntExA(szRHS, STIF_SUPPORT_HEX, &val))
  1590.         g_bUseNewLeakDetection = BOOLIFY(val);
  1591.     TraceMsgA(DM_DEBUG, "CcshellGetDebugFlags(): %s set to %#08x.",
  1592.              c_szIniKeyProtoFlags, g_dwPrototype);
  1593.     GetPrivateProfileStringA(c_szCcshellIniSecDebug,
  1594.                             "DebugOutputFile",
  1595.                             c_szNull,
  1596.                             szRHS,
  1597.                             SIZECHARS(szRHS),
  1598.                             c_szCcshellIniFile);
  1599.     if (szRHS != TEXT(''))
  1600.     {
  1601.         g_hDebugOutputFile = CreateFileA(szRHS, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  1602.     }
  1603.     return TRUE;
  1604.     }
  1605. // Function to call in allocspy.dll (GetShellMallocSpy)
  1606. typedef BOOL (__stdcall *pfnGSMS) (IShellMallocSpy **ppout);
  1607. STDAPI_(void) IMSAddToList(BOOL bAdd, void*pv, DWORD cb)
  1608. {
  1609.     static BOOL bDontTry=FALSE;
  1610.     static IShellMallocSpy *pms=NULL;
  1611.     if (!bDontTry && pms == NULL)
  1612.     {
  1613.         pfnGSMS pfnGetShellMallocSpy;
  1614.         HMODULE hmod;
  1615.         bDontTry = TRUE; // assume failure
  1616.         if (hmod = LoadLibraryA("ALLOCSPY.DLL"))
  1617.         {
  1618.             pfnGetShellMallocSpy = (pfnGSMS) GetProcAddress(hmod, "GetShellMallocSpy");
  1619.             pfnGetShellMallocSpy(&pms);
  1620.         }
  1621.     }
  1622.     if (bDontTry)
  1623.         return;
  1624.     if (bAdd)
  1625.         pms->lpVtbl->AddToList(pms, pv, cb);
  1626.     else
  1627.         pms->lpVtbl->RemoveFromList(pms, pv);
  1628. }
  1629. #endif // DEBUG
  1630. #ifdef PRODUCT_PROF
  1631. DWORD g_dwProfileCAP = 0;        
  1632. BOOL PUBLIC CcshellGetDebugFlags(void)
  1633. {
  1634.     CHAR szRHS[MAX_PATH];
  1635.     int val;
  1636.     GetPrivateProfileStringA(c_szCcshellIniSecDebug,
  1637.                             "Profile",
  1638.                             "",
  1639.                             szRHS,
  1640.                             SIZECHARS(szRHS),
  1641.                             c_szCcshellIniFile);
  1642.     if (MyStrToIntExA(szRHS, STIF_SUPPORT_HEX, &val))
  1643.         g_dwProfileCAP = (DWORD)val;
  1644.     return TRUE;
  1645. }
  1646. #endif // PRODUCT_PROF 
  1647. #ifdef DEBUG
  1648. // turn on path whacking for full-debug builds
  1649. #ifdef FULL_DEBUG
  1650. static BOOL g_fWhackPathBuffers = TRUE;
  1651. #else
  1652. static BOOL g_fWhackPathBuffers = FALSE;
  1653. #endif
  1654. void DEBUGWhackPathBufferA(LPSTR psz, UINT cch)
  1655. {
  1656.     if (g_fWhackPathBuffers)
  1657.     {
  1658.         if (psz && IS_VALID_WRITE_BUFFER(psz, char, cch))
  1659.         {
  1660.             FillMemory(psz, cch * sizeof(char), 0xFE);
  1661.         }
  1662.     }
  1663. }
  1664. void DEBUGWhackPathBufferW(LPWSTR psz, UINT cch)
  1665. {
  1666.     if (g_fWhackPathBuffers)
  1667.     {
  1668.         if (psz && IS_VALID_WRITE_BUFFER(psz, WCHAR, cch))
  1669.         {
  1670.             FillMemory(psz, cch * sizeof(WCHAR), 0xFE);
  1671.         }
  1672.     }
  1673. }
  1674. void DEBUGWhackPathStringA(LPSTR psz, UINT cch)
  1675. {
  1676.     if (g_fWhackPathBuffers)
  1677.     {
  1678.         if (psz && IS_VALID_WRITE_BUFFER(psz, char, cch) && IS_VALID_STRING_PTRA(psz, -1))
  1679.         {
  1680.             UINT len = lstrlenA(psz);
  1681.             if (len >= cch)
  1682.             {
  1683.                 TraceMsg(TF_WARNING, "DEBUGWhackPathStringA: caller of caller passed strange Path string (strlen > buffer size)");
  1684.             }
  1685.             else
  1686.             {
  1687.                 FillMemory(psz+len+1, (cch-len-1) * sizeof(char), 0xFE);
  1688.             }
  1689.         }
  1690.     }
  1691. }
  1692. void DEBUGWhackPathStringW(LPWSTR psz, UINT cch)
  1693. {
  1694.     if (g_fWhackPathBuffers)
  1695.     {
  1696.         if (psz && IS_VALID_WRITE_BUFFER(psz, WCHAR, cch) && IS_VALID_STRING_PTRW(psz, -1))
  1697.         {
  1698.             UINT len = lstrlenW(psz);
  1699.             if (len >= cch)
  1700.             {
  1701.                 TraceMsg(TF_WARNING, "DEBUGWhackPathStringW: caller of caller passed strange Path string (strlen > buffer size)");
  1702.             }
  1703.             else
  1704.             {
  1705.                 FillMemory(psz+len+1, (cch-len-1) * sizeof(WCHAR), 0xFE);
  1706.             }
  1707.         }
  1708.     }
  1709. }
  1710. #endif // DEBUG