<html> <head> <title>How to register a class object</title> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> <link rel="stylesheet" href="highlight.css" type="text/css"> </head> <body bgcolor="#FFFFFF" text="#000000"> <p><font size="6"><i><b>How to register a class object</b></i></font></p> <p align="left"><font size="4">In the <a href="howto_class.html">previous HowTo</a> we created a class object for the C++ class Simple. Before this class object can be used by the zeitgeist framework it must be registered with a zeitgeist::Core object. The Core is the object hierarchy, which is basically a virtual file system where instances of classes represent the directories and 'files'. Therefore, each class instance can be identified by a path. The Core has a function called RegisterClassObject() which inserts the class object into the object hierarchy. Class objects are located under the '/classes/' branch of the hierarchy. We have two major scenarios of how a class object can be registered: Directly or indirectly!</font></p> <p align="left"><font size="4"><b>Direct Registration</b></font></p> <p align="left"><font size="4">This scenario is used in the case of static libraries and executables, which want to expose custom classes to the object hierarchy. An example of a library, which does this is Kerosin. This way of registering is pretty straight forward and involves an initialization function which has a means to access the zeitgeist::Core instance where the class objects are to be registered. Then it (directly) calls the RegisterClassObject()-method to successively add class objects. Here's a short snippet from the Kerosin library:</font></p> <pre><span class="dir">#include </span><span class="dstr">"kerosin.h"</span><span class="dir"></span> <span class="dir">#include <zeitgeist/scriptserver/scriptserver.h> </span> <span class="key">using namespace </span>kerosin; <span class="key">using namespace </span>zeitgeist; Kerosin::Kerosin(zeitgeist::Zeitgeist &zg) { zg.GetCore()->RegisterClassObject(<span class="key">new </span>CLASS(SoundServer), <span class="str">"kerosin/"</span>); zg.GetCore()->RegisterClassObject(<span class="key">new </span>CLASS(InputServer), <span class="str">"kerosin/"</span>); zg.GetCore()->RegisterClassObject(<span class="key">new </span>CLASS(ImageServer), <span class="str">"kerosin/"</span>); zg.GetCore()->RegisterClassObject(<span class="key">new </span>CLASS(FontServer), <span class="str">"kerosin/"</span>); zg.GetCore()->RegisterClassObject(<span class="key">new </span>CLASS(OpenGLServer), <span class="str">"kerosin/"</span>); </pre> <p align="left"><font size="4">The Kerosin library is initialized by creating an instance of the Kerosin class. The constructor needs a reference to the Zeitgeist object (which represents the Zeitgeist library), so it can get access to the Core. The class objects are all added to the object hierarchy under the '/classes/' branch. The second parameter of RegisterClassObject() allows to specify an additional subpath. So, the class object for the SoundServer (for example) will be located at '/classes/kerosin/SoundServer' ... in a way, this allows to create a form of namespaces among the class objects. As we can see, it is possible to add a class object directly at any time during the execution of the program.</font></p> <p align="left"> </p> <p align="left"><font size="4"><b>Indirect Registration</b></font></p> <p align="left"><font size="4">The second scenario involves packaging a bunch of class objects into a shared library (DLL). The DLL becomes a class library, containing a collection of classes to be added to the object hierarchy. This kind of DLL is referred to as a Bundle. The Bundle contains a well-defined entry point function, which registers its contents with the calling Core. This (again) is simplified through the use of several macros. First, we have to create a DLL project, containing a bunch of classes and their corresponding class objects (see the <a href="howto_class.html">previous HowTo</a>). Then, we create an additional CPP file. I usually call this file export.cpp. Let's say we have two classes in our bundle, Simple and Complex. The corresponding export.cpp would look like this:</font></p> <pre><span class="dir">#include </span><span class="dstr">"simple.h"</span><span class="dir"></span> <span class="dir">#include </span><span class="dstr">"complex.h"</span><span class="dir"></span> <span class="dir">#include <zeitgeist/zeitgeist.h> </span> ZEITGEIST_EXPORT_BEGIN() ZEITGEIST_EXPORT(Simple); ZEITGEIST_EXPORT(Complex); ZEITGEIST_EXPORT_END() </pre> <p align="left"><font size="4">Thanks to the macros, this is again very easy to grasp. We just include the header files of all classes we want to expose. These should also incorporate the correct class object declarations. Then we include the zeitgeist framework. The following macros implement the entry point function. ZEITGEIST_EXPORT_BEGIN() implements the beginning of the function. Then we use ZEITGEIST_EXPORT() for every class we want to export, and finally ZEITGEIST_EXPORT_END() to 'terminate' the function. Now, we just compile the shared library and 'presto' ... a Zeitgeist-capable Bundle has been created. The ZEITGEIST_EXPORT_EX() macro can be used to specify a subpath as above with RegisterClassObject().</font></p> <p align="left"><font size="4">To indirectly register the classes contained in a Bundle, you just import the bundle into the Core. This is done with the ImportBundle()-member function. This function opens the shared library. Gets the entry point function and calls it with an STL list. The class objects are added to this list within the entry point function. After returning, all class objects contained in this list are added to the object hierarchy.</font></p> <p align="left"><font size="4">In the <a href="howto_script.html">next HowTo</a>, we will take a look at executing Ruby scripts, loading Bundles via scripts and creating instances of classes via scripts.</font></p> </body> </html>