OLD | NEW |
(Empty) | |
| 1 //------------------------------------------------------------------------------
------------------- |
| 2 // <copyright file="dutil.cpp" company="Outercurve Foundation"> |
| 3 // Copyright (c) 2004, Outercurve Foundation. |
| 4 // This software is released under Microsoft Reciprocal License (MS-RL). |
| 5 // The license and further copyright text can be found in the file |
| 6 // LICENSE.TXT at the root directory of the distribution. |
| 7 // </copyright> |
| 8 // |
| 9 // <summary> |
| 10 // Utility layer that provides standard support for asserts, exit macros |
| 11 // </summary> |
| 12 //------------------------------------------------------------------------------
------------------- |
| 13 |
| 14 #include "../precomp.h" |
| 15 |
| 16 // No need for OACR to warn us about using non-unicode APIs in this file. |
| 17 #pragma prefast(disable:25068) |
| 18 |
| 19 // Asserts & Tracing |
| 20 |
| 21 const int DUTIL_STRING_BUFFER = 1024; |
| 22 static HMODULE Dutil_hAssertModule = NULL; |
| 23 static DUTIL_ASSERTDISPLAYFUNCTION Dutil_pfnDisplayAssert = NULL; |
| 24 static BOOL Dutil_fNoAsserts = FALSE; |
| 25 static REPORT_LEVEL Dutil_rlCurrentTrace = REPORT_STANDARD; |
| 26 static BOOL Dutil_fTraceFilenames = FALSE; |
| 27 |
| 28 |
| 29 /******************************************************************* |
| 30 Dutil_SetAssertModule |
| 31 |
| 32 *******************************************************************/ |
| 33 extern "C" void DAPI Dutil_SetAssertModule( |
| 34 __in HMODULE hAssertModule |
| 35 ) |
| 36 { |
| 37 Dutil_hAssertModule = hAssertModule; |
| 38 } |
| 39 |
| 40 |
| 41 /******************************************************************* |
| 42 Dutil_SetAssertDisplayFunction |
| 43 |
| 44 *******************************************************************/ |
| 45 extern "C" void DAPI Dutil_SetAssertDisplayFunction( |
| 46 __in DUTIL_ASSERTDISPLAYFUNCTION pfn |
| 47 ) |
| 48 { |
| 49 Dutil_pfnDisplayAssert = pfn; |
| 50 } |
| 51 |
| 52 |
| 53 /******************************************************************* |
| 54 Dutil_AssertMsg |
| 55 |
| 56 *******************************************************************/ |
| 57 extern "C" void DAPI Dutil_AssertMsg( |
| 58 __in_z LPCSTR szMessage |
| 59 ) |
| 60 { |
| 61 static BOOL fInAssert = FALSE; // TODO: make this thread safe (this is a che
ap hack to prevent re-entrant Asserts) |
| 62 |
| 63 HRESULT hr = S_OK; |
| 64 DWORD er = ERROR_SUCCESS; |
| 65 |
| 66 int id = IDRETRY; |
| 67 HKEY hkDebug = NULL; |
| 68 HANDLE hAssertFile = INVALID_HANDLE_VALUE; |
| 69 char szPath[MAX_PATH] = { }; |
| 70 DWORD cch = 0; |
| 71 |
| 72 if (fInAssert) |
| 73 { |
| 74 return; |
| 75 } |
| 76 fInAssert = TRUE; |
| 77 |
| 78 char szMsg[DUTIL_STRING_BUFFER]; |
| 79 hr = ::StringCchCopyA(szMsg, countof(szMsg), szMessage); |
| 80 ExitOnFailure(hr, "failed to copy message while building assert message"); |
| 81 |
| 82 if (Dutil_pfnDisplayAssert) |
| 83 { |
| 84 // call custom function to display the assert string |
| 85 if (!Dutil_pfnDisplayAssert(szMsg)) |
| 86 { |
| 87 ExitFunction(); |
| 88 } |
| 89 } |
| 90 else |
| 91 { |
| 92 OutputDebugStringA(szMsg); |
| 93 } |
| 94 |
| 95 if (!Dutil_fNoAsserts) |
| 96 { |
| 97 er = ::RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Delivery
\\Debug", 0, KEY_QUERY_VALUE, &hkDebug); |
| 98 if (ERROR_SUCCESS == er) |
| 99 { |
| 100 cch = countof(szPath); |
| 101 er = ::RegQueryValueExA(hkDebug, "DeliveryAssertsLog", NULL, NULL, r
einterpret_cast<BYTE*>(szPath), &cch); |
| 102 szPath[countof(szPath) - 1] = '\0'; // ensure string is null termina
ted since registry won't guarantee that. |
| 103 if (ERROR_SUCCESS == er) |
| 104 { |
| 105 hAssertFile = ::CreateFileA(szPath, GENERIC_WRITE, FILE_SHARE_RE
AD | FILE_SHARE_DELETE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); |
| 106 if (INVALID_HANDLE_VALUE != hAssertFile) |
| 107 { |
| 108 ::SetFilePointer(hAssertFile, 0, 0, FILE_END); |
| 109 ::StringCchCatA(szMsg, countof(szMsg), "\r\n"); |
| 110 ::WriteFile(hAssertFile, szMsg, lstrlenA(szMsg), &cch, NULL)
; |
| 111 } |
| 112 } |
| 113 } |
| 114 |
| 115 // if anything went wrong while fooling around with the registry, just s
how the usual assert dialog box |
| 116 if (ERROR_SUCCESS != er) |
| 117 { |
| 118 hr = ::StringCchCatA(szMsg, countof(szMsg), "\nAbort=Debug, Retry=Sk
ip, Ignore=Skip all"); |
| 119 ExitOnFailure(hr, "failed to concat string while building assert mes
sage"); |
| 120 |
| 121 id = ::MessageBoxA(0, szMsg, "Debug Assert Message", |
| 122 MB_SERVICE_NOTIFICATION | MB_TOPMOST | |
| 123 MB_DEFBUTTON2 | MB_ABORTRETRYIGNORE); |
| 124 } |
| 125 } |
| 126 |
| 127 if (id == IDABORT) |
| 128 { |
| 129 if (Dutil_hAssertModule) |
| 130 { |
| 131 ::GetModuleFileNameA(Dutil_hAssertModule, szPath, countof(szPath)); |
| 132 |
| 133 hr = ::StringCchPrintfA(szMsg, countof(szMsg), "Module is running fr
om: %s\nIf you are not using pdb-stamping, place your PDB near the module and at
tach to process id: %d (0x%x)", szPath, ::GetCurrentProcessId(), ::GetCurrentPro
cessId()); |
| 134 if (SUCCEEDED(hr)) |
| 135 { |
| 136 ::MessageBoxA(0, szMsg, "Debug Assert Message", MB_SERVICE_NOTIF
ICATION | MB_TOPMOST | MB_OK); |
| 137 } |
| 138 } |
| 139 |
| 140 ::DebugBreak(); |
| 141 } |
| 142 else if (id == IDIGNORE) |
| 143 { |
| 144 Dutil_fNoAsserts = TRUE; |
| 145 } |
| 146 |
| 147 LExit: |
| 148 ReleaseFileHandle(hAssertFile); |
| 149 ReleaseRegKey(hkDebug); |
| 150 fInAssert = FALSE; |
| 151 } |
| 152 |
| 153 |
| 154 /******************************************************************* |
| 155 Dutil_Assert |
| 156 |
| 157 *******************************************************************/ |
| 158 extern "C" void DAPI Dutil_Assert( |
| 159 __in_z LPCSTR szFile, |
| 160 __in int iLine |
| 161 ) |
| 162 { |
| 163 HRESULT hr = S_OK; |
| 164 char szMessage[DUTIL_STRING_BUFFER] = { }; |
| 165 hr = ::StringCchPrintfA(szMessage, countof(szMessage), "Assertion failed in
%s, %i", szFile, iLine); |
| 166 if (SUCCEEDED(hr)) |
| 167 { |
| 168 Dutil_AssertMsg(szMessage); |
| 169 } |
| 170 else |
| 171 { |
| 172 Dutil_AssertMsg("Assert failed to build string"); |
| 173 } |
| 174 } |
| 175 |
| 176 |
| 177 /******************************************************************* |
| 178 Dutil_AssertSz |
| 179 |
| 180 *******************************************************************/ |
| 181 extern "C" void DAPI Dutil_AssertSz( |
| 182 __in_z LPCSTR szFile, |
| 183 __in int iLine, |
| 184 __in_z __format_string LPCSTR szMsg |
| 185 ) |
| 186 { |
| 187 HRESULT hr = S_OK; |
| 188 char szMessage[DUTIL_STRING_BUFFER] = { }; |
| 189 |
| 190 hr = ::StringCchPrintfA(szMessage, countof(szMessage), "Assertion failed in
%s, %i\n%s", szFile, iLine, szMsg); |
| 191 if (SUCCEEDED(hr)) |
| 192 { |
| 193 Dutil_AssertMsg(szMessage); |
| 194 } |
| 195 else |
| 196 { |
| 197 Dutil_AssertMsg("Assert failed to build string"); |
| 198 } |
| 199 } |
| 200 |
| 201 |
| 202 /******************************************************************* |
| 203 Dutil_TraceSetLevel |
| 204 |
| 205 *******************************************************************/ |
| 206 extern "C" void DAPI Dutil_TraceSetLevel( |
| 207 __in REPORT_LEVEL rl, |
| 208 __in BOOL fTraceFilenames |
| 209 ) |
| 210 { |
| 211 Dutil_rlCurrentTrace = rl; |
| 212 Dutil_fTraceFilenames = fTraceFilenames; |
| 213 } |
| 214 |
| 215 |
| 216 /******************************************************************* |
| 217 Dutil_TraceGetLevel |
| 218 |
| 219 *******************************************************************/ |
| 220 extern "C" REPORT_LEVEL DAPI Dutil_TraceGetLevel() |
| 221 { |
| 222 return Dutil_rlCurrentTrace; |
| 223 } |
| 224 |
| 225 |
| 226 /******************************************************************* |
| 227 Dutil_Trace |
| 228 |
| 229 *******************************************************************/ |
| 230 extern "C" void DAPI Dutil_Trace( |
| 231 __in_z LPCSTR szFile, |
| 232 __in int iLine, |
| 233 __in REPORT_LEVEL rl, |
| 234 __in_z __format_string LPCSTR szFormat, |
| 235 ... |
| 236 ) |
| 237 { |
| 238 AssertSz(REPORT_NONE != rl, "REPORT_NONE is not a valid tracing level"); |
| 239 |
| 240 HRESULT hr = S_OK; |
| 241 char szOutput[DUTIL_STRING_BUFFER] = { }; |
| 242 char szMsg[DUTIL_STRING_BUFFER] = { }; |
| 243 |
| 244 if (Dutil_rlCurrentTrace < rl) |
| 245 { |
| 246 return; |
| 247 } |
| 248 |
| 249 va_list args; |
| 250 va_start(args, szFormat); |
| 251 hr = ::StringCchVPrintfA(szOutput, countof(szOutput), szFormat, args); |
| 252 va_end(args); |
| 253 |
| 254 if (SUCCEEDED(hr)) |
| 255 { |
| 256 LPCSTR szPrefix = "Trace/u"; |
| 257 switch (rl) |
| 258 { |
| 259 case REPORT_STANDARD: |
| 260 szPrefix = "Trace/s"; |
| 261 break; |
| 262 case REPORT_VERBOSE: |
| 263 szPrefix = "Trace/v"; |
| 264 break; |
| 265 case REPORT_DEBUG: |
| 266 szPrefix = "Trace/d"; |
| 267 break; |
| 268 } |
| 269 |
| 270 if (Dutil_fTraceFilenames) |
| 271 { |
| 272 hr = ::StringCchPrintfA(szMsg, countof(szMsg), "%s [%s,%d]: %s\r\n",
szPrefix, szFile, iLine, szOutput); |
| 273 } |
| 274 else |
| 275 { |
| 276 hr = ::StringCchPrintfA(szMsg, countof(szMsg), "%s: %s\r\n", szPrefi
x, szOutput); |
| 277 } |
| 278 |
| 279 if (SUCCEEDED(hr)) |
| 280 { |
| 281 OutputDebugStringA(szMsg); |
| 282 } |
| 283 // else fall through to the case below |
| 284 } |
| 285 |
| 286 if (FAILED(hr)) |
| 287 { |
| 288 if (Dutil_fTraceFilenames) |
| 289 { |
| 290 ::StringCchPrintfA(szMsg, countof(szMsg), "Trace [%s,%d]: message to
o long, skipping\r\n", szFile, iLine); |
| 291 } |
| 292 else |
| 293 { |
| 294 ::StringCchPrintfA(szMsg, countof(szMsg), "Trace: message too long,
skipping\r\n"); |
| 295 } |
| 296 |
| 297 szMsg[countof(szMsg)-1] = '\0'; |
| 298 OutputDebugStringA(szMsg); |
| 299 } |
| 300 } |
| 301 |
| 302 |
| 303 /******************************************************************* |
| 304 Dutil_TraceError |
| 305 |
| 306 *******************************************************************/ |
| 307 extern "C" void DAPI Dutil_TraceError( |
| 308 __in_z LPCSTR szFile, |
| 309 __in int iLine, |
| 310 __in REPORT_LEVEL rl, |
| 311 __in HRESULT hrError, |
| 312 __in_z __format_string LPCSTR szFormat, |
| 313 ... |
| 314 ) |
| 315 { |
| 316 HRESULT hr = S_OK; |
| 317 char szOutput[DUTIL_STRING_BUFFER] = { }; |
| 318 char szMsg[DUTIL_STRING_BUFFER] = { }; |
| 319 |
| 320 // if this is NOT an error report and we're not logging at this level, bail |
| 321 if (REPORT_ERROR != rl && Dutil_rlCurrentTrace < rl) |
| 322 { |
| 323 return; |
| 324 } |
| 325 |
| 326 va_list args; |
| 327 va_start(args, szFormat); |
| 328 hr = ::StringCchVPrintfA(szOutput, countof(szOutput), szFormat, args); |
| 329 va_end(args); |
| 330 |
| 331 if (SUCCEEDED(hr)) |
| 332 { |
| 333 if (Dutil_fTraceFilenames) |
| 334 { |
| 335 if (FAILED(hrError)) |
| 336 { |
| 337 hr = ::StringCchPrintfA(szMsg, countof(szMsg), "TraceError 0x%x
[%s,%d]: %s\r\n", hrError, szFile, iLine, szOutput); |
| 338 } |
| 339 else |
| 340 { |
| 341 hr = ::StringCchPrintfA(szMsg, countof(szMsg), "TraceError [%s,%
d]: %s\r\n", szFile, iLine, szOutput); |
| 342 } |
| 343 } |
| 344 else |
| 345 { |
| 346 if (FAILED(hrError)) |
| 347 { |
| 348 hr = ::StringCchPrintfA(szMsg, countof(szMsg), "TraceError 0x%x:
%s\r\n", hrError, szOutput); |
| 349 } |
| 350 else |
| 351 { |
| 352 hr = ::StringCchPrintfA(szMsg, countof(szMsg), "TraceError: %s\r
\n", szOutput); |
| 353 } |
| 354 } |
| 355 |
| 356 if (SUCCEEDED(hr)) |
| 357 { |
| 358 OutputDebugStringA(szMsg); |
| 359 } |
| 360 // else fall through to the failure case below |
| 361 } |
| 362 |
| 363 if (FAILED(hr)) |
| 364 { |
| 365 if (Dutil_fTraceFilenames) |
| 366 { |
| 367 if (FAILED(hrError)) |
| 368 { |
| 369 ::StringCchPrintfA(szMsg, countof(szMsg), "TraceError 0x%x [%s,%
d]: message too long, skipping\r\n", hrError, szFile, iLine); |
| 370 } |
| 371 else |
| 372 { |
| 373 ::StringCchPrintfA(szMsg, countof(szMsg), "TraceError [%s,%d]: m
essage too long, skipping\r\n", szFile, iLine); |
| 374 } |
| 375 } |
| 376 else |
| 377 { |
| 378 if (FAILED(hrError)) |
| 379 { |
| 380 ::StringCchPrintfA(szMsg, countof(szMsg), "TraceError 0x%x: mess
age too long, skipping\r\n", hrError); |
| 381 } |
| 382 else |
| 383 { |
| 384 ::StringCchPrintfA(szMsg, countof(szMsg), "TraceError: message t
oo long, skipping\r\n"); |
| 385 } |
| 386 } |
| 387 |
| 388 szMsg[countof(szMsg)-1] = '\0'; |
| 389 OutputDebugStringA(szMsg); |
| 390 } |
| 391 } |
| 392 |
| 393 |
| 394 |
| 395 /******************************************************************* |
| 396 Dutil_RootFailure |
| 397 |
| 398 *******************************************************************/ |
| 399 extern "C" void DAPI Dutil_RootFailure( |
| 400 __in_z LPCSTR szFile, |
| 401 __in int iLine, |
| 402 __in HRESULT hrError |
| 403 ) |
| 404 { |
| 405 #ifndef DEBUG |
| 406 UNREFERENCED_PARAMETER(szFile); |
| 407 UNREFERENCED_PARAMETER(iLine); |
| 408 UNREFERENCED_PARAMETER(hrError); |
| 409 #endif // DEBUG |
| 410 |
| 411 TraceError2(hrError, "Root failure at %s:%d", szFile, iLine); |
| 412 } |
| 413 |
| 414 /******************************************************************* |
| 415 LoadSystemLibrary - Fully qualifies the path to a module in the |
| 416 Windows system directory and loads it. |
| 417 |
| 418 Returns |
| 419 E_MODNOTFOUND - The module could not be found. |
| 420 * - Another error occured. |
| 421 ********************************************************************/ |
| 422 extern "C" HRESULT DAPI LoadSystemLibrary( |
| 423 __in_z LPCWSTR wzModuleName, |
| 424 __out HMODULE *phModule |
| 425 ) |
| 426 { |
| 427 HRESULT hr = S_OK; |
| 428 DWORD cch = 0; |
| 429 WCHAR wzPath[MAX_PATH] = { }; |
| 430 |
| 431 cch = ::GetSystemDirectoryW(wzPath, MAX_PATH); |
| 432 ExitOnNullWithLastError(cch, hr, "Failed to get the Windows system directory
."); |
| 433 |
| 434 if (L'\\' != wzPath[cch - 1]) |
| 435 { |
| 436 hr = ::StringCchCatNW(wzPath, MAX_PATH, L"\\", 1); |
| 437 ExitOnRootFailure(hr, "Failed to terminate the string with a backslash."
); |
| 438 } |
| 439 |
| 440 hr = ::StringCchCatW(wzPath, MAX_PATH, wzModuleName); |
| 441 ExitOnRootFailure1(hr, "Failed to create the fully-qualified path to %ls.",
wzModuleName); |
| 442 |
| 443 *phModule = ::LoadLibraryW(wzPath); |
| 444 ExitOnNullWithLastError1(*phModule, hr, "Failed to load the library %ls.", w
zModuleName); |
| 445 |
| 446 LExit: |
| 447 return hr; |
| 448 } |
OLD | NEW |