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