【问题标题】:C# Dynamic COM Object can't find MethodC# 动态 COM 对象找不到方法
【发布时间】:2020-07-30 23:44:11
【问题描述】:

我正在尝试通过 C# 访问 COM 对象(CST Studio Suite)。我之前已经通过以下 MATLAB 脚本成功访问并控制了这个对象:

CST = actxserver('CSTStudio.Application'); % Opens CST
CST.FileNew();                             % Creates a new file
MWS = CST.Active3D;                        % Set focus to the new file
MWS.invoke("AddToHistory","Test","");      % Append to history list

这是我试图用来控制 COM 对象的 C# 代码

cst_design_environmentLib.IApplication CST = new cst_design_environmentLib.Application(); // Opens CST
CST.FileNew(); // Creates a new file
dynamic MWS = CST.Active3D(); // Set focus to the new file
MWS.AddToHistory("Test", ""); // Doesn't work, produces an error

一切正常,直到我尝试运行方法 AddToHistory,该方法失败并给出以下错误:

Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: 'System.__ComObject' does not contain a definition for 'AddToHistory'

我知道 AddToHistory 方法存在是因为 1) 我通过 MATLAB 访问了它,并且 2) 它位于 documentation 中。那么为什么它不能通过 C# 运行呢?由于MWS 对象是动态类型的,我知道在编译时找不到该方法,但在运行时仍应找到它,对吧?我已经调试并检查了对象的类型,CSTMWS 都是System.__ComObject。当我检查这些对象的动态视图时,它显示“无法发现有关此对象的更多信息”,因此它似乎没有找到任何方法。

另外CST的类型是类型库cst_design_environmentLib的一部分所以FileNew()等方法是intellisense预测的,但是我不相信MWS的类型是类型库的一部分类型库。

对此的任何帮助将不胜感激。

【问题讨论】:

  • 我注意到您正在使用互操作包装器直到 CST.Active3D() 然后您下拉到 dynamic 这向我建议 AddToHistory 不可用,因为您使用的是较旧的/错误的 COM 引用。第一个示例是如何创建一个独立于版本的 CSTStudio.Application。也许通过Activator.CreateInstance 尝试similar 的事情

标签: c# matlab com


【解决方案1】:

如 cmets 中所述,您可以只使用 C# 4 功能 dynamic。它是为 COM 后期绑定而设计的。我的回答是基于你的,但已经解决了。

MSDN 在dynamic 上有this 可以说

C# 团队在 C# 4 版本中专门针对的 COM 互操作方案是针对 Microsoft Office 应用程序(例如 Word 和 Excel)进行编程。其目的是让 C# 中的这项任务像在 Visual Basic 中一样简单自然。这也是 Visual Basic 和 C# 共同进化战略的一部分,在这种战略中,两种语言都旨在实现功能对等,并相互借鉴最佳和最高效的解决方案。

// Create an instance of CST
Type t = Type.GetTypeFromProgID("CSTStudio.Application");
dynamic CST = Activator.CreateInstance(t);

// Create a new file
CST.FileNew();

// Set focus to the new file
dynamic MWS = CST.Active3D();

// Add something to the model history
MWS.AddToHistory (new string[] {"Test", ""});

这可行,但如果有人能解释为什么我的原始代码不起作用,那就太好了。

正如我在上面的 cmets 中提到的:

我注意到您在 CST.Active3D() 之前一直在使用互操作包装器,然后您下拉到 dynamic,这表明 AddToHistory 不可用,因为您使用的是旧的/错误的 COM 引用。第一个示例是如何创建独立于版本的 CSTStudio.Application。也许通过 Activator.CreateInstance 尝试类似的事情

然后您将动态与Type.InvokeMethod 混合在一起。虽然可以,但当dynamic 可以按上述方式节省时间时,这有点冗长。

操作:

如果我将最后两行代码更改为以下代码,它将不再起作用 dynamic MWS = t.InvokeMember("Active3D", BindingFlags.InvokeMethod, null, CST, null); MWS.AddToHistory("测试", "");。它说它找不到方法。

那是因为您使用Type 来调用这些方法。我怀疑它不使用后期绑定,因此为什么dynamic。您应该将变量t 用于Activator.CreateInstance(t) 行,而不要在其他地方使用。 CSTMWS 应该是 dynamic

【讨论】:

  • 感谢您迄今为止的所有帮助,我非常感谢。我尝试运行您在此评论中发布的代码,它运行良好,直到行 CST.FileNew() 并且它给出了错误 'System.__ComObject' does not contain a definition for 'FileNew'。到目前为止,我让它工作的唯一方法是调用所有东西,dynamic 从来没有工作过。我怀疑我正在与之交互的 COM .dll 是旧的并且不符合当前标准。
  • @PaperBee 很好,先生,很乐意提供帮助。 COM 有时可能是个讨厌的恶魔 ;)
【解决方案2】:

我设法通过使用InvokeMember 使其工作,如下所示:

// Create an instance of CST
Type t = Type.GetTypeFromProgID("CSTStudio.Application");
object CST = Activator.CreateInstance(t);

// Create a new file
t.InvokeMember("FileNew", BindingFlags.InvokeMethod, null, CST, null);

// Set focus to the new file
object MWS = t.InvokeMember("Active3D", BindingFlags.InvokeMethod, null, CST, null);

// Add something to the model history
t.InvokeMember("AddToHistory", BindingFlags.InvokeMethod, null, MWS, new string[] {"Test", ""});

这可行,但如果有人能解释为什么我的原始代码不起作用,那就太好了。

【讨论】:

  • 嗯,是的,但是你改变了两件事,你只需要使用Activator.CreateInstance。您不必删除 dynamic - 这就是它在 C# 4+ 中的用途。很高兴你能做到这一点。看起来您之前使用的是较旧的 COM 引用/包装器
  • 如果我将最后两行代码更改为以下代码,它将不再起作用dynamic MWS = t.InvokeMember("Active3D", BindingFlags.InvokeMethod, null, CST, null); MWS.AddToHistory("Test", "");。它说它找不到方法。
  • 那是因为您使用Type 来调用方法。您应该将变量t 用于Activator.CreateInstance(t) 行,而不要在其他地方使用。 CST 应该是 dynamic
猜你喜欢
  • 2012-12-15
  • 2015-01-22
  • 2013-10-08
  • 2013-10-04
  • 2011-07-05
  • 1970-01-01
  • 2015-03-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多