2009-12-14 11 views
0

Je veux créer un programme qui utilise ClickOnce pour l'installation et enregistre une association de fichiers, et ne démarre toujours qu'une seule instance, de sorte que si un fichier de cette extension de fichier est cliqué à nouveau, il sera envoyé à la première (déjà ouvert) programme.Projet C# ClickOnce SingleInstance - comment?

Quelqu'un connaît-il un bon code-exemple de la façon de faire cela?

Veuillez garder à l'esprit la partie ClickOnce - car cela modifie la façon dont vous devez gérer le bit SingleInstance.

+4

Peut-être que si vous accepté certaines réponses, vous seriez plus enclin à obtenir une bonne aide – Brendan

+0

duplication possible de [Comment puis-je créer une application d'instance unique en utilisant Click Once?] (http://stackoverflow.com/questions/248721/how-can-i -build-a-single-instance-application-using-click-once) –

Répondre

1
+0

Merci, mais cela ignore complètement l'aspect ClickOnce! – Pygmy

+0

ok :(ce qui est différent avec les applications ClickOnce dans cet aspect? –

+0

Qu'une application ClickOnce démarre l'exécutable d'une manière différente qui peut inclure des mises à jour automatiques et transmet des paramètres d'une manière différente, autant que j'ai pu comprendre out ... Mais je ne suis pas sûr de ce que tout cela signifie pour les trucs SingleInstance, ce qui explique pourquoi je pose cette question :) – Pygmy

-1

Vous pouvez faire quelque chose de similaire à ceci:

using System.Diagnostics; 

    namespace Foo 

    { 

     class Bar 

     { 

      static void Main(string[] args) 

      { 

       Process p = Process.GetCurrentProcess(); 

       Process [] processSearch = Process.GetProcessesByName(p.ProcessName); 

       if (processSearch.Length > 1) 

       { 

        return; 

       } 

      } 
     } 
    } 
+0

La vérification par nom de processus ne conduit qu'à des attaques DoS simplistes. Vous devriez utiliser un mutex. –

1

Vous devez utiliser un Mutex pour vérifier si votre application est en cours d'exécution:

static void Main() 
    { 
     bool createdNew; 

     using (Mutex mutex = new Mutex(true, Application.ProductName, out createdNew)) 
     { 
      mutex.ReleaseMutex(); 
      if (createdNew) 
      { 
       Application.EnableVisualStyles(); 
       Application.SetCompatibleTextRenderingDefault(false); 
       Application.Run(new FormMain()); 
      } 
      else 
      { 
       using (Process currentProcess = Process.GetCurrentProcess()) 
       { 
        foreach (Process process in Process.GetProcessesByName(currentProcess.ProcessName)) 
        { 
         if (process.Id != currentProcess.Id) 
         { 
          User32.SetForegroundWindow(process.MainWindowHandle); 
          break; 
         } 
        } 
       } 
      } 
     } 
    } 

Le SetForegroundWindow:

[DllImport("user32.dll")] 
    [return: MarshalAs(UnmanagedType.Bool)] 
    public static extern bool SetForegroundWindow(IntPtr hWnd); 
+0

Notez que ce code va planter. La deuxième instance ne possède pas le mutex. ReleaseMutex() va lancer. Cela devrait aller à l'intérieur de la première condition. –

0

J'ai fait une application qui fonctionne de cette façon. Il utilise des messages Windows pour communiquer. Donc, dans la seconde, vous n'avez besoin que du handle du MainForm en premier lieu. J'ai enregistré ce handle dans un paramètre ClickOnce nommé hwnd.

using ProjectApplicationTemplate.Properties; 
using System; 
using System.Globalization; 
using System.IO; 
using System.Reflection; 
using System.Runtime.Hosting; 
using System.Runtime.InteropServices; 
using System.Threading; 
using System.Windows.Forms; 

namespace ProjectApplicationTemplate 
{ 
    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 
      { 
       Settings.Default.Reload(); 
       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]; 
     } 

     /// <summary> 
     /// The main entry point for the application. 
     /// </summary> 
     [STAThread] 
     static void Main() 
     { 
      if (mutex.WaitOne(TimeSpan.Zero, true)) 
      { 
       #region standaard 
       Application.EnableVisualStyles(); 
       Application.SetCompatibleTextRenderingDefault(false); 
       #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(5); 
        hwnd = MainWindowHandle; 
       } 

       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(); 
       } 
      } 
     } 
    } 
} 

Et dans votre MainForm

using System; 
using System.Data; 
using System.IO; 
using System.Linq; 
using System.Runtime.InteropServices; 
using System.Security.Permissions; 
using System.Windows.Forms; 

namespace ProjectApplicationTemplate 
{ 
    public partial class MainForm : Form 
    { 
     public MainForm() 
     { 
      InitializeComponent(); 
      OpenFile(Program.GetFileName()); 
     } 

     [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; 
      } 
     } 

     void OpenFile(string filename) 
     { 
      if (filename == "") return; 
      if (!File.Exists(filename)) return; 
      IDocument[] vensters = MdiChildren.Select(T => (IDocument)T).Where(T => T.CurrentFileName == filename).ToArray(); 
      if (vensters.Length == 0) 
      { 
       ChildForm frm = new ChildForm(); 
       frm.OpenFile(filename); 
       frm.MdiParent = this; 
       frm.Show(); 
      } 
      else 
      { 
       vensters[0].Activate(); 
      } 
     } 

     private void fileMenu_DropDownOpening(object sender, EventArgs e) 
     { 
      IDocument active = (IDocument)ActiveMdiChild; 
      if (active == null) 
      { 
       saveToolStripMenuItem.Enabled = false; 
       saveAsToolStripMenuItem.Enabled = false; 
       printToolStripMenuItem.Enabled = false; 
       printSetupToolStripMenuItem.Enabled = false; 
       printPreviewToolStripMenuItem.Enabled = false; 
      } 
      else 
      { 
       saveToolStripMenuItem.Enabled = active.Changed; 
       saveAsToolStripMenuItem.Enabled = true; 
       printToolStripMenuItem.Enabled = active.CanPrint; 
       printSetupToolStripMenuItem.Enabled = active.CanPrint; 
       printPreviewToolStripMenuItem.Enabled = active.CanPrint; 
      } 

      // fill the MRU-list 

      tmiOnlangsGeopend.DropDownItems.Clear(); 
      string RecentFolder = Environment.GetFolderPath(Environment.SpecialFolder.Recent); 
      string[] bestanden = Directory.GetFiles(RecentFolder).Where(T => T.EndsWith(".text.lnk")).ToArray(); 
      if (bestanden.Length == 0) 
      { 
       tmiOnlangsGeopend.DropDownItems.Add(new ToolStripMenuItem(Properties.Resources.NoRecent) { Enabled = false }); 
      } 
      else 
      { 
       foreach (string bestand in bestanden.OrderBy(T => File.GetLastWriteTime(T)).Reverse()) 
       { 
        ToolStripMenuItem tmi = new ToolStripMenuItem(Path.GetFileNameWithoutExtension(bestand.Substring(0, bestand.Length - 4))); 
        tmi.Click += delegate { OpenFile(ResolveShortCut(bestand)); }; 
        tmiOnlangsGeopend.DropDownItems.Add(tmi); 
       } 
      } 
     } 

     string ResolveShortCut(string shc) 
     { 
      // Add Reference -> COM -> Windows Script Host Object Model 
      if (File.Exists(shc)) 
      { 
       IWshRuntimeLibrary.WshShell shell = new IWshRuntimeLibrary.WshShell(); 
       IWshRuntimeLibrary.IWshShortcut link = (IWshRuntimeLibrary.IWshShortcut)shell.CreateShortcut(shc); 
       return link.TargetPath; 
      } 
      else 
      { 
       return ""; 
      } 
     } 
    } 
} 

Win32.cs

using System; 
using System.Runtime.InteropServices; 

namespace ProjectApplicationTemplate 
{ 
    public partial class Win32 
    { 
     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; 
       } 
      } 
     } 

     /// <summary> 
     /// The SendMessage API 
     /// </summary> 
     /// <param name="hWnd">handle to the required window</param> 
     /// <param name="Msg">the system/Custom message to send</param> 
     /// <param name="wParam">first message parameter</param> 
     /// <param name="lParam">second message parameter</param> 
     /// <returns></returns> 
     [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); 

    } 
} 

Si quelqu'un veut un peu plus d'informations à ce sujet: http://pieterjan.pro/?a=Projecten_csharp_DrawIt.php

Et celui-ci est modèle aC# avec plein de choses: - péché l'application gle instance avec fichier-associations - Localisation (lors de l'exécution ainsi) - MDI et de l'interface pour parcourir l'utilisateur des commandes - Vérification des mises à jour - liste utilisée plus récemment

http://pieterjan.pro/Projecten/csharp/ProjectApplicationTemplate.zip