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 = π + + 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*)×tamp), 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
- Follow-Ups:
- Re: [ethereal-dev] Win32 DLL Plugin code
- From: Guy Harris
- Re: [ethereal-dev] Win32 DLL Plugin code
- Prev by Date: [ethereal-dev] ethereal 0.8.3
- Next by Date: Re: [ethereal-dev] Win32 DLL Plugin code
- Previous by thread: Re: [ethereal-dev] ethereal 0.8.3
- Next by thread: Re: [ethereal-dev] Win32 DLL Plugin code
- Index(es):