首先,我是新手使用Windows' C ++ API,所以可能有一些我不知道的东西。
我试图在Windows中用C ++启动一个提升的子进程。我设法写了这个代码,它启动一个提升的子进程,向它传递2个参数,然后子进程弹出一个带有这些参数的窗口:
#include <shlobj.h>
#include <shlwapi.h>
#include <objbase.h>
#include <string>
#include <QString>
#include <QDebug>
#include <QMessageBox>
#include <QApplication>
auto getWinError()
{
auto dw =GetLastError();
LPTSTR* lpMsgBuf;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
dw,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &lpMsgBuf,
0, NULL );
auto str = QString::fromWCharArray(*lpMsgBuf);
LocalFree(*lpMsgBuf);
return str;
}
int main(int argc, char** argv)
{
if (argc == 1){
// start self as admin with 2 arguments
SHELLEXECUTEINFO info = {};
info.cbSize = sizeof(SHELLEXECUTEINFO);
info.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_UNICODE;
info.lpVerb = L"runas";
auto filestr = QString{argv[0]}.toStdWString();
info.lpFile = filestr.c_str();
info.lpParameters = LR"("first parameter" "żółć")";
info.nShow = SW_SHOW;
auto success = ShellExecuteEx(&info);
if (!success || (int)info.hInstApp <= 32){
qDebug()<<getWinError();
return -1;
}
HANDLE handle = info.hProcess;
auto exitCode = [handle]{
DWORD status;
GetExitCodeProcess(handle, &status);
return status;
};
while (exitCode() == STILL_ACTIVE) Sleep(100);
qDebug()<<"process exited with exit code "<<exitCode();
CloseHandle(handle);
return 0;
} else {
// show popup with arguments
QApplication a(argc, argv);
QStringList s;
for (int i = 1; i<argc; i++){
s += argv[i];
}
QMessageBox::information(0, "", s.join('\n'));
return 42;
}
}
它主要起作用,但它会破坏非ASCII字符:
我应该更改什么才能正确处理unicode? p>
答案 0 :(得分:4)
问题在于您依赖于argv
的窄版main()
数组,该数组无法在Windows上接收Unicode输入。您需要使用广泛版本的wmain()
代替。
但是,QApplication
会为您解析命令行。在Windows上,QApplication
忽略argv
,而是使用Win32 API GetCommandLine()
函数,以便它可以接收Unicode输入。但是你直接使用argv
而不是使用Qt解析的内容。您应该使用QApplication::arguments()
方法将解析的命令行检索为QStringList
。
您还错误地使用了FormatMessage()
。您应该使用WaitForSingleObject()
而不是GetExitCodeProcess()
循环。
请改为尝试:
#include <windows.h>
#include <shlobj.h>
#include <shlwapi.h>
#include <objbase.h>
#include <string>
#include <QString>
#include <QDebug>
#include <QMessageBox>
#include <QApplication>
QString getWinError()
{
DWORD dw = GetLastError();
LPWSTR lpMsgBuf = NULL;
FormatMessageW(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
dw,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPWSTR) &lpMsgBuf,
0, NULL );
QString str = QString::fromWCharArray(lpMsgBuf);
LocalFree(lpMsgBuf);
return str;
}
int main(int argc, char** argv)
{
if (argc == 1)
{
// start self as admin with 2 arguments
SHELLEXECUTEINFOW info = {};
info.cbSize = sizeof(info);
info.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_UNICODE;
info.lpVerb = L"runas";
WCHAR szFileName[MAX_PATH] = {};
GetModuleFileNameW(NULL, szFileName, MAX_PATH);
info.lpFile = szFileName;
/* alternatively:
std::wstring filePath = QCoreApplication::applicationFilePath().toStdWString();
info.lpFile = filePath.c_str();
or:
QString filePath = QCoreApplication::applicationFilePath();
info.lpFile = (LPCWSTR) filePath.utf16();
*/
info.lpParameters = L"\"first parameter\" \"żółć\"";
info.nShow = SW_SHOW;
if (!ShellExecuteEx(&info)){
qDebug() << getWinError();
return -1;
}
WaitForSingleObject(info.hProcess, INFINITE);
DWORD status = 0;
GetExitCodeProcess(info.hProcess, &status);
CloseHandle(info.hProcess);
qDebug() << "process exited with exit code " << status;
return 0;
}
else
{
// show popup with arguments
QApplication a(argc, argv);
QStringList s = a.arguments();
QMessageBox::information(0, "", s.join('\n'));
return 42;
}
}