How to bind a window library (in C) to Haskell?

Hi - I'd like to be able to use Haskell for the project I'm working on but the problem is that I've already written a lot of code for a nice GUI using DirectX in Visual C++. I thought it might be possible to make up some kind of simple API for it which I could call from Haskell, so I started with the following simple Haskell module to try and see if I could understand the FFI: module Main where data Window = Window_Edit | Window_List | Window_Tree data Layout = Layout_Left | Layout_Right type Callback = () -> Bool foreign import ccall gui_init :: [(Window, Layout, Callback)] -> IO () main = gui_init [(Window_Edit, Layout_Left, \_->True)] Of course my "init" function is far too simple, but I was thinking this captures the essence of the kinds of things that would need to be passed to the C++ code ie a list of windows and call back functions etc. However I've immediately run into a major problem. When I try to compile with ghc -fglasgow-exts --make main.hs I get an error: "unacceptable argument type in foreign declaration..." My questions are: 1) Does this mean that the FFI can only pass Int, Char etc and not user defined data types or compound data types? 2) I'm also really confused by the different kinds of pointers available, and how to safely store a function closure in some C data structure, and how to use this to call the function from within C and access the result safely 3) When does GHC do garbage collection? Is the garbage collection done in the same thread as the executing program? Does GHC run a normal Haskell program using multiple threads? Would I need to link my C DLL with a multithreaded version of the C runtime to avoid problems? Alternatively, has anyone managed to use DirectX or COM from within a Haskell program? (because then I could perhaps rewrite all my gui code from scratch in Haskell...) (I'm loathe to switch to OpenGL because OpenGL is very poorly supported on windows - a default WinXP installation does not come with hardware accelerated OpenGL drivers, afaik, and also I can't find any documentation on the Haskell OpenGL bindings except the Haddock type signatures which are just not nearly enough to understand how to use it, and some out of date docs) Thanks, Brian.

On 2/27/06, Brian Hulley
1) Does this mean that the FFI can only pass Int, Char etc and not user defined data types or compound data types?
Yes. The idea is that instead of pointers/references you have Ptr a, and instance Storable a that provides marshalling between haskell and C. Very often you actually get two sets of bindings, "raw", exact C-signatures, enums as variables etc, and higher level, implemented on top of the raw-level, where you have data and class declarations to simulate usefull parts of foreign C hierarchy - your code looks more like the higher-level part.
2) I'm also really confused by the different kinds of pointers available, and how to safely store a function closure in some C data structure, and how to use this to call the function from within C and access the result safely
Ptr is basically plain old c-pointer. Haskell, however, just sees it as an address with typetag, and accessing object requires marshalling, typically through Storable-class. FunPtr is basically plain c-function pointer. To create FunPtr's, you need to declare and use ffi-wrappers. Something like (taken from Win32-packages Graphics.Win32.Window): type WindowClosure = HWND -> WindowMessage -> WPARAM -> LPARAM -> IO LRESULT foreign import ccall "wrapper" mkWindowClosure :: WindowClosure -> IO (FunPtr WindowClosure) If you are resource-handling savvy, you need to call freeHaskellFunPtr after you finish using that FunPtr. Of course, plain C-function pointers are naturally FunPtr's, and require no freeing.
3) When does GHC do garbage collection? Is the garbage collection done in the same thread as the executing program? Does GHC run a normal Haskell program using multiple threads? Would I need to link my C DLL with a multithreaded version of the C runtime to avoid problems?
C and ghc memory management are not tied together. You should use your own functions in C to release any memory allocated in C. As far as I understand, haskell gc only happens when you are executing haskell.
Alternatively, has anyone managed to use DirectX or COM from within a Haskell program? (because then I could perhaps rewrite all my gui code from
I have written, but not published, experimental DirectX9.D3D bindings. I plan to publish it at some point, but it's pretty hairy at the moment (and incomplete, not all of D3D is done, also no docs etc). I don't have time to work on them right now, so you might need to put quite an effort in if you wish to use them. (And there is no DirectX 7 bindings, if you are using that for 2D.) Using COM might be pretty obvious if you are willing to play around with IDL and HaskellDirect. (There is no IDL files for DirectX9, so I used various hacks and COM c-interface) Or ofcourse, manually reading COM vtables isn't that hard, either. There are various other things one can do, also. Like using C-interface and thin c-wrapper funcionts (COM interface c-parts are usually preprocessor macros, so linking them in haskell isn't really convient). Or C++. of course, but then
scratch in Haskell...) (I'm loathe to switch to OpenGL because OpenGL is very poorly supported on windows - a default WinXP installation does not come with hardware accelerated OpenGL drivers, afaik, and also I can't find any documentation on the Haskell OpenGL bindings except the Haddock type signatures which are just not nearly enough to understand how to use it, and some out of date docs)
If you are comfortable reading OpenGL spec, the haddock documentation should be pretty simple to follow. HTH, -Esa

Hi Esa! Thanks for the very detailed and clear explanation! I was going to wait till I'd implemented a simple example of passing/calling a function closure to post a reply but I've wasted all day just trying to think up a good name for my graphics library! :-) Regarding DirectX bindings, if you've not already done so you may be interested to see how the DirectX9 .NET api is structured. Certainly when I wrote a small graphics program in C# a year or so ago I was quite impressed by the way the DX9.NET api managed to hide a lot of the mess that you have to deal with in the C/C++ api such as keeping track of resources that suddenly disappear and dealing with reset properly. It looks like I won't need to go to such a low level though for my api - I imagine my call back functions will be implemented easily by using a FunPtr to something which returns a suitable monadic type which will keep track of the state of the app's 'document' and be combined with the IO monad in some way. Also thanks for pointing out the existence of the Win32 bindings. Also I noticed that a Haskell version of the ObjectIO library was hiding in my GHC installation too, so this will be a further useful source of ideas for how to structure my api. Best regards, Brian.
participants (2)
-
Brian Hulley
-
Esa Ilari Vuokko