【问题标题】:If an instance of the application is already running, call a method within the already running instance如果应用程序的一个实例已经在运行,则在已经运行的实例中调用一个方法
【发布时间】:2016-02-18 00:16:32
【问题描述】:

我有一个由系统托盘 notifyIcon 及其上下文菜单组成的应用程序。在 program.cs 代码中,我使用 Mutex 来检查程序实例是否已经在运行,然后再启动一个新实例。目前,如果一个已经在运行,那么新实例就在那里退出。相反,当用户尝试启动应用程序的新实例时,我希望它触发正在运行的实例中 notifyIcon 的上下文菜单。有没有办法做到这一点?有没有一种好方法可以在已经运行的进程中调用方法并告诉它打开菜单?

我发现this 有趣的文章,参考this 文章。两者都有一些非常有前途的代码,说明如何基本上做我想做的事情。但是,他们的代码覆盖了我对此知之甚少的 WndProc 方法。当我使用他们的代码时,我得到了“找不到合适的方法来覆盖”的错误,我收集到这是因为我的 notifyIcon 和上下文菜单的主要代码没有实际的形式,并且根据我对here 的有限理解, WndProc 是一个实际形式的方法。

我是否了解他们的解决方案以及我得到的错误是否正确?如果不是请解释一下,我很高兴学习。如果我理解,那么有没有一种方法可以让我只触发一个 notifyIcon 的上下文菜单而不必有一个实际的表单?

注意:作为记录,我的 program.cs 遵循提供的第二个链接中的格式。

如前所述,我的 program.cs 与第二个链接中的几乎相同,但这里要明确一点:

using System;
using System.Threading;
using System.Windows.Forms;

namespace Context_Menu
{
    static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>

        static Mutex mutex = new Mutex(true, "{41264ee37e7688d64250ffb50dc681d2}");

        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);

            if (mutex.WaitOne(TimeSpan.Zero, true))
            {
                Application.Run(new PCMLnotifyIcon());
                mutex.ReleaseMutex();
            }
            else
            {
                // send our Win32 message to make the currently running instance
                // jump on top of all the other windows
                NativeMethods.PostMessage(
                    (IntPtr)NativeMethods.HWND_BROADCAST,
                    NativeMethods.WM_SHOWME,
                    IntPtr.Zero,
                    IntPtr.Zero);
            }
        }
    }
}

我的 NativeMethods 类也与链接中的类相同,如下所示:

internal class NativeMethods {
    public const int HWND_BROADCAST = 0xffff;
    public static readonly int WM_SHOWME = RegisterWindowMessage("WM_SHOWME");
    [DllImport("user32")]
    public static extern bool PostMessage(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam);
    [DllImport("user32")]
    public static extern int RegisterWindowMessage(string message);
}

最后,PCMLNotifyIcon 很大程度上基于this 指南,因此只是一个没有随附表单的 notifyIcon。这是一个 sn-p,显示了我从第二个链接中删除代码的位置:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Windows.Forms;

namespace Context_Menu
{
    class PCMLnotifyIcon : ApplicationContext
    {  
        private NotifyIcon niIcon;
        private ContextMenuStrip cmsMenu;
        private ToolStripMenuItem tsmiUpdate;
        private ToolStripSeparator tssOne;
        private ToolStripMenuItem tsmiQuickAdd;
        private ToolStripSeparator tssTwo;
        private ToolStripSeparator tssThree;
        private ToolStripMenuItem tsmiSettings;
        private ToolStripMenuItem tsmiAbout;
        private ToolStripMenuItem tsmiFeedback;
        private ToolStripMenuItem tsmiExit;

        public PCMLnotifyIcon()
        {
            InitializeComponent();
        }
        protected override void WndProc(ref Message m)
        {
            if (m.Msg == NativeMethods.WM_SHOWME)
            {
                ShowMe();
            }
            base.WndProc(ref m);
        }

如上所述,我怀疑给出的错误是因为缺少表单:错误1

'Context_Menu.PCMLnotifyIcon.WndProc(参考 System.Windows.Forms.Message)': 找不到合适的方法来覆盖

【问题讨论】:

  • 选择 IPC。 “我收到了错误” - 请发布您的代码。见minimal reproducible example
  • “因为我的 notifyIcon 和上下文菜单的主要代码没有实际的形式” - 您是否使用 NotifyIcon 而不将其嵌入到 Form 中?
  • 我确实是。我正在使用这里详述的方法。 codeproject.com/Tips/627796/… 原因是程序启动时不需要表单。只是 notifyIcon 及其菜单。
  • 我用要显示的代码更新了问题。就像我在原始问题中提到的那样,代码与第二个链接几乎没有变化,问题似乎在于我没有实际的形式。所以我假设这意味着我需要找到一种完全不同的方法来解决这个问题?

标签: c# winforms ipc


【解决方案1】:

我会提供一些代码,但我不确定您要完成什么。相反,我会看看能否为您指明正确的方向 :) 在一个非常相似的情况下,我使用了 IPC 频道并取得了巨大成功。但是,似乎这已被弃用,有利于 WCF。不过看起来还不错。您可以使用命名管道代替 TCP,它应该非常高效。我想你会发现这比窗口消息更可靠,窗口消息充其量是笨重的。您可以轻松地以原生方式传递相当大且复杂的有效负载。

查看这篇文章:https://gorillacoding.wordpress.com/2013/02/03/using-wcf-for-inter-process-communication/

这是另一个您可能会发现有用的示例:http://adndevblog.typepad.com/cloud_and_mobile/2013/12/inter-process-communication-using-wcf.html

编辑:作为奖励,您可以删除互斥体以支持测试命名管道的存在

【讨论】:

  • 啊,是的 .NET Remoting。我同意作为直接的通信选择(即使对于本地计算机),它已被弃用。尽管在沙盒插件系统中与孩子AppDomains 进行通信,但我离题了:) 顺便说一句,“IPC”只是指一个程序与另一个程序通信的功能。它实际上并不指任何特定的交通工具。技术或协议。 .NET Remoting 是一个 IPC 但它不是 IPC
  • “我不确定 MSMQ 在哪里输入图片” - 哦不,那是我的错。我看到“比窗口消息”,想到了MSMQ。我现在看到 OP 正在通过 Windows 消息泵发布消息。对不起朋友
  • 是的,我也可以更具体地了解 IPC,这就是我所引用的:msdn.microsoft.com/en-us/library/…
  • 是的,Microsoft 将许多人与“IPC”名称混淆了。他们的意思是命名管道。洛瑞在他的awesome book 中提到了这一点。 :P
  • 我仍然会保留互斥锁...管道很棒,只是在不编写一些(可能很多?)脚手架代码的情况下确保唯一性不太好...
【解决方案2】:

我讨厌颠倒范式,但你为什么不选择使用管道之类的东西?恕我直言,这样做会容易得多。继续讨论手头的主要问题:在ShowMe(); 之后,添加return。像这样:

protected override void WndProc(ref Message m)
{
    if (m.Msg == NativeMethods.WM_SHOWME)
    {
        ShowMe();
        return;  // <-- right here!
    }
    base.WndProc(ref m);
}

HTH!

【讨论】:

  • 感谢您的建议,但我不确定我是否看到这会有所帮助。但是,我试了一下,但我仍然遇到 WndProc 实际上不是我的类派生自 ApplicationContext 的方法的问题。我认为该方法仅在您有实际表格时才可用。除非我在这里误会了你。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-10-09
  • 1970-01-01
  • 2013-07-30
  • 1970-01-01
  • 2010-10-02
  • 2015-01-24
  • 1970-01-01
相关资源
最近更新 更多