Com+ late binding c# 4.0
Asked Answered
P

2

10

In my program I create Com+ objects dynamicly (late binding) using

Type comObjectType = Type.GetTypeFromProgID(progId, true); 
object comObject = Activator.CreateInstance(comObjectType); 

And then call one of the methods using reflection

object result = comObjectType.InvokeMember(MethodToActivate, BindingFlags.InvokeMethod, null, comObjec, new object[] {....});

It works greate in .Net 1.1/2.0/3.5

Now I'm trying to run the same code on the same machine (Windows XP) compiled for .Net 4.0, but I've got a

Exception: Method 'System.__ComObject.{MethodName}' not found. 

I've got the exception for most of Com+ objects (not for all). Does anybody know what is the problem? Why do I get the exception in FW 4.0 environment? What should I do to avoid it?

Thanks a lot, Daniel

After some more investigation I have discovered that some of the Com+ proxies are created as System._ComObject (those are the native ones, I suppose), and some are created as System.Runtime.Remoting.Proxies._TransparentProxy (I think that those are .Net Com+ objects). Method invocation works fine for those that are created as System._ComObject and does not work for System.Runtime.Remoting.Proxies._TransparentProxy. The most intersting fact is that in .Net 2.0 the all the objects are created in the same way (_ComObject and _TransparentProxy) but the method invocation does work fine. Another interesting fact is that I can see the "missing" method in the debugger using reflecton

((System.EnterpriseServices.RemoteServicedComponentProxy)((((System.Runtime.Remoting.Proxies.__TransparentProxy)(ObjectToActivate)))._rp)).ProxiedType.GetMethods()

I thought for some moment that it could be a security issue, but I run the code as WindowsService logged on as a user with Administrator privileges

Pectize answered 14/4, 2011 at 6:11 Comment(5)
Have you checked any 32/64-bit issue? Maybe your process is 64-bit and therefore hitting the 64-bit COM registry (where no one lives :-)?Rawson
I don't think it's a 32/34-bit issue, my local machine is 32 bit, so is the remote serverPectize
ok for 32/64-bit. Now, it looks like your COM server is not in-process or has a specific threading model (hence the proxies). Can you give more details on this? are they hosted out-of-process? In component services? And what about the Invoke arguments? are your sure there is no ambiguity? What about the BindingFlags? don't you need Public|Instance?Rawson
Most of the com+ servers are actualy located on the remote machine (2003 server), but not all. They run as a server application with its dedicated user. I've been focused on one that is local and gets to strings as parameters and return string (very simple). The binding falg is set for BindingFlags.InvokeMethod, i did not use Public|Instance in other .Net versions and it was not a problem, but I'll try, may be 4.0 version has more runtime restrictions then the previos versionsPectize
Isn't .NET 4.0 supposed to handle this automatically? Instead of declaring comObject as object, declare it as dynamic. Try reading this msmvps.com/blogs/paulomorgado/archive/2010/04/19/…Oleary
P
8

I have discovered that there is a difference between the .NET FW in COM type creation, and as far as I understand the difference exists only for .NET COM objects. When the COM object type is created with

Type comObjectType = Type.GetTypeFromProgID(progId, true);

the type that is returned in .NET 1.1/2.0/3.5 is the actual .NET type of the object, so there is no problem in its method invocation, but in .NET 4.0 the System.__ComObject type is returned so the code

result = comObjectType.InvokeMember(
   MethodToActivate, BindingFlags.InvokeMethod, null, ObjectToActivate, InputParams);

fails with a method not found exception.

The solution that I have found is the following:

Type comObjectType = Type.GetTypeFromProgID(progId, true);        
object comObject = Activator.CreateInstance(comObjectType);

// here the real object type is returned
Type acctualObjectType = comObject.GetType();
result = acctualObjectType.InvokeMember(
   "MethodToActivate", BindingFlags.InvokeMethod, null, comObject, InputParams);

This code works fine for all environments.

Pectize answered 27/4, 2011 at 11:33 Comment(3)
Interesting - I actually posted an answer previous that I suspect would have helped by ironically deleted it after reading another question that convinced me that I was wrong! - Anyway, glad you got your problem fixed.Antimicrobial
In your solution code, is comObject supposed to be the same as ObjectToActivate?Amperage
Yes, it is. ObjectToActivate is a property that returns comObject.Pectize
A
1

I'm not sure why your previously running code no longer works however I believe that in .Net 4.0 you can call COM methods using IDispatch / late binding via the dynamic type - see Does C# .NET support IDispatch late binding?.

Antimicrobial answered 27/4, 2011 at 6:3 Comment(3)
I thought about this kind of solution, but it is not acceptable for me, because I need the same code run for all .Net FW versions. It is part of a core library the runs in different environmentsPectize
@Daniel: Regardless of whether it's satisfactory, does using dynamic still show the error?Realist
I've tried a little sample with the 'dynamic', it works (but unuseful for me (: )Pectize

© 2022 - 2024 — McMap. All rights reserved.