[Haskell-cafe] FFI and Excel VBA

Lewis-Sandy, Darrell darrelll at amgen.com
Thu Jun 21 10:46:56 EDT 2007


I was able to figure out how to get the example in chapter 11 of the GHC
manual to work.  Since it was not intuitive (to a non C programmer), I
thought that I should post this so that others might take advantage of it.

KEYWORDS: Foreign, Export, Win32, DLL, VBA, Excel, GCH, Example

The contents of adder.hs are as follows:
--------------------------------------------
module Adder(adder) where

import Foreign

adder :: Int -> Int -> IO Int  
adder x y = return (id$!(x+y))

foreign export stdcall adder :: Int -> Int -> IO Int
--------------------------------------------

The contents of the dllMain.c file are below:
--------------------------------------------

#include <windows.h>
#include <Rts.h>

extern void __stginit_Adder(void);

static char* args[] = { "ghcDll", NULL };

BOOL STDCALL DllMain ( HANDLE hModule, DWORD reason, void* reserved )
{
  if (reason == DLL_PROCESS_ATTACH) {
      startupHaskell(1, args, __stginit_Adder);
      return TRUE;
  }

  if (reason == DLL_PROCESS_DETACH) {
        shutdownHaskell();
        return TRUE;
  }

  return TRUE;
}

--------------------------------------------
Note that the GHC manual omits the space between the "void" and the
__stgint_Adder(void) which causes a compile error.  The second case (if
(reason == DLL_PROCESS_DETACH) is essential for garbage collection, and
shuts down the Haskell runtime when the DLL is unloaded.

To execute the Haskell code, I created a VBA module in an Excel workbook
with the following code snippet:
--------------------------------------------
Private Declare Function adder Lib "adder.dll" _
  (ByVal x As Integer, ByVal y As Integer) As Integer

Private Sub test()
Debug.Print adder(1, 2)
End Sub
--------------------------------------------
NOTE: If the dll is not ultimately placed in your environments' PATH, then
you may have to modify the library name to include the actual path
information (or else you will get an error indicating that the library can't
be found).  Example:  ... adder Lib "c:\myDlls\adder\adder.dll" ...

Finally, you need to explicitly define an exports file to keep the c
compiler from mangling the names too badly.  The contents of adder.def are
as follows:
--------------------------------------------
EXPORTS
   adder
   suber
   hello
--------------------------------------------

With these preliminaries out of the way, you can compile this to a dll using
the following sequence of commands:
--------------------------------------------
ghc -c adder.hs -fglasgow-exts
ghc -c dllMain.c
ghc --mk-dll -optdll--def=adder.def -o adder.dll adder.o adder_stub.o
dllMain.o
--------------------------------------------

When this is all done, open the XLProject and press F5 to run, or simply
type "=adder(1,2)" in any cell of the workbook. 

I hope that this was helpful.

-Darrell Lewis-Sandy


More information about the Haskell-Cafe mailing list