C# 动态 COM 对象找不到方法

C# Dynamic COM Object can't find Method

我正在尝试通过 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 是类型库的一部分。

如有任何帮助,我们将不胜感激。

我按照以下方法使用 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", ""});

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

如评论中所述,您可以只使用 C# 4 功能 dynamic。它是为 COM 后期绑定而设计的。我的回答基于您的回答,但经过整理。

MSDN 在 dynamic

上有 this

The COM interop scenario that the C# team specifically targeted in the C# 4 release was programming against Microsoft Office applications, such as Word and Excel. The intent was to make this task as easy and natural in C# as it always was in Visual Basic. This is also a part of the Visual Basic and C# co-evolution strategy, where both languages aim at feature parity and borrow the best and most productive solutions from one another.

// 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", ""});

This works but it would be great if someone could explain why my original code didn't work.

正如我在上面的评论中提到的:

我注意到您一直在使用互操作包装器直到 CST.Active3D() 然后您下降到动态,这对我来说表明 AddToHistory 不可用,因为您使用的是 older/wrong COM 参考。第一个例子是如何创建一个独立的版本 CSTStudio.Application。也许通过 Activator.CreateInstance

尝试类似的事情

然后您将动态与 Type.InvokeMethod 混合。虽然没关系,但当 dynamic 可以按上述方式挽救一天时,它有点冗长。

原帖:

If I change the last two lines of code to the following it doesn't work anymore dynamic MWS = t.InvokeMember("Active3D", BindingFlags.InvokeMethod, null, CST, null); MWS.AddToHistory("Test", "");. It says it can't find the method.

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