【问题标题】:How to use IPC without being a local Admin?如何在没有本地管理员的情况下使用 IPC?
【发布时间】:2011-03-05 13:24:15
【问题描述】:

我目前在 .Net 中维护一个内部应用程序。应用程序使用 IPC 一次维护一个正在运行的会话;如果另一个会话尝试打开(有人再次单击图标,有人打开保存的结果文件),第二个会话将其传达给第一个会话然后终止,第一个会话然后启动请求的操作。

我目前使用 System.ServiceModel 命名空间来执行此操作,如下所示:

命名空间 EventLogViewer.IPCServer { //为进程相互通信提供通用框架。

[ServiceContract(Namespace = "http://ELV.domain")]
interface IELVLauncher
{
    [OperationContract]
    bool LaunchTabs(String[] fileNames);
}
public delegate void TabLauncher(String[] fileNames);
class ELVLauncherServer : IDisposable
{
    ServiceHost ipcService;
    public ELVLauncherServer()
    {
        Uri baseAddress = new Uri("Http://localhost:45600/elvlauncher/service");
        String address = "net.pipe://localhost/elvlauncher/tablauncher";

        ipcService = new ServiceHost(typeof(ELVLauncher), baseAddress);

        NetNamedPipeBinding binding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None);
        ipcService.AddServiceEndpoint(typeof(IELVLauncher), binding, address);

        ServiceMetadataBehavior behavior = new ServiceMetadataBehavior();
        behavior.HttpGetEnabled = true;
        behavior.HttpGetUrl = new Uri("http://localhost:45601/elvlauncher");
        ipcService.Description.Behaviors.Add(behavior);
        Utilities.WriteMemoryDebugStatement(new DebugStatement(DebugStatement.StatementType.INFO, "Registering IPC Service"));
        ipcService.Open();

    }

    #region IDisposable Members

    public void Dispose()
    {
        ipcService.Close();
    }

    #endregion
}
public class ELVLauncher : IELVLauncher
{
    #region IELVLauncher Members

    public bool LaunchTabs(string[] fileNames)
    {
        try
        {
            Utilities.WriteMemoryDebugStatement(new DebugStatement(DebugStatement.StatementType.INFO, String.Format("IPC request received, files: {0}", String.Join(", ", fileNames))));
            Program.mainWindow.backgroundListener_OnLaunchRequestReceived(fileNames);
        }
        catch (Exception exception)
        {
            Utilities.WriteMemoryDebugStatement(new DebugStatement(exception));
        }
        return (true);
    }

    #endregion

}

此代码最初是在 Windows XP 下开发的,就像大多数公司一样,我们没有迁移到 Vista。由于我们都以本地管理员身份运行,因此这段代码运行没有问题。

但是,我们现在正在过渡到 Win 7,并且此代码在启动时会产生异常,因为它无法注册 IPC 端点。更多信息在这里:http://mark.michaelis.net/Blog/WindowsCommunicationFoundationWithWindowsVistaAndUAC.aspx

给出的解决方法是将应用程序升级为需要管理员权限。这不起作用有两个原因:

  1. 此应用不需要管理员权限,否则
  2. 我们使用 ClickOnce 来部署我们的内部工具,并且 ClickOnce 不支持除了作为进程启动器运行之外的任何内容。

所以此时我需要找到一个不需要管理员权限的 IPC 解决方案,并让我实现最初的目标:检测已经运行的代码实例并告诉它要做什么,否则会自行启动。任何关于做什么的建议(在 .Net 框架内,请不要第三方解决方案)将不胜感激。

【问题讨论】:

  • 请不要在标题中重复标签“.Net 3.5 C#:”。

标签: c# .net-3.5 ipc servicehost


【解决方案1】:

确保应用程序的单个会话非常困难(并且您已经发现,这是一种有问题的方式)。您应该将功能重构/重做为use a mutex

这是另一个example. 还有必要的wiki article about mutexes

编辑

为了绕过通信位,您可以在操作系统提供的临时文件夹中生成一个带有您自己的特殊前缀和/或扩展名的临时文件,单个应用程序将轮询(过滤您的特殊前缀和/或扩展名)以查看是否有更多提出了要求。见:

System.IO.Path.GetTempFileName 

System.IO.Path.GetTempPath

【讨论】:

  • 奖励:无需管理员权限即可创建互斥锁。
  • @Cheeso:完全正确。我想我应该在答案中明确说明这一点。
  • 谢谢,但这只能解决一半的问题。第二个过程必须告诉第一个它要做什么(启动,加载保存的报告)。互斥体不允许这样做。
  • @Dan:如何将启动请求放到一个可识别的临时位置,让应用每隔一段时间轮询一下,看看是否发出了这样的请求?
  • @Paul:我不是文件系统轮询的忠实拥护者,但如果没有人为基于内存的方法提供另一种解决方案,那么我想这就是我必须要做的。
【解决方案2】:

一定要使用named mutex 将应用程序限制为单个实例,然后您可以使用NamedPipeServerStreamNamedPipeClientStream 来执行不需要管理员权限的IPC。

【讨论】:

  • 谢谢,这看起来像我要去的路线。
猜你喜欢
  • 2014-03-17
  • 1970-01-01
  • 2015-04-06
  • 1970-01-01
  • 2019-09-20
  • 1970-01-01
  • 2021-03-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多