【问题标题】:Com+ late binding c# 4.0Com+后期绑定c#4.0
【发布时间】:2011-04-14 06:11:58
【问题描述】:

在我的程序中,我使用

动态创建 Com+ 对象(后期绑定)
Type comObjectType = Type.GetTypeFromProgID(progId, true); 
object comObject = Activator.CreateInstance(comObjectType); 

然后使用反射调用其中一种方法

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

它在 .Net 1.1/2.0/3.5 中效果更好

现在我尝试在为 .Net 4.0 编译的同一台机器 (Windows XP) 上运行 相同的代码,但我有一个

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

我对大多数 Com+ 对象(不是全部)都有例外。 有谁知道是什么问题? 为什么在 FW 4.0 环境中会出现异常? 我应该怎么做才能避免它?

非常感谢, 丹尼尔

经过进一步调查,我发现一些 Com+ 代理被创建为 System._ComObject(我想那些是本机代理),有些被创建为 System.Runtime.Remoting.Proxies._TransparentProxy(我认为那些是 .Net Com+对象)。方法调用适用于创建为System._ComObject 的方法,不适用于System.Runtime.Remoting.Proxies._TransparentProxy。 最有趣的事实是,在 .Net 2.0 中,所有对象都是以相同的方式创建的(_ComObject_TransparentProxy),但方法调用确实可以正常工作。 另一个有趣的事实是,我可以使用反射在调试器中看到“缺失”的方法

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

我一度认为这可能是一个安全问题,但我在 WindowsService 以具有管理员权限的用户身份登录时运行代码

【问题讨论】:

  • 您检查过任何 32/64 位问题吗?也许您的进程是 64 位的,因此访问了 64 位 COM 注册表(没有人居住的地方 :-)?
  • 我觉得不是 32/34 位的问题,我的本地机器是 32 位的,远程服务器也是
  • 适用于 32/64 位。现在,您的 COM 服务器似乎不在进程中或具有特定的线程模型(因此是代理)。你能提供更多细节吗?他们是在进程外托管的吗?在组件服务中?那么 Invoke 参数呢?你确定没有歧义吗? BindingFlags 呢?你不需要公共|实例吗?
  • 大多数 com+ 服务器实际上位于远程机器(2003 服务器)上,但不是全部。它们作为服务器应用程序与其专用用户一起运行。我一直专注于一个本地的并将字符串作为参数并返回字符串(非常简单)。绑定 falg 是为 BindingFlags.InvokeMethod 设置的,我没有在其他 .Net 版本中使用 Public|Instance,这不是问题,但我会尝试,可能是 4.0 版本比以前的版本有更多的运行时限制
  • .NET 4.0 不应该自动处理这个吗?与其将 comObject 声明为对象,不如将其声明为动态的。试试看这个msmvps.com/blogs/paulomorgado/archive/2010/04/19/…

标签: c# .net com+


【解决方案1】:

我发现 .NET FW 在 COM 类型创建方面存在差异,据我了解,差异仅存在于 .NET COM 对象中。当 COM 对象类型创建时使用

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

.NET 1.1/2.0/3.5 中返回的类型是对象的实际 .NET 类型,所以它的方法调用没有问题,但是在 .NET 4.0 中返回的是 System.__ComObject 类型,所以代码

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

因方法未找到异常而失败。

我找到的解决方案如下:

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);

此代码适用于所有环境。

【讨论】:

  • 有趣 - 我实际上发布了一个答案,我怀疑在阅读另一个让我相信我错了的问题后讽刺地删除它会有所帮助! - 无论如何,很高兴你的问题得到解决。
  • 在您的解决方案代码中,comObject 是否应该与 ObjectToActivate 相同?
  • 是的。 ObjectToActivate 是一个返回 comObject 的属性。
【解决方案2】:

我不确定为什么您之前运行的代码不再有效,但是我相信在 .Net 4.0 中,您可以通过 dynamic 类型使用 IDispatch / 后期绑定调用 COM 方法 - 请参阅 Does C# .NET support IDispatch late binding?

【讨论】:

  • 我想过这种解决方案,但我无法接受,因为我需要为所有 .Net FW 版本运行相同的代码。它是在不同环境中运行的核心库的一部分
  • @Daniel:不管是否令人满意,使用dynamic是否仍然显示错误?
  • 我尝试了一个带有“动态”的小样本,它可以工作(但对我来说没用(:)
猜你喜欢
  • 2012-07-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多