C#, full .NET 4.7 framework
Here is the code to demonstrate the problem. Console applications, single thread.
static void Main()
{
var appType = System.Type.GetTypeFromProgID("Word.Application");
dynamic app = System.Activator.CreateInstance(appType);
dynamic documents = app.Documents;
object ConfirmConversions = false;
dynamic document = documents.Open(@"document.docx", ref ConfirmConversions);
var b1 = true;
var b2 = true;
if (b1)
{
object doNotSaveChanges = 0;
document.Close(SaveChanges: ref doNotSaveChanges);
}
if (b2)
{
// Exception here for b1 = true -AND- b2 = true. Why ?!
System.Action<object> a = (o) => { };
1: a(document);
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(document);
}
// Exception here for b1 = true -OR- b2 = true
2: var name = document.Name;
...
}
If b1 = true and b2 = false, then exception is at line 2:
System.Runtime.InteropServices.COMException
HResult=0x80010108
Message=The object invoked has disconnected from its clients. (Exception from HRESULT: 0x80010108 (RPC_E_DISCONNECTED))
Source=mscorlib
StackTrace:
at System.Runtime.InteropServices.Marshal.ThrowExceptionForHRInternal(Int32 errorCode, IntPtr errorInfo)
at System.Dynamic.ComRuntimeHelpers.CheckThrowException(Int32 hresult, ExcepInfo& excepInfo, UInt32 argErr, String message)
at System.Dynamic.UpdateDelegates.UpdateAndExecute1[T0,TRet](CallSite site, T0 arg0)
This is to be expected since COM object was closed, and RCW has nothing to talk to.
Now if b1 = false and b2 = true, exception is on line 2:
System.Runtime.InteropServices.InvalidComObjectException
HResult=0x80131527
Message=COM object that has been separated from its underlying RCW cannot be used.
Source=System.Core
StackTrace:
at System.Dynamic.DynamicMetaObject.Create(Object value, Expression expression)
at System.Dynamic.DynamicMetaObjectBinder.Bind(Object[] args, ReadOnlyCollection`1 parameters, LabelTarget returnLabel)
at System.Runtime.CompilerServices.CallSiteBinder.BindCore[T](CallSite`1 site, Object[] args)
at System.Dynamic.UpdateDelegates.UpdateAndExecute1[T0,TRet](CallSite site, T0 arg0)
This is to be expected either since RCW was released and cannot be used anymore. Yet exception advices that we were talking to COM object and not RCW, hugh?
But when b1 = true and b2 = true, there is an exception on line 1!:
System.Runtime.InteropServices.COMException
HResult=0x80010114
Message=The requested object does not exist. (Exception from HRESULT: 0x80010114)
Source=mscorlib
StackTrace:
at System.WeakReference.Create(Object target, Boolean trackResurrection)
at System.Dynamic.BindingRestrictions.InstanceRestriction.GetExpression()
at System.Dynamic.BindingRestrictions.ToExpression()
at System.Dynamic.DynamicMetaObjectBinder.Bind(Object[] args, ReadOnlyCollection`1 parameters, LabelTarget returnLabel)
at System.Runtime.CompilerServices.CallSiteBinder.BindCore[T](CallSite`1 site, Object[] args)
at System.Dynamic.UpdateDelegates.UpdateAndExecuteVoid2[T0,T1](CallSite site, T0 arg0, T1 arg1)
This is what I do not understand. Why it fails even though RCW is in scope and should not have been released?
If this program is changed to not use 'dynamic' but rely on good old interop assemblies this exception does not show up and everything works just fine. The same happens if 'document' is cast to 'object' first - no exception.
So the question is why using 'dynamic' changes this behavior? What happens behind the scenes here with dynamic object and why?
P.S. Lets not discuss whether or not FinalReleaseComObject is necessary. It does not matter, any method which takes 'document' as a parameter would fail even before control enters into that method.
User contributions licensed under CC BY-SA 3.0