Making Windows executables...
Juan Carlos Arevalo Baeza
jcab.lists at JCABs-Rumblings.com
Sat Aug 27 22:03:00 EDT 2005
Seth Kurtzberg wrote:
> Juan Carlos Arevalo Baeza wrote:
>
>> Thanx! That's exactly what I needed. The swhich was undocumented! :-P
>>
>> :-) I understand the caveats well enough. You can avoid the
>> exceptions very easily using this code:
>>
>> ---8<--------------------------------------
>> import Foreign.C.Types
>> import Foreign.C.String
>>
>> foreign import ccall unsafe "HsBase.h __hscore_open" c_open ::
>> CString -> CInt -> CInt -> IO CInt
>> foreign import ccall unsafe "HsBase.h dup2" dup2 :: CInt -> CInt ->
>> IO CInt
>>
>> open fname oflag pmode = withCString fname $ \c_fname -> c_open
>> c_fname oflag pmode
>>
>> main =
>> fd <- open "nul" 2 0
>> dup2 fd 0
>> dup2 fd 1
>> dup2 fd 2
>
>
> I guess Windows can make even Haskell programs look ugly. Or at the
> very least esthetically unpleasing. :)
He he... I seriously doubt that Windows has much to do with the
uglyness in thic case, as the above code is just a workarround for a
shortcoming in the compiler more than anything else, but yes. Win32
programming is very imperative, so it doesn't look very good in Haskell.
Nothing much to do about that. OpenGL is just as bad (or worse - it adds
the concept of the hidden "current" context).
Incidentally, given that the Win32 (and HGL too!) support in GHC 6.4
was so completely broken that it doesn't even compile, I've been
learning FFI by implementing my own bindings for Win32. I took to
porting Raymond Chen's chinese dictionary example:
http://blogs.msdn.com/oldnewthing/archive/2005/04/22/410773.aspx
http://blogs.msdn.com/oldnewthing/archive/2005/05/10/415991.aspx
http://blogs.msdn.com/oldnewthing/archive/2005/05/11/416430.aspx
http://blogs.msdn.com/oldnewthing/archive/2005/05/13/417183.aspx
http://blogs.msdn.com/oldnewthing/archive/2005/05/16/417865.aspx
http://blogs.msdn.com/oldnewthing/archive/2005/05/18/419130.aspx
http://blogs.msdn.com/oldnewthing/archive/2005/05/19/420038.aspx
http://blogs.msdn.com/oldnewthing/archive/2005/06/13/428534.aspx
http://blogs.msdn.com/oldnewthing/archive/2005/06/14/428892.aspx
http://blogs.msdn.com/oldnewthing/archive/2005/06/15/429338.aspx
http://blogs.msdn.com/oldnewthing/archive/2005/07/11/437522.aspx
http://blogs.msdn.com/oldnewthing/archive/2005/07/12/437974.aspx
http://blogs.msdn.com/oldnewthing/archive/2005/07/13/438381.aspx
http://blogs.msdn.com/oldnewthing/archive/2005/08/11/450383.aspx
http://blogs.msdn.com/oldnewthing/archive/2005/08/12/450818.aspx
and added all the platform support I needed into Haskell to get the
program working. It works very well: I didn't even need to use any C
code at all, just FFI. There's something to be said about the
possibility of doing the mesage-handling callback like so (and don't
look at the hardcoded peeks and pokes, please ;-)):
---8<---------------------------------------
mainWindowProc :: IORef MainWindowData -> WNDPROC
mainWindowProc wdataRef hwnd msg wParam lParam
...
| msg == wM_PAINT = do
withPaint hwnd $ \dc ps -> do
return 0
return 0
| msg == wM_CLOSE = do
postQuitMessage 0
return 1
| msg == wM_COMMAND = do
let id = loWORD wParam
let cmd = CMD $ hiWORD wParam
when_ (id == 2 && cmd == eN_CHANGE) $ do
refilterRef wdataRef
defWindowProc hwnd msg wParam lParam
| msg == wM_NOTIFY = do
let p = nullPtr `plusPtr` fromIntegral lParam
wdata <- readIORef wdataRef
let lvHwnd = lvWindow wdata
childHwnd <- peekByteOff p 0
--childId <- peekByteOff p 4
code <- peekByteOff p 8
case code of
_| code == lVN_GETDISPINFO -> do
i <- peekByteOff p 16 :: IO INT
when_ ((i >= 0) && (i < (fromIntegral $ dictIndexSize
wdata))) $ do
mask <- peekByteOff p 12
when_ ((mask .&. lVIF_TEXT) /= LVIF 0) $ do
let (trad, simp, pinyin, english) = dict wdata !
(dictIndex wdata ! fromIntegral i)
col <- peekByteOff p 20 :: IO INT
pokeByteOff p 32 $ case col of
_| col == cOL_TRAD -> trad
_| col == cOL_SIMP -> simp
_| col == cOL_PINYIN -> pinyin
_| col == cOL_ENGLISH -> english
when_ ((mask .&. lVIF_IMAGE) /= LVIF 0) $ do
pokeByteOff p 40 (-1 :: INT)
when_ ((mask .&. lVIF_STATE) /= LVIF 0) $ do
pokeByteOff p 24 (0 :: UINT)
return 0
_| code == nM_CUSTOMDRAW && lvHwnd == childHwnd -> do
drawStage <- peekByteOff p 12
case drawStage of
_| drawStage == cDDS_PREPAINT -> return
cDRF_NOTIFYITEMDRAW
_| drawStage == cDDS_ITEMPREPAINT -> do
clrText <- peekByteOff p 48
writeIORef wdataRef $ wdata { normalTextColor =
clrText }
return cDRF_NOTIFYSUBITEMDRAW
_| drawStage == cDDS_SUBITEMPREPAINT -> do
itemSpec <- peekByteOff p 36 :: IO DWORD
subItem <- peekByteOff p 56
if subItem == cOL_PINYIN && itemSpec <
(fromIntegral $ arrayLength $ dict wdata) then do
let (ctrad, csimp, cpinyin, cenglish) =
dict wdata ! fromIntegral itemSpec
pinyin <- peekCWString cpinyin
if pinyin == "" || head pinyin == 'a' then
pokeByteOff p 48 $ rgb 0x80 0 0x80
else
pokeByteOff p 48 $
normalTextColor wdata
else
pokeByteOff p 48 $ normalTextColor wdata
return cDRF_DODEFAULT
otherwise -> do
return cDRF_DODEFAULT
otherwise -> do
return 0
| msg == wM_NOTIFYFORMAT = do
return nFR_UNICODE
| otherwise =
defWindowProc hwnd msg wParam lParam
---8<---------------------------------------
Hopefully, I'll find better ways to expose different things to the
Haskell program. Like proper lazy access to parameters passed by pointer
to structure (I started a thread about this in Haskell Cafe), or a
better way to dispatch the messages (Hash?).
JCAB
More information about the Glasgow-haskell-users
mailing list