开发者

How to use IPC without being a local Admin?

I currently maintain an internal application in .Net. The application uses IPC to maintain one running session at a time; if another session attempt to open (Someone clicks the icon again, some opens up a saved result file), the second session communicates this to the first session and then terminates, with the first session then launching the requested action.

I currently do this using the the System.ServiceModel namespace, like so:

namespace EventLogViewer.IPCServer { //Provides the common framework for processes to communicate to oneanother.

[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

}

This code was originally developed under Windows XP, as like most corporations we did not move to Vista. Since we all run as local admins, this code ran without a problem.

However, we are transitioning to Win 7 now, and this code produces an exception on startup because it cannot register the IPC endpoint. More information is here: http://mark.michaelis.net/Blog/WindowsCommunicationFoundationWithWindowsVistaAndUAC.aspx

The workaround given is to up the app to requiring admin privledges. This doesn't work for two reasons:

  1. This app does not need admin privledges otherwise
  2. We use ClickOnce for deployment of our internal tools and ClickOnce does not support anything other than running as the process launcher.
  3. 开发者_开发知识库

So at this point I need to find an IPC solution which does not require admin privledges and lets me achieve the original goal: detecting an already running instance of the code and telling it what to do, otherwise launching itself. Any suggestions on what to do (within the .Net framework, no 3rd party solutions please) would be much appreciated.


That is an incredibly difficult (and as you have discovered, problematic way) to ensure a single session of your app. You should just refactor/redo the feature to use a mutex.

Here is another example. And the requisite wiki article about mutexes.

EDIT

To get around the communication bit you could generate a temp file with your own special prefix and or extension in OS-provided temp folder which the single app would poll (filtering for your special prefix and/or extension) to see whether more requests were made. See:

System.IO.Path.GetTempFileName 

and

System.IO.Path.GetTempPath


Definately use a named mutex to limit the application to a single instance, then you can use NamedPipeServerStream and NamedPipeClientStream to do your IPC which would not require admin rights.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜