-- Haskell version of "Hello, World" using the Win32 library. -- Demonstrates how the Win32 library can be put to use. -- (c) sof 1999 module Main(main) where import qualified Win32 import Addr -- Toplevel main just creates a window and pumps messages. -- The window procedure (wndProc) we pass in is partially -- applied with the user action that takes care of responding -- to repaint messages (WM_PAINT). main :: IO () main = do lpps <- Win32.malloc Win32.sizeofPAINTSTRUCT hwnd <- createWindow 200 200 (wndProc lpps onPaint) messagePump hwnd -- OnPaint handler for a window - draw a string centred -- inside it. onPaint :: Win32.RECT -> Win32.HDC -> IO () onPaint (_,_,w,h) hdc = do Win32.setBkMode hdc Win32.tRANSPARENT Win32.setTextColor hdc (Win32.rgb 255 255 0) let y | h==10 = 0 | otherwise = ((h-10) `div` 2) x | w==50 = 0 | otherwise = (w-50) `div` 2 Win32.textOut hdc x y "Hello, world" return () -- Simple window procedure - one way to improve and generalise -- it would be to pass it a message map (represented as a -- finite map from WindowMessages to actions, perhaps). wndProc :: Win32.LPPAINTSTRUCT -> (Win32.RECT -> Win32.HDC -> IO ()) -- on paint action -> Win32.HWND -> Win32.WindowMessage -> Win32.WPARAM -> Win32.LPARAM -> IO Win32.LRESULT wndProc lpps onPaint hwnd wmsg wParam lParam | wmsg == Win32.wM_DESTROY = do Win32.sendMessage hwnd Win32.wM_QUIT 1 0 return 0 | wmsg == Win32.wM_PAINT && hwnd /= nullAddr = do r <- Win32.getClientRect hwnd paintWith lpps hwnd (onPaint r) return 0 | otherwise = Win32.defWindowProc (Just hwnd) wmsg wParam lParam createWindow :: Int -> Int -> Win32.WindowClosure -> IO Win32.HWND createWindow width height wndProc = do let winClass = Win32.mkClassName "Hello" icon <- Win32.loadIcon Nothing Win32.iDI_APPLICATION cursor <- Win32.loadCursor Nothing Win32.iDC_ARROW bgBrush <- Win32.createSolidBrush (Win32.rgb 0 0 255) mainInstance <- Win32.getModuleHandle Nothing Win32.registerClass ( Win32.cS_VREDRAW + Win32.cS_HREDRAW , mainInstance , Just icon , Just cursor , Just bgBrush , Nothing , winClass ) w <- Win32.createWindow winClass "Hello, World example" Win32.wS_OVERLAPPEDWINDOW Nothing Nothing -- leave it to the shell to decide the position -- at where to put the window initially (Just width) (Just height) Nothing -- no parent, i.e, root window is the parent. Nothing -- no menu handle mainInstance wndProc Win32.showWindow w Win32.sW_SHOWNORMAL Win32.updateWindow w return w messagePump :: Win32.HWND -> IO () messagePump hwnd = do msg <- Win32.getMessage (Just hwnd) `catch` \ _ -> return nullAddr if msg == nullAddr then return () else do Win32.translateMessage msg Win32.dispatchMessage msg messagePump hwnd paintWith :: Win32.LPPAINTSTRUCT -> Win32.HWND -> (Win32.HDC -> IO a) -> IO a paintWith lpps hwnd p = do hdc <- Win32.beginPaint hwnd lpps a <- p hdc Win32.endPaint hwnd lpps return a