Why can't a dynamic
object invoke these methods on the NameTranslate COM object when reflection can?
Failing example using dynamic:
Type ntt = Type.GetTypeFromProgID("NameTranslate");
dynamic nto = Activator.CreateInstance(ntt);
nto.Init(3,null)
The third line fails with a NotImplementedException and the message The method or operation is not implemented.
A similar attempt that works using a different COM object (WScript.Shell and SendKeys):
Type shellType = Type.GetTypeFromProgID("WScript.Shell");
dynamic shell = Activator.CreateInstance(shellType);
shell.SendKeys("abc");
Getting back to the first sample. If I use reflection and invoke the methods using the InvokeMethod method things work fine.
Working example using reflection:
Type ntt = Type.GetTypeFromProgID("NameTranslate");
object nto = Activator.CreateInstance(ntt);
object[] initParams = new object[]{3,null};
ntt.InvokeMember("Init", BindingFlags.InvokeMethod, null, nto, initParams);
I believe this must have something to do with how the COM object is created or marked - but for the life of me I can't see anything in the docs, object browser or registry that indicates these COM objects and their subs/functions are marked private or something else that would normally throw off the dynamic
keyword.
NameTranslate documentation on MSDN: http://msdn.microsoft.com/en-us/library/windows/desktop/aa706046.aspx
Interestingly, none of NameTranslate
methods are callable via dynamic
. I have only a theoretical explanation of this, below.
AFAIK, when .NET DLR deals with COM objects for dynamic
invocation, it tries to make use of a COM type library, if available, and then resorts to IDispatch
. That's how it is different from Reflection, which calls IDispatch
right away when used with COM objects.
The ActiveDS type library (C:\Windows\System32\activeds.tlb
), as viewed with OleView, appears to be somewhat ill-formed. It includes a lot of non-automation compatible declarations, including interfaces:
interface IPrivateDispatch;
interface ITypeInfo;
interface ITypeComp;
interface ITypeLib;
interface IPrivateUnknown;
The class definition for NameTranslate
itself looks like this:
[
uuid(274FAE1F-3626-11D1-A3A4-00C04FB950DC)
]
coclass NameTranslate {
[default] interface IADsNameTranslate;
interface IDispatch;
};
It's unusual (although not prohibited) to declare IDispatch
inside coclass
.
So, I'd assume such type library and/or coclass
definition might be confusing the DLR in this case.
As a workaround, you can import it with TlbImp.exe activeds.tlb
(that would produce a bunch of warnings), add the output interop assembly to your project and call the API directly. This works:
Type ntt = Type.GetTypeFromProgID("NameTranslate");
var nto = Activator.CreateInstance(ntt) as ActiveDs.IADsNameTranslate;
nto.Init(3, null);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With