Ethereal-dev: [ethereal-dev] Win32 DLL Plugin code

Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.

From: Gilbert Ramirez <gram@xxxxxxxxxx>
Date: Thu, 3 Feb 2000 08:50:40 -0600
Here's the code to enable DLL plugins for the Win32 version of ethereal. 

Win32 DLLs cannot reference symbols that are defined in the parent
executable, i.e., the executable that loads the DLL at run time. To get
around this problem, the parent exectuable will pass pointers to the DLL
initialization routine that let the DLL know the address of functions
and variables in the parent executable.  The parent executable will do
this by passing a pointer to a struct which contains pointers to the
functions and variables that a plugin might need.

This pointer-derefencing will only be done on those platforms that require it.
On sane OSes, the struct of pointer won't be passed to the plugin.

Each plugin will #include "plugins/plugin_api.h". On Unix, this
header file does almost nothing. On Win32, it defines prototypes for
functions that are wrappers for functions in the parent executable.
Win32 plugins must link against plugins/plugin_api.obj, which contains
the wrapper functions. By providing plugin_api.obj, the plugin code
can still call proto_tree_add_item(), for example, and the wrapper
function in plugin_api.obj does the pointer dereferencing to call the
function in the parent executable.

The function proto_init() in the plugins are renamed plugin_init(). They
are passed a pointer; NULL on Unix, and a pointer to the struct containing
the symbol pointers on Win32. The DLL is initialized with this function.

I like how the changes came out, except for one thing.  The plugins
need to access the variable pi (because of macros like END_OF_FRAME),
which is of type packet_info.  I can provide the address to the one
global packet_info through the plugin_init() initialization, but I need
to assign this address to a pointer variable in plugin_api.c, not to a
struct variable.

So, I have this in plugin_api.h

extern packet_info *p_pi;

When initializing the DLL, I assign the address of the exectuable's
global pi to p_pi.

In order to not break compatibility in the plugin between Unix and
Win32 compilation, I define this in plugin_api.h:

#define pi	(*p_pi)

A cleaner way to do this would be to create a global pointer to the
pi variable, and use that in the ethereal exectuable. That way I won't
have to worry about using the struct pi in ethereal and the pointer
p_pi in the modules.

Or, I could redefine the packet.h macros that use pi and put the
definitions that use p_pi in plugin_api.h. 


I want to make a few notes about the patch:

--------------------------------------------------------------------------
diff -u -r1.7 plugins.c
--- plugins.c	2000/01/31 19:50:58	1.7
+++ plugins.c	2000/02/03 14:27:45
@@ -57,12 +57,22 @@
 #include "globals.h"
 #include "util.h"
 
+#ifdef PLUGINS_NEED_ADDRESS_TABLE
+#include "plugins/plugin_api.h"
+plugin_address_table_t	patable;
+extern int hf_text_only;
+#endif
 
 /* linked list of all plugins */
 plugin *plugin_list;
 
+#ifdef WIN32
+static gchar std_plug_dir[] = "c:/program files/ethereal/plugins/0.8";
+static gchar local_plug_dir[] = "c:/ethereal/plugins/0.8";
+#else
 static gchar std_plug_dir[] = "/usr/lib/ethereal/plugins/0.8";
 static gchar local_plug_dir[] = "/usr/local/lib/ethereal/plugins/0.8";
+#endif
--------------------------------------------------------------------------


What would be good values for std_plug_dir and local_plug_dir?


--------------------------------------------------------------------------
@@ -360,12 +379,11 @@
 	    if (!(strcmp(file->d_name, "..") &&
 		  strcmp(file->d_name, "."))) continue;
 
-            /* skip anything but .la */
+            /* skip anything but files with LT_LIB_EXT */
             dot = strrchr(file->d_name, '.');
-            if (dot == NULL || ! strcmp(dot, LT_LIB_EXT)) continue;
+            if (dot == NULL || strcmp(dot, LT_LIB_EXT) != 0) continue;
 
 	    sprintf(filename, "%s/%s", dirname, file->d_name);
-
 	    if ((handle = g_module_open(filename, 0)) == NULL) continue;
 	    name = (gchar *)file->d_name;
 	    if (g_module_symbol(handle, "version", (gpointer*)&version) == FALSE)
--------------------------------------------------------------------------


I found I needed to reverse the result of strcmp() to get the right
behavior. strcmp() will return 0 if the extension (dot) is equal
to LT_LIB_EXT. Without this change, gryphon.dll was not found in
$HOME/.ethereal/plugins (where HOME is c:\ because of get_home_dir()).


--------------------------------------------------------------------------
diff -u -r1.52 proto.c
--- proto.c	2000/01/22 04:59:55	1.52
+++ proto.c	2000/02/03 14:27:45
@@ -75,9 +75,6 @@
 static struct header_field_info*
 find_hfinfo_record(int hfindex);
 
-static proto_item *
-proto_tree_add_item_value(proto_tree *tree, int hfindex, gint start,
-	gint length, int include_format, int visible, va_list ap);
--------------------------------------------------------------------------


I had to make proto_tree_add_item_value() non-static because I have
to call it from plugin_api.c. :-(

 
--------------------------------------------------------------------------
diff -u -r1.4 packet-gryphon.c
--- packet-gryphon.c	2000/01/08 19:37:11	1.4
+++ packet-gryphon.c	2000/02/03 14:27:46
 #include "dfilter.h"
 #include "packet-gryphon.h"
 
-const gchar version[] = VERSION;
-const gchar desc[] = "DG Gryphon Protocol";
-const gchar protocol[] = "tcp";
-const gchar filter_string[] = "tcp.port == 7000";
+DLLEXPORT const gchar version[] = VERSION;
+DLLEXPORT const gchar desc[] = "DG Gryphon Protocol";
+DLLEXPORT const gchar protocol[] = "tcp";
+DLLEXPORT const gchar filter_string[] = "tcp.port == 7000";
--------------------------------------------------------------------------


We now need DLLEXPORT, which I define in plugin_api.h


--------------------------------------------------------------------------
+#ifdef WIN32 
+	unsigned __int64	lnglng;
+#else
+	unsigned long long int	lnglng;
+#endif
--------------------------------------------------------------------------


Guy was right; MSVC 6.0 has __int64


In plugin_api.c, I had to copy the proto_tree_add_*() routines
because they take a variable number of arguments and then pass
a va_list to proto_tree_add_item_value(), which is now renamed
_proto_tree_add_item_value() to denote that no one besides the proto
routines (that is, no dissectors) should be calling it.

--------------------------------------------------------------------------
/* plugin_api.c */

proto_item *
proto_tree_add_item(proto_tree *tree, int hfindex, gint start, gint length, ...)
{
	proto_item	*pi;
	va_list		ap;

	va_start(ap, length);
	pi = patable->_proto_tree_add_item_value(tree, hfindex, start, length, 0, 1, ap);
	va_end(ap);

	return pi;
}
--------------------------------------------------------------------------


Any comments?

--gilbert
? plugins/plugin_api.h
? plugins/plugin_api.c
Index: plugins.c
===================================================================
RCS file: /usr/local/cvsroot/ethereal/plugins.c,v
retrieving revision 1.7
diff -u -r1.7 plugins.c
--- plugins.c	2000/01/31 19:50:58	1.7
+++ plugins.c	2000/02/03 14:27:45
@@ -57,12 +57,22 @@
 #include "globals.h"
 #include "util.h"
 
+#ifdef PLUGINS_NEED_ADDRESS_TABLE
+#include "plugins/plugin_api.h"
+plugin_address_table_t	patable;
+extern int hf_text_only;
+#endif
 
 /* linked list of all plugins */
 plugin *plugin_list;
 
+#ifdef WIN32
+static gchar std_plug_dir[] = "c:/program files/ethereal/plugins/0.8";
+static gchar local_plug_dir[] = "c:/ethereal/plugins/0.8";
+#else
 static gchar std_plug_dir[] = "/usr/lib/ethereal/plugins/0.8";
 static gchar local_plug_dir[] = "/usr/local/lib/ethereal/plugins/0.8";
+#endif
 static gchar *user_plug_dir = NULL;
 static gchar *plugin_status_file = NULL;
 
@@ -289,7 +299,7 @@
     gchar   *ref_string;
     guint16  ref_string_len;
     gchar    line[512];
-    void   (*proto_init)();
+    void   (*plugin_init)(void*);
     dfilter *filter;
 
     if (!statusfile) return;
@@ -306,9 +316,18 @@
 	else { /* found the plugin */
 	    if (line[ref_string_len+1] == '1') {
 		enable_plugin(name, version);
-		if (g_module_symbol(handle, "proto_init", (gpointer*)&proto_init) == TRUE) {
-		    proto_init();
+		if (g_module_symbol(handle, "plugin_init", (gpointer*)&plugin_init) == TRUE) {
+#ifdef PLUGINS_NEED_ADDRESS_TABLE
+		    plugin_init(&patable);
+#else
+		    plugin_init(NULL);
+#endif
+		}
+#ifdef PLUGINS_NEED_ADDRESS_TABLE
+		else {
+			return;
 		}
+#endif
 	    }
 
 	    if (fgets(line, 512, statusfile) == NULL) return;
@@ -360,12 +379,11 @@
 	    if (!(strcmp(file->d_name, "..") &&
 		  strcmp(file->d_name, "."))) continue;
 
-            /* skip anything but .la */
+            /* skip anything but files with LT_LIB_EXT */
             dot = strrchr(file->d_name, '.');
-            if (dot == NULL || ! strcmp(dot, LT_LIB_EXT)) continue;
+            if (dot == NULL || strcmp(dot, LT_LIB_EXT) != 0) continue;
 
 	    sprintf(filename, "%s/%s", dirname, file->d_name);
-
 	    if ((handle = g_module_open(filename, 0)) == NULL) continue;
 	    name = (gchar *)file->d_name;
 	    if (g_module_symbol(handle, "version", (gpointer*)&version) == FALSE)
@@ -430,6 +448,32 @@
 
     if (plugin_list == NULL)      /* ensure init_plugins is only run once */
     {
+
+#ifdef PLUGINS_NEED_ADDRESS_TABLE
+#ifdef pi
+#undef pi
+#endif
+	/* Intialize address table */
+	patable.check_col			= check_col;
+	patable.col_add_fstr			= col_add_fstr;
+	patable.col_append_fstr			= col_append_str;
+	patable.col_add_str			= col_add_str;
+	patable.col_append_str			= col_append_str;
+
+	patable.dfilter_init			= dfilter_init;
+	patable.dfilter_cleanup			= dfilter_cleanup;
+
+	patable.pi				= &pi;
+
+	patable.proto_register_protocol		= proto_register_protocol;
+	patable.proto_register_field_array	= proto_register_field_array;
+	patable.proto_register_subtree_array	= proto_register_subtree_array;
+
+	patable.proto_item_add_subtree		= proto_item_add_subtree;
+	patable._proto_tree_add_item_value	= _proto_tree_add_item_value;
+	patable.hf_text_only			= hf_text_only;
+#endif
+
 	plugins_scan_dir(std_plug_dir);
 	plugins_scan_dir(local_plug_dir);
         if ((strcmp(std_plug_dir, PLUGIN_DIR) != 0) &&
Index: proto.c
===================================================================
RCS file: /usr/local/cvsroot/ethereal/proto.c,v
retrieving revision 1.52
diff -u -r1.52 proto.c
--- proto.c	2000/01/22 04:59:55	1.52
+++ proto.c	2000/02/03 14:27:45
@@ -75,9 +75,6 @@
 static struct header_field_info*
 find_hfinfo_record(int hfindex);
 
-static proto_item *
-proto_tree_add_item_value(proto_tree *tree, int hfindex, gint start,
-	gint length, int include_format, int visible, va_list ap);
 
 static void fill_label_boolean(field_info *fi, gchar *label_str);
 static void fill_label_uint(field_info *fi, gchar *label_str);
@@ -235,7 +232,7 @@
 	va_list		ap;
 
 	va_start(ap, length);
-	pi = proto_tree_add_item_value(tree, hfindex, start, length, 0, 1, ap);
+	pi = _proto_tree_add_item_value(tree, hfindex, start, length, 0, 1, ap);
 	va_end(ap);
 
 	return pi;
@@ -248,7 +245,7 @@
 	va_list		ap;
 
 	va_start(ap, length);
-	pi = proto_tree_add_item_value(tree, hfindex, start, length, 0, 0, ap);
+	pi = _proto_tree_add_item_value(tree, hfindex, start, length, 0, 0, ap);
 	va_end(ap);
 
 	return pi;
@@ -261,7 +258,7 @@
 	va_list		ap;
 
 	va_start(ap, length);
-	pi = proto_tree_add_item_value(tree, hfindex, start, length, 1, 1, ap);
+	pi = _proto_tree_add_item_value(tree, hfindex, start, length, 1, 1, ap);
 	va_end(ap);
 
 	return pi;
@@ -274,7 +271,7 @@
 	va_list		ap;
 
 	va_start(ap, length);
-	pi = proto_tree_add_item_value(tree, hf_text_only, start, length, 0, 1, ap);
+	pi = _proto_tree_add_item_value(tree, hf_text_only, start, length, 0, 1, ap);
 	va_end(ap);
 
 	return pi;
@@ -287,14 +284,14 @@
 	va_list		ap;
 
 	va_start(ap, length);
-	pi = proto_tree_add_item_value(tree, hf_text_only, start, length, 1, 1, ap);
+	pi = _proto_tree_add_item_value(tree, hf_text_only, start, length, 1, 1, ap);
 	va_end(ap);
 
 	return pi;
 }
 
-static proto_item *
-proto_tree_add_item_value(proto_tree *tree, int hfindex, gint start,
+proto_item *
+_proto_tree_add_item_value(proto_tree *tree, int hfindex, gint start,
 	gint length, int include_format, int visible, va_list ap)
 {
 	proto_item	*pi;
Index: proto.h
===================================================================
RCS file: /usr/local/cvsroot/ethereal/proto.h,v
retrieving revision 1.21
diff -u -r1.21 proto.h
--- proto.h	2000/01/22 04:59:55	1.21
+++ proto.h	2000/02/03 14:27:45
@@ -179,6 +179,12 @@
 void
 proto_register_subtree_array(gint **indices, int num_indices);
 
+/* We have to make this prototype accessible for plugin_api.c, but we
+   don't want anybody except plugin_api.c to use it directly */
+proto_item *
+_proto_tree_add_item_value(proto_tree *tree, int hfindex, gint start,
+	gint length, int include_format, int visible, va_list ap);
+
 proto_item *
 proto_tree_add_item(proto_tree *tree, int hfindex, gint start,
 	gint length, ...);
Index: gtk/plugins_dlg.c
===================================================================
RCS file: /usr/local/cvsroot/ethereal/gtk/plugins_dlg.c,v
retrieving revision 1.12
diff -u -r1.12 plugins_dlg.c
--- plugins_dlg.c	2000/01/17 20:30:17	1.12
+++ plugins_dlg.c	2000/02/03 14:27:45
@@ -38,6 +38,11 @@
 #include "prefs_dlg.h"
 #include "simple_dialog.h"
 
+#ifdef PLUGINS_NEED_ADDRESS_TABLE
+#include "plugins/plugin_api.h"
+extern plugin_address_table_t	patable;
+#endif
+
 #ifdef HAVE_PLUGINS
 
 static gint selected_row;
@@ -238,12 +243,12 @@
 {
     plugin    *pt_plug;
     gpointer symbol;
-    void     (*proto_init)(void);
+    void     (*plugin_init)(void*);
 
     /* nothing selected */
     if (selected_row == -1) return;
     /* already enabled */
-    if (!strcmp(selected_enabled, "Yes")) return;
+    if (strcmp(selected_enabled, "Yes") == 0) return;
 
     if ((pt_plug = enable_plugin(selected_name, selected_version)) == NULL)
     {
@@ -253,10 +258,21 @@
 
     /* Try to get the initialization routine for the plugin, and, if it
        has one, call it. */
-    if (g_module_symbol(pt_plug->handle, "proto_init", &symbol) == TRUE) {
-	proto_init = symbol;
-	proto_init();
-    }
+    if (g_module_symbol(pt_plug->handle, "plugin_init", &symbol) == TRUE) {
+	plugin_init = symbol;
+#ifdef PLUGINS_NEED_ADDRESS_TABLE
+		    plugin_init(&patable);
+#else
+		    plugin_init(NULL);
+#endif
+	}
+#ifdef PLUGINS_NEED_ADDRESS_TABLE
+	else {
+		simple_dialog(ESD_TYPE_WARN, NULL, "Failed to find plugin_init()");
+		return;
+	}
+#endif
+
 
     gtk_clist_set_text(GTK_CLIST(clist), selected_row, 3, "Yes");
 }
Index: plugins/gryphon/packet-gryphon.c
===================================================================
RCS file: /usr/local/cvsroot/ethereal/plugins/gryphon/packet-gryphon.c,v
retrieving revision 1.4
diff -u -r1.4 packet-gryphon.c
--- packet-gryphon.c	2000/01/08 19:37:11	1.4
+++ packet-gryphon.c	2000/02/03 14:27:46
@@ -29,6 +29,8 @@
 #include "config.h"
 #endif
 
+#include "plugins/plugin_api.h"
+
 #include "moduleinfo.h"
 
 #ifdef HAVE_SYS_TYPES_H
@@ -37,6 +39,7 @@
 
 #include <string.h>
 #include <ctype.h>
+#include <time.h>
 
 #include <glib.h>
 #ifdef HAVE_NETINET_IN_H
@@ -46,10 +49,10 @@
 #include "dfilter.h"
 #include "packet-gryphon.h"
 
-const gchar version[] = VERSION;
-const gchar desc[] = "DG Gryphon Protocol";
-const gchar protocol[] = "tcp";
-const gchar filter_string[] = "tcp.port == 7000";
+DLLEXPORT const gchar version[] = VERSION;
+DLLEXPORT const gchar desc[] = "DG Gryphon Protocol";
+DLLEXPORT const gchar protocol[] = "tcp";
+DLLEXPORT const gchar filter_string[] = "tcp.port == 7000";
 
 static int proto_gryphon = -1;
 
@@ -77,15 +80,9 @@
 static gint ett_gryphon_pgm_list = -1;
 static gint ett_gryphon_pgm_status = -1;
 static gint ett_gryphon_pgm_options = -1;
-
-#define gryphon_LTX_desc          desc
-#define gryphon_LTX_dissector     dissector
-#define gryphon_LTX_filter_string filter_string
-#define gryphon_LTX_proto_init    proto_init
-#define gryphon_LTX_protocol      protocol
-#define gryphon_LTX_version       version
 
-void dissector(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
+DLLEXPORT void
+dissector(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
 {
 
     proto_tree	    *gryphon_tree, *header_tree, *body_tree;
@@ -648,14 +645,22 @@
     int     hours, minutes, seconds, fraction;
     union {
     	unsigned int	   lng[2];
-	unsigned long long int  lnglng;
+#ifdef WIN32 
+	unsigned __int64	lnglng;
+#else
+	unsigned long long int	lnglng;
+#endif
     } ts;
     unsigned int    timestamp;
     unsigned char   date[45];
-    
+   
     ts.lng[1] = pntohl ((unsigned int *)(*data));
     ts.lng[0] = pntohl ((unsigned int *)((*data)+4));
+#ifdef WIN32
+    timestamp = ts.lnglng / 100000;
+#else
     timestamp = ts.lnglng / 100000LL;
+#endif
     strncpy (date, ctime((time_t*)&timestamp), sizeof(date));
     date[strlen(date)-1] = 0x00;
     proto_tree_add_text(pt, *offset, 8, "Date/Time: %s", date);
@@ -1517,8 +1522,8 @@
     BUMP (*offset, *data, 4);
 }
 
-void
-proto_init(void)
+DLLEXPORT void
+plugin_init(plugin_address_table_t *pat)
 {
     static hf_register_info hf[] = {
 	{ &hf_gryph_src,
@@ -1560,7 +1565,7 @@
 	&ett_gryphon_pgm_status,
 	&ett_gryphon_pgm_options,
     };
-    
+    plugin_address_table_init(pat);
     dfilter_cleanup();
     proto_gryphon = proto_register_protocol("DG Gryphon Protocol", "gryphon");
     proto_register_field_array(proto_gryphon, hf, array_length(hf));
/* plugin_api.c
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <stdarg.h>

#include "plugin_api.h"

static plugin_address_table_t	*patable = NULL;
packet_info			*p_pi;


#ifdef pi
#undef pi
#endif

void
plugin_address_table_init(plugin_address_table_t *pat)
{
	patable = pat;
	p_pi = pat->pi;
}

gint
check_col(frame_data* fd, gint col)
{
	return patable->check_col(fd, col);
}

/*void col_add_fstr(frame_data*, gint, gchar*, ...);
void col_append_fstr(frame_data*, gint, gchar*, ...);*/

void
col_add_str(frame_data* fd, gint col, const gchar* str)
{
	patable->col_add_str(fd, col, str);
}

void
col_append_str(frame_data* fd, gint col, gchar* str)
{
	patable->col_append_str(fd, col, str);
}

void
dfilter_init(void)
{
	patable->dfilter_init();
}

void
dfilter_cleanup(void)
{
	patable->dfilter_cleanup();
}

int
proto_register_protocol(char* name, char* abbrev)
{
	return patable->proto_register_protocol(name, abbrev);
}

void
proto_register_field_array(int parent, hf_register_info* hf, int num_records)
{
	patable->proto_register_field_array(parent, hf, num_records);
}

void
proto_register_subtree_array(int** indices, int num_indices)
{
	patable->proto_register_subtree_array(indices, num_indices);
}

proto_tree*
proto_item_add_subtree(proto_item* pi, gint idx)
{
	patable->proto_item_add_subtree(pi, idx);
}

proto_item *
proto_tree_add_item(proto_tree *tree, int hfindex, gint start, gint length, ...)
{
	proto_item	*pi;
	va_list		ap;

	va_start(ap, length);
	pi = patable->_proto_tree_add_item_value(tree, hfindex, start, length, 0, 1, ap);
	va_end(ap);

	return pi;
}

proto_item *
proto_tree_add_item_hidden(proto_tree *tree, int hfindex, gint start, gint length, ...)
{
	proto_item	*pi;
	va_list		ap;

	va_start(ap, length);
	pi = patable->_proto_tree_add_item_value(tree, hfindex, start, length, 0, 0, ap);
	va_end(ap);

	return pi;
}

proto_item *
proto_tree_add_item_format(proto_tree *tree, int hfindex, gint start, gint length, ...)
{
	proto_item	*pi;
	va_list		ap;

	va_start(ap, length);
	pi = patable->_proto_tree_add_item_value(tree, hfindex, start, length, 1, 1, ap);
	va_end(ap);

	return pi;
}

proto_item *
proto_tree_add_notext(proto_tree *tree, gint start, gint length, ...)
{
	proto_item	*pi;
	va_list		ap;

	va_start(ap, length);
	pi = patable->_proto_tree_add_item_value(tree, patable->hf_text_only, start, length, 0, 1, ap);
	va_end(ap);

	return pi;
}

proto_item *
proto_tree_add_text(proto_tree *tree, gint start, gint length, ...)
{
	proto_item	*pi;
	va_list		ap;

	va_start(ap, length);
	pi = patable->_proto_tree_add_item_value(tree, patable->hf_text_only, start, length, 1, 1, ap);
	va_end(ap);

	return pi;
}
/* plugin_api.h
 */

#ifndef __PACKET_H__
#include "packet.h"
#endif

#ifdef PLUGINS_NEED_ADDRESS_TABLE
#define DLLEXPORT    __declspec(dllexport)

/* Some OSes (Win32) have DLLs that cannot reference symbols in the parent executable.
   So, the executable needs to provide a table of pointers for the DLL plugin to use. */

/* Typedefs to make our plugin_address_table_t struct look prettier */
typedef gint (*addr_check_col)(frame_data*, gint);
typedef void (*addr_col_add_fstr)(frame_data*, gint, gchar*, ...);
typedef void (*addr_col_append_fstr)(frame_data*, gint, gchar*, ...);
typedef void (*addr_col_add_str)(frame_data*, gint, const gchar*);
typedef void (*addr_col_append_str)(frame_data*, gint, gchar*);

typedef void (*addr_dfilter_init)(void);
typedef void (*addr_dfilter_cleanup)(void);

typedef int (*addr_proto_register_protocol)(char*, char*);
typedef void (*addr_proto_register_field_array)(int, hf_register_info*, int);
typedef void (*addr_proto_register_subtree_array)(int**, int);

typedef proto_tree* (*addr_proto_item_add_subtree)(proto_item*, gint);
typedef proto_item* (*addr_proto_tree_add_item)(proto_tree*, int, gint, gint, ...);
typedef proto_item* (*addr_proto_tree_add_item_hidden)(proto_tree*, int, gint, gint, ...);
typedef proto_item* (*addr_proto_tree_add_item_format)(proto_tree*, int, gint, gint, ...);
typedef proto_item* (*addr_proto_tree_add_notext)(proto_tree*, gint, gint, ...);
typedef proto_item* (*addr_proto_tree_add_item_value)(proto_tree*, int, gint, gint, int, int,
				va_list);
extern packet_info *p_pi;

typedef struct  {

	addr_check_col				check_col;
	addr_col_add_fstr			col_add_fstr;
	addr_col_append_fstr			col_append_fstr;
	addr_col_add_str			col_add_str;
	addr_col_append_str			col_append_str;

	addr_dfilter_init			dfilter_init;
	addr_dfilter_cleanup			dfilter_cleanup;

	packet_info				*pi;

	addr_proto_register_protocol		proto_register_protocol;
	addr_proto_register_field_array		proto_register_field_array;
	addr_proto_register_subtree_array	proto_register_subtree_array;

	addr_proto_item_add_subtree		proto_item_add_subtree;
	addr_proto_tree_add_item_value		_proto_tree_add_item_value;
	int					hf_text_only;
} plugin_address_table_t;

/* The parent executable will send us the pointer to a filled in
   plugin_address_table_t struct, and we keep a copy of that pointer
   so that we can use functions in the parent executable. */
void plugin_address_table_init(plugin_address_table_t*);

/* Wrapper functions that use plugin_address_table_t */
gint check_col(frame_data*, gint);
void col_add_fstr(frame_data*, gint, gchar*, ...);
void col_append_fstr(frame_data*, gint, gchar*, ...);
void col_add_str(frame_data*, gint, const gchar*);
void col_append_str(frame_data*, gint, gchar*);

void dfilter_init(void);
void dfilter_cleanup(void);

int proto_register_protocol(char*, char*);
void proto_register_field_array(int, hf_register_info*, int);
void proto_register_subtree_array(int**, int);

proto_tree* proto_item_add_subtree(proto_item*, gint);
proto_item* proto_tree_add_item(proto_tree*, int, gint, gint, ...);
proto_item* proto_tree_add_item_hidden(proto_tree*, int, gint, gint, ...);
proto_item* proto_tree_add_item_format(proto_tree*, int, gint, gint, ...);
proto_item* proto_tree_add_notext(proto_tree*, gint, gint, ...);
proto_item* proto_tree_add_text(proto_tree*, gint, gint, ...);

#define pi	(*p_pi)


#else

/* ! PLUGINS_NEED_ACCESS_TABLE */
#define DLLEXPORT 
typedef void	plugin_address_table_t;
#define plugin_address_table_init(x) ;

#endif