如何在不同的线程上监听此事件?

发布于 2024-11-15 12:57:00 字数 1359 浏览 2 评论 0原文

我编写了一个小测试程序,尝试使用制造商提供的 ActiveX 控件让 USB 读卡器正常工作。

只要不使用单独的线程,该表单就可以正常工作。我创建了一个新的 Reader 实例并监听 Reader 事件,一切正常。我刷卡,事件触发并且文本框得到更新。

private Reader _reader;

public Form1()
{
    InitializeComponent();
    CreateScanner();
}

public void CreateScanner()
{
    _reader = new Reader();
    _reader.Read += Read;
}

void Read(object sender, EventArgs e)
{
    CardData.Text = "Card Read";
}

Reader 类,以防有帮助:

public class Reader
{
    private AxUSBHIDInsert _axUsbHid;
    public event EventHandler Read;

    public Reader()
    {
        _axUsbHid = new AxUSBHIDInsert();
        _axUsbHid.CreateControl();
        _axUsbHid.BeginInit();
        _axUsbHid.MSRReadDir = MSRReadDirection.ReadWithdrawal;
        _axUsbHid.EndInit();

        _axUsbHid.PortOpen = true;

        _axUsbHid.CardDataChanged += CardDataChanged;
    }

    void CardDataChanged(object sender, EventArgs e)
    {
        if (Read != null)
            Read(this, new EventArgs());
    }
}

但是,我需要在单独的线程上运行它。所以我将构造函数更改为

Thread thread = new Thread(CreateScanner);
thread.SetApartmentState(ApartmentState.STA);
thread.Start();

它必须是 STA 线程,否则 ActiveX 控件会抱怨它无法实例化。然而,这样做后,该事件不再触发。我不太熟悉线程的工作原理,所以我不确定为什么。

有什么想法吗?请注意,它必须以这种方式工作(单独的线程,连接到 Read 事件),因为代码最终将驻留在与我无法更改的应用程序一起部署的类库中。

I've made a little test program to try and get a USB card reader working using an ActiveX control provided by the manufacturer.

The form works fine as long as it doesn't use a separate thread. I create a new instance of Reader and listen to the Read event and everything works fine. I swipe a card, the event fires and the textbox gets updated.

private Reader _reader;

public Form1()
{
    InitializeComponent();
    CreateScanner();
}

public void CreateScanner()
{
    _reader = new Reader();
    _reader.Read += Read;
}

void Read(object sender, EventArgs e)
{
    CardData.Text = "Card Read";
}

Reader class in case it helps:

public class Reader
{
    private AxUSBHIDInsert _axUsbHid;
    public event EventHandler Read;

    public Reader()
    {
        _axUsbHid = new AxUSBHIDInsert();
        _axUsbHid.CreateControl();
        _axUsbHid.BeginInit();
        _axUsbHid.MSRReadDir = MSRReadDirection.ReadWithdrawal;
        _axUsbHid.EndInit();

        _axUsbHid.PortOpen = true;

        _axUsbHid.CardDataChanged += CardDataChanged;
    }

    void CardDataChanged(object sender, EventArgs e)
    {
        if (Read != null)
            Read(this, new EventArgs());
    }
}

However, I need to run this on a separate thread. So I change the constructor to be

Thread thread = new Thread(CreateScanner);
thread.SetApartmentState(ApartmentState.STA);
thread.Start();

It has to be an STA thread otherwise the ActiveX control will complain that it cannot be instantiated. However doing this, the event doesn't fire anymore. I'm not that familiar with how threading works, so I'm not sure why.

Any ideas? Note that it has to work this way (separate thread, hooked up to the Read event), because the code will eventually reside in a class library that gets deployed with an application that I cannot change.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

∞梦里开花 2024-11-22 12:57:00

您的 COM 对象将消息发送到第二个线程,这意味着它必须在应用程序运行时始终处于活动状态。

尝试这样做:

public class Reader
{
  public Reader()
  {
    // leave empty
  }

  public Read() {
    _axUsbHid = new AxUSBHIDInsert();
    ...
  }
}

public Form1()
{
  InitializeComponent();
  _reader = new Reader();
  _reader.Read += Read;
  StartRead(_reader);
}

void StartRead(Reader reader) {
  Thread thread = new Thread(ReadRoutine);
  thread.SetApartmentState(ApartmentState.STA);
  thread.Start(reader);
}

void ReadRoutine(object param) {
  Reader reader = (Reader)param;
  reader.Read();
  while (AppIsAlive) { // add logic here
    // bad code, import GetMessage from user32.dll
    Application.DoEvents();
    Thread.Sleep(100);
  }
}

但读取事件必须同步处理:

void Read(object sender, EventArgs e)
{
  if (this.InvokeRequired)
    this.BeginInvoke(new EventHandler(Read), new object[2] { sender, e } );
  else {
    CardData.Text = "Card Read";
  }
}

Your COM object sends messages to the second thread, that means it must be alive all the time application is running.

Try to do like this:

public class Reader
{
  public Reader()
  {
    // leave empty
  }

  public Read() {
    _axUsbHid = new AxUSBHIDInsert();
    ...
  }
}

public Form1()
{
  InitializeComponent();
  _reader = new Reader();
  _reader.Read += Read;
  StartRead(_reader);
}

void StartRead(Reader reader) {
  Thread thread = new Thread(ReadRoutine);
  thread.SetApartmentState(ApartmentState.STA);
  thread.Start(reader);
}

void ReadRoutine(object param) {
  Reader reader = (Reader)param;
  reader.Read();
  while (AppIsAlive) { // add logic here
    // bad code, import GetMessage from user32.dll
    Application.DoEvents();
    Thread.Sleep(100);
  }
}

But the Read event must be processed synchronously:

void Read(object sender, EventArgs e)
{
  if (this.InvokeRequired)
    this.BeginInvoke(new EventHandler(Read), new object[2] { sender, e } );
  else {
    CardData.Text = "Card Read";
  }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文