C++ plugin needs to know when Sketchup is closing

I inherited the code for a c++ SketchUp plugin, with the usual Ruby loading process. The c function Init_sketchupplugin() does run, and the commands it maps run as they should.

extern “C” __declspec(dllexport)
void Init_sketchupplugin()
{
mSUEX_MyApp = rb_define_module(“SUEX_MyApp”);
rb_define_module_function(mSUEX_MyApp, “do_license”, VALUEFUNC(DoLicense), 0);
rb_define_module_function(mSUEX_MyApp, “do_about”, VALUEFUNC(DoAbout), 0);
myAppInitFunction();
}

Now need to know when SketchUp is closing, so I can have my plugin free up memory it no longer needs. Do I need to put some specific code in my loader, or a specially name function in my c code?

I think you might need to use an AppObserver from the Ruby API, and it’s #onQuit callback.

The examples always show a subclass implementation, but in reality the observers are abstract (have no superclass functionality,) and the #add_observer methods do not do any type or class checking.

This means that any kind of object that has public accessible callback methods can “act” as a observer object.

So you could simply define an “onQuit” callback method to your “SUEX_MyApp” module, …
a singleton method will also do.

rb_define_module_function(mSUEX_MyApp,"onQuit", VALUEFUNC(DoOnQuit), 0);

… and then attach that module to the Sketchup application. …

rb_eval_string("Sketchup.add_observer(SUEX_MyApp)");

You can also set up a finalizer for your module that is supposed to run after it gets destroyed. See:
https://ruby-doc.org/core-2.5.5/ObjectSpace.html#method-c-define_finalizer

1 Like

That worked perfectly! Thank you!

1 Like

To invoke the logic without eval you can do something like this:

VALUE cAppObserver = rb_define_class_under(mSUEX_MyApp, "MyAppObserver", rb_cObject);
rb_define_method(cAppObserver ,"onQuit", VALUEFUNC(DoOnQuit), 0);

VALUE mSketchup = rb_const_get("Sketchup");

VALUE observer_instance = rb_class_new_instance(0, NULL, cAppObserver );
rb_funcall(mSketchup, rb_intern("add_observer"), 1, observer_instance);

I know I could also have shown one of the rb_funcall functions but didn’t have time (to look them up) and eval is not that big a time waster as it’ll be done once per session, most likely.


There is no reason whatsoever, to follow a subclassing pattern for abstract observer superclasses that (1) have no functionality to pass down to subclasses, … and (2) the SketchUp API’s observer attachment methods do no typechecking, ie, they only require an object that has publicly available callback methods.

If you have need of only one observer object, a module (usually the plugin submodule itself,) will do fine (as it is an instance of class Module.) Especially when it comes to AppObserver callbacks as there will always only be one application instance. (Ie, no one will ever need multiple AppObserver subclass instances.)