使用SendMessage()向不同进程循环发送消息

本文关键字:循环 进程 消息 SendMessage 使用 | 更新日期: 2023-09-27 18:07:51

UPD: added MCVE.

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

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

我必须使两个不同的应用程序与GUI通信的消息。在收到"start"这样的消息后,1 app必须开始每5秒向2 app发送"Ask value"消息。2 app1 app发送消息"send value",并附带一些数据。

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都是正确的。


更新:I tried check error here:

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秒从不同的线程发送此消息

使用SendMessage()向不同进程循环发送消息

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