aboutsummaryrefslogtreecommitdiff
path: root/src/dutil/dutil.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/dutil/dutil.cpp')
-rw-r--r--src/dutil/dutil.cpp462
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
10const int DUTIL_STRING_BUFFER = 1024;
11static HMODULE Dutil_hAssertModule = NULL;
12static DUTIL_ASSERTDISPLAYFUNCTION Dutil_pfnDisplayAssert = NULL;
13static BOOL Dutil_fNoAsserts = FALSE;
14static REPORT_LEVEL Dutil_rlCurrentTrace = REPORT_STANDARD;
15static BOOL Dutil_fTraceFilenames = FALSE;
16
17
18/*******************************************************************
19Dutil_SetAssertModule
20
21*******************************************************************/
22extern "C" void DAPI Dutil_SetAssertModule(
23 __in HMODULE hAssertModule
24 )
25{
26 Dutil_hAssertModule = hAssertModule;
27}
28
29
30/*******************************************************************
31Dutil_SetAssertDisplayFunction
32
33*******************************************************************/
34extern "C" void DAPI Dutil_SetAssertDisplayFunction(
35 __in DUTIL_ASSERTDISPLAYFUNCTION pfn
36 )
37{
38 Dutil_pfnDisplayAssert = pfn;
39}
40
41
42/*******************************************************************
43Dutil_AssertMsg
44
45*******************************************************************/
46extern "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
136LExit:
137 ReleaseFileHandle(hAssertFile);
138 ReleaseRegKey(hkDebug);
139 fInAssert = FALSE;
140}
141
142
143/*******************************************************************
144Dutil_Assert
145
146*******************************************************************/
147extern "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/*******************************************************************
167Dutil_AssertSz
168
169*******************************************************************/
170extern "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/*******************************************************************
192Dutil_TraceSetLevel
193
194*******************************************************************/
195extern "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/*******************************************************************
206Dutil_TraceGetLevel
207
208*******************************************************************/
209extern "C" REPORT_LEVEL DAPI Dutil_TraceGetLevel()
210{
211 return Dutil_rlCurrentTrace;
212}
213
214
215/*******************************************************************
216Dutil_Trace
217
218*******************************************************************/
219extern "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/*******************************************************************
293Dutil_TraceError
294
295*******************************************************************/
296extern "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/*******************************************************************
385Dutil_RootFailure
386
387*******************************************************************/
388extern "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********************************************************************/
411extern "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********************************************************************/
429extern "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
460LExit:
461 return hr;
462}