diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/burn/engine/bundlepackageengine.cpp | 71 | ||||
-rw-r--r-- | src/burn/engine/embedded.cpp | 18 | ||||
-rw-r--r-- | src/burn/engine/embedded.h | 5 | ||||
-rw-r--r-- | src/burn/engine/exeengine.cpp | 83 | ||||
-rw-r--r-- | src/burn/engine/exeengine.h | 3 | ||||
-rw-r--r-- | src/burn/engine/msuengine.cpp | 9 | ||||
-rw-r--r-- | src/burn/engine/netfxchainer.cpp | 16 | ||||
-rw-r--r-- | src/burn/engine/netfxchainer.h | 5 |
8 files changed, 119 insertions, 91 deletions
diff --git a/src/burn/engine/bundlepackageengine.cpp b/src/burn/engine/bundlepackageengine.cpp index 0bee054f..89488b91 100644 --- a/src/burn/engine/bundlepackageengine.cpp +++ b/src/burn/engine/bundlepackageengine.cpp | |||
@@ -252,12 +252,12 @@ extern "C" HRESULT BundlePackageEngineExecuteRelatedBundle( | |||
252 | { | 252 | { |
253 | HRESULT hr = S_OK; | 253 | HRESULT hr = S_OK; |
254 | LPCWSTR wzArguments = NULL; | 254 | LPCWSTR wzArguments = NULL; |
255 | LPWSTR sczArguments = NULL; | ||
256 | LPWSTR sczArgumentsFormatted = NULL; | ||
257 | LPWSTR sczArgumentsObfuscated = NULL; | ||
258 | LPWSTR sczCachedDirectory = NULL; | 255 | LPWSTR sczCachedDirectory = NULL; |
259 | LPWSTR sczExecutablePath = NULL; | 256 | LPWSTR sczExecutablePath = NULL; |
260 | LPWSTR sczCommand = NULL; | 257 | LPWSTR sczBaseCommand = NULL; |
258 | LPWSTR sczUnformattedUserArgs = NULL; | ||
259 | LPWSTR sczUserArgs = NULL; | ||
260 | LPWSTR sczUserArgsObfuscated = NULL; | ||
261 | LPWSTR sczCommandObfuscated = NULL; | 261 | LPWSTR sczCommandObfuscated = NULL; |
262 | HANDLE hExecutableFile = INVALID_HANDLE_VALUE; | 262 | HANDLE hExecutableFile = INVALID_HANDLE_VALUE; |
263 | STARTUPINFOW si = { }; | 263 | STARTUPINFOW si = { }; |
@@ -309,7 +309,7 @@ extern "C" HRESULT BundlePackageEngineExecuteRelatedBundle( | |||
309 | // now add optional arguments | 309 | // now add optional arguments |
310 | if (wzArguments && *wzArguments) | 310 | if (wzArguments && *wzArguments) |
311 | { | 311 | { |
312 | hr = StrAllocString(&sczArguments, wzArguments, 0); | 312 | hr = StrAllocString(&sczUnformattedUserArgs, wzArguments, 0); |
313 | ExitOnFailure(hr, "Failed to copy package arguments."); | 313 | ExitOnFailure(hr, "Failed to copy package arguments."); |
314 | } | 314 | } |
315 | 315 | ||
@@ -323,26 +323,26 @@ extern "C" HRESULT BundlePackageEngineExecuteRelatedBundle( | |||
323 | 323 | ||
324 | if (fCondition) | 324 | if (fCondition) |
325 | { | 325 | { |
326 | if (sczArguments) | 326 | if (sczUnformattedUserArgs) |
327 | { | 327 | { |
328 | hr = StrAllocConcat(&sczArguments, L" ", 0); | 328 | hr = StrAllocConcat(&sczUnformattedUserArgs, L" ", 0); |
329 | ExitOnFailure(hr, "Failed to separate command-line arguments."); | 329 | ExitOnFailure(hr, "Failed to separate command-line arguments."); |
330 | } | 330 | } |
331 | 331 | ||
332 | switch (action) | 332 | switch (action) |
333 | { | 333 | { |
334 | case BOOTSTRAPPER_ACTION_STATE_INSTALL: | 334 | case BOOTSTRAPPER_ACTION_STATE_INSTALL: |
335 | hr = StrAllocConcat(&sczArguments, commandLineArgument->sczInstallArgument, 0); | 335 | hr = StrAllocConcat(&sczUnformattedUserArgs, commandLineArgument->sczInstallArgument, 0); |
336 | ExitOnFailure(hr, "Failed to get command-line argument for install."); | 336 | ExitOnFailure(hr, "Failed to get command-line argument for install."); |
337 | break; | 337 | break; |
338 | 338 | ||
339 | case BOOTSTRAPPER_ACTION_STATE_UNINSTALL: | 339 | case BOOTSTRAPPER_ACTION_STATE_UNINSTALL: |
340 | hr = StrAllocConcat(&sczArguments, commandLineArgument->sczUninstallArgument, 0); | 340 | hr = StrAllocConcat(&sczUnformattedUserArgs, commandLineArgument->sczUninstallArgument, 0); |
341 | ExitOnFailure(hr, "Failed to get command-line argument for uninstall."); | 341 | ExitOnFailure(hr, "Failed to get command-line argument for uninstall."); |
342 | break; | 342 | break; |
343 | 343 | ||
344 | case BOOTSTRAPPER_ACTION_STATE_REPAIR: | 344 | case BOOTSTRAPPER_ACTION_STATE_REPAIR: |
345 | hr = StrAllocConcat(&sczArguments, commandLineArgument->sczRepairArgument, 0); | 345 | hr = StrAllocConcat(&sczUnformattedUserArgs, commandLineArgument->sczRepairArgument, 0); |
346 | ExitOnFailure(hr, "Failed to get command-line argument for repair."); | 346 | ExitOnFailure(hr, "Failed to get command-line argument for repair."); |
347 | break; | 347 | break; |
348 | 348 | ||
@@ -353,75 +353,72 @@ extern "C" HRESULT BundlePackageEngineExecuteRelatedBundle( | |||
353 | } | 353 | } |
354 | } | 354 | } |
355 | 355 | ||
356 | // build command | 356 | // build base command |
357 | AppAppendCommandLineArgument(&sczCommand, sczExecutablePath); | 357 | hr = StrAllocFormatted(&sczBaseCommand, L"\"%ls\"", sczExecutablePath); |
358 | ExitOnFailure(hr, "Failed to create executable command."); | 358 | ExitOnFailure(hr, "Failed to allocate base command."); |
359 | 359 | ||
360 | if (!fRunEmbedded) | 360 | if (!fRunEmbedded) |
361 | { | 361 | { |
362 | hr = StrAllocConcat(&sczCommand, L" -quiet", 0); | 362 | hr = StrAllocConcat(&sczBaseCommand, L" -quiet", 0); |
363 | ExitOnFailure(hr, "Failed to append quiet argument."); | 363 | ExitOnFailure(hr, "Failed to append quiet argument."); |
364 | } | 364 | } |
365 | 365 | ||
366 | if (wzOperationCommandLine) | 366 | if (wzOperationCommandLine) |
367 | { | 367 | { |
368 | hr = StrAllocConcatFormatted(&sczCommand, L" %ls", wzOperationCommandLine); | 368 | hr = StrAllocConcatFormatted(&sczBaseCommand, L" %ls", wzOperationCommandLine); |
369 | ExitOnFailure(hr, "Failed to append operation argument."); | 369 | ExitOnFailure(hr, "Failed to append operation argument."); |
370 | } | 370 | } |
371 | 371 | ||
372 | if (wzRelationTypeCommandLine) | 372 | if (wzRelationTypeCommandLine) |
373 | { | 373 | { |
374 | hr = StrAllocConcatFormatted(&sczCommand, L" -%ls", wzRelationTypeCommandLine); | 374 | hr = StrAllocConcatFormatted(&sczBaseCommand, L" -%ls", wzRelationTypeCommandLine); |
375 | ExitOnFailure(hr, "Failed to append relation type argument."); | 375 | ExitOnFailure(hr, "Failed to append relation type argument."); |
376 | } | 376 | } |
377 | 377 | ||
378 | // Add the list of dependencies to ignore, if any, to the burn command line. | 378 | // Add the list of dependencies to ignore, if any, to the burn command line. |
379 | if (pExecuteAction->relatedBundle.sczIgnoreDependencies) | 379 | if (pExecuteAction->relatedBundle.sczIgnoreDependencies) |
380 | { | 380 | { |
381 | hr = StrAllocConcatFormatted(&sczCommand, L" -%ls=%ls", BURN_COMMANDLINE_SWITCH_IGNOREDEPENDENCIES, pExecuteAction->relatedBundle.sczIgnoreDependencies); | 381 | hr = StrAllocConcatFormatted(&sczBaseCommand, L" -%ls=%ls", BURN_COMMANDLINE_SWITCH_IGNOREDEPENDENCIES, pExecuteAction->relatedBundle.sczIgnoreDependencies); |
382 | ExitOnFailure(hr, "Failed to append the list of dependencies to ignore to the command line."); | 382 | ExitOnFailure(hr, "Failed to append the list of dependencies to ignore to the command line."); |
383 | } | 383 | } |
384 | 384 | ||
385 | // Add the list of ancestors, if any, to the burn command line. | 385 | // Add the list of ancestors, if any, to the burn command line. |
386 | if (pExecuteAction->relatedBundle.sczAncestors) | 386 | if (pExecuteAction->relatedBundle.sczAncestors) |
387 | { | 387 | { |
388 | hr = StrAllocConcatFormatted(&sczCommand, L" -%ls=%ls", BURN_COMMANDLINE_SWITCH_ANCESTORS, pExecuteAction->relatedBundle.sczAncestors); | 388 | hr = StrAllocConcatFormatted(&sczBaseCommand, L" -%ls=%ls", BURN_COMMANDLINE_SWITCH_ANCESTORS, pExecuteAction->relatedBundle.sczAncestors); |
389 | ExitOnFailure(hr, "Failed to append the list of ancestors to the command line."); | 389 | ExitOnFailure(hr, "Failed to append the list of ancestors to the command line."); |
390 | } | 390 | } |
391 | 391 | ||
392 | hr = CoreAppendEngineWorkingDirectoryToCommandLine(pExecuteAction->relatedBundle.sczEngineWorkingDirectory, &sczCommand, NULL); | 392 | hr = CoreAppendEngineWorkingDirectoryToCommandLine(pExecuteAction->relatedBundle.sczEngineWorkingDirectory, &sczBaseCommand, NULL); |
393 | ExitOnFailure(hr, "Failed to append the custom working directory to the bundlepackage command line."); | 393 | ExitOnFailure(hr, "Failed to append the custom working directory to the bundlepackage command line."); |
394 | 394 | ||
395 | hr = CoreAppendFileHandleSelfToCommandLine(sczExecutablePath, &hExecutableFile, &sczCommand, NULL); | 395 | hr = CoreAppendFileHandleSelfToCommandLine(sczExecutablePath, &hExecutableFile, &sczBaseCommand, NULL); |
396 | ExitOnFailure(hr, "Failed to append %ls", BURN_COMMANDLINE_SWITCH_FILEHANDLE_SELF); | 396 | ExitOnFailure(hr, "Failed to append %ls", BURN_COMMANDLINE_SWITCH_FILEHANDLE_SELF); |
397 | 397 | ||
398 | // Always add user supplied arguments last. | 398 | // build user args |
399 | if (sczArguments && *sczArguments) | 399 | if (sczUnformattedUserArgs && *sczUnformattedUserArgs) |
400 | { | 400 | { |
401 | hr = VariableFormatString(pVariables, sczArguments, &sczArgumentsFormatted, NULL); | 401 | hr = VariableFormatString(pVariables, sczUnformattedUserArgs, &sczUserArgs, NULL); |
402 | ExitOnFailure(hr, "Failed to format argument string."); | 402 | ExitOnFailure(hr, "Failed to format argument string."); |
403 | 403 | ||
404 | hr = VariableFormatStringObfuscated(pVariables, sczArguments, &sczArgumentsObfuscated, NULL); | 404 | hr = VariableFormatStringObfuscated(pVariables, sczUnformattedUserArgs, &sczUserArgsObfuscated, NULL); |
405 | ExitOnFailure(hr, "Failed to format obfuscated argument string."); | 405 | ExitOnFailure(hr, "Failed to format obfuscated argument string."); |
406 | 406 | ||
407 | hr = StrAllocFormatted(&sczCommandObfuscated, L"%ls %ls", sczCommand, sczArgumentsObfuscated); | 407 | hr = StrAllocFormatted(&sczCommandObfuscated, L"%ls %ls", sczBaseCommand, sczUserArgsObfuscated); |
408 | ExitOnFailure(hr, "Failed to copy obfuscated formatted arguments."); | 408 | ExitOnFailure(hr, "Failed to allocate obfuscated bundle command."); |
409 | |||
410 | hr = StrAllocConcatFormattedSecure(&sczCommand, L" %ls", sczArgumentsFormatted); | ||
411 | ExitOnFailure(hr, "Failed to copy formatted arguments."); | ||
412 | } | 409 | } |
413 | 410 | ||
414 | // Log before we add the secret pipe name and client token for embedded processes. | 411 | // Log obfuscated command, which won't include raw hidden variable values or protocol specific arguments to avoid exposing secrets. |
415 | LogId(REPORT_STANDARD, MSG_APPLYING_PACKAGE, LoggingRollbackOrExecute(fRollback), pPackage->sczId, LoggingActionStateToString(action), sczExecutablePath, sczCommandObfuscated); | 412 | LogId(REPORT_STANDARD, MSG_APPLYING_PACKAGE, LoggingRollbackOrExecute(fRollback), pPackage->sczId, LoggingActionStateToString(action), sczExecutablePath, sczCommandObfuscated ? sczCommandObfuscated : sczBaseCommand); |
416 | 413 | ||
417 | if (fRunEmbedded) | 414 | if (fRunEmbedded) |
418 | { | 415 | { |
419 | hr = EmbeddedRunBundle(sczExecutablePath, sczCommand, pfnGenericMessageHandler, pvContext, &dwExitCode); | 416 | hr = EmbeddedRunBundle(sczExecutablePath, sczBaseCommand, sczUserArgs, pfnGenericMessageHandler, pvContext, &dwExitCode); |
420 | ExitOnFailure(hr, "Failed to run bundle as embedded from path: %ls", sczExecutablePath); | 417 | ExitOnFailure(hr, "Failed to run bundle as embedded from path: %ls", sczExecutablePath); |
421 | } | 418 | } |
422 | else | 419 | else |
423 | { | 420 | { |
424 | hr = ExeEngineRunProcess(pfnGenericMessageHandler, pvContext, pPackage, sczExecutablePath, sczCommand, sczCachedDirectory, &dwExitCode); | 421 | hr = ExeEngineRunProcess(pfnGenericMessageHandler, pvContext, pPackage, sczExecutablePath, sczBaseCommand, sczUserArgs, sczCachedDirectory, &dwExitCode); |
425 | ExitOnFailure(hr, "Failed to run BUNDLE process"); | 422 | ExitOnFailure(hr, "Failed to run BUNDLE process"); |
426 | } | 423 | } |
427 | 424 | ||
@@ -429,12 +426,12 @@ extern "C" HRESULT BundlePackageEngineExecuteRelatedBundle( | |||
429 | ExitOnRootFailure(hr, "Process returned error: 0x%x", dwExitCode); | 426 | ExitOnRootFailure(hr, "Process returned error: 0x%x", dwExitCode); |
430 | 427 | ||
431 | LExit: | 428 | LExit: |
432 | StrSecureZeroFreeString(sczArguments); | ||
433 | StrSecureZeroFreeString(sczArgumentsFormatted); | ||
434 | ReleaseStr(sczArgumentsObfuscated); | ||
435 | ReleaseStr(sczCachedDirectory); | 429 | ReleaseStr(sczCachedDirectory); |
436 | ReleaseStr(sczExecutablePath); | 430 | ReleaseStr(sczExecutablePath); |
437 | StrSecureZeroFreeString(sczCommand); | 431 | ReleaseStr(sczBaseCommand); |
432 | ReleaseStr(sczUnformattedUserArgs); | ||
433 | StrSecureZeroFreeString(sczUserArgs); | ||
434 | ReleaseStr(sczUserArgsObfuscated); | ||
438 | ReleaseStr(sczCommandObfuscated); | 435 | ReleaseStr(sczCommandObfuscated); |
439 | 436 | ||
440 | ReleaseHandle(pi.hThread); | 437 | ReleaseHandle(pi.hThread); |
diff --git a/src/burn/engine/embedded.cpp b/src/burn/engine/embedded.cpp index 1c295d59..58af5574 100644 --- a/src/burn/engine/embedded.cpp +++ b/src/burn/engine/embedded.cpp | |||
@@ -36,12 +36,13 @@ static HRESULT OnEmbeddedProgress( | |||
36 | // function definitions | 36 | // function definitions |
37 | 37 | ||
38 | /******************************************************************* | 38 | /******************************************************************* |
39 | EmbeddedLaunchChildProcess - | 39 | EmbeddedRunBundle - |
40 | 40 | ||
41 | *******************************************************************/ | 41 | *******************************************************************/ |
42 | extern "C" HRESULT EmbeddedRunBundle( | 42 | extern "C" HRESULT EmbeddedRunBundle( |
43 | __in LPCWSTR wzExecutablePath, | 43 | __in_z LPCWSTR wzExecutablePath, |
44 | __in LPCWSTR wzArguments, | 44 | __in_z LPWSTR sczBaseCommand, |
45 | __in_z_opt LPCWSTR wzUserArgs, | ||
45 | __in PFN_GENERICMESSAGEHANDLER pfnGenericMessageHandler, | 46 | __in PFN_GENERICMESSAGEHANDLER pfnGenericMessageHandler, |
46 | __in LPVOID pvContext, | 47 | __in LPVOID pvContext, |
47 | __out DWORD* pdwExitCode | 48 | __out DWORD* pdwExitCode |
@@ -68,8 +69,15 @@ extern "C" HRESULT EmbeddedRunBundle( | |||
68 | hr = PipeCreatePipes(&connection, FALSE, &hCreatedPipesEvent); | 69 | hr = PipeCreatePipes(&connection, FALSE, &hCreatedPipesEvent); |
69 | ExitOnFailure(hr, "Failed to create embedded pipe."); | 70 | ExitOnFailure(hr, "Failed to create embedded pipe."); |
70 | 71 | ||
71 | hr = StrAllocFormattedSecure(&sczCommand, L"%ls -%ls %ls %ls %u", wzArguments, BURN_COMMANDLINE_SWITCH_EMBEDDED, connection.sczName, connection.sczSecret, dwCurrentProcessId); | 72 | hr = StrAllocFormatted(&sczCommand, L"%ls -%ls %ls %ls %u", sczBaseCommand, BURN_COMMANDLINE_SWITCH_EMBEDDED, connection.sczName, connection.sczSecret, dwCurrentProcessId); |
72 | ExitOnFailure(hr, "Failed to allocate embedded command."); | 73 | ExitOnFailure(hr, "Failed to append embedded args."); |
74 | |||
75 | // Always add user supplied arguments last. | ||
76 | if (wzUserArgs) | ||
77 | { | ||
78 | hr = StrAllocConcatFormattedSecure(&sczCommand, L" %ls", wzUserArgs); | ||
79 | ExitOnFailure(hr, "Failed to append user args."); | ||
80 | } | ||
73 | 81 | ||
74 | if (!::CreateProcessW(wzExecutablePath, sczCommand, NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi)) | 82 | if (!::CreateProcessW(wzExecutablePath, sczCommand, NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi)) |
75 | { | 83 | { |
diff --git a/src/burn/engine/embedded.h b/src/burn/engine/embedded.h index 08adeae0..905b227f 100644 --- a/src/burn/engine/embedded.h +++ b/src/burn/engine/embedded.h | |||
@@ -15,8 +15,9 @@ typedef enum _BURN_EMBEDDED_MESSAGE_TYPE | |||
15 | 15 | ||
16 | 16 | ||
17 | HRESULT EmbeddedRunBundle( | 17 | HRESULT EmbeddedRunBundle( |
18 | __in LPCWSTR wzExecutablePath, | 18 | __in_z LPCWSTR wzExecutablePath, |
19 | __in LPCWSTR wzArguments, | 19 | __in_z LPWSTR sczBaseCommand, |
20 | __in_z_opt LPCWSTR wzUserArgs, | ||
20 | __in PFN_GENERICMESSAGEHANDLER pfnGenericMessageHandler, | 21 | __in PFN_GENERICMESSAGEHANDLER pfnGenericMessageHandler, |
21 | __in LPVOID pvContext, | 22 | __in LPVOID pvContext, |
22 | __out DWORD* pdwExitCode | 23 | __out DWORD* pdwExitCode |
diff --git a/src/burn/engine/exeengine.cpp b/src/burn/engine/exeengine.cpp index 9754002f..0a2084e5 100644 --- a/src/burn/engine/exeengine.cpp +++ b/src/burn/engine/exeengine.cpp | |||
@@ -362,12 +362,12 @@ extern "C" HRESULT ExeEngineExecutePackage( | |||
362 | { | 362 | { |
363 | HRESULT hr = S_OK; | 363 | HRESULT hr = S_OK; |
364 | LPCWSTR wzArguments = NULL; | 364 | LPCWSTR wzArguments = NULL; |
365 | LPWSTR sczArguments = NULL; | ||
366 | LPWSTR sczArgumentsFormatted = NULL; | ||
367 | LPWSTR sczArgumentsObfuscated = NULL; | ||
368 | LPWSTR sczCachedDirectory = NULL; | 365 | LPWSTR sczCachedDirectory = NULL; |
369 | LPWSTR sczExecutablePath = NULL; | 366 | LPWSTR sczExecutablePath = NULL; |
370 | LPWSTR sczCommand = NULL; | 367 | LPWSTR sczBaseCommand = NULL; |
368 | LPWSTR sczUnformattedUserArgs = NULL; | ||
369 | LPWSTR sczUserArgs = NULL; | ||
370 | LPWSTR sczUserArgsObfuscated = NULL; | ||
371 | LPWSTR sczCommandObfuscated = NULL; | 371 | LPWSTR sczCommandObfuscated = NULL; |
372 | HANDLE hExecutableFile = INVALID_HANDLE_VALUE; | 372 | HANDLE hExecutableFile = INVALID_HANDLE_VALUE; |
373 | DWORD dwExitCode = 0; | 373 | DWORD dwExitCode = 0; |
@@ -406,7 +406,7 @@ extern "C" HRESULT ExeEngineExecutePackage( | |||
406 | } | 406 | } |
407 | 407 | ||
408 | // now add optional arguments | 408 | // now add optional arguments |
409 | hr = StrAllocString(&sczArguments, wzArguments && *wzArguments ? wzArguments : L"", 0); | 409 | hr = StrAllocString(&sczUnformattedUserArgs, wzArguments && *wzArguments ? wzArguments : L"", 0); |
410 | ExitOnFailure(hr, "Failed to copy package arguments."); | 410 | ExitOnFailure(hr, "Failed to copy package arguments."); |
411 | 411 | ||
412 | for (DWORD i = 0; i < pPackage->Exe.cCommandLineArguments; ++i) | 412 | for (DWORD i = 0; i < pPackage->Exe.cCommandLineArguments; ++i) |
@@ -419,23 +419,23 @@ extern "C" HRESULT ExeEngineExecutePackage( | |||
419 | 419 | ||
420 | if (fCondition) | 420 | if (fCondition) |
421 | { | 421 | { |
422 | hr = StrAllocConcat(&sczArguments, L" ", 0); | 422 | hr = StrAllocConcat(&sczUnformattedUserArgs, L" ", 0); |
423 | ExitOnFailure(hr, "Failed to separate command-line arguments."); | 423 | ExitOnFailure(hr, "Failed to separate command-line arguments."); |
424 | 424 | ||
425 | switch (pExecuteAction->exePackage.action) | 425 | switch (pExecuteAction->exePackage.action) |
426 | { | 426 | { |
427 | case BOOTSTRAPPER_ACTION_STATE_INSTALL: | 427 | case BOOTSTRAPPER_ACTION_STATE_INSTALL: |
428 | hr = StrAllocConcat(&sczArguments, commandLineArgument->sczInstallArgument, 0); | 428 | hr = StrAllocConcat(&sczUnformattedUserArgs, commandLineArgument->sczInstallArgument, 0); |
429 | ExitOnFailure(hr, "Failed to get command-line argument for install."); | 429 | ExitOnFailure(hr, "Failed to get command-line argument for install."); |
430 | break; | 430 | break; |
431 | 431 | ||
432 | case BOOTSTRAPPER_ACTION_STATE_UNINSTALL: | 432 | case BOOTSTRAPPER_ACTION_STATE_UNINSTALL: |
433 | hr = StrAllocConcat(&sczArguments, commandLineArgument->sczUninstallArgument, 0); | 433 | hr = StrAllocConcat(&sczUnformattedUserArgs, commandLineArgument->sczUninstallArgument, 0); |
434 | ExitOnFailure(hr, "Failed to get command-line argument for uninstall."); | 434 | ExitOnFailure(hr, "Failed to get command-line argument for uninstall."); |
435 | break; | 435 | break; |
436 | 436 | ||
437 | case BOOTSTRAPPER_ACTION_STATE_REPAIR: | 437 | case BOOTSTRAPPER_ACTION_STATE_REPAIR: |
438 | hr = StrAllocConcat(&sczArguments, commandLineArgument->sczRepairArgument, 0); | 438 | hr = StrAllocConcat(&sczUnformattedUserArgs, commandLineArgument->sczRepairArgument, 0); |
439 | ExitOnFailure(hr, "Failed to get command-line argument for repair."); | 439 | ExitOnFailure(hr, "Failed to get command-line argument for repair."); |
440 | break; | 440 | break; |
441 | 441 | ||
@@ -446,71 +446,68 @@ extern "C" HRESULT ExeEngineExecutePackage( | |||
446 | } | 446 | } |
447 | } | 447 | } |
448 | 448 | ||
449 | // build command | 449 | // build base command |
450 | AppAppendCommandLineArgument(&sczCommand, sczExecutablePath); | 450 | hr = StrAllocFormatted(&sczBaseCommand, L"\"%ls\"", sczExecutablePath); |
451 | ExitOnFailure(hr, "Failed to create executable command."); | 451 | ExitOnFailure(hr, "Failed to allocate base command."); |
452 | 452 | ||
453 | if (pPackage->Exe.fBundle) | 453 | if (pPackage->Exe.fBundle) |
454 | { | 454 | { |
455 | hr = StrAllocConcat(&sczCommand, L" -norestart", 0); | 455 | hr = StrAllocConcat(&sczBaseCommand, L" -norestart", 0); |
456 | ExitOnFailure(hr, "Failed to append quiet argument."); | 456 | ExitOnFailure(hr, "Failed to append norestart argument."); |
457 | 457 | ||
458 | // Add the list of dependencies to ignore, if any, to the burn command line. | 458 | // Add the list of dependencies to ignore, if any, to the burn command line. |
459 | if (pExecuteAction->exePackage.sczIgnoreDependencies) | 459 | if (pExecuteAction->exePackage.sczIgnoreDependencies) |
460 | { | 460 | { |
461 | hr = StrAllocConcatFormatted(&sczCommand, L" -%ls=%ls", BURN_COMMANDLINE_SWITCH_IGNOREDEPENDENCIES, pExecuteAction->exePackage.sczIgnoreDependencies); | 461 | hr = StrAllocConcatFormatted(&sczBaseCommand, L" -%ls=%ls", BURN_COMMANDLINE_SWITCH_IGNOREDEPENDENCIES, pExecuteAction->exePackage.sczIgnoreDependencies); |
462 | ExitOnFailure(hr, "Failed to append the list of dependencies to ignore to the command line."); | 462 | ExitOnFailure(hr, "Failed to append the list of dependencies to ignore to the command line."); |
463 | } | 463 | } |
464 | 464 | ||
465 | // Add the list of ancestors, if any, to the burn command line. | 465 | // Add the list of ancestors, if any, to the burn command line. |
466 | if (pExecuteAction->exePackage.sczAncestors) | 466 | if (pExecuteAction->exePackage.sczAncestors) |
467 | { | 467 | { |
468 | hr = StrAllocConcatFormatted(&sczCommand, L" -%ls=%ls", sczCommand, BURN_COMMANDLINE_SWITCH_ANCESTORS, pExecuteAction->exePackage.sczAncestors); | 468 | hr = StrAllocConcatFormatted(&sczBaseCommand, L" -%ls=%ls", BURN_COMMANDLINE_SWITCH_ANCESTORS, pExecuteAction->exePackage.sczAncestors); |
469 | ExitOnFailure(hr, "Failed to append the list of ancestors to the command line."); | 469 | ExitOnFailure(hr, "Failed to append the list of ancestors to the command line."); |
470 | } | 470 | } |
471 | 471 | ||
472 | if (pExecuteAction->exePackage.sczEngineWorkingDirectory) | 472 | if (pExecuteAction->exePackage.sczEngineWorkingDirectory) |
473 | { | 473 | { |
474 | hr = CoreAppendEngineWorkingDirectoryToCommandLine(pExecuteAction->exePackage.sczEngineWorkingDirectory, &sczCommand, NULL); | 474 | hr = CoreAppendEngineWorkingDirectoryToCommandLine(pExecuteAction->exePackage.sczEngineWorkingDirectory, &sczBaseCommand, NULL); |
475 | ExitOnFailure(hr, "Failed to append the custom working directory to the exepackage command line."); | 475 | ExitOnFailure(hr, "Failed to append the custom working directory to the exepackage command line."); |
476 | } | 476 | } |
477 | 477 | ||
478 | hr = CoreAppendFileHandleSelfToCommandLine(sczExecutablePath, &hExecutableFile, &sczCommand, NULL); | 478 | hr = CoreAppendFileHandleSelfToCommandLine(sczExecutablePath, &hExecutableFile, &sczBaseCommand, NULL); |
479 | ExitOnFailure(hr, "Failed to append %ls", BURN_COMMANDLINE_SWITCH_FILEHANDLE_SELF); | 479 | ExitOnFailure(hr, "Failed to append %ls", BURN_COMMANDLINE_SWITCH_FILEHANDLE_SELF); |
480 | } | 480 | } |
481 | 481 | ||
482 | // Always add user supplied arguments last. | 482 | // build user args |
483 | if (sczArguments && *sczArguments) | 483 | if (sczUnformattedUserArgs && *sczUnformattedUserArgs) |
484 | { | 484 | { |
485 | hr = VariableFormatString(pVariables, sczArguments, &sczArgumentsFormatted, NULL); | 485 | hr = VariableFormatString(pVariables, sczUnformattedUserArgs, &sczUserArgs, NULL); |
486 | ExitOnFailure(hr, "Failed to format argument string."); | 486 | ExitOnFailure(hr, "Failed to format argument string."); |
487 | 487 | ||
488 | hr = VariableFormatStringObfuscated(pVariables, sczArguments, &sczArgumentsObfuscated, NULL); | 488 | hr = VariableFormatStringObfuscated(pVariables, sczUnformattedUserArgs, &sczUserArgsObfuscated, NULL); |
489 | ExitOnFailure(hr, "Failed to format obfuscated argument string."); | 489 | ExitOnFailure(hr, "Failed to format obfuscated argument string."); |
490 | 490 | ||
491 | hr = StrAllocFormatted(&sczCommandObfuscated, L"%ls %ls", sczCommand, sczArgumentsObfuscated); | 491 | hr = StrAllocFormatted(&sczCommandObfuscated, L"%ls %ls", sczBaseCommand, sczUserArgsObfuscated); |
492 | ExitOnFailure(hr, "Failed to copy obfuscated formatted arguments."); | 492 | ExitOnFailure(hr, "Failed to allocate obfuscated exe command."); |
493 | |||
494 | hr = StrAllocConcatFormattedSecure(&sczCommand, L" %ls", sczArgumentsFormatted); | ||
495 | ExitOnFailure(hr, "Failed to copy formatted arguments."); | ||
496 | } | 493 | } |
497 | 494 | ||
498 | // Log before we add the secret pipe name and client token for embedded processes. | 495 | // Log obfuscated command, which won't include raw hidden variable values or protocol specific arguments to avoid exposing secrets. |
499 | LogId(REPORT_STANDARD, MSG_APPLYING_PACKAGE, LoggingRollbackOrExecute(fRollback), pPackage->sczId, LoggingActionStateToString(pExecuteAction->exePackage.action), sczExecutablePath, sczCommandObfuscated); | 496 | LogId(REPORT_STANDARD, MSG_APPLYING_PACKAGE, LoggingRollbackOrExecute(fRollback), pPackage->sczId, LoggingActionStateToString(pExecuteAction->exePackage.action), sczExecutablePath, sczCommandObfuscated ? sczCommandObfuscated : sczBaseCommand); |
500 | 497 | ||
501 | if (!pPackage->Exe.fFireAndForget && BURN_EXE_PROTOCOL_TYPE_BURN == pPackage->Exe.protocol) | 498 | if (!pPackage->Exe.fFireAndForget && BURN_EXE_PROTOCOL_TYPE_BURN == pPackage->Exe.protocol) |
502 | { | 499 | { |
503 | hr = EmbeddedRunBundle(sczExecutablePath, sczCommand, pfnGenericMessageHandler, pvContext, &dwExitCode); | 500 | hr = EmbeddedRunBundle(sczExecutablePath, sczBaseCommand, sczUserArgs, pfnGenericMessageHandler, pvContext, &dwExitCode); |
504 | ExitOnFailure(hr, "Failed to run exe with Burn protocol from path: %ls", sczExecutablePath); | 501 | ExitOnFailure(hr, "Failed to run exe with Burn protocol from path: %ls", sczExecutablePath); |
505 | } | 502 | } |
506 | else if (!pPackage->Exe.fFireAndForget && BURN_EXE_PROTOCOL_TYPE_NETFX4 == pPackage->Exe.protocol) | 503 | else if (!pPackage->Exe.fFireAndForget && BURN_EXE_PROTOCOL_TYPE_NETFX4 == pPackage->Exe.protocol) |
507 | { | 504 | { |
508 | hr = NetFxRunChainer(sczExecutablePath, sczCommand, pfnGenericMessageHandler, pvContext, &dwExitCode); | 505 | hr = NetFxRunChainer(sczExecutablePath, sczBaseCommand, sczUserArgs, pfnGenericMessageHandler, pvContext, &dwExitCode); |
509 | ExitOnFailure(hr, "Failed to run netfx chainer: %ls", sczExecutablePath); | 506 | ExitOnFailure(hr, "Failed to run netfx chainer: %ls", sczExecutablePath); |
510 | } | 507 | } |
511 | else | 508 | else |
512 | { | 509 | { |
513 | hr = ExeEngineRunProcess(pfnGenericMessageHandler, pvContext, pPackage, sczExecutablePath, sczCommand, sczCachedDirectory, &dwExitCode); | 510 | hr = ExeEngineRunProcess(pfnGenericMessageHandler, pvContext, pPackage, sczExecutablePath, sczBaseCommand, sczUserArgs, sczCachedDirectory, &dwExitCode); |
514 | ExitOnFailure(hr, "Failed to run EXE process"); | 511 | ExitOnFailure(hr, "Failed to run EXE process"); |
515 | } | 512 | } |
516 | 513 | ||
@@ -518,12 +515,12 @@ extern "C" HRESULT ExeEngineExecutePackage( | |||
518 | ExitOnRootFailure(hr, "Process returned error: 0x%x", dwExitCode); | 515 | ExitOnRootFailure(hr, "Process returned error: 0x%x", dwExitCode); |
519 | 516 | ||
520 | LExit: | 517 | LExit: |
521 | StrSecureZeroFreeString(sczArguments); | ||
522 | StrSecureZeroFreeString(sczArgumentsFormatted); | ||
523 | ReleaseStr(sczArgumentsObfuscated); | ||
524 | ReleaseStr(sczCachedDirectory); | 518 | ReleaseStr(sczCachedDirectory); |
525 | ReleaseStr(sczExecutablePath); | 519 | ReleaseStr(sczExecutablePath); |
526 | StrSecureZeroFreeString(sczCommand); | 520 | ReleaseStr(sczBaseCommand); |
521 | ReleaseStr(sczUnformattedUserArgs); | ||
522 | StrSecureZeroFreeString(sczUserArgs); | ||
523 | ReleaseStr(sczUserArgsObfuscated); | ||
527 | ReleaseStr(sczCommandObfuscated); | 524 | ReleaseStr(sczCommandObfuscated); |
528 | 525 | ||
529 | ReleaseFileHandle(hExecutableFile); | 526 | ReleaseFileHandle(hExecutableFile); |
@@ -540,12 +537,14 @@ extern "C" HRESULT ExeEngineRunProcess( | |||
540 | __in LPVOID pvContext, | 537 | __in LPVOID pvContext, |
541 | __in BURN_PACKAGE* pPackage, | 538 | __in BURN_PACKAGE* pPackage, |
542 | __in_z LPCWSTR wzExecutablePath, | 539 | __in_z LPCWSTR wzExecutablePath, |
543 | __in_z LPWSTR wzCommand, | 540 | __in_z LPWSTR sczBaseCommand, |
541 | __in_z_opt LPCWSTR wzUserArgs, | ||
544 | __in_z_opt LPCWSTR wzCachedDirectory, | 542 | __in_z_opt LPCWSTR wzCachedDirectory, |
545 | __inout DWORD* pdwExitCode | 543 | __inout DWORD* pdwExitCode |
546 | ) | 544 | ) |
547 | { | 545 | { |
548 | HRESULT hr = S_OK; | 546 | HRESULT hr = S_OK; |
547 | LPWSTR sczCommand = NULL; | ||
549 | STARTUPINFOW si = { }; | 548 | STARTUPINFOW si = { }; |
550 | PROCESS_INFORMATION pi = { }; | 549 | PROCESS_INFORMATION pi = { }; |
551 | GENERIC_EXECUTE_MESSAGE message = { }; | 550 | GENERIC_EXECUTE_MESSAGE message = { }; |
@@ -555,10 +554,17 @@ extern "C" HRESULT ExeEngineRunProcess( | |||
555 | BOOL fFireAndForget = BURN_PACKAGE_TYPE_EXE == pPackage->type && pPackage->Exe.fFireAndForget; | 554 | BOOL fFireAndForget = BURN_PACKAGE_TYPE_EXE == pPackage->type && pPackage->Exe.fFireAndForget; |
556 | BOOL fInheritHandles = BURN_PACKAGE_TYPE_BUNDLE == pPackage->type; | 555 | BOOL fInheritHandles = BURN_PACKAGE_TYPE_BUNDLE == pPackage->type; |
557 | 556 | ||
557 | // Always add user supplied arguments last. | ||
558 | if (wzUserArgs) | ||
559 | { | ||
560 | hr = StrAllocFormattedSecure(&sczCommand, L"%ls %ls", sczBaseCommand, wzUserArgs); | ||
561 | ExitOnFailure(hr, "Failed to append user args."); | ||
562 | } | ||
563 | |||
558 | // Make the cache location of the executable the current directory to help those executables | 564 | // Make the cache location of the executable the current directory to help those executables |
559 | // that expect stuff to be relative to them. | 565 | // that expect stuff to be relative to them. |
560 | si.cb = sizeof(si); | 566 | si.cb = sizeof(si); |
561 | if (!::CreateProcessW(wzExecutablePath, wzCommand, NULL, NULL, fInheritHandles, CREATE_NO_WINDOW, NULL, wzCachedDirectory, &si, &pi)) | 567 | if (!::CreateProcessW(wzExecutablePath, sczCommand ? sczCommand : sczBaseCommand, NULL, NULL, fInheritHandles, CREATE_NO_WINDOW, NULL, wzCachedDirectory, &si, &pi)) |
562 | { | 568 | { |
563 | ExitWithLastError(hr, "Failed to CreateProcess on path: %ls", wzExecutablePath); | 569 | ExitWithLastError(hr, "Failed to CreateProcess on path: %ls", wzExecutablePath); |
564 | } | 570 | } |
@@ -632,6 +638,7 @@ extern "C" HRESULT ExeEngineRunProcess( | |||
632 | } | 638 | } |
633 | 639 | ||
634 | LExit: | 640 | LExit: |
641 | StrSecureZeroFreeString(sczCommand); | ||
635 | ReleaseHandle(pi.hThread); | 642 | ReleaseHandle(pi.hThread); |
636 | ReleaseHandle(pi.hProcess); | 643 | ReleaseHandle(pi.hProcess); |
637 | 644 | ||
diff --git a/src/burn/engine/exeengine.h b/src/burn/engine/exeengine.h index 636988f1..b74d5c9a 100644 --- a/src/burn/engine/exeengine.h +++ b/src/burn/engine/exeengine.h | |||
@@ -47,7 +47,8 @@ HRESULT ExeEngineRunProcess( | |||
47 | __in LPVOID pvContext, | 47 | __in LPVOID pvContext, |
48 | __in BURN_PACKAGE* pPackage, | 48 | __in BURN_PACKAGE* pPackage, |
49 | __in_z LPCWSTR wzExecutablePath, | 49 | __in_z LPCWSTR wzExecutablePath, |
50 | __in_z LPWSTR wzCommand, | 50 | __in_z LPWSTR sczBaseCommand, |
51 | __in_z_opt LPCWSTR wzUserArgs, | ||
51 | __in_z_opt LPCWSTR wzCachedDirectory, | 52 | __in_z_opt LPCWSTR wzCachedDirectory, |
52 | __inout DWORD* pdwExitCode | 53 | __inout DWORD* pdwExitCode |
53 | ); | 54 | ); |
diff --git a/src/burn/engine/msuengine.cpp b/src/burn/engine/msuengine.cpp index 2591973f..de8e8c38 100644 --- a/src/burn/engine/msuengine.cpp +++ b/src/burn/engine/msuengine.cpp | |||
@@ -273,6 +273,7 @@ extern "C" HRESULT MsuEngineExecutePackage( | |||
273 | LPWSTR sczSystemPath = NULL; | 273 | LPWSTR sczSystemPath = NULL; |
274 | LPWSTR sczWusaPath = NULL; | 274 | LPWSTR sczWusaPath = NULL; |
275 | LPWSTR sczCommand = NULL; | 275 | LPWSTR sczCommand = NULL; |
276 | LPWSTR sczEscapedKB = NULL; | ||
276 | SC_HANDLE schWu = NULL; | 277 | SC_HANDLE schWu = NULL; |
277 | BOOL fWuWasDisabled = FALSE; | 278 | BOOL fWuWasDisabled = FALSE; |
278 | STARTUPINFOW si = { }; | 279 | STARTUPINFOW si = { }; |
@@ -328,8 +329,11 @@ extern "C" HRESULT MsuEngineExecutePackage( | |||
328 | break; | 329 | break; |
329 | 330 | ||
330 | case BOOTSTRAPPER_ACTION_STATE_UNINSTALL: | 331 | case BOOTSTRAPPER_ACTION_STATE_UNINSTALL: |
332 | hr = AppEscapeCommandLineArgumentFormatted(&sczEscapedKB, L"%ls", pPackage->Msu.sczKB); | ||
333 | ExitOnFailure(hr, "Failed to escape MSU KB."); | ||
334 | |||
331 | // format command | 335 | // format command |
332 | hr = StrAllocFormatted(&sczCommand, L"\"%ls\" /uninstall /kb:%ls /quiet /norestart", sczWusaPath, pPackage->Msu.sczKB); | 336 | hr = StrAllocFormatted(&sczCommand, L"\"%ls\" /uninstall /kb:%ls /quiet /norestart", sczWusaPath, sczEscapedKB); |
333 | ExitOnFailure(hr, "Failed to format MSU uninstall command."); | 337 | ExitOnFailure(hr, "Failed to format MSU uninstall command."); |
334 | break; | 338 | break; |
335 | 339 | ||
@@ -352,7 +356,7 @@ extern "C" HRESULT MsuEngineExecutePackage( | |||
352 | hr = EnsureWUServiceEnabled(fStopWusaService, &schWu, &fWuWasDisabled); | 356 | hr = EnsureWUServiceEnabled(fStopWusaService, &schWu, &fWuWasDisabled); |
353 | ExitOnFailure(hr, "Failed to ensure WU service was enabled to install MSU package."); | 357 | ExitOnFailure(hr, "Failed to ensure WU service was enabled to install MSU package."); |
354 | 358 | ||
355 | hr = ExeEngineRunProcess(pfnGenericMessageHandler, pvContext, pPackage, sczWusaPath, sczCommand, NULL, &dwExitCode); | 359 | hr = ExeEngineRunProcess(pfnGenericMessageHandler, pvContext, pPackage, sczWusaPath, sczCommand, NULL, NULL, &dwExitCode); |
356 | ExitOnFailure(hr, "Failed to run MSU process"); | 360 | ExitOnFailure(hr, "Failed to run MSU process"); |
357 | 361 | ||
358 | // We'll normalize the restart required error code from wusa.exe just in case. Most likely | 362 | // We'll normalize the restart required error code from wusa.exe just in case. Most likely |
@@ -389,6 +393,7 @@ LExit: | |||
389 | ReleaseStr(sczWindowsPath); | 393 | ReleaseStr(sczWindowsPath); |
390 | ReleaseStr(sczWusaPath); | 394 | ReleaseStr(sczWusaPath); |
391 | ReleaseStr(sczCommand); | 395 | ReleaseStr(sczCommand); |
396 | ReleaseStr(sczEscapedKB); | ||
392 | 397 | ||
393 | ReleaseHandle(pi.hProcess); | 398 | ReleaseHandle(pi.hProcess); |
394 | ReleaseHandle(pi.hThread); | 399 | ReleaseHandle(pi.hThread); |
diff --git a/src/burn/engine/netfxchainer.cpp b/src/burn/engine/netfxchainer.cpp index af4f03f5..6f223eed 100644 --- a/src/burn/engine/netfxchainer.cpp +++ b/src/burn/engine/netfxchainer.cpp | |||
@@ -329,8 +329,9 @@ LExit: | |||
329 | } | 329 | } |
330 | 330 | ||
331 | extern "C" HRESULT NetFxRunChainer( | 331 | extern "C" HRESULT NetFxRunChainer( |
332 | __in LPCWSTR wzExecutablePath, | 332 | __in_z LPCWSTR wzExecutablePath, |
333 | __in LPCWSTR wzArguments, | 333 | __in_z LPWSTR sczBaseCommand, |
334 | __in_z_opt LPCWSTR wzUserArgs, | ||
334 | __in PFN_GENERICMESSAGEHANDLER pfnGenericMessageHandler, | 335 | __in PFN_GENERICMESSAGEHANDLER pfnGenericMessageHandler, |
335 | __in LPVOID pvContext, | 336 | __in LPVOID pvContext, |
336 | __out DWORD* pdwExitCode | 337 | __out DWORD* pdwExitCode |
@@ -360,8 +361,15 @@ extern "C" HRESULT NetFxRunChainer( | |||
360 | hr = CreateNetFxChainer(sczSectionName, sczEventName, &pNetfxChainer); | 361 | hr = CreateNetFxChainer(sczSectionName, sczEventName, &pNetfxChainer); |
361 | ExitOnFailure(hr, "Failed to create netfx chainer."); | 362 | ExitOnFailure(hr, "Failed to create netfx chainer."); |
362 | 363 | ||
363 | hr = StrAllocFormattedSecure(&sczCommand, L"%ls /pipe %ls", wzArguments, sczSectionName); | 364 | hr = StrAllocFormatted(&sczCommand, L"%ls /pipe %ls", sczBaseCommand, sczSectionName); |
364 | ExitOnFailure(hr, "Failed to allocate netfx chainer arguments."); | 365 | ExitOnFailure(hr, "Failed to append netfx chainer args."); |
366 | |||
367 | // Always add user supplied arguments last. | ||
368 | if (wzUserArgs) | ||
369 | { | ||
370 | hr = StrAllocConcatFormattedSecure(&sczCommand, L" %ls", wzUserArgs); | ||
371 | ExitOnFailure(hr, "Failed to append user args."); | ||
372 | } | ||
365 | 373 | ||
366 | si.cb = sizeof(si); | 374 | si.cb = sizeof(si); |
367 | if (!::CreateProcessW(wzExecutablePath, sczCommand, NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi)) | 375 | if (!::CreateProcessW(wzExecutablePath, sczCommand, NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi)) |
diff --git a/src/burn/engine/netfxchainer.h b/src/burn/engine/netfxchainer.h index 7d3aff1c..d59b28f3 100644 --- a/src/burn/engine/netfxchainer.h +++ b/src/burn/engine/netfxchainer.h | |||
@@ -87,8 +87,9 @@ struct NetFxCloseApplications | |||
87 | }; | 87 | }; |
88 | 88 | ||
89 | HRESULT NetFxRunChainer( | 89 | HRESULT NetFxRunChainer( |
90 | __in LPCWSTR wzExecutablePath, | 90 | __in_z LPCWSTR wzExecutablePath, |
91 | __in LPCWSTR wzArguments, | 91 | __in_z LPWSTR sczBaseCommand, |
92 | __in_z_opt LPCWSTR wzUserArgs, | ||
92 | __in PFN_GENERICMESSAGEHANDLER pfnGenericMessageHandler, | 93 | __in PFN_GENERICMESSAGEHANDLER pfnGenericMessageHandler, |
93 | __in LPVOID pvContext, | 94 | __in LPVOID pvContext, |
94 | __out DWORD* pdwExitCode | 95 | __out DWORD* pdwExitCode |