At first I used Ruby's Win32API. It works fine, provided that the dll function does not return a pointer. For example, if the DLL function is
char * controlx (int a, int b, some_struct * c)
In ruby you can process arguments a, b, and even c, but I almost vomited blood trying to process the return pointer. The thing is, Ruby do not use pointers ! This makes it very tricky to process return pointers from functions.
I was about to use plain old C to do the job, or maybe even Python (I got a Python friend - or fiend - who is telling me that this is no prob in Python, even though Python doesn't use pointers too). Then I googled upon the SWIG project (www.swig.org).
It do me a while to get SWIG working for Ruby. SWIG is pretty well documented, but the below gives the juice of the process and some gotchas. SWIG essentially generates a Ruby wrapper module (in c) for the DLL.
To save hassles, get the same c compiler and environment that created the Ruby windows version you are using. Ruby 1.9 uses MINGW compiler (basically an open source Windows C compiler that uses the Windows libraries, unlike CYGWIN that uses the POSIX libraries). You also need the make program. So I installed MINGW and MSYS, which gives a POSIX-like shell with the essential make program and other usual shell goodies. I think it may be possible to use Microsoft Visual C and nmake.exe (same Windows library calls right?), but I didn't to bother to try that.
You have to create a interface.i file that lists down the DLL functions. It looks like this.
%module your_desired_ruby_name%{ /* Put header files here or struct declarations that are needed by the functions below */ %}
%feature("autodoc", "1"); /* this is for Ruby's rdoc */extern char * DLL_function1(void);
%feature("autodoc", "1");extern bool DLL_function2(void);...............
Then just execute
> swig -ruby interface.i
or for c++
> swig -c++ -ruby interface.i
SWIG is supposed to be able to wrap both C and C++ functions for Ruby. However when I tried it with the c++ option, the generated c++ wrapper code is not compilable. No problem, I just changed all the bool types in my interface to char, and I had switched to a nice C interface. Anyway why would anyone export C++ functions in a DLL? DLLs are meant to be called from any language.
SWIG generates a c program named interface_wrapper.c. This is just a Ruby c module. So you can now use the standard Ruby ways to compile the module. You can either go the gcc way, or use Ruby built-in mkmf class. mkmf is recommended because it handles all the gcc settings for your Ruby installation (mostly the include dirs etc).
To use mkmf, create a extconf.rb file that looks like this
require 'mkmf'$libs = append_library($libs, "your_dll_name")create_makefile('your_ruby_module_name')
Now execute
>ruby extconf.rb
This creates a Makefile in the local directory
>make
This compiles the wrapper Ruby module. Put the DLL in the same directory as the wrapper c code to avoid any linking problems. Then just
>make install
Viola! Your Ruby wrapper module had been compiled and copied to your Ruby installation. In my case it is
C:\Ruby19\lib\ruby\site_ruby\1.9.1\i386-msvcrt
To use your DLL functions, just fire up irb or type in a ruby program
irb> require 'your_module_name'irb> YOUR_MODULE_NAME_IN_CAPITAL.dll_function_xxxx
Oh yeah one last thing. Use rdoc to generate some nice documentation of what the DLL input/output parameters are.
rdoc -f html interface_wrap.c