65.9K
CodeProject 正在变化。 阅读更多。
Home

ClickOnce 部署 vs. requestedExecutionLevel = requireAdministrator

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.97/5 (16投票s)

2013年7月29日

CPOL

3分钟阅读

viewsIcon

76663

如何绕过 ClickOnce 的一个限制

引言

我制作了一个小型工具应用程序,我想在每次启动计算机时都启动它。把它做成 Windows 服务并使用 Windows 安装程序安装它太复杂了。我也想尽可能简单地将其分发给我的同事(他们是程序员,但并非个个都那么聪明 ;-))。所以我认为 ClickOnce 部署绝对是该程序的理想选择。

所以我把它做成一个简单的 WinForms 程序,并且让程序将自己添加到 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run 注册表项中。

为了做到这一点,程序必须以管理员权限运行(非常令人恼火,但不幸的是对此无能为力)。

我向我的项目添加了一个应用程序清单并更改了

<requestedExecutionLevel level="asInvoker" uiAccess="false" /> 

to

<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />  

一切在我的开发机器上运行完美。

然后我尝试创建一个 ClickOnce 部署。但这被证明是不可能的。 ClickOnce 应用程序在设计上无法以管理员权限运行。因此,当您尝试创建部署时,它已经抱怨 requireAdministrator 不是 requestedExecutionLevel 的有效设置。

然后我感觉就像无桨的小溪一样。我该怎么办?我想使用 ClickOnce,并且我想以管理员身份运行,因为启动项是程序的重要组成部分。但这两件事是相互排斥的。

我想,一定有办法解决这个问题,我在谷歌上搜索了几个小时。我看到的一切都是:ClickOnce 应用程序无法以管理员权限运行。

我几乎要放弃了,直到我终于找到了解决方案。我发现了一篇 AntsCode 上的文章,作者是一个名叫 Anthony 的人,他有一个可行的解决方案。您运行程序,首先要做的就是检查您是否拥有管理员权限。如果您没有,您就以管理员权限启动自己并关闭非管理员实例(当然,您的应用程序不能是单例应用程序,但幸运的是,我的情况也不是这样)。

它对我来说非常有效,所以我想在这里与大家分享这个技巧。

致谢和免责声明

我没有声称拥有该代码的任何所有权,也没有为该代码或该想法做出任何贡献。所有功劳都应该归功于 AntsCode 上的 Anthony。

但在我看来,这才是 CodeProject 技巧的全部意义所在。一篇文章是关于您自己一直在努力并且想要与社区分享的事情。但一个技巧是关于您发现并想要提醒他人的事情,因为您认为他们也会觉得它很有趣。它不必是您自己做的。至少我是这样认为的。如果 CodeProject 管理员有不同的看法,我希望他们能启发我。

如果您想称之为抄袭,我的观点是,只有当您为别人的工作自己邀功时,才是抄袭,而且如前所述:我没有这样做!

Using the Code

所以这里是您如何操作的!您保持您的清单不变

<requestedExecutionLevel level="asInvoker" uiAccess="false" /> 

然后,您可以像这样编辑您的 Program.cs 文件

using System;
using System.Diagnostics;
using System.Reflection;
using System.Security.Principal;
using System.Windows.Forms;

namespace MyProgramNamespace
{
    static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            var wi = WindowsIdentity.GetCurrent();
            var wp = new WindowsPrincipal(wi);
 
            bool runAsAdmin = wp.IsInRole(WindowsBuiltInRole.Administrator);

            if (!runAsAdmin)
            {
                // It is not possible to launch a ClickOnce app as administrator directly,
                // so instead we launch the app as administrator in a new process.
                var processInfo = 
                    new ProcessStartInfo(Assembly.GetExecutingAssembly().CodeBase);

                // The following properties run the new process as administrator
                processInfo.UseShellExecute = true;
                processInfo.Verb = "runas";

                // Start the new process
                try
                {
                    Process.Start(processInfo);
                }
                catch (Exception)
                {
                    // The user did not allow the application to run as administrator
                    MessageBox.Show("Sorry, but I don't seem to be able to start " + 
                       "this program with administrator rights!");
                }

                // Shut down the current process
                Application.Exit();
            }
            else
            {
                // We are running as administrator
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                Application.Run(new Form1());
            }
        }
    }
}  

瞧!效果很好(至少在我的机器上是这样)!

关注点

完全无关的话题,但仍然是:我注意到了一件奇怪的事情。我将注册表值添加到 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run,如前所述,并且代码一路运行,没有任何错误。但无论我做什么,我仍然无法在 RegEdit 中看到添加的值。

事实证明,如果您的操作系统是 64 位,那么就有一个专门用于此的特殊 hive。该程序声称它正在将该值添加到上面的键中,并且所有调试都支持该声明。但实际上,它将它添加到了这个键中

HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Run

如果您问我,这非常狡猾!

历史

  • 版本 1.00 - 初始发布
© . All rights reserved.