COM objects, RCWs and dynamic... something does not play right?

0

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.

c#
dynamic
interop
asked on Stack Overflow Apr 30, 2020 by Michael • edited Apr 30, 2020 by Michael

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0