提问人:theateist 提问时间:11/10/2023 更新时间:11/10/2023 访问量:56
如何取消在STA线程中创建COM对象的等待?
How to cancel waiting on COM object creation within STA thread?
问:
我正在使用第三方 COM API。因此,我有创建COM对象的STA线程。问题在于,对象的创建可能需要几分钟左右的时间。我希望能够从外面取消它。我想按照 ATTEMPT 中所示包装它,但是我该如何等待它,并且由于它位于同一线程中,这不会造成死锁吗?new IThirdPartyClass()
Task.Factory.StartNew(...);
这是正确的方法还是更好的方法?
尝试
var cancelTokenSource = new CancellationTokenSource();
var staThread = new Thread(() =>
{
try
{
var comMessageFilter = CComMessageFilter.Create();
if (comMessageFilter == null) return;
Task.Factory.StartNew(()=>
{
_thirdPartyObj = new IThirdPartyClass();
}, cancelTokenSource.Token, TaskScheduler.FromCurrentSynchronizationContext());
_thirdPartyObj.Do(...);
...
}
catch(...) {...}
});
staThread.IsBackground = true;
staThread.SetApartmentState(ApartmentState.STA);
staThread.Start();
原始代码
var staThread = new Thread(() =>
{
try
{
var comMessageFilter = CComMessageFilter.Create();
if (comMessageFilter == null) return;
_thirdPartyObj = new IThirdPartyClass();
...
_thirdPartyObj.Do(...);
...
}
catch(...) {...}
});
staThread.IsBackground = true;
staThread.SetApartmentState(ApartmentState.STA);
staThread.Start();
IThirdParty类
[ComImport]
[TypeLibType(TypeLibTypeFlags.FCanCreate)]
[ClassInterface(ClassInterfaceType.None)]
public class IThirdPartyClass : ...
{
[MethodImpl(MethodImplOptions.InternalCall)]
public extern IThirdPartyClass();
...
}
CComMessageFilter
class CComMessageFilter : IMessageFilter, IDisposable
{
private const int RETRY_TIME_IN_MS = 200;
[DllImport("Ole32.dll")]
private static extern int CoRegisterMessageFilter(IMessageFilter newFilter, out IMessageFilter oldFilter);
private IMessageFilter m_previousFilter;
// =================================================================================================
// Private Constructor. Immediately register the filter.
// -------------------------------------------------------------------------------------------------
private CComMessageFilter()
{
CoRegisterMessageFilter(this, out m_previousFilter);
}
// =================================================================================================
// Creates a CComMessageFilter or null if creation failed.
// Should be used like this: using ( CComMessageFilter.Create() ) {}
// -------------------------------------------------------------------------------------------------
public static CComMessageFilter Create()
{
if (Thread.CurrentThread.GetApartmentState() == ApartmentState.STA)
{
return new CComMessageFilter();
}
return null;
}
// =================================================================================================
// Implementation of the IDisposable interface. Unregister the filter.
// -------------------------------------------------------------------------------------------------
public void Dispose()
{
IMessageFilter oldFilter = null;
CoRegisterMessageFilter(m_previousFilter, out oldFilter);
}
// =================================================================================================
// Implementation of IMessageFilter. See Microsoft documentation.
// In our case we accept all calls.
// -------------------------------------------------------------------------------------------------
int IMessageFilter.HandleInComingCall(int dwCallType, IntPtr hTaskCaller, int dwTickCount, IntPtr lpInterfaceInfo)
{
return (int)SERVERCALL.SERVERCALL_ISHANDLED;
}
// =================================================================================================
// Implementation of IMessageFilter. See Microsoft documentation.
// In our case we always ask for a retry when it is possible.
// -------------------------------------------------------------------------------------------------
int IMessageFilter.RetryRejectedCall(IntPtr hTaskCallee, int dwTickCount, int dwRejectType)
{
if (dwRejectType == (int)SERVERCALL.SERVERCALL_RETRYLATER)
{
return RETRY_TIME_IN_MS;
}
return -1;
}
// =================================================================================================
// Implementation of IMessageFilter. See Microsoft documentation.
// -------------------------------------------------------------------------------------------------
int IMessageFilter.MessagePending(IntPtr hTaskCallee, int dwTickCount, int dwPendingType)
{
return (int)PENDINGMSG.PENDINGMSG_WAITDEFPROCESS;
}
}
答: 暂无答案
评论