0

我正在编写一个 C++ DLL 来连接到 MySQL 数据库。除其他外,它尝试向 Windows 防火墙列表添加一个例外,以便它可以通过 TCP(端口 3306)连接到远程 MySQL 服务器。当我尝试添加端口时,我得到一个HRESULTof E_ACCESSDENIED,除非我以管理员身份运行该程序。

我想提示用户输入管理员密码,但前提是端口不在例外列表中。这意味着我不能只创建UAC manifest,因为据我所知,设置level="requireAdministrator"总是会提示输入管理员密码。我可以有条件地提出管理员提示吗?

4

3 回答 3

3

根据您的要求,我正在根据我的评论做出回答。


执行此操作的正确方法是让您的 DLL 的用户自己处理这种情况。作为 API 开发人员,你的工作绝对不是担心防火墙之类的事情:要么 API 用户和/或最终用户确保它正常工作,要么你优雅地失败了。正如其他人所说,最终用户无法回答 UAC 请求(例如在无头服务器上)的原因有很多,因此您不能依赖在交互式上下文中使用您的 DLL。这根本不是你的责任。


如果你真的必须继续你最初的想法(我再次强调,恕我直言,这是一个坏主意),我最好的选择是将你的 DLL 一分为二:

  • DLL 本身,没有任何清单,因此它可以在任何用户下运行,
  • 和一个单独.exe的清单,需要管理员权限,只有在需要时才会由您的 DLL 运行。

只需要求两者都存储在同一个目录中,这样您就可以轻松找到您的 DLL(以及.exe's)目录GetModuleFileName

其他人已经指出runasRunDll(这是同样有效的答案 IMO),但我更多的是 Unix-y 类型,因此我建议完全使用单独的二进制文件。从长远来看,我发现它更容易维护。


“介于两者之间”的解决方案是您的 DLL 根本不打扰防火墙(应该如此),但您提供了一个完全独立的工具(.exe带有清单),可以帮助您的用户在需要时正确设置防火墙。这可能是最好的解决方案:简洁的设计(责任分离),您仍然为用户提供所有必需的工具。

于 2013-06-21T21:04:12.710 回答
2

一旦应用程序启动,就无法提升应用程序的权限。在您的情况下,一种解决方法是使用ShellExecuteEx提升权限启动一个小型外部应用程序,并在那里添加防火墙例外。添加异常后,进行必要的清理并退出。然后,您可以等待应用程序完成,然后再继续执行。


非常感谢Cody Gray指出为什么不应使用 RunDll以及 Raymond Chen 的附加博客条目,其中包含有关问题的更多信息RunDll

于 2013-06-21T19:56:21.183 回答
1

You can relaunch your program using ShellExecuteEx with "runas" verb whenever you get E_ACCESSDENIED. Something like this

        wchar_t szPath[MAX_PATH];
        if (GetModuleFileName(NULL, szPath, ARRAYSIZE(szPath)))
        {`enter code here`
            // Launch itself as administrator.
            SHELLEXECUTEINFO sei = { sizeof(sei) };
            sei.lpVerb = L"runas";
            sei.lpFile = szPath;
            sei.lpParameters=L"admin";
            sei.nShow = SW_NORMAL;

            if (!ShellExecuteEx(&sei))
            {
                DWORD dwError = GetLastError();
                if (dwError == ERROR_CANCELLED)
                {
                    ExitProcess(0);
                }
            }
            else
            {
                ExitProcess(0);
            }
        }
于 2013-06-21T19:53:28.293 回答