0

I want to create a program that uses ClickOnce for installation and registers a file-association, and always only starts a single instance, so that if a file of that file extension is clicked again it will be sent to the first (already opened) program.

Does anybody know of a good code-example of how to do that ?

Please keep in mind the ClickOnce part - because that changes how one should handle the SingleInstance bit.

Pygmy
  • 675
  • 2
  • 10
  • 13
  • 4
    Maybe if you accepted some answers, you'd be more prone to get good help – Brendan Lesniak Dec 14 '09 at 14:32
  • possible duplicate of [How can I build a single instance application using Click Once?](http://stackoverflow.com/questions/248721/how-can-i-build-a-single-instance-application-using-click-once) – Dour High Arch Aug 31 '10 at 04:48

5 Answers5

1

I guess this will help you: http://www.openwinforms.com/single_instance_application.html

Carl Hörberg
  • 5,973
  • 5
  • 41
  • 47
  • Thanks, but this completely ignores the ClickOnce aspect! – Pygmy Dec 14 '09 at 14:42
  • ok :( what is different with ClickOnce applications in that aspect? – Carl Hörberg Dec 14 '09 at 18:28
  • That a ClickOnce application starts the executable in a different way which can include auto-updates and passes parameters in a different way, as far as I've been able to figure out... But I'm not sure what all of this means for the SingleInstance stuff, which is why I'm asking this question :) – Pygmy Dec 15 '09 at 09:10
  • the problems seems to be solved here: http://stackoverflow.com/questions/248721/how-can-i-build-a-single-instance-application-using-click-once – Carl Hörberg Dec 15 '09 at 12:39
1

You should use a Mutex to check if you application is running:

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

The SetForegroundWindow:

    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool SetForegroundWindow(IntPtr hWnd);
Cory Charlton
  • 8,868
  • 4
  • 48
  • 68
  • Note that this code will crash. Second instance doesn't own the mutex. ReleaseMutex() will throw. It should go inside the first condition. – Robert Važan Jun 25 '14 at 20:59
0

Same question over here: How can I build a single instance application using Click Once?

Try this on: http://northhorizon.net/2010/single-instance-clickonce/

Community
  • 1
  • 1
Daniel Moore
  • 1,116
  • 1
  • 9
  • 16
0

I made an application that works this way. It uses Windows-messages to communicate. So in the seconde instance, you only need the Handle of the MainForm in the first instance. I saved this handle in a ClickOnce setting named 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();
                }
            }
        }
    }
}

And in your 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);

    }
}

If anyone wants some more information about this: http://pieterjan.pro/?a=Projecten_csharp_DrawIt.php

And this one is a c# template featuring loads of stuff: - single-instance application with file-associations - Localization (at runtime as well) - MDI and interface for traversing the user commands - Checking for updates - Most-recently used list

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

-1

You could do something similar to this:

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;

                }

            }
         }
    }
Benjamin Ortuzar
  • 7,801
  • 6
  • 41
  • 46