FREE Subscription to Dr. Dobb’s Digest: Same Great Content, New Digital Edition
Site Archive (Complete)
C++
Email
Print
Reprint

add to:
Del.icio.us
Digg
Google
Furl
Slashdot
Y! MyWeb
Blink
February 13, 2008

Building Your Own Plugin Framework: Part 5

(Page 3 of 7)

Dynamic C Plugins

C plugins register objects that implement the C_Actor interface. The plugin itself -- and even the C_Actor implementation -- may be C++ classes (using static methods). In this case, I implemented everything in C, just to ensure the system supports pure C plugins (there were a few compilation gotchas before it worked). The C plugin registers a single monster called MellowMonster. The header file of this quaint monster is presented in Example 4. This is a C object, so there is no class definition only the global functions MellowMonster_create() and MellowMonster_destroy(), which correspond to PF_CreateFunc and PF_DestroyFunc. The names are qualified with the monster type because, in general, a single plugin may register monster types with different pairs of create()/destroy() functions and in C we can't hide them in a namespace or as static methods of a class.

#ifndef MELLOW_MONSTER_H
#define MELLOW_MONSTER_H

#include <plugin_framework/plugin.h>

// static plugin interface void * MellowMonster_create(PF_ObjectParams *); apr_int32_t MellowMonster_destroy(void *); #endif

Example 4

Example 5 presents the actual monster. It's just a struct that contains a C_Actor member and optionally more monster-specific data. Not much of a monster so far.

typedef struct MellowMonster_
{
  C_Actor actor;

/* additional monster-specific data */ apr_uint32_t dummy; } MellowMonster;

Example 5

Example 6 is the implementation of the C_Actor interface and consists of two static functions (not visible outside of this compilation unit) -- MellowMonster_getInitialInfo() and MellowMonster_play() -- that correspond to the IActor methods. The big difference is that the C++ methods get the object instance as the implicit 'this' pointer. In C, you must pass a C_ActorHandle explicitly (well, not you, but the PluginManager) and the C functions laboriously cast the handle to a MellowMonster pointer. When the C_Turn object is used in the play() function, you must pass it its own handle too.

void MellowMonster_getInitialInfo(C_ActorHandle handle, C_ActorInfo * info)
{
  MellowMonster * mm = (MellowMonster *)handle;
  strcpy((char *)info->name, "MellowMonster");
  info->attack = 10;
  info->damage = 3;
  info->defense = 8;
  info->health = 20;
  info->movement = 2;

  /* Irrelevant. Will be assigned by system later */
  info->id = 0;
  info->location_x = 0;
  info->location_y = 0;
}
void MellowMonster_play(C_ActorHandle handle, C_Turn * turn)
{
  MellowMonster * mm = (MellowMonster *)handle;
  C_ActorInfoIterator * friends = turn->getFriends(turn->handle);
}
Example 6

Example 7 contains the MellowMonster_create() and MellowMonster_destroy() functions and ties up loose ends. The MellowMonster_create() function allocates a MellowMonster struct (using malloc, of course), assigns the pointer to the handle member of the actor field (without checking if the memory allocation failed, boo :-), and goes one to assign the MellowMonster_getInitialInfo() and MellowMonster_play() functions to proper function pointers. Finally it returns the MellowMonster pointer as an opaque void pointer. It is important that the C_Actor interface be the first member of the MellowMonster struct, because the PluginManager (via the adapter) casts the returned void pointer to a C_Actor pointer and treats it as such from then on.

The MellowMonster_destroy() frees the memory. If there is any need for destructor-like cleanup, it can do it too.

Let's check the initialization code of the C plugin in Listing Four. It looks just like the C++ plugin. This isn't surprising because it is a C function that needs to prepare a C struct and call yet another C function. The only real difference is that the registered programming language for MellowMonster is PF_ProgrammingLanguage_C. That tells the PluginManager that it's dealing with a C object and it should adapt it.

#ifdef WIN32
#include "stdafx.h"
#endif

#include "c_plugin.h" #include "c_plugin.h" #include "plugin_framework/plugin.h" #include "MellowMonster.h"

PLUGIN_API apr_int32_t ExitFunc() { return 0; }

PLUGIN_API PF_ExitFunc PF_initPlugin(const PF_PlatformServices * params) { int res = 0; PF_RegisterParams rp; rp.version.major = 1; rp.version.minor = 0; // Regiater MellowMonster rp.createFunc = MellowMonster_create; rp.destroyFunc = MellowMonster_destroy; rp.programmingLanguage = PF_ProgrammingLanguage_C; res = params->registerObject((const apr_byte_t *)"MellowMonster", &rp); if (res < 0) return NULL; return ExitFunc; }

Listing Four

As you can see, working at the C API level is much thornier. You need pass explicit handles around, cast a lot, pay attention to function names, and hook up free functions to your monster C_Actor interfaces. It's not fun, but it's survivable if you must work with C.

Previous Page | 1 Dynamic C++ Plugins | 2 Static C++ Plugins | 3 Dynamic C Plugins | 4 Hybrid C/C++ Plugins | 5 Let's Play! | 6 Source Code Walkthrough | 7 The NuPIC Plugin Framework Next Page
TOP 5 ARTICLES
No Top Articles.



MICROSITES
FEATURED TOPIC

ADDITIONAL TOPICS

INFO-LINK