2010-06-18 8 views
6

Attualmente mantengo un'applicazione interna in .Net. L'applicazione utilizza IPC per mantenere una sessione in esecuzione alla volta; se un'altra sessione tenta di aprirsi (Qualcuno fa nuovamente clic sull'icona, alcuni apre un file dei risultati salvato), la seconda sessione lo comunica alla prima sessione e quindi termina, con la prima sessione che quindi avvia l'azione richiesta.Come utilizzare IPC senza essere un amministratore locale?

Io attualmente faccio utilizzando il namespace System.ServiceModel, in questo modo:

namespace EventLogViewer.IPCServer {// fornisce il quadro comune per i processi di comunicare a 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 

} 

Questo codice è stato originariamente sviluppato in ambiente Windows XP, come come la maggior parte delle aziende non ci siamo mossi a Vista. Dato che tutti eseguiamo come amministratori locali, questo codice ha funzionato senza problemi.

Tuttavia, stiamo passando a Win 7 ora e questo codice genera un'eccezione all'avvio perché non può registrare l'endpoint IPC. Ulteriori informazioni sono disponibili al seguente indirizzo: http://mark.michaelis.net/Blog/WindowsCommunicationFoundationWithWindowsVistaAndUAC.aspx

La soluzione proposta consiste nell'applicare l'app per richiedere i privilegi di amministratore. Questo non funziona per due motivi:

  1. Questa applicazione non necessita di privilegi di Admin altrimenti
  2. Usiamo ClickOnce per la distribuzione dei nostri strumenti interni ed ClickOnce non sosteniamo altro che correre come il programma di avvio del processo.

Quindi a questo punto ho bisogno di trovare una soluzione IPC che non richiede privilegi di admin e mi permette di raggiungere l'obiettivo originale: rilevare un'istanza già in esecuzione del codice e dirgli che cosa fare, altrimenti il ​​lancio stesso. Qualsiasi suggerimento su cosa fare (all'interno del framework .Net, nessuna soluzione di terze parti per favore) sarebbe molto apprezzato.

+1

Si prega di non ripetere tag ".Net 3.5 C#:" nel titolo. Bonus –

risposta

3

Questo è un modo incredibilmente difficile (e come hai scoperto, in modo problematico) per garantire una singola sessione della tua app. Dovresti semplicemente rifattare/ripetere la funzione su use a mutex.

Ecco un altro example. E il requisito wiki article about mutexes.

EDIT

Per aggirare il bit di comunicazione, è possibile generare un file temporaneo con il proprio prefisso speciale e o estensione nella cartella Temp OS-condizione che la singola applicazione sarebbe il polling (filtraggio per il vostro prefisso speciale e/o estensione) per vedere se sono state fatte più richieste. Vedi:

System.IO.Path.GetTempFileName 

e

System.IO.Path.GetTempPath 
+0

: Un Mutex può essere creato senza privilegi di amministratore. – Cheeso

+0

@Cheeso: esattamente.Credo che dovrei essere esplicito a riguardo nella risposta. –

+0

Grazie, ma questo risolve solo metà del problema. Il secondo processo deve dire il primo a cosa avrebbe dovuto fare (avvio, caricamento di un rapporto salvato). I mutex non lo permettono. – Dan

2

sicuramente usare un named mutex per limitare l'applicazione per una singola istanza, quindi è possibile utilizzare NamedPipeServerStream e NamedPipeClientStream di fare il vostro IPC che non richiede diritti di amministratore.

+0

Grazie, questo sembra il percorso che andrò. – Dan

Problemi correlati