Multiple Servers in One Module

A single plug-in module can, and often will, contain multiple servers. This page describes the approach that I have found useful for organizing and maintaining a related set of servers.

initialize() Member Function

When writing a class that will be a server or exported object, I always add a static intialize() function as a member of the class. Placing it at the top of the class declaration helps remind you to change the initialization if you change the set of interfaces that your class supports.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
 class CInstance :
                public CLxImpl_PackageInstance,
                public CLxImpl_MeshInfluence,
                public CLxImpl_ItemInfluence,
                public CLxImpl_WeightMapDeformerItem
 {
     public:
                static void
        initialize ()
        {
                CLxGenericPolymorph             *srv;
1
2
3
4
5
6
7
8
9
                srv = new CLxPolymorph<CInstance>;
                srv->AddInterface (new CLxIfc_PackageInstance      <CInstance>);
                srv->AddInterface (new CLxIfc_MeshInfluence        <CInstance>);
                srv->AddInterface (new CLxIfc_ItemInfluence        <CInstance>);
                srv->AddInterface (new CLxIfc_WeightMapDeformerItem<CInstance>);
                lx::AddSpawner (SPWNAME_INSTANCE, srv);
        }
        ...
 };
1
2
3
4
5
6
7
8
9
 class CPackage :
                public CLxImpl_Package,
                public CLxImpl_SceneItemListener
 {
     public:
                static void
        initialize ()
        {
                CLxGenericPolymorph             *srv;
1
2
3
4
5
6
7
8
                srv = new CLxPolymorph<CPackage>;
                srv->AddInterface (new CLxIfc_Package          <CPackage>);
                srv->AddInterface (new CLxIfc_SceneItemListener<CPackage>);
                srv->AddInterface (new CLxIfc_StaticDesc       <CPackage>);
                lx::AddServer (SRVNAME_ITEMTYPE, srv);
        }
        ...
 };

Namespaces

You’ll note that the classes above have very generic names – CInstance and CPackage – named simply for the type of object. They maintain uniqueness by being wrapped in a namespace that actually describes the specific thing they implement. This also facilitates code reuse by copy and paste (when necessary) by allowing common elements to have the same names. Inside the namespace there’s an ‘’initialize(‘’) function that calls the object initialize() methods for everything in the namespace.

1
        namespace Influence_General {
1
2
 class CInstance :
         ...
1
2
 class CPackage :
         ...
1
2
3
4
5
6
        void
 initialize ()
 {
        CPackage   :: initialize ();
        CInstance  :: initialize ();
 }
1
        };      // END namespace

Single Entry Point

Finally there’s a single ‘’initialize(‘’) function, not declared as part of any namespace, that serves as the common entry point for all server and object initialization for the entire module. This is typically a file by itself, and it calls all the namespace-qualified initialize() functions. They could be declared in a header, but they are so ‘’pro forma’’ that hardly seems necessary.

1
 #include <lx_plugin.hpp>
1
2
3
 namespace Influence_General    {       extern void     initialize ();  };
 namespace Falloff_Radial       {       extern void     initialize ();  };
 namespace Command_Morph        {       extern void     initialize ();  };
1
2
3
4
5
6
7
        void
 initialize ()
 {
        Influence_General       :: initialize ();
        Falloff_Radial          :: initialize ();
        Command_Morph           :: initialize ();
 }