| 911 | { |
| 912 | |
| 913 | bool helperExec(QWidget* parent, const std::wstring& moDirectory, |
| 914 | const std::wstring& commandLine, BOOL async) |
| 915 | { |
| 916 | const std::wstring fileName = moDirectory + L"\\helper.exe"; |
| 917 | |
| 918 | env::HandlePtr process; |
| 919 | |
| 920 | { |
| 921 | SHELLEXECUTEINFOW execInfo = {}; |
| 922 | |
| 923 | ULONG flags = SEE_MASK_FLAG_NO_UI; |
| 924 | if (!async) |
| 925 | flags |= SEE_MASK_NOCLOSEPROCESS; |
| 926 | |
| 927 | execInfo.cbSize = sizeof(SHELLEXECUTEINFOW); |
| 928 | execInfo.fMask = flags; |
| 929 | execInfo.hwnd = 0; |
| 930 | execInfo.lpVerb = L"runas"; |
| 931 | execInfo.lpFile = fileName.c_str(); |
| 932 | execInfo.lpParameters = commandLine.c_str(); |
| 933 | execInfo.lpDirectory = moDirectory.c_str(); |
| 934 | execInfo.nShow = SW_SHOW; |
| 935 | |
| 936 | if (!::ShellExecuteExW(&execInfo) && execInfo.hProcess == 0) { |
| 937 | const auto e = GetLastError(); |
| 938 | |
| 939 | spawn::dialogs::helperFailed(parent, e, "ShellExecuteExW()", fileName, |
| 940 | moDirectory, commandLine); |
| 941 | |
| 942 | return false; |
| 943 | } |
| 944 | |
| 945 | if (async) { |
| 946 | return true; |
| 947 | } |
| 948 | |
| 949 | process.reset(execInfo.hProcess); |
| 950 | } |
| 951 | |
| 952 | const auto r = ::WaitForSingleObject(process.get(), INFINITE); |
| 953 | |
| 954 | if (r != WAIT_OBJECT_0) { |
| 955 | // for WAIT_ABANDONED, the documentation doesn't mention that GetLastError() |
| 956 | // returns something meaningful, but code ERROR_ABANDONED_WAIT_0 exists, so |
| 957 | // use that instead |
| 958 | const auto code = (r == WAIT_ABANDONED ? ERROR_ABANDONED_WAIT_0 : GetLastError()); |
| 959 | |
| 960 | spawn::dialogs::helperFailed(parent, code, "WaitForSingleObject()", fileName, |
| 961 | moDirectory, commandLine); |
| 962 | |
| 963 | return false; |
| 964 | } |
| 965 | |
| 966 | DWORD exitCode = 0; |
| 967 | if (!GetExitCodeProcess(process.get(), &exitCode)) { |
| 968 | const auto e = GetLastError(); |
| 969 | |
| 970 | spawn::dialogs::helperFailed(parent, e, "GetExitCodeProcess()", fileName, |
no test coverage detected