【问题标题】:C# ClickOnce SingleInstance project - how?C# ClickOnce SingleInstance 项目 - 如何?
【发布时间】:2010-12-26 10:52:58
【问题描述】:

我想创建一个程序使用 ClickOnce 进行安装并注册一个文件关联, 并且总是只启动一个实例,因此如果再次单击该文件扩展名的文件,它将被发送到第一个(已经打开的)程序。

有人知道如何做到这一点的好代码示例吗?

请记住 ClickOnce 部分 - 因为这会改变处理 SingleInstance 位的方式。

【问题讨论】:

标签: c# clickonce single-instance


【解决方案1】:

【讨论】:

  • 谢谢,但这完全忽略了 ClickOnce 方面!
  • ok :( ClickOnce 应用程序在这方面有什么不同?
  • ClickOnce 应用程序以不同的方式启动可执行文件,其中可以包括自动更新并以不同的方式传递参数,据我所知......但我我不确定这一切对 SingleInstance 意味着什么,这就是我问这个问题的原因:)
  • 问题似乎在这里解决了:stackoverflow.com/questions/248721/…
【解决方案2】:

您应该使用 Mutex 来检查您的应用程序是否正在运行:

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

SetForegroundWindow:

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

【讨论】:

  • 注意这段代码会崩溃。第二个实例不拥有互斥锁。 ReleaseMutex() 将抛出。它应该进入第一个条件。
【解决方案3】:
【解决方案4】:

我制作了一个以这种方式工作的应用程序。它使用 Windows 消息进行通信。所以在第二个实例中,您只需要第一个实例中的 MainForm 的句柄。我将此句柄保存在名为 hwnd 的 ClickOnce 设置中。

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

在你的 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);

    }
}

如果有人想了解更多关于此的信息: http://pieterjan.pro/?a=Projecten_csharp_DrawIt.php

这是一个包含大量内容的 c# 模板: - 具有文件关联的单实例应用程序 - 本地化(在运行时也是如此) - 用于遍历用户命令的 MDI 和接口 - 查询更新 - 最近使用列表

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

【讨论】:

    【解决方案5】:

    你可以做类似这样的事情:

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

    【讨论】:

    • 按进程名称检查只会导致简单的 DoS 攻击。您应该使用互斥锁。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多