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

Daniel Kabzon
  • 326
  • 2
  • 17
  • 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 :-)? – Simon Mourier Apr 27 '11 at 06:17
  • I don't think it's a 32/34-bit issue, my local machine is 32 bit, so is the remote server – Daniel Kabzon Apr 27 '11 at 07:14
  • 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? – Simon Mourier Apr 27 '11 at 07:49
  • 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 versions – Daniel Kabzon Apr 27 '11 at 08:09
  • Isn't .NET 4.0 supposed to handle this automatically? Instead of declaring comObject as object, declare it as dynamic. Try reading this https://msmvps.com/blogs/paulomorgado/archive/2010/04/19/c-4-0-com-interop-improvements.aspx – Jon Limjap Apr 27 '11 at 08:26

2 Answers2

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.

MFedatto
  • 134
  • 2
  • 16
Daniel Kabzon
  • 326
  • 2
  • 17
  • 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. – Justin Apr 27 '11 at 11:38
  • In your solution code, is `comObject` supposed to be the same as `ObjectToActivate`? – Dave Cousineau Sep 12 '14 at 20:43
  • Yes, it is. ObjectToActivate is a property that returns comObject. – Daniel Kabzon Sep 13 '14 at 21:42
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?.

Community
  • 1
  • 1
Justin
  • 84,773
  • 49
  • 224
  • 367
  • 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 environments – Daniel Kabzon Apr 27 '11 at 07:18
  • @Daniel: Regardless of whether it's satisfactory, does using `dynamic` still show the error? – Gabe Apr 27 '11 at 08:27
  • I've tried a little sample with the 'dynamic', it works (but unuseful for me (: ) – Daniel Kabzon Apr 27 '11 at 08:28