我正在使用Qt在Visual C ++(2015)中创建自配置软件工具,该工具将根据需要运行其他一些第三方安装程序。当软件发现需要的库或驱动程序不可用时,它将使用ShellExecuteEx调用相应的安装程序以打开相应的可执行文件。
如果只需要安装一件事(ShellExecuteEx只运行一次),则一切正常。如果需要一次安装两个程序,则大约有25%的时间一次安装程序将正确运行,另一个将打开包含可执行文件的文件夹,而不是运行该可执行文件。关于是正确执行的第一项操作还是第二项操作,没有一致性。
ShellExecuteEx声称在两种情况下都可以正确运行(返回true)。我已验证每次都提供了指向可执行文件(和工作目录)的正确路径。我已经尝试过在ShellExecuteEx中使用动词“ open”和“ NULL”,而没有改变行为。
如果有关系,两个可执行文件都将请求管理权限。当一切正常时,它们都按预期进行。如果失败,它会不要求管理员特权。
我找不到任何人遇到类似问题的记录,这可能意味着我以某种基本方式滥用了ShellExecuteEx,但我没有看到它。预先感谢您的任何建议。
代码如下:
if(dummy1Required && !dummy1Present){
SHELLEXECUTEINFOA execinfo = {};
execinfo.cbSize = sizeof(SHELLEXECUTEINFOA);
execinfo.fMask = NULL;
execinfo.hwnd = NULL;
execinfo.lpVerb = NULL;
execinfo.lpFile = QDir::toNativeSeparators(QCoreApplication::applicationDirPath() + "/Drivers/dummy1/install.bat").toLocal8Bit().data();
execinfo.lpParameters = NULL;
execinfo.lpDirectory = QDir::toNativeSeparators(QCoreApplication::applicationDirPath() + "/Drivers/dummy1").toLocal8Bit().data();
printf("Dummy1 Executing: %s\n In directory:%s\n", QDir::toNativeSeparators(QCoreApplication::applicationDirPath() + "/Drivers/dummy1/install.bat").toLocal8Bit().data(), QDir::toNativeSeparators(QCoreApplication::applicationDirPath() + "/Drivers/dummy1").toLocal8Bit().data());
fflush(stdout);
execinfo.nShow = SW_SHOW;
execinfo.hInstApp = NULL;
execinfo.fMask = execinfo.fMask | SEE_MASK_NOCLOSEPROCESS;
if(ShellExecuteExA(&execinfo)){
WaitForSingleObject(execinfo.hProcess,INFINITE);
CloseHandle(execinfo.hProcess);
}else{
printf("Failed to launch dummy1 installer because...%lu\n", GetLastError());
fflush(stdout);
}
}
if(dummy2Required && !dummy2Present){
SHELLEXECUTEINFOA execinfo = {};
execinfo.cbSize = sizeof(SHELLEXECUTEINFOA);
execinfo.fMask = NULL;
execinfo.hwnd = NULL;
execinfo.lpVerb = NULL;
execinfo.lpFile = QDir::toNativeSeparators(QCoreApplication::applicationDirPath() + "/Drivers/dummy2/setup.exe").toLocal8Bit().data();
execinfo.lpParameters = "setupParamters.ini /qb /acceptlicenses y /norestart";
execinfo.lpDirectory = QDir::toNativeSeparators(QCoreApplication::applicationDirPath() + "/Drivers/dummy2").toLocal8Bit().data();
printf("Dummy2 Executing: %s\n In directory:%s\n", QDir::toNativeSeparators(QCoreApplication::applicationDirPath() + "/Drivers/dummy2/setup.exe").toLocal8Bit().data(), QDir::toNativeSeparators(QCoreApplication::applicationDirPath() + "/Drivers/dummy2").toLocal8Bit().data());
fflush(stdout);
execinfo.nShow = SW_SHOW;
execinfo.hInstApp = NULL;
execinfo.fMask = execinfo.fMask | SEE_MASK_NOCLOSEPROCESS;
if(ShellExecuteExA(&execinfo)){
WaitForSingleObject(execinfo.hProcess,INFINITE);
CloseHandle(execinfo.hProcess);
}else{
printf("Failed to launch dummy2 installer because...%lu\n", GetLastError());
fflush(stdout);
}
}
编辑:我不正确。如果只运行一个可执行文件,我将观察不到这种现象的发生的频率就会降低,因此它与运行两个操作没有内在的联系。
编辑2:PaulMckenzie指出我没有正确初始化结构,这很尴尬。不幸的是,修复它并没有改变行为。不过谢谢!
答案 0 :(得分:1)
发布的代码中至少存在两个错误。
if(dummy1Required && !dummy1Present){
SHELLEXECUTEINFOA execinfo; // <-- Uninitialized
...
}
if(dummy2Required && !dummy2Present){
SHELLEXECUTEINFOA execinfo; // <-- Uninitialized
...
}
然后您去设置SHELLEXECUTEINFOA
的某些成员,但是是否都设置了所有成员?如果您错过了一些会员怎么办?
对于许多需要使用诸如SHELLEXECUTEINFOA
之类的结构的Windows API函数,应在设置任何成员之前通过将所有成员清零来初始化该结构。由于struct是局部变量,因此以这种方式声明时,它不会被初始化。
这种不正常行为的可能原因是此结构包含您可能不知道存在的成员,但是将使用Win32 API。如果这些成员未初始化,则API函数将使用未初始化成员持有的任何值。
初始化结构的最简单方法是简单地使用大括号初始化:
SHELLEXECUTEINFOA execInfo = {};
如果您看到Win32 API struct
编程示例,可能会遇到的C
归零的另一种方法是使用ZeroMemory。但是对于C ++,由于C ++中存在{ }
初始化语法,因此不需要。