I have a long running COM+ method that I need to be able to cancel from another thread. I am using C#/.NET to interact the COM+ objects. I configured both COM+ objects to have a "Free" threading model. This C# sample demonstrates how I intend to use the COM+ objects.
static void Main(string[] args)
{
var sampleCOMClass = new SampleCOMObjectClass();
var cancelToken = new CancelCOMObjectClass();
try
{
Task.Factory.StartNew(() =>
{
Thread.Sleep(TimeSpan.FromSeconds(10));
cancelToken.Cancel(); // this method never makes it to COM
Console.WriteLine("Cancelled!");
});
sampleCOMClass.LongProcess(cancelToken);
}
finally
{
Marshal.ReleaseComObject(sampleCOMClass);
Marshal.ReleaseComObject(cancelToken);
}
}
My long running process correctly checks the cancellation token to determine if we should finish processing, but the Cancel
method never makes it to the COM+ objects. It is as if the method is blocking, waiting for LongProcess
to finish. I don't know why it is doing this, because I thought the "Free" threading model allowed the implementations to manage synchronization.
Here is a BitBucket repository with a minimal example to reproduce. https://bitbucket.org/theonlylawislove/so-blocking-com-call
Why is Cancel
never getting called/blocking?
CancelCOMObject
STDMETHODIMP CCancelCOMObject::Cancel(void)
{
_isCancelled = VARIANT_TRUE;
return S_OK;
}
STDMETHODIMP CCancelCOMObject::get_IsCancelled(VARIANT_BOOL* pVal)
{
*pVal = _isCancelled;
return S_OK;
}
SampleCOMObject
STDMETHODIMP CSampleCOMObject::LongProcess(ICancelCOMObject* cancel)
{
VARIANT_BOOL isCancelled = VARIANT_FALSE;
while(isCancelled == VARIANT_FALSE)
{
Sleep(1000);
cancel->get_IsCancelled(&isCancelled);
}
return S_OK;
}