Search code examples
c#matlabcom

C# Dynamic COM Object can't find Method


I am trying to access a COM object (CST Studio Suite) through C#. I have previously successfully accessed and controlled this object through the following MATLAB script:

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

This is the C# code I am trying to use to control the COM object

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

It all works up until I try to run the method AddToHistory, which fails and gives the following error:

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

I know that the method AddToHistory exists because 1) I have accessed it through MATLAB and 2) it is here in the documentation. So why won't it run through C#? Since the MWS object is dynamically typed, I get that the method won't be found at compile time, but it should still be found at runtime right? I have debugged and inspected the types of the objects and both CST and MWS are System.__ComObject. When I inspect the dynamic view of these objects, it says "No further information on this object could be discovered" so it doesn't seem to be finding any methods.

Also, the type of CST is part of the type library cst_design_environmentLib so the methods such as FileNew() are predicted by intellisense, but I don't believe that the type of MWS is part of the type library.

Any help with this would be greatly appreciated.


Solution

  • As mentioned in the comments you can just use the C# 4 feature dynamic. It was made for COM late-binding in mind. I've based my answer on yours but tided it up.

    MSDN has this to say on dynamic

    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.

    As I mentioned in the comments above:

    I notice you are using the interop wrapper up to the point of CST.Active3D() then you drop down to dynamic which suggests to me AddToHistory isn't available because you are using an older/wrong COM reference. The first example is how one would go about creating a version independent CSTStudio.Application. Maybe try a similar thing via Activator.CreateInstance

    You then mixed dynamic with Type.InvokeMethod. Whilst OK it's kinda verbose when dynamic can save the day as per above.

    OP:

    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.

    That's because you are using Type to call the methods. I suspect it doesn't use late-binding hence why dynamic. You should only be using the variable t for the line Activator.CreateInstance(t) and no where else. CST and MWS should be dynamic.