又是我!
这个问题很难,因为我会尽力解释它:正如我在上一个问题中提到的,我正在使用提供程序发送的 C++ dll 在 C# 上进行扫描程序管理。根据API的手册,在某些条件下会发送某些消息。例如:启动扫描程序后,它应DEVICE_CONNECTED发送消息(值为 0),然后更改其状态。
这些消息值在.dll中定义
我的问题是尝试在我的 C# 项目上获取这些消息
我一直在寻找有关消息传输的信息,我发现有一个处理Windows消息的WndProc,因为我尝试遵循他们的例子:
private const int DEVICE_CONNECTED = 0;
/*Some code*/
[System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust")]
protected override void WndProc(ref Message m)
{
if (m.Msg == DEVICE_CONNECTED)
listBox1.Items.Add("Connected");
base.WndProc(ref m);
}
当然,那次失败了。
后来,我一直在检查 API 的手册,我想我得到了一个线索,我可以从哪里获取消息:
// This is how is defined at .dll (C++)
DWORD StartUp( HWND Handle, UINT SorterMessage )
其中"句柄"是应用程序消息目标窗口的句柄。
所以我的 C# 导入如下所示:
[DllImport(path, EntryPoint = "?StartUp@@YGKPAUHWND__@@I@Z")]
public static extern int StartUp(IntPtr HWMD, uint SorterMessage);
现在我得到了一个指针,我可以从中提取消息。我的问题是:如何?
我在另一个论坛中找到了这个例子:
[Serializable, StructLayout(LayoutKind.Sequential)]
public struct MSG
{
public IntPtr hwnd;
public int message;
public IntPtr wParam;
public IntPtr lParam;
public int time;
public int pt_x;
public int pt_y;
};
[DllImport("user32.dll", CharSet = CharSet.Ansi)]
public static extern bool GetMessage([In, Out] ref MSG msg, IntPtr hWnd, int uMsgFilterMin, int uMsgFilterMax);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr DispatchMessage([In] ref MSG msg);
MSG msg = new MSG();
while (GetMessage(ref msg, IntPtr.Zero, 0, 0))
DispatchMessage(ref msg);
我尝试使用它,如下所示:
// Added a constructor inside of the struct:
public MSG(IntPtr hwndPtr)
{
hwnd = hwndPtr;
message = -1;
wParam = new IntPtr();
lParam = new IntPtr();
time = 0;
pt_x = 0;
pt_y = 0;
}
// Left the dll imports like in their example (although I fixed the path)
// Calling the method in my main
int ID, st;
ID = Class1.StartUp(hwnd, 10); // Just used 10 like in the API's manual
Console.WriteLine("Turning on device");
MSG msg = new MSG(hwnd);
while(Class1.GetMessage(ref msg, IntPtr.Zero, 0, 0))
Class1.DispatchMessage(ref msg);
Console.WriteLine(msg.message);
do { Class1.GetState(ID, out st); }
while (st != (int) DevStates.chgParams);
Console.WriteLine("Device on");
我期待什么?打印"打开设备"后,我会收到消息(因为在启动期间,根据手动,它会在更改状态之前发送一条消息),然后是"设备打开"字符串。
我能得到什么?打印"打开设备"程序后,除了闪烁光标外什么都不做(当然,"设备打开"字符串永远不会出现)。看起来它正在等待任何消息。尝试将消息呼叫放在不同的地方,行为是相同的。
有什么建议吗?提前谢谢。
解决了(终于)
我是这样做的:
- 使用的窗口窗体,因为它具有类"消息">
- 导入了我正在处理的.dll,以使事情变得更容易,放置 "ScanMgr"类中的所有方法。
using ...
using APIcsharp;
class ScanMgr
{
int ID = 0;
public string startUp(IntPtr hwmd, uint wmApp)
{
int state;
ID = NativeAPI.StartUp(hwmd, wmApp);
if(ID != 0)
{
do { NativeAPI.GetState(ID, out state); }
while(state == (int)(DevStates.StartingUp)); // DevStates is a enum
return "Device on";
}
return "Error turning on";
}
/* Other stuff to do */
}
- 然后,为消息定义一个覆盖方法
public partial class Form1 : Form
{
const uint wm_channel = 0x8000 + 1;
ScanMgr scanner = new ScanMgr();
public Form1()
{ InitializeComponent(); }
private void StartBtn_Click(object sender, EventArgs e)
{ log.Items.Add(scanner.startUp(this.Handle, wm_channel)); }
/* Other stuff yadda yadda */
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if(m.Msg == wm_channel)
{ /* To do stuff with m.WParam and m.LParam */ }
}
}