【问题标题】:Cyclic sending of messages to different procces using SendMessage()使用 SendMessage() 将消息循环发送到不同的进程
【发布时间】:2015-08-14 09:52:54
【问题描述】:

UPD:添加了 MCVE。

这是一项教育任务。我必须使用SendMessage()函数:

[DllImport("user32.dll")]
public static extern IntPtr SendMessage(IntPtr hWnd, 
    uint wMsg, UIntPtr wParam, IntPtr lParam);

我必须通过消息的 GUI 通信来制作两个不同的应用程序。在收到类似“开始”1 app 的消息后,必须每 5 秒开始向2 app 发送消息“询问值”。并且2 app 发送到1 app 消息“发送值”以及一些数据。

1 app是WinForms程序:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace Oven_Monitor
{
    public partial class Form1 : Form
    {
        [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
        public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern int GetCurrentProcessId();

        [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        static extern uint RegisterWindowMessage(string lpString);

        [DllImport("user32.dll")]
        public static extern IntPtr SendMessage(IntPtr hWnd, uint wMsg, UIntPtr wParam, IntPtr lParam);

        private uint askMessageID      = RegisterWindowMessage("Ask value");
        private uint dataMessageID     = RegisterWindowMessage("Send value");
        private uint registerMessageID = RegisterWindowMessage("Register sensor");

        public Form1() {
            InitializeComponent();
            this.Text = "Really rare title";
        }

        public void checkSensors() {
            while (true) {
                SendMessage(secondAppHWnd, askMessageID, (UIntPtr)0, (IntPtr)0);
                System.Threading.Thread.Sleep(500);
            }
        }

        private IntPtr secondAppHWnd;

        protected override void WndProc(ref Message m) {
            if (m.Msg == registerMessageID) {
                secondAppHWnd = m.LParam;
                Thread tr = new Thread(checkSensors);
                tr.Start();
            } else if (m.Msg == dataMessageID) {
                //do some stuff
            }
            base.WndProc(ref m);
        }
    }
}

2 app 是控制台项目,但它需要System.Windows.Forms 引用:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace HeatSensor
{
    class Program
    {
        [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
        public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

        static void Main(string[] args)
        {
            IntPtr mainAppHandle = FindWindow(null, "Really rare title");
            while (mainAppHandle == IntPtr.Zero)
            {
                Console.ReadKey();
                mainAppHandle = FindWindow(null, "Really rare title");
            }
            HiddenForm form = new HiddenForm(mainAppHandle);

            while (true) //it's actually not infinit
            {
                //do some stuff
            }
        }
    }
}

以及隐藏表单类:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace HeatSensor
{
    public partial class HiddenForm : Form
    {
        [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
        public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

        [DllImport("user32.dll")]
        public static extern IntPtr SendMessage(IntPtr hWnd, uint wMsg, UIntPtr wParam, IntPtr lParam);

        [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        static extern uint RegisterWindowMessage(string lpString);

        static private IntPtr mainAppHandle;

        public HiddenForm(IntPtr mainAppHWnd)
        {
            InitializeComponent();
            mainAppHandle = mainAppHWnd;
            string title = System.DateTime.Now.ToLongDateString();
            title += System.DateTime.Now.ToLongTimeString();
            title += System.DateTime.Now.Ticks.ToString();
            this.Text = title;
            this.CreateHandle();
            int currentWindowHandle = (int)FindWindow(null, title);
            SendMessage(mainAppHandle, RegisterWindowMessage("Register sensor"),
                (UIntPtr)0, currentWindowHandle);
        }

        private uint askMessageID = RegisterWindowMessage("Ask value");
        private uint dataMessageID = RegisterWindowMessage("Send value");
        private uint registerMessageID = RegisterWindowMessage("Register sensor");

        protected override void WndProc(ref Message m)
        {
            if (m.Msg == askMessageID)
            {
                SendMessage(mainAppHandle, dataMessageID, (UIntPtr)1, (IntPtr)1);
            }
            base.WndProc(ref m);
        }
    }
}

由于某种原因,这个程序表现得很奇怪。几乎每次2 app 都没有收到“询问价值”消息,有时checkSensors() 发送 1-3 条消息并停止。

怎么了?

两个 HWnd 都是正确的。


更新:我试图在这里检查错误:

public void checkSensors() {
    while (true) {
        SendMessage(secondAppHWnd, askMessageID, (UIntPtr)0, (IntPtr)0);
        int error = Marshal.GetLastWin32Error();                
        System.Threading.Thread.Sleep(500);
    }
}

然后看看。在执行SendMessage 时,该线程被阻塞(意味着SendMessage 未完成。在我关闭2 app 后,线程被解除阻塞,我收到164 错误(ERROR_MAX_THRDS_REACHED:系统中无法创建更多线程。 ). 它应该是什么意思?

另外,补充:

protected override void WndProc(ref Message m)
            {
                //here is all message checks
                int erro2r = Marshal.GetLastWin32Error();
                if (erro2r != 0) {
                    int j; //stop to debug here
                }
                base.WndProc(ref m);
            }

它只是不断地返回 1400 ERROR_INVALID_WINDOW_HANDLE(我当时不发送任何消息)。

所以我看起来完全不清楚。


更新 2:如果我从 WndProc() 调用它,一切正常:

SendMessage(secondAppHWnd, askMessageID, (UIntPtr)0, (IntPtr)0);

但我需要每 5 秒从不同的线程发送此消息。

【问题讨论】:

  • HWNDs 可能是正确的,但您的 P/Invoke 签名完全错误。对于hWndlParam,您必须使用IntPtrwParam 应该使用 UIntPtr 类型。同样,返回值应该是IntPtr。如果您想保持 CLS 兼容,请使用 IntPtr 进行上述所有操作。
  • 请制作一个 MCVE。停止多次调用 RegisterWindowMessage。添加错误检查。也请考虑做一些调试。尝试在没有调试的情况下进行编程是没有效率的。
  • 您不会在任何地方检查错误。
  • 没有。您调用的 Win32 函数不会引发异常。你不检查错误。
  • 不清楚是哪个线程在运行隐藏表单。该线程需要泵送消息。隐藏表单的SendMessage 挂起这一事实强烈表明隐藏表单位于未发送消息的线程上。

标签: c# winapi ipc sendmessage


【解决方案1】:

所以,如果两个程序都是 WinForms 项目,它最终可以工作。我可以从2 app 运行控制台窗口并隐藏主窗口。

【讨论】:

  • 这与其说是一种解决方案,不如说是一种解决方法。您放弃了尝试理解消息泵的尝试,而是改用另一种设计,让其他人为您运行消息泵。
猜你喜欢
  • 2023-03-23
  • 2016-10-27
  • 1970-01-01
  • 2011-07-21
  • 1970-01-01
  • 1970-01-01
  • 2021-05-05
  • 2017-02-04
  • 1970-01-01
相关资源
最近更新 更多