2014-11-14 28 views
5

Un esempio:Aprire il file nell'istanza attualmente in esecuzione del mio programma?

Se Visual Studio (2010) è aperto e in esecuzione, quindi fai doppio clic su un file misc * .cs sul desktop del PC, il file verrà aperto nell'istanza corrente in esecuzione di Visual Studio, di aprire un'altra istanza di VS.

Come posso ottenere il mio programma C# per simulare questo comportamento?

In altre parole, se ho un tipo di file come ad esempio * .myfile associato con il mio programma, e l'utente fa doppio clic * .myfile in Esplora risorse, e .... il mio programma è già in esecuzione ..... dovrebbe aprire il file senza che Windows avvii un'altra istanza del mio programma. Se il programma non è in esecuzione, Windows può avviare normalmente un'istanza.

Si noti che sono consentite più istanze del mio programma, come Visual Studio.

Qualsiasi suggerimento sarebbe apprezzato !!

+0

Hai provato a verificare i processi attualmente in esecuzione nel sistema e se il tuo programma è già in esecuzione forse gli passa qualche informazione? Per chiarire, lo fai all'inizio del tuo programma prima di mostrare un'interfaccia utente e se c'è un'istanza basta passarci le informazioni e chiudere la nuova istanza –

+0

@Jafar Kofahi - Grazie per la risposta. Sulla base del tuo commento, sembra che una seconda istanza del programma dovrebbe iniziare brevemente, controllare se il file può essere passato a un'altra istanza in esecuzione, quindi passare il file e spegnere se trovato. Ci ho pensato, ma il programma è abbastanza grande. Suppongo che stavo cercando un modo per dire a Windows di non avviare un'altra istanza, quindi ottenere una notifica in qualche modo se l'utente ha fatto doppio clic sul file associato. – user1689175

+0

In genere questo viene implementato utilizzando [applicazioni a singola istanza] (http://stackoverflow.com/questions/424368/opening-a-known-file-type-into-running-stance-of-custom-app-net), che non è quello che vuoi Dai un'occhiata a questo - [Qual è il metodo più semplice per la comunicazione tra processi tra processi 2 C#?] (Http://stackoverflow.com/questions/528652/what-is-the-simplest-method-of-inter-process- comunicazione-tra-2-c-sharp-pro). – Neolisk

risposta

3

Se si guarda ciò che è registrato per il file .cs nel Registro di sistema, si noterà che non è Visual Studio. Per l'edizione Express, ad es. l'applicazione registrata è 'VCSExpress.exe' e lo studio è in esecuzione in 'WDExpress.exe'. Nelle versioni avanzate penso che lo studio funzioni come "devenv.exe". Il punto interessante è che ci sono due applicazioni: la tua applicazione UI e una specie di applicazione di avvio. Non so come faccia il VS, ma potrei immaginare in questo modo: launcher comunica con l'interfaccia utente con qualsiasi tipo di comunicazione tra processi, ad es. named pipe. (See here) Forse prova questo:

  • Applicazione di avvio (l'estensione del file è registrata con esso) tenta di aprire una pipa per l'interfaccia utente come client.
  • Se non riesce, avvia una nuova istanza dell'applicazione UI e passa il nome del file come parametro. L'interfaccia utente avvia il lato server della pipe denominata
  • Se pipe viene aperto correttamente, ovvero è già in esecuzione un'istanza dell'interfaccia utente, il programma di avvio invia il nome del file al processo dell'interfaccia utente esistente tramite pipe.
  • Launcher uscite dopo aver superato il lavoro alla UI
+0

Non sembra esserci via libera all'avvio di "alcuni" programmi quando l'utente fa doppio clic su un file associato, e quindi avere un programma di caricamento separato avviare in background ha più senso. Il programma può essere mantenuto piccolo e quindi verrà caricato molto velocemente. Come bonus, posso quindi utilizzare lo stesso programma per coordinare gli aggiornamenti automatici dell'applicazione principale. Grazie per aver studiato il comportamento di Visual Studio. Dal momento che questo tecnicamente risponde alla mia domanda (come imitare Visual Studio), contrassegnerò questa come risposta. Grazie Fratyx !! – user1689175

0

Sono passati quasi 20 anni da quando ho dovuto fare una cosa del genere, ma IIRC, è fare qualcosa di simile:

  1. Prima di tutto, creare un Mailslot (o qualsiasi altro conveniente IPC strumento)
  2. Se ti viene chiesto di aprire un documento del tipo che dovrebbe andare a un'istanza esistente e se non ci sono altri Mailslot, continua su
  3. Se c'è un Mailslot, devi inviare al Mailslot un messaggio aperto con le informazioni del file e poi esci.
  4. Scrive il codice per rispondere ai messaggi aperti Mailslot.

Se si esegue la procedura prima di creare Windows, dovrebbe funzionare come si desidera.

+0

Grazie per la risposta. Questo sta ancora tecnicamente avviando un'altra istanza del programma, tuttavia comunicherà solo al primo e spegnerà. Hai ragione che posso eseguire questo controllo prima che vengano create tutte le finestre, e sarà invisibile all'utente. Segnalo come una risposta accettata se nessuno può suggerire un modo per farlo senza avviare ulteriori istanze. – user1689175

0

ho fatto qualche progetto-modello che implementa questa roba, utilizzando Windows-messaging. Il modello è enorme e contiene alcune altre cose (come la localizzazione, gli aggiornamenti, formclosing, appunti e un'interfaccia per i documenti, in questo modo le azioni nella MDI possono essere facilmente inoltrate ai figli MDI). Se si desidera visualizzare il modello, provare this link (o this link)

Parte del codice:

Win32.cs:

public partial class Win32 
{ 
    //public const int WM_CLOSE = 16; 
    //public const int BN_CLICKED = 245; 
    public const int WM_COPYDATA = 0x004A; 

    public struct CopyDataStruct : IDisposable 
    { 
     public IntPtr dwData; 
     public int cbData; 
     public IntPtr lpData; 

     public void Dispose() 
     { 
      if (this.lpData != IntPtr.Zero) 
      { 
       LocalFree(this.lpData); 
       this.lpData = IntPtr.Zero; 
      } 
     } 
    } 

    [DllImport("user32.dll")] 
    public static extern int SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, ref CopyDataStruct lParam); 

    [DllImport("kernel32.dll", SetLastError = true)] 
    public static extern IntPtr LocalAlloc(int flag, int size); 

    [DllImport("kernel32.dll", SetLastError = true)] 
    public static extern IntPtr LocalFree(IntPtr p); 

} 

Program.cs:

static class Program 
{ 
    static Mutex mutex = new Mutex(true, guid()); 
    static string guid() 
    { 
     // http://stackoverflow.com/questions/502303/how-do-i-programmatically-get-the-guid-of-an-application-in-net2-0 
     Assembly assembly = Assembly.GetExecutingAssembly(); 
     var attribute = (GuidAttribute)assembly.GetCustomAttributes(typeof(GuidAttribute), true)[0]; 
     return attribute.Value; 
    } 

    static int MainWindowHandle 
    { 
     get 
     { 
      return Settings.Default.hwnd; 
     } 
     set 
     { 
      Settings sett = Settings.Default; 
      sett.hwnd = value; 
      sett.Save(); 
     } 
    } 
    public static string GetFileName() 
    { 
     ActivationArguments a = AppDomain.CurrentDomain.SetupInformation.ActivationArguments; 
     // aangeklikt bestand achterhalen 
     string[] args = a == null ? null : a.ActivationData; 
     return args == null ? "" : args[0]; 
    } 

    [STAThread] 
    static void Main() 
    { 
     if (mutex.WaitOne(TimeSpan.Zero, true)) 
     { 
      #region standaard 
      Application.EnableVisualStyles(); 
      Application.SetCompatibleTextRenderingDefault(false); 
      #endregion 
      #region Culture instellen 
      string cult = CultureInfo.CurrentCulture.Name; 
      Thread.CurrentThread.CurrentUICulture = new CultureInfo(cult); 
      Thread.CurrentThread.CurrentCulture = new CultureInfo(cult); 
      #endregion 
      MainForm frm = new MainForm(); 
      MainWindowHandle = (int)frm.Handle; 
      Application.Run(frm); 
      MainWindowHandle = 0; 
      mutex.ReleaseMutex(); 
     } 
     else 
     { 
      int hwnd = 0; 
      while (hwnd == 0) 
      { 
       Thread.Sleep(600); 
       hwnd = MainWindowHandle; 
      } 
      if (hwnd != 0) 
      { 
       Win32.CopyDataStruct cds = new Win32.CopyDataStruct(); 
       try 
       { 
        string data = GetFileName(); 
        cds.cbData = (data.Length + 1) * 2; // number of bytes 
        cds.lpData = Win32.LocalAlloc(0x40, cds.cbData); // known local-pointer in RAM 
        Marshal.Copy(data.ToCharArray(), 0, cds.lpData, data.Length); // Copy data to preserved local-pointer 
        cds.dwData = (IntPtr)1; 
        Win32.SendMessage((IntPtr)hwnd, Win32.WM_COPYDATA, IntPtr.Zero, ref cds); 
       } 
       finally 
       { 
        cds.Dispose(); 
       } 
      } 
     } 
    } 
} 

MainFrom.cs:

[PermissionSet(SecurityAction.Demand, Name = "FullTrust")] 
protected override void WndProc(ref Message m) 
{ 
    switch (m.Msg) 
    { 
     case Win32.WM_COPYDATA: 
      Win32.CopyDataStruct st = (Win32.CopyDataStruct)Marshal.PtrToStructure(m.LParam, typeof(Win32.CopyDataStruct)); 
      string strData = Marshal.PtrToStringUni(st.lpData); 
      OpenFile(strData); 
      Activate(); 
      break; 
     default: 
      // let the base class deal with it 
      base.WndProc(ref m); 
      break; 
    } 
} 

Funziona anche quando si lanciano fino a 15 file contemporaneamente.

Problemi correlati