0

我创建了一个管理应用程序。我的应用程序所做的事情之一是在插件上注册,该插件可以检测指纹读取器是否插入或拔出。该类订阅事件,如下所示:

//Subscribe to the plug, unplug and imageAcquired events from the GrFingerXCtrlClass library.
FingerXCtrlClass.SensorPlug += ReaderPlug;
FingerXCtrlClass.SensorUnplug += ReaderUnplug;
FingerXCtrlClass.ImageAcquired += ImageAcquired;

首先,当我积极开发该程序时,我开发了一个 WPF 应用程序。通过这个应用程序,我可以看到一些列表并切换一些设置,所以我确信我的服务运行良好。在这个 WPF 应用程序中,我通过实例化它来创建我的服务:

ProjectServiceLogic logic = new ProjectServiceLogic();

现在我创建了一个安装程序。因此,我有一个 ProjectService 类,用于初始化应用程序。这样做是这样的:

protected override void OnStart(string[] args)
{
    log.Debug("Starting service...");
    _worker = new Thread(new ThreadStart(StartService));
    _worker.IsBackground = true;
    _worker.Name = "ServiceThread";
    _worker.SetApartmentState(ApartmentState.STA);
    _worker.Start();
    log.Debug("Successfully started service");
}

void StartService()
{
    serviceLogic = new ProjectServiceLogic();
    while (!_shutdownEvent.WaitOne(0))
    {

    }
}

程序安装完毕,服务启动。在调试服务时,我注意到订阅代码被执行。但是,当我插入设备时不会触发事件,而在通过 WPF 应用程序在本地运行设备时会触发事件,实例化服务逻辑。为什么现在不行了?

4

1 回答 1

1
_worker.SetApartmentState(ApartmentState.STA);

选择单线程单元需要您实现 STA 线程的协定。只有两个基本要求:您永远不能阻塞线程并且您必须泵送消息循环。消息循环是必不可少的,它允许 COM 保证对 COM 对象的方法调用始终由创建对象的线程进行,从而确保线程安全。还有 .NET 中使 Control.BeginInvoke 和 Dispatcher.BeginInvoke 工作的机制。

COM 组件依赖于有该保证,它通常依赖消息调度程序来处理它自己的线程间封送处理。就像 Dispatcher.BeginInvoke 一样。

当您实际上没有按要求发送消息循环时,会出现两件事。首先,正如预期的那样,您从工作线程对对象进行的任何调用都将死锁。COM 将使用 PostMessage 要求 STA 线程调度调用。但是当线程没有从消息队列中检索消息时,就不会发生这种情况。出错的第二件事可能是您在这里看到的情况,组件本身使用 PostMessage 在 STA 线程上引发事件。使用永远不会引发事件的故障模式。同样经典的 WebBrowser 行为不端的方式,你永远不会得到 DocumentCompleted 事件。

您需要抽出一个消息循环,Application.Run()。无论是 Winforms 还是它的 WPF 版本都可以,请自行选择。Winforms 示例在这里

于 2013-05-08T11:19:23.700 回答