带有用于 IPC 的 WndProc 覆盖的本机 SendMessage 不起作用

Posted

技术标签:

【中文标题】带有用于 IPC 的 WndProc 覆盖的本机 SendMessage 不起作用【英文标题】:Native SendMessage with WndProc Override for IPC not working 【发布时间】:2013-11-13 20:27:42 【问题描述】:

我有一个没有参数或标志的 WPF 应用程序。在App.xaml.cs 中,我添加了一个OnStartUp 处理程序,该处理程序尝试对应用程序的另一个实例执行一些IPC,如果它使用参数执行。例如,我的主应用程序可以通过简单地执行mainApp 来启动,这将加载主窗口。然后我可能稍后会执行mainApp msg bob some_message,它将传递OnStartUp 中的条件并将“msg bob some_message”发送到正在运行的应用程序以在其WndProc 覆盖中处理。

App.xaml.cs 中的代码:

private void OnStartUp(object sedner, StartupEventArgs e)

   Process localProcess = Process.GetCurrentProcess();

   foreach (Process process in Process.GetProcessesByName(localProcess.ProcessName))
   
      if (process.Id != localProcess.Id)
      
         NativeMethods.SendMessage(process.MainWindowHandle, NativeMethods.HWND_IPC, IntPtr.Zero, IntPtr.Zero);
         Environment.Exit(0);
      
   

主窗口代码隐藏中的代码:

public IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr iParam, ref bool handled)

   if (msg == NativeMethods.HWND_IPC)
   
      MessageBox.Show("Message Received!");
   

   return IntPtr.Zero;


internal class NativeMethods

   public const int HWND_BROADCAST = 0xffff;
   public const int HWND_IPC = 0xfffe;
   public static readonly int WM_IPC = RegisterWindowMessage("WM_IPC");
   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.dll")]//, CharSet = CharSet.Auto, SetLastError = true)]
   public static extern IntPtr SendMessage(IntPtr hwnd, uint Msg, IntPtr wParam, IntPtr lParam);
   [DllImport("user32")]
   public static extern int RegisterWindowMessage(string message);

我已经尝试过多次使用 PostMessage、SendMessage、仅使用静态 int 消息,实际上调用 RegisterWindowMessage。似乎没有任何效果。

此外,我希望不仅能够指定特定消息,还希望能够指定其他动态详细信息,例如用户名和一些消息文本。

【问题讨论】:

How to handle WndProc messages in WPF?的可能重复 【参考方案1】:

您正在发送消息 HWND_IPC(窗口句柄?)而不是 WM_IPC。 HWND_IPC 的值为 0xFFFE,不在用户消息 WM_USER+x 的范围内。

您不能以这种方式传输数据。有一个 WM_COPYDATA 复制 从一个进程的私有地址空间到另一个进程的给定缓冲区...

我认为您应该使用命名管道来传输数据。 SendMessage 是如此 Win31 ;-)

【讨论】:

我希望我能绕过编写管道服务器的整个问题。我想我应该能够用两个左右非常短的方法通过本机窗口消息传递来实现这一点。 我认为命名管道解决方案是最方便的:您设置一个“服务器”流并等待一些“客户端”连接。然后,您可以像通过任何其他流一样传输数据。这是 NamedPipeServerStream:msdn.microsoft.com/en-us/library/… 这是 NamedPipeClientStream:msdn.microsoft.com/en-us/library/… 那里的代码示例几乎涵盖了它。 我们说话的时候检查一下。感谢您的链接!【参考方案2】:

我认为您需要覆盖,但我不确定它是否存在于 WPF 视图中:

试试这个:

protected override void WndProc( etc...

[更新] 不能以这种方式覆盖 WPF 的 Window 类中的 WndProc。

How to handle WndProc messages in WPF?

将解释你需要一个钩子:

    protected override void OnSourceInitialized(EventArgs e)
    
        base.OnSourceInitialized(e);
        HwndSource source = PresentationSource.FromVisual(this) as HwndSource;
        source.AddHook(WndProc);
    

把这些放在一起:

在您的 App.xml.cs 中,您将初始化您的 App 启动参数。创建一些静态属性是最简单的。保持简单,没有集合以避免以后多线程崩溃:

/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application

    public static string SomeValue  get; private set; 

    protected override void OnStartup(StartupEventArgs e)
    
        base.OnStartup(e);
        SomeValue = e.Args[0];
    

现在您只需调用App.SomeValue,即可在整个代码中访问SomeValue

然后;必须将 WndProc 实现到窗口中。一个窗口有一个消息泵。如果没有消息泵,您将无法发送消息(您可以创建自己的消息,但这太多了)

所以在一个窗口中,例如 MainWindow,实现覆盖:

public partial class MainWindow : Window

    public MainWindow()
      
        InitializeComponent();
    

    protected override void OnSourceInitialized(EventArgs e)
    
        base.OnSourceInitialized(e);
        HwndSource source = PresentationSource.FromVisual(this) as HwndSource;
        source.AddHook(WndProc);
    

    public IntPtr WndProc(IntPtr hwnd, int msg, 
                          IntPtr wParam, IntPtr iParam, ref bool handled)
    
        if (msg == NativeMethods.HWND_IPC)
            MessageBox.Show("Message Received!");

        return IntPtr.Zero;
    


internal class NativeMethods


etc. etc.

唯一要实现的是触发消息的时刻,但由于它是 IPC,因此您基本上可以从任何地方发送它,只要您有目标窗口的句柄。

将此信息与 Franks 关于 WM_COPYDATA 的评论结合起来,就可以开始使用了。有关 WM_COPYDATA 的信息:

http://msdn.microsoft.com/en-us/library/windows/desktop/ms649011%28v=vs.85%29.aspx

希望对你有帮助。

【讨论】:

感谢您的回复。那个覆盖不是有像“ref Message message”这样的参数吗?我的目标是框架 4,所以我认为我不能使用类型 Message 谢谢,刚刚看了更新。我以前尝试过与此非常相似的方法,但问题是 WndProc 在我的 MainWindow 类中。每当我尝试通过 App.xaml.cs 访问时,我都会得到“对象未使用”异常。 我无法编译它。不过,我仍在使用 App.xaml StartUp 事件处理程序。我看不到 SourceInitialization 的任何内容。 但是当我的应用程序以这种方式启动时,这不会影响我处理命令行参数的能力吗?我以为只有在顶层的 App.xaml 中直接处理 OnStartUp 时才能获得必要的 e.Args 数组。

以上是关于带有用于 IPC 的 WndProc 覆盖的本机 SendMessage 不起作用的主要内容,如果未能解决你的问题,请参考以下文章

IPC_RMID 不适用于带有 C++ 的 linux

TControl的消息覆盖函数大全(15个WM_函数和17个CM_函数,它的WndProc就处理鼠标与键盘消息)

TWinControl的消息覆盖函数大全(41个WM_函数和31个CM_函数,它的WndProc就处理鼠标(转发)键盘(取消拖动)焦点和WM_NCHITTEST一共4类消息)

如何在 WPF 中处理 WndProc 消息?

Win32 ListBox WNDPROC 从未调用过

IPC进程间通讯之二管道Pipe