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

C++ DLL in ASP.NET Core STA thread not invoking callback

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

To create a user thread and access the camera from that thread, be sure to execute CoInitializeEx( NULL, COINIT_APARTMENTTHREADED ) at the start of the thread and CoUnInitialize() at the end.

例如

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();
    }
}

更新:这实际上是固定的,请参阅下面的答案

我找到了一种方法,使用 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);