ASP.NET核心STA线程中的C ++ DLL没有调用回调

时间:2018-02-25 06:48:47

标签: c# asp.net-core com pinvoke sta

我需要从ASP.NET核心API中控制摄像头,所有通信都是通过pInvoke dll进行的。 在文档中明确指出

  

要创建用户线程并从该线程访问摄像头,请务必执行CoInitializeEx(NULL,   COINIT_APARTMENTTHREADED)在线程的开头和最后的CoUnInitialize()。

e.g

CoInitializeEx( NULL, COINIT_APARTMENTTHREADED );
EdsSendCommand(camera, kEdsCameraCommand_TakePicture, 0);
CoUninitialize()

我的相机服务在winforms应用程序(STA)中运行,但是当我将其移动到我的API时,回调不会在事件发生时触发。 我已经尝试在STA线程中包装组件并设置执行循环,但回调仍然不会触发。

我想我可能需要一个消息泵,但我不确定它应该如何工作。

非工作代码:

Thread handlerThread;
handlerThread = new Thread(STAThreadLoop);
handlerThread.SetApartmentState(ApartmentState.STA);
handlerThread.Start();

并在线程循环中

void STAThreadLoop()
{
    logger.LogInformation("Starting STAThreadLoop...");
    lock (handlerThreadLock)
    {
        handlerSignal.Set();
        while (!exitHandlerThreadLoop)
        {
            Thread.Yield();
            Monitor.Wait(handlerThreadLock);
            if (handlerThreadAction != null)
            {
                try
                {
                    handlerThreadAction();
                }
                catch (Exception ex)
                {
                    logger.LogError(ex, "Error executing action on STA thread: {ThreadName}", Thread.CurrentThread.Name);
                }
            }
            Monitor.Pulse(handlerThreadLock);
        }
    }
}

然后创建组件

RunSTAAction(() =>
{
    handler = new SDKHandler(loggerFactory.CreateLogger<SDKHandler>());
});

和转换到STA线程的方法

void RunSTAAction(Action action)
{
    if (Thread.CurrentThread.GetApartmentState() != ApartmentState.STA)
    {
        lock (handlerThreadLock)
        {
            handlerThreadAction = action;
            Monitor.Pulse(handlerThreadLock);
            Monitor.Wait(handlerThreadLock);
        }
    }
    else
    {
        action();
    }
}

更新:这实际上已修复,请参阅下面的答案

1 个答案:

答案 0 :(得分:1)

我在Noseratio

中使用StaTaskScheduler and STA thread message pumping 的优秀答案找到了一种方法。

实际上,我们创建了ThreadAffinityTaskScheduler的实例,并将WaitHelpers.WaitWithMessageLoop作为等待函数传递。

ThreadAffinityTaskScheduler messageScheduler;
messageScheduler = new ThreadAffinityTaskScheduler(3, staThreads: true, waitHelper: WaitHelpers.WaitWithMessageLoop);
messageScheduler.Run(new Action(STAThreadLoop), CancellationToken.None);