C# WndProc 方法未收到预期的消息类型
C# WndProc method not receiving expected Msg type
我一直在尝试使用其记录的 COPYDATA API 与另一个软件进行通信。用户 Xanotos 提供了令人难以置信的帮助 which has the sending method sorted and working fine. I am having issues that the receiving WndProc
method does not seem to catch the expected response. Here is the link to COPYDATA API 参考文档。
目前的方法如下。测试显示 WndProc
确实收到消息,但不是我期望的消息,即 struct
取决于发送的消息。
声明:
[DllImport("User32.dll", SetLastError = true, EntryPoint = "FindWindow")]
public static extern IntPtr FindWindow(String lpClassName, String lpWindowName);
[DllImport("User32.dll", SetLastError = true, EntryPoint = "SendMessage")]
public static extern IntPtr SendMessage(IntPtr hWnd, int Msg, int wParam, ref COPYDATASTRUCT lParam);
[StructLayout(LayoutKind.Sequential)]
public struct COPYDATASTRUCT
{
public IntPtr dwData; // Any value the sender chooses. Perhaps its main window handle?
public int cbData; // The count of bytes in the message.
public IntPtr lpData; // The address of the message.
}
public struct ExternalGetPositionType
{
public double X;
public double Y;
public double Z;
public double W;
}
const int WM_COPYDATA = 0x004A;
const int EXTERNAL_CD_COMMAND_RUN_ASYNC = 0x8001;
const int EXTERNAL_CD_GET_POSITION_PCS = 0x8011;
const int EXTERNAL_CD_GET_POSITION_MCS = 0x8012;
发送方法(这些都工作正常并且 return 正确):
public static IntPtr RunAsync(IntPtr hwnd, string str)
{
// We have to add a [=11=] terminator, so len + 1 / len + 2 for Unicode
int len = Encoding.Default.GetByteCount(str);
var buff = new byte[len + 1]; // len + 2 for Unicode
Encoding.Default.GetBytes(str, 0, str.Length, buff, 0);
IntPtr ret;
GCHandle h = default(GCHandle);
try
{
h = GCHandle.Alloc(buff, GCHandleType.Pinned);
var cds = new COPYDATASTRUCT();
cds.dwData = (IntPtr)EXTERNAL_CD_COMMAND_RUN_ASYNC;
cds.lpData = h.AddrOfPinnedObject();
cds.cbData = buff.Length;
ret = SendMessage(hwnd, WM_COPYDATA, 0, ref cds);
}
finally
{
if (h.IsAllocated)
{
h.Free();
}
}
return ret;
}
public static IntPtr GetPosition(IntPtr hwnd, bool pcs, ExternalGetPositionType position)
{
// We cheat here... It is much easier to pin an array than to copy around a struct
var positions = new[]
{
position
};
IntPtr ret;
GCHandle h = default(GCHandle);
try
{
h = GCHandle.Alloc(positions, GCHandleType.Pinned);
var cds = new COPYDATASTRUCT();
cds.dwData = pcs ? (IntPtr)EXTERNAL_CD_GET_POSITION_PCS : (IntPtr)EXTERNAL_CD_GET_POSITION_MCS;
cds.lpData = h.AddrOfPinnedObject();
cds.cbData = Marshal.SizeOf<ExternalGetPositionType>();
ret = SendMessage(hwnd, WM_COPYDATA, 0, ref cds);
}
finally
{
if (h.IsAllocated)
{
h.Free();
}
}
return ret;
}
WndProc
方法 - 这是事情没有按预期工作的地方。当调用 GetPosition
时,if(m.Msg == WM_COPYDATA)
永远不会 return 为真。
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_COPYDATA) //this does not execute
{
COPYDATASTRUCT cds = Marshal.PtrToStructure<COPYDATASTRUCT>(m.LParam);
label5.Text = "message received";
if (cds.dwData == (IntPtr)EXTERNAL_CD_COMMAND_RUN_ASYNC)
{
label5.Text = "NORMAL";
string str = Marshal.PtrToStringAnsi(cds.lpData);
Debug.WriteLine($"EXTERNAL_CD_COMMAND_RUN_ASYNC: {str}");
toolStripStatusLabel1.Text = $"COMMAND";
m.Result = (IntPtr)100; // If you want to return a value
}
else if (cds.dwData == (IntPtr)EXTERNAL_CD_GET_POSITION_PCS) //this does not execute
{
label5.Text = "MSC";
if (cds.cbData >= Marshal.SizeOf<ExternalGetPositionType>())
{
var position = Marshal.PtrToStructure<ExternalGetPositionType>(cds.lpData);
Debug.WriteLine($"EXTERNAL_CD_GET_POSITION_PCS: X = {position.X}, Y = {position.Y}, Z = {position.Z}, W = {position.W}");
toolStripStatusLabel1.Text = $"External MCS = {position.X}";
label4.Text = position.X.ToString();
m.Result = (IntPtr)200;
}
else
{
m.Result = (IntPtr)0;
}
}
else if (cds.dwData == (IntPtr)EXTERNAL_CD_GET_POSITION_MCS) //this does not execute
{
label5.Text = "MSC"; //this does not execute
if (cds.cbData >= Marshal.SizeOf<ExternalGetPositionType>())
{
var position = Marshal.PtrToStructure<ExternalGetPositionType>(cds.lpData);
Debug.WriteLine($"EXTERNAL_CD_GET_POSITION_MCS: X = {position.X}, Y = {position.Y}, Z = {position.Z}, W = {position.W}");
toolStripStatusLabel1.Text = $"External MCS = {position.X}";
label4.Text = position.X.ToString();
m.Result = (IntPtr)300;
}
else
{
m.Result = (IntPtr)0;
}
}
return;
}
MessageBox.Show(m.Msg.ToString()); //this DOES execute
base.WndProc(ref m);
}
两个程序都是 32 位的。
为什么我没有收到预期的 Msg
?
您提供的文档不清楚,但您似乎需要将 wParam
设置为接收 window 句柄才能接收响应数据。
第 3 页底部有一个示例:
::SendMessage(m_pWnd->GetSafeHwnd(), WM_COPYDATA,(WPARAM)this->GetSafeHwnd( ,(LPARAM)&MyCDS);
而您的代码是这样的:
ret = SendMessage(hwnd, WM_COPYDATA, 0, ref cds);
相反你需要
ret = SendMessage(hwnd, WM_COPYDATA, this.Handle, ref cds);
您 必须 也将 SendMessage
上的 wParam
重新定义为 IntPtr
。它在任何情况下都是错误的,并且可能只是因为你使用的是 32 位才有效。
我一直在尝试使用其记录的 COPYDATA API 与另一个软件进行通信。用户 Xanotos 提供了令人难以置信的帮助 WndProc
method does not seem to catch the expected response. Here is the link to COPYDATA API 参考文档。
目前的方法如下。测试显示 WndProc
确实收到消息,但不是我期望的消息,即 struct
取决于发送的消息。
声明:
[DllImport("User32.dll", SetLastError = true, EntryPoint = "FindWindow")]
public static extern IntPtr FindWindow(String lpClassName, String lpWindowName);
[DllImport("User32.dll", SetLastError = true, EntryPoint = "SendMessage")]
public static extern IntPtr SendMessage(IntPtr hWnd, int Msg, int wParam, ref COPYDATASTRUCT lParam);
[StructLayout(LayoutKind.Sequential)]
public struct COPYDATASTRUCT
{
public IntPtr dwData; // Any value the sender chooses. Perhaps its main window handle?
public int cbData; // The count of bytes in the message.
public IntPtr lpData; // The address of the message.
}
public struct ExternalGetPositionType
{
public double X;
public double Y;
public double Z;
public double W;
}
const int WM_COPYDATA = 0x004A;
const int EXTERNAL_CD_COMMAND_RUN_ASYNC = 0x8001;
const int EXTERNAL_CD_GET_POSITION_PCS = 0x8011;
const int EXTERNAL_CD_GET_POSITION_MCS = 0x8012;
发送方法(这些都工作正常并且 return 正确):
public static IntPtr RunAsync(IntPtr hwnd, string str)
{
// We have to add a [=11=] terminator, so len + 1 / len + 2 for Unicode
int len = Encoding.Default.GetByteCount(str);
var buff = new byte[len + 1]; // len + 2 for Unicode
Encoding.Default.GetBytes(str, 0, str.Length, buff, 0);
IntPtr ret;
GCHandle h = default(GCHandle);
try
{
h = GCHandle.Alloc(buff, GCHandleType.Pinned);
var cds = new COPYDATASTRUCT();
cds.dwData = (IntPtr)EXTERNAL_CD_COMMAND_RUN_ASYNC;
cds.lpData = h.AddrOfPinnedObject();
cds.cbData = buff.Length;
ret = SendMessage(hwnd, WM_COPYDATA, 0, ref cds);
}
finally
{
if (h.IsAllocated)
{
h.Free();
}
}
return ret;
}
public static IntPtr GetPosition(IntPtr hwnd, bool pcs, ExternalGetPositionType position)
{
// We cheat here... It is much easier to pin an array than to copy around a struct
var positions = new[]
{
position
};
IntPtr ret;
GCHandle h = default(GCHandle);
try
{
h = GCHandle.Alloc(positions, GCHandleType.Pinned);
var cds = new COPYDATASTRUCT();
cds.dwData = pcs ? (IntPtr)EXTERNAL_CD_GET_POSITION_PCS : (IntPtr)EXTERNAL_CD_GET_POSITION_MCS;
cds.lpData = h.AddrOfPinnedObject();
cds.cbData = Marshal.SizeOf<ExternalGetPositionType>();
ret = SendMessage(hwnd, WM_COPYDATA, 0, ref cds);
}
finally
{
if (h.IsAllocated)
{
h.Free();
}
}
return ret;
}
WndProc
方法 - 这是事情没有按预期工作的地方。当调用 GetPosition
时,if(m.Msg == WM_COPYDATA)
永远不会 return 为真。
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_COPYDATA) //this does not execute
{
COPYDATASTRUCT cds = Marshal.PtrToStructure<COPYDATASTRUCT>(m.LParam);
label5.Text = "message received";
if (cds.dwData == (IntPtr)EXTERNAL_CD_COMMAND_RUN_ASYNC)
{
label5.Text = "NORMAL";
string str = Marshal.PtrToStringAnsi(cds.lpData);
Debug.WriteLine($"EXTERNAL_CD_COMMAND_RUN_ASYNC: {str}");
toolStripStatusLabel1.Text = $"COMMAND";
m.Result = (IntPtr)100; // If you want to return a value
}
else if (cds.dwData == (IntPtr)EXTERNAL_CD_GET_POSITION_PCS) //this does not execute
{
label5.Text = "MSC";
if (cds.cbData >= Marshal.SizeOf<ExternalGetPositionType>())
{
var position = Marshal.PtrToStructure<ExternalGetPositionType>(cds.lpData);
Debug.WriteLine($"EXTERNAL_CD_GET_POSITION_PCS: X = {position.X}, Y = {position.Y}, Z = {position.Z}, W = {position.W}");
toolStripStatusLabel1.Text = $"External MCS = {position.X}";
label4.Text = position.X.ToString();
m.Result = (IntPtr)200;
}
else
{
m.Result = (IntPtr)0;
}
}
else if (cds.dwData == (IntPtr)EXTERNAL_CD_GET_POSITION_MCS) //this does not execute
{
label5.Text = "MSC"; //this does not execute
if (cds.cbData >= Marshal.SizeOf<ExternalGetPositionType>())
{
var position = Marshal.PtrToStructure<ExternalGetPositionType>(cds.lpData);
Debug.WriteLine($"EXTERNAL_CD_GET_POSITION_MCS: X = {position.X}, Y = {position.Y}, Z = {position.Z}, W = {position.W}");
toolStripStatusLabel1.Text = $"External MCS = {position.X}";
label4.Text = position.X.ToString();
m.Result = (IntPtr)300;
}
else
{
m.Result = (IntPtr)0;
}
}
return;
}
MessageBox.Show(m.Msg.ToString()); //this DOES execute
base.WndProc(ref m);
}
两个程序都是 32 位的。
为什么我没有收到预期的 Msg
?
您提供的文档不清楚,但您似乎需要将 wParam
设置为接收 window 句柄才能接收响应数据。
第 3 页底部有一个示例:
::SendMessage(m_pWnd->GetSafeHwnd(), WM_COPYDATA,(WPARAM)this->GetSafeHwnd( ,(LPARAM)&MyCDS);
而您的代码是这样的:
ret = SendMessage(hwnd, WM_COPYDATA, 0, ref cds);
相反你需要
ret = SendMessage(hwnd, WM_COPYDATA, this.Handle, ref cds);
您 必须 也将 SendMessage
上的 wParam
重新定义为 IntPtr
。它在任何情况下都是错误的,并且可能只是因为你使用的是 32 位才有效。