【发布时间】: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 签名完全错误。对于hWnd和lParam,您必须使用IntPtr。wParam应该使用UIntPtr类型。同样,返回值应该是IntPtr。如果您想保持 CLS 兼容,请使用IntPtr进行上述所有操作。 -
请制作一个 MCVE。停止多次调用 RegisterWindowMessage。添加错误检查。也请考虑做一些调试。尝试在没有调试的情况下进行编程是没有效率的。
-
您不会在任何地方检查错误。
-
没有。您调用的 Win32 函数不会引发异常。你不检查错误。
-
不清楚是哪个线程在运行隐藏表单。该线程需要泵送消息。隐藏表单的
SendMessage挂起这一事实强烈表明隐藏表单位于未发送消息的线程上。
标签: c# winapi ipc sendmessage