如何修改Wix代码使安装结束时以管理员权限启动自定义Run.exe?
我制作了一款Wix安装程序,期望实现以下功能:在安装即将结束(点击「完成」按钮前),启动自定义的Run.exe,完成VS Redistributable的安装并启动主应用Converter。
目前遇到的问题:代码无法启动Converter,会收到来自Converter的错误提示「Failed to launch Converter for Windows.」,但以管理员身份打开命令行窗口执行以下命令时,Converter可以正常启动:
msiexec.exe /i C:\ConverterWixSetup64.msi /L*vx c:\Log.txt
请问需要修改哪些代码,才能让Run.exe以管理员权限启动,从而无需以管理员身份运行命令行即可正常启动Converter?
现有代码
Wix代码
<?xml version="1.0" encoding="UTF-8"?> <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension"> <?include "..\include\Variables.wxi" ?> <Fragment> <CustomAction Id='LaunchApplication' Directory="INSTALLFOLDER" ExeCommand='cmd.exe /c Run.exe' Execute='deferred' Impersonate='no' Return='asyncNoWait' /> </Fragment> </Wix> <InstallExecuteSequence> <Custom Action="LaunchApplication" Before="InstallFinalize"></Custom> </InstallExecuteSequence>
Run.exe启动Converter的代码
//_tprintf(_T("\nLaunching %s..."), appDisplayName); STARTUPINFO si; PROCESS_INFORMATION pi; ZeroMemory(&si, sizeof(STARTUPINFO)); ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); si.cb = sizeof(STARTUPINFO); //start Converter application if (!CreateProcess(appName, NULL, NULL, NULL, false, CREATE_NEW_PROCESS_GROUP, NULL, NULL, &si, &pi)) { //if failed to open, give user feed back /*_tprintf(_T("\n> %s failed to launch."), appDisplayName); _tprintf(_T("\n%s"), closingApp);*/ MessageBox(NULL, appFailedString.c_str(), failedToOpenConverterForWindows, MB_OK); return 3; } HWND hWnd = GetConsoleWindow(); ShowWindow(hWnd, SW_HIDE); //WaitForSingleObject(pi.hProcess, INFINITE); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); return 0;
针对你的问题,需要从Wix配置和Run.exe代码两方面修改,确保Run.exe以管理员权限启动,同时解决路径/工作目录问题:
1. 优化Wix自定义动作配置
当前通过cmd.exe /c调用Run.exe会额外创建cmd进程,可能导致权限传递或工作目录异常,建议直接调用Run.exe:
<CustomAction Id='LaunchApplication' Directory="INSTALLFOLDER" ExeCommand='Run.exe' Execute='deferred' Impersonate='no' Return='asyncNoWait' />
- 移除
cmd.exe /c,直接执行Run.exe,避免额外进程带来的干扰 - 保留
Execute='deferred'和Impersonate='no',确保自定义动作以系统管理员权限运行
2. 修复Run.exe的CreateProcess调用
Converter启动失败核心原因大概率是路径错误或工作目录不正确,需要做以下调整:
(1)使用Converter的绝对路径
确保appName是Converter.exe的完整绝对路径,可以通过Run.exe自身路径拼接获取:
TCHAR runPath[MAX_PATH]; GetModuleFileName(NULL, runPath, MAX_PATH); PathRemoveFileSpec(runPath); // 获取Run.exe所在目录 TCHAR appPath[MAX_PATH]; PathCombine(appPath, runPath, _T("Converter.exe")); // 拼接Converter的绝对路径
之后用appPath替代原代码中的appName传入CreateProcess。
(2)指定正确的工作目录
在CreateProcess的第8个参数(lpCurrentDirectory)传入Run.exe所在目录,确保Converter启动时工作目录正确:
if (!CreateProcess(appPath, NULL, NULL, NULL, false, CREATE_NEW_PROCESS_GROUP, NULL, runPath, &si, &pi))
(3)简化窗口隐藏逻辑(可选)
替换手动隐藏控制台窗口的代码,在CreateProcess中添加CREATE_NO_WINDOW标志直接隐藏窗口:
if (!CreateProcess(appPath, NULL, NULL, NULL, false, CREATE_NEW_PROCESS_GROUP | CREATE_NO_WINDOW, NULL, runPath, &si, &pi))
这样可以省去GetConsoleWindow()和ShowWindow()的代码。
3. 确认安装序列时机
当前Before="InstallFinalize"的配置是正确的,此时所有安装文件已复制到目标目录,Run.exe和Converter都已存在,无需调整。
内容的提问来源于stack exchange,提问作者Ming

