1

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.

Blanko
  • 684
  • 8
  • 26
PaperBee
  • 35
  • 6
  • 2
    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](https://stackoverflow.com/q/9787809/585968) thing via `Activator.CreateInstance` – MickyD Jul 30 '20 at 23:56

2 Answers2

1

I managed to get it working by using InvokeMember as per the following:

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

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

MickyD
  • 13,463
  • 6
  • 39
  • 60
PaperBee
  • 35
  • 6
  • 1
    Well yes but you changed two things, you only needed to use `Activator.CreateInstance`. You didn't have to remove `dynamic` - that's what it's for in C# 4+. Glad you got it going just the same. It looks like you were using an older COM reference/wrapper before – MickyD Jul 31 '20 at 02:27
  • 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. – PaperBee Jul 31 '20 at 04:05
  • That's because you are using `Type` to call the methods. You should **only** be using the variable `t` for the line `Activator.CreateInstance(t)` and no where else. `CST` should be `dynamic`. – MickyD Jul 31 '20 at 04:31
1

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.

MickyD
  • 13,463
  • 6
  • 39
  • 60
  • Thanks for all your help so far, I really appreciate it. I tried running the code you posted in this comment, it runs fine until the line ```CST.FileNew()``` and this it gives the error, ```'System.__ComObject' does not contain a definition for 'FileNew'```. So far the only way I have gotten it working is by invoking everything, ```dynamic``` has never worked. I suspect the COM .dll that I am interfacing with is old and isn't up to current standards. – PaperBee Jul 31 '20 at 06:04
  • @PaperBee that's quite ok good sir, happy to help. COM can be a pesky devil at times ;) – MickyD Jul 31 '20 at 06:08