2006-12-15
■[Haskell] ドラッグ & ドロップしたファイルのパスをクリップボードにコピーする

Win32SDKを使って、ドラッグ & ドロップしたファイルのパスをクリップボードにコピーするプログラムを書いてみました。うーん、見事なほどにIOの山。ついでにスーパーpre記法のシンタックス・ハイライトを使ってソースコードに色をつけてみました。でもHaskellはあんまりきれいに色がつかないなー。
ファイル: pathcopy.hs
module Main (main) where import Data.Bits ((.&.), (.|.)) import Data.IORef (IORef, newIORef, readIORef, modifyIORef) import Data.List (intersperse) import Foreign.C.String (withCStringLen, peekCAString) import Foreign.Marshal.Alloc (allocaBytes) import Foreign.Ptr (castPtr) import Graphics.Win32 import System.Exit (exitWith, ExitCode (ExitSuccess)) import System.Win32 putTextIntoClipboard :: String -> IO () putTextIntoClipboard s = withCStringLen s $ \ (cstr, len) -> do let len' = fromInteger $ toInteger $ len + 1 h <- globalAlloc (gMEM_DDESHARE .&. gMEM_MOVEABLE) len' s <- globalLock h copyMemory (castPtr s) cstr len' globalUnlock h openClipboard nullPtr emptyClipboard setClipboardData cF_TEXT h closeClipboard foreign import stdcall unsafe "DragQueryFileA" cDragQueryFile :: WPARAM -> UINT -> LPTSTR -> UINT -> IO UINT dragQueryFiles :: WPARAM -> IO [FilePath] dragQueryFiles wParam = do f 0 =<< cDragQueryFile wParam (-1) nullPtr 0 where bufSize = 4096 f i n | i == n = return [] | otherwise = do file <- allocaBytes bufSize $ \ p -> do cDragQueryFile wParam i p (fromInteger $ toInteger bufSize) peekCAString $ castPtr p files <- f (i + 1) n return $ file : files createMainWindow :: String -> Pos -> Pos -> IORef [String] -> IO HWND createMainWindow title width height var = do hinst <- getModuleHandle Nothing icon <- loadIcon Nothing iDI_APPLICATION cursor <- loadCursor Nothing iDC_ARROW brush <- getStockBrush lTGRAY_BRUSH registerClass ((cS_HREDRAW .|. cS_VREDRAW), hinst, Just icon, Just cursor, Just brush, Nothing, mkClassName $ title) hwnd <- createWindowEx wS_EX_ACCEPTFILES (mkClassName $ title) title wS_OVERLAPPEDWINDOW Nothing Nothing (Just width) (Just height) Nothing Nothing hinst $ wndProc var showWindow hwnd sW_SHOWNORMAL updateWindow hwnd return hwnd wndProc :: IORef [String] -> HWND -> WindowMessage -> WPARAM -> LPARAM -> IO LRESULT wndProc var hwnd wmsg wParam lParam | wmsg == wM_DESTROY = onDestroy | wmsg == wM_PAINT = onPaint | wmsg == wM_DROPFILES = onDropFiles | wmsg == wM_LBUTTONDOWN = onClicked | wmsg == wM_KEYDOWN = onKeyDown | otherwise = defWindowProc (Just hwnd) wmsg wParam lParam where onDestroy = do putTextIntoClipboard . formatCopyString =<< readIORef var sendMessage hwnd wM_QUIT 1 0 onPaint = do files <- readIORef var allocaPAINTSTRUCT $ \ lpps -> do hdc <- beginPaint hwnd lpps setBkMode hdc tRANSPARENT setTextColor hdc $ rgb 0 0 0 textOut hdc 40 60 "Drop on me!!" textOut hdc 40 80 $ (show $ length files) ++ " files dropped." endPaint hwnd lpps updateWindow hwnd return 0 onDropFiles = do files <- dragQueryFiles wParam modifyIORef var (\ ss -> ss ++ files) invalidateRect (Just hwnd) (Just nullPtr) True return 0 onClicked = sendMessage hwnd wM_CLOSE 1 0 onKeyDown = onClicked messageLoop :: HWND -> IO () messageLoop = allocaMessage . loop where loop hwnd msg = do getMessage msg (Just hwnd) `catch` \ _ -> exitWith ExitSuccess translateMessage msg dispatchMessage msg loop hwnd msg basename :: FilePath -> String basename = reverse . takeWhile (/= '\\') . reverse formatCopyString :: [FilePath] -> String formatCopyString = concat . intersperse "\n" . map f where f file = "\x81\x9b " ++ basename file ++ "\n<" ++ file ++ ">\n" main :: IO () main = messageLoop =<< createMainWindow "Drop on me!!" 200 200 =<< newIORef [] -- Local Variables: -- compile-command: "ghc -W -fno-warn-unused-matches -optl-mwindows -ffi -package Win32 -lshell32 -o pathcopy pathcopy.hs" -- End:
コンパイル方法。
$ ghc -W -fno-warn-unused-matches -optl-mwindows -ffi -package Win32 -lshell32 -o pathcopy pathcopy.hs
使い方。
■[Haskell] 指定した桁数で改行を入れる

おおー、id:hakobe932くんもHaskellかー。id:hakobe932:20061215:1166201940
僕も大体同じ動きをするプログラムを書いてみました。参考まで。
module Main (main) where import System (getArgs) import System.IO (stderr, hPutStrLn) readFiles :: [String] -> IO String readFiles [] = getContents readFiles files = return . concat =<< mapM readFile files groupn :: Int -> [a] -> [[a]] groupn _ [] = [] groupn n s = s1 : groupn n s2 where (s1, s2) = splitAt n s filln :: Int -> [FilePath] -> IO () filln column files = putStr . unlines . concatMap (groupn column) . lines =<< readFiles files main :: IO () main = do args <- getArgs case args of (column : files) -> filln (read column) files _ -> usage where usage = hPutStrLn stderr $ "usage: filln column files..."
■Hello, world!といえば…

世の中、いかに小さいHello, world!を作るかというすばらしいチャレンジをされているかたがいるようです。こんなの年賀状でもらっても…
そういえばしばらく前にBinary Hacksは買ったんだけど、目次をパラパラめくってそのまま積ん読です。うーむ。冬休みの課題かなー。(その前に僕のPCにまともに動くUNIXを入れなきゃ。)
Binary Hacks ―ハッカー秘伝のテクニック100選
- 作者: 高林哲,鵜飼文敏,佐藤祐介,浜地慎一郎,首藤一幸
- 出版社/メーカー: オライリー・ジャパン
- 発売日: 2006/11/14
- メディア: 単行本(ソフトカバー)
- 購入: 20人 クリック: 318回
- この商品を含むブログ (220件) を見る
あ、そうそうBinary HacksといえばBinary 2.0 カンファレンスも本日開催されているようです。こちらの資料も楽しみ。
■そうだ京都行こう

明日Ruby勉強会で京都に行きます。折角なので京都のガイドブックを買ってみました。明日早起きできたら早めに京都に行ってぶらぶらしてみよう。
- 作者: 京阪神エルマガジン社
- 出版社/メーカー: 京阪神エルマガジン社
- 発売日: 2006/03
- メディア: ムック
- クリック: 2回
- この商品を含むブログ (45件) を見る
ついでに神戸のガイドブックも買ってみました。普通自分が住んでる街のガイドブックってあまり買わないと思うのですが、意外と行ってみたいお店がいっぱいありました。こういう刺激がないといつも行くお店が固定化されて行動範囲が広がりにくいのかも。
- 作者: 京阪神エルマガジン社
- 出版社/メーカー: 京阪神エルマガジン社
- 発売日: 2006/07
- メディア: ムック
- クリック: 2回
- この商品を含むブログ (9件) を見る
■[読書][英語] My Family and Other Animals(6,900語)

"My Family and Other Animals" (Penguin Readers (Graded Readers))
- 作者: Gerald Durrell
- 出版社/メーカー: Penguin
- 発売日: 1999/11/01
- メディア: ペーパーバック
- クリック: 1回
- この商品を含むブログ (1件) を見る
■[ウクレレ] Eの押え方

僕は、4弦から4(中指)4(中指)4(薬指)2(人差し指)かな。人差し指は2フレットをセーハしてしまうことも多いです。Eを使うキーでは、セーハが必要がコードが多いような気がするので…



プログラム。趣味ですから… あ、音楽も趣味で普段はウクレレをへろへろ弾いています。