【问题标题】:ShellExecute bat file elevated (FMX, Win32)ShellExecute bat 文件提升(FMX,Win32)
【发布时间】:2019-07-03 04:23:40
【问题描述】:

我想以提升的权限从我的 FMX 应用程序(在 Win32 上)生成一个批处理文件。从 Remy 在 ShellExecute 底部of this thread 的回答中,我找到了如何启动批处理文件。现在,我不知道如何以提升的权限启动它。以下是我的代码:

String Prog = "c:\\Users\\rwp\\Desktop\\test.bat";
int nErrorCode = (int) ShellExecute(NULL, L"runas", Prog.c_str(), NULL, NULL, SW_SHOWNORMAL);
if (nErrorCode <= 32) {
 ShowMessage("an error occured");
}

在阅读this 后,我为第二个参数添加了“runas”,但无济于事。手动运行批处理文件(右键单击并以管理员身份运行)有效。这是批处理文件 fyi 的内容(只是系统映像的一部分):

c:\Windows\system32\wbAdmin.exe start backup -backupTarget:D: -include:C: -allCritical -quiet

我如何以管理员身份 ShellExecute 这个批处理文件?

更新 1:我正在尝试根据 Remy 的建议使用 CreateProcess。这是我的代码(基于this example):

//Code is inside a __fastcall button click
    PROCESS_INFORMATION     piProcInfo;
    STARTUPINFO             siStartInfo;
    siStartInfo.cb          = sizeof(STARTUPINFO);
    siStartInfo.lpReserved  = NULL;
    siStartInfo.lpReserved2 = NULL;
    siStartInfo.cbReserved2 = 0;
    siStartInfo.lpDesktop   = NULL;
    siStartInfo.dwFlags     = 0;

   //   String strCmdLine = "C:\\Users\\rwpatter\\Desktop\\test.bat";
    String strCmdLine = "C:\\Windows\\System32\\wbAdmin.exe start backup -backupTarget:T: -include:C: -allCritical -quiet";

    // Create the child process.
    int rtrn =  CreateProcess(

        NULL,
        strCmdLine.c_str(),
        NULL,           // process security attributes
        NULL,           // primary thread security attributes
        0,              // handles are inherited
        0,              // creation flags
        0,              // use parent's environment
        0,           // use parent's current directory
        &siStartInfo,   // STARTUPINFO pointer
        &piProcInfo);   // receives PROCESS_INFORMATION

        // Wait for the processs to finish
        DWORD rc = WaitForSingleObject(
                      piProcInfo.hProcess, // process handle
                      INFINITE);
        ShowMessage(IntToStr(rtrn));

如果我如图所示运行它(右键单击 exe 并以管理员身份运行),它会返回 0,这意味着它是 failed。如果我通过将 wbAdmin 命令行放在 test.bat 文件中来运行它(请参阅代码中 String strCmdLine 正上方的注释行),则 CreateProcess 返回 1(成功)但 wbAdmin 仍然没有运行。它闪现了一个 DOS 窗口,我捕获了它,如下图所示。它在标题栏中显示东方字符,并表示无法识别为内部或外部命令。但是,如果我直接(提升)运行那个 test.bat,它运行 wbAdmin 没问题。

关于什么是错的任何想法?除了我显然是无知的。 (附言我将在此之后在 ShellExecute 上测试 Golvind 的答案......)

【问题讨论】:

  • 由于bat 由一个命令组成,我将直接使用CreateProcess() 运行wbAdmin.exe,如果它还没有自行提升运行,那么让您的应用程序运行提升在调用该命令之前。
  • 不是直接的答案,但您可以从那里获得灵感:github.com/TurboPack/DOSCommand

标签: winapi firemonkey c++builder


【解决方案1】:

您需要使用"runas" 以管理员身份启动CMD.exe,并将批处理文件指定为命令提示符的“run-me-then-exit”(即/c)参数,如下所示:

WCHAR wszCmdPath[MAX_PATH];
GetEnvironmentVariableW(L"ComSpec", wszCmdPath, MAX_PATH);
ShellExecuteW(NULL, L"runas", wszCmdPath, L"/c \"C:\\Path\\BatchFile.bat\"", L"", SW_SHOW);

此处调用的两个函数都可能失败,并且健壮的代码会在继续之前测试是否成功。

【讨论】:

  • 不明白为什么你可以让shell解决如何打开一个bat文件
  • @DavidHeffernan 我相信如果您只是使用批处理文件的路径作为ShellExecute 中的命令,那么无论runas 动词如何,它都不会请求提升
  • 感谢戈文德。这不起作用,与我所做的 CreateProcess 尝试的结果相同(请参阅上面的更新 1)。我可以右键单击并以管理员身份运行 test.bat 文件,它可以正常工作(启动 wbAdmin 并开始创建系统映像)。您上面的代码不起作用。如果我用“notepad.exe”替换 wbAdmin 行,它会打开记事本并保持 CMD 打开,直到我关闭记事本。看起来它不喜欢海拔高度。
【解决方案2】:

手动运行批处理文件(右键单击并以管理员身份运行)有效。

因为手动启动时运行的是 64 位版本的 cmd。

它在标题栏中显示东方字符并显示无法识别 作为内部或外部命令。

因为您的应用程序是 32 位的。 32 位应用程序不会看到与 64 位应用程序相同的 System32 文件夹。您可以通过虚拟 sysnative 文件夹访问 32 位应用程序中的 64 位 System32 文件夹。

#include <shellapi.h>
...
    String strCmdLine = "wbAdmin.exe start backup -backupTarget:T: -include:C: -allCritical -quiet";
    int rtrn = CreateProcess(
        NULL,
        strCmdLine.c_str(),
        NULL,           // process security attributes
        NULL,           // primary thread security attributes
        0,              // handles are inherited
        0,              // creation flags
        0,              // use parent's environment
        0,           // use parent's current directory
        &siStartInfo,   // STARTUPINFO pointer
        &piProcInfo);   // receives PROCESS_INFORMATION
    if (!rtrn)
    {
        String newCmdLine = "c:\\windows\\sysnative\\wbAdmin.exe start backup -backupTarget:T: -include:C: -allCritical -quiet";
        rtrn = CreateProcess(
            NULL,
            newCmdLine.c_str(),
            NULL,           // process security attributes
            NULL,           // primary thread security attributes
            0,              // handles are inherited
            0,              // creation flags
            0,              // use parent's environment
            0,           // use parent's current directory
            &siStartInfo,   // STARTUPINFO pointer
            &piProcInfo);   // receives PROCESS_INFORMATION
    }

或者将您的应用程序编译为 64 位。

【讨论】:

  • 编译为 64 位作品 - 让我启动 test.bat 文件并运行 wbAdmin。使用您的其他方法(使用 c:\\windows\\sysnative 路径)会导致 KERNELLBASE.dll 违规。从来没有听说过那个 sysnative 文件夹并且找不到它。谢谢。
  • sysnative是一个虚拟文件夹,所以找不到。它只是64位Windows系统提供的一种重定向机制。 64 位 Windows 将其重定向到真正的 System 32 文件夹。
猜你喜欢
  • 1970-01-01
  • 2010-09-10
  • 2014-12-26
  • 2013-05-31
  • 2014-09-04
  • 1970-01-01
  • 2014-08-20
  • 1970-01-01
  • 2019-05-20
相关资源
最近更新 更多