Linking to an existing DLL

Back to main list

Sometimes you have an existing DLL and you need to call routines in it from R. Changing the contents of the DLL is not an option, but the DLL doesn't follow the R calling conventions. In this case, you probably need to write a wrapper DLL.

R is written using the MinGW port of gcc, and you'll get the best support from other R users if you write your wrapper in MinGW using C. The steps to follow are:

  1. Finding the exports from your DLL
  2. Creating an import library
  3. Writing C wrapper functions
  4. Calling from R
These instructions assume that you have correctly installed the R Windows toolset, as described in the R Installation and Administration manual.

Finding the DLL's exports

The easiest way to find the exports is using the MinGW utility function pexports. (This is not part of the R Windows toolset; you need to download it separately from the MinGW page, in the "MinGW Utilities" collection.) This will list the names of the functions, and from those one can often guess the calling convention. Exports that have a suffix @n, where n is a number, almost certainly use the stdcall convention. Exports with no suffix may use stdcall (e.g. Windows API functions), or cdecl, or another convention (e.g. if produced by Delphi). For example,

$ pexports teststdcall.dll
LIBRARY teststdcall.dll
EXPORTS
dostdcall@8
is an example where dostdcall is an exported function using the stdcallconvention. (I use the Cygwin bash shell, so the dollar sign "$" above is the command prompt. Doing this in the Windows CMD shell would be very similar.)

See Wu Yongwei's web page for more details about naming conventions.


Creating an import library


The MinGW linker needs an import library in order to link to a DLL. (It can produce this automatically, but the process was buggy in the past, and is less flexible than the following description.) These instructions are based on the MinGW Wiki page on this topic. The first thing to do is to create a text description of the contents of the DLL. Typically the output of pexports is sufficient, e.g.
$ pexports teststdcall.dll >teststdcall.def
Then use dlltool -D <DLLname> -d <defs> -l <libname> to create the library, e.g.
$ dlltool -D teststdcall.dll -d teststdcall.def -l libteststdcall.a
See the Wiki for some other dlltool options.

Writing C wrapper functions


The Writing R Extensions manual describes the sorts of C functions that R knows how to call. You need to write one of those, and have it make a call into the DLL in whatever format it expects. For example, if the DLL has a function taking a double and returning a double, and using the stdcall calling convention, you'd write something like this:
__stdcall double dostdcall(double x);

void callit(double *x)
{
     double y;
     y = dostdcall(*x);
     *x = y;
}
Put this in a file named e.g. callstdcall.c. You need to tell MinGW to include the import library that you defined above. Do this using the "-L. -lteststdcall" option (NB: notice no "lib" in the library name). You pass options to MinGW on its command line, or (better!) through the PKG_LIBS environment variable when using Rcmd SHLIB. For example,
$ export PKG_LIBS="-L. -lteststdcall"
$ Rcmd SHLIB callstdcall.c
making callstdcall.d from callstdcall.c
gcc   -If:/R/svn/r-devel/R/include -Wall -O2   -c callstdcall.c -o callstdcall.o

ar cr callstdcall.a callstdcall.o
ranlib callstdcall.a
gcc  --shared -s  -o callstdcall.dll callstdcall.def callstdcall.a 
  -Lf:/R/svn/r-devel/R/src/gnuwin32  -L. -lteststdcall -lg2c -lR

Calling your function from R


At this point you have created a DLL which can be called from R, using the standard methods as described in Writing R Extensions. For example,
> dyn.load('callstdcall.dll')
> .C('callit', x=as.double(  ))

Last modified: $Date: 2006-07-06 15:47:05 -0400 (Thu, 06 Jul 2006) $, by Duncan Murdoch