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);
我需要从 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);