我正在使用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指出我没有正确初始化结构,这很尴尬。不幸的是,修复它并没有改变行为。不过谢谢!
最佳答案
发布的代码中至少存在两个错误。
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 ++中存在{ }
初始化语法,因此不需要这样做。