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