Stack Trace in XSI
Usually, when an uncaught exception is thrown, XSI will print out the Exception.message to the scripting history log in the script editor. However, that usually does not tell you where the error was. What line number? What file?
I have found a little trick to get a stack trace printed out. An example is below:
1: public override void createMuscle(XSI.Model model) {
2: try {
3: this.createMuscle(model, MuscleType.POLY);
4: } catch (Exception e) {
5: XSIDotNetUtil.CommonCommands.LogMessage(XSIApp, e.StackTrace, XSI.siSeverity.siError);
6: throw e;
7: }
8: }
I recommend surrounding the body of any method you intend to call from XSI in a try/catch block like this. You do not need to surround the body of a method that is being called by another method within your library. Only methods that are called directly by XSI should be nested like this. So, for example, in the library above, the body of the method "createMuscle" would not be surrounded by a try/catch block.
Interfaces and Inheritence in XSI
If you look at the scripting reference in the XSI SDK (btw, the scripting reference is the correct reference to use for the COM library version of the XSI SDK), you'll see that each object has a nice little inheritence notation on its docs. For example, the XSIApplication object is said to have the following inhertence.
Now I don't know how C or C++ programmers would interpret this. But I have a Java background as well as a c# background. So when I see something like that my immediate understanding is that the XSIApplication interface implements the Application interface which implements the SIObject interface. That is to say, the XSIApplication interface contains all the methods and fields of the SIObject interface. But apparently thats wrong.
I'm not sure if its the way the COM library is implemented, or the way COMinterop in dotNet is handling it... but within XSI programming with dotNet, thats not how things work.
The instance of the object you get likely implements all three of those intefaces. But the interface definitions themselves are standalone. You need to type cast to get your hands on methods that are from different interfaces. As such the following code does not work:
1: using XSI = SI3DOBJECTMODELLIB;
2: public static void LogMessage(XSI.XSIApplication app, string message, XSI.siSeverity severity){
3: app.LogMessage(message, severity);
4: }
However, the following code does work:
1: using XSI = SI3DOBJECTMODELLIB;
2: public static void LogMessage(XSI.XSIApplication app, string message, XSI.siSeverity severity){
3: ((XSI.Application) app).LogMessage(message, severity);
4: }
This is true not just for the intrinsic objects such as XSIApplication but for the entire XSI object model as far as I can tell.
Getting the XSIApplication object
In most XSI scripting languages, one gets access to a late bound XSIApplication through ActiveX. The jscript code for such an attempt looks like this:
1: var objApplication = new ActiveXObject("XSI.Application");
2: objApplication.LogMessage("Application object saying hi!");
3: var objXSIApplication = objApplication.Application;
4: objXSIApplication.LogMessage("XSIApplication object saying hi!");
Notice that the object you get directly is not an XSIApplication, but an Application. One has to get the XSIApplication from the application field of the Application object (thats a mouthful eh?).
However, when using dotNet languages, one gets the XSIApplication object in an early bound method from the type library directly via COM, not via ActiveX. The c# code for something like that looks like this:
1: using XSI = SI3DOBJECTMODELLIB;
2: public SimpleMuscle() {
3: XSI.CXSIApplication app = new XSI.CXSIApplicationClass();
4: this.pXSIApp = (XSI.XSIApplication) app;
5:
6: }
Note that in this case, I get the XSIApplication object directly. No confusing word jumble involving the word "application". So how do you access the methods and fields of the Application object? Simple: the XSIApplication implements the Application interface as well as the XSIApplication interface. So you can type cast it as follows:
1: using XSI = SI3DOBJECTMODELLIB;
2: public static void LogMessage(XSI.XSIApplication app, string message, XSI.siSeverity severity){
3: ((XSI.Application) app).LogMessage(message, severity);
4: }