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:
- This app does not need admin privledges otherwise
- We use ClickOnce for deployment of our internal tools and ClickOnce does not support anything other than running as the process launcher.
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.