Как я могу прослушать это событие в другой теме? - PullRequest
1 голос
/ 14 июня 2011

Я сделал небольшую тестовую программу, чтобы попытаться заставить устройство чтения карт USB работать с использованием элемента управления ActiveX, предоставленного производителем.

Форма работает нормально, если она не использует отдельный поток,Я создаю новый экземпляр Reader и слушаю событие Read, и все работает отлично.Я провожу карточкой, событие запускается и текстовое поле обновляется.

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), потому что код в конечном итоге будет находиться в библиотеке классов, которая развернута с приложением, которое я не могу изменить.

1 Ответ

2 голосов
/ 14 июня 2011

Ваш 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);
  }
}

Но событие Read должно обрабатываться синхронно:

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