Channels ▼
RSS

Design

Building Your Own Plugin Framework: Part 5


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.


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.
 

Video