如何在 C# 项目中收听设备的消息

How can I listen a device's messages in a C# project

又是我!

这个问题很难,因为我会尽力解释它:正如我在上一个问题中提到的,我正在使用 C# 上的扫描仪管理工作,使用提供商发送的 C++ dll。根据 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 )

其中 "Handle" 是应用程序消息目标的句柄 window。

所以我的 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");

我期待什么?打印 "Turning on device" 后我应该收到消息(因为在启动期间,根据手册,它会在更改状态之前发送一条消息),然后是 "Device on" 字符串。

我能得到什么?在打印 "Turning on device" 之后,程序除了闪烁光标外什么都不做(当然, "Device on" 字符串永远不会出现)。看起来它正在等待任何消息。尝试将消息调用放置在不同的地方并且行为是相同的。

有什么建议吗?提前致谢。

解决了(终于)

我是这样做的:

  1. 使用 windows 形式,因为它有 class "Message"
  2. 导入了我正在处理的 .dll 以简化操作,放置 "ScanMgr" class.
  3. 中的所有方法
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 */
}
  1. 然后,为消息定义一个覆盖方法
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 */ }
  }
}