- ffi.c : C側のメモリは Haskell で確保してのを受け取って使うか、malloc で確保して開放する関数を Haskell から呼べば良い、たぶん。
- 勿論、C で開放できるならその方が楽です。
#include <stdio.h> #include <windows.h> #include <malloc.h> #include <objbase.h> /* CLSID構造体へのポインタを返す */ CLSID* emptyCLSIDstruct (void) { static CLSID clsid; static CLSID *p; p=&clsid; return p; } /* CLSID構造体のポインタを受け取ってサイズを返す */ int getCLSIDstructSize (CLSID *clsid) { static int size; size = sizeof(*clsid); return size; } /* 文字列を合成して返す */ char *changeString (char *fromList, char *clsid) { static char buf[256]; sprintf(buf,"%s --> sizeof(CLSID) = %s", fromList, clsid); return buf; }
ごちゃごちゃやっていますが、やっている内容に意味はなく C と Haskell との間でデータを渡しあえるかどうかテストしているだけです。
- FFItest.hs
{-# LANGUAGE ForeignFunctionInterface #-} -- ghc --make FFItest.hs ffi.c -main-is FFItest -lole32 -loleaut32 -luuid -o FFItest module FFItest where import Foreign.Ptr import Foreign.C.String import Foreign.C.Types import Foreign.Marshal.Alloc data CLSID = CLSID main = do -- C の関数でCLSID構造体を作って、そのポインタを取得。 let pclsid = c_emptyCLSIDstruct -- 受け取ったポインタのアドレスを渡してサイズを取得。 let size = c_getCLSIDstructSize (castPtr pclsid) -- リスト文字列からC文字列を作成。 cstrFFI <- newCString "Foreign Function Interface" -- CLSID構造体サイズからリスト文字列を作り、そこからC文字列を作成。 cstrSize <- newCString (show size) -- 文字列を連結するCの関数に cstrFFI、cstrSize のふたつの文字列を渡し、 -- 加工された文字列を受け取る。 let cstrFromC = c_changeString cstrFFI cstrSize -- C文字列からリスト文字列を作成。 lstr <- peekCString cstrFromC -- リスト文字列を表示 putStrLn lstr -- C文字列のメモリを開放 Foreign.Marshal.Alloc.free cstrFFI Foreign.Marshal.Alloc.free cstrSize foreign import ccall "emptyCLSIDstruct" c_emptyCLSIDstruct :: (Ptr CLSID) foreign import ccall "getCLSIDstructSize" c_getCLSIDstructSize :: (Ptr (Ptr CLSID)) -> CInt foreign import ccall "changeString" c_changeString :: CString -> CString -> CString {- The Haskell 98 Foreign Function Interface 1.0 An Addendum to the Haskell 98 Report 3.1 Calling Conventions http://www.cse.unsw.edu.au/~chak/haskell/ffi/ffi/ffise3.html#x6-110003.1 ccall C compiler on a system cplusplus C++ compiler on a system dotnet .net platform jvm Java Virtual Machine stdcall Win32 API (matches Pascal conventions) -}
> ghc --make FFItest.hs ffi.c -main-is FFItest -lole32 -loleaut32 -luuid -o FFItest Linking FFItest.exe ... > ./FFItest Foreign Function Interface --> sizeof(CLSID) = 16