Pure RubyでWindowsアプリ

DLを使ってコールバックできれば、ウィンドウプロシージャも作れてWindowsアプリが書けるのではなかろうか。
という話だったので、試してみた。

require "dl/import"
require "dl/struct"

module LIBC
  extend DL::Importable
  dlload "user32.dll"
  dlload "kernel32.dll"

  extern "int RegisterClassEx(int*)"
  extern "int DefWindowProc(int,int,int,int)"
  extern "int CreateWindowEx(int,char*,char*,int,int,int,int,int,int*,int*,int*,int*)"
  extern "int PeekMessage(int*,int*,int,int,int)"
  extern "int TranslateMessage(int*)"
  extern "int DispatchMessage(int*)"
  extern "void PostQuitMessage(int)"

  WndClassEx = struct [
    "int   cbSize",
    "int   style",
    "int*  lpfnWndProc",
    "int   cbClsExtra",
    "int   cbWndExtra",
    "int*  hInstance",
    "int*  hIcon",
    "int*  hCursor",
    "int  hbrBackground",
    "char* lpszMenuName",
    "char* lpszClassName",
    "int*  hIconSm"
  ]

  MSG = struct [
    "int hwnd",
    "int message",
    "int wParam",
    "int lParam",
    "int time",
    "int ptx",
    "int pty"
  ]

  def wndproc(a,b,c,d)
    if b == 2 then # WM_DESTROY
      postQuitMessage(0)
      return 0
    end
    defWindowProc(a,b,c,d)
  end
  WNDPROC = callback "int wndproc(int,int,int,int)"
end
wndclass = LIBC::WndClassEx.malloc

wndclass.cbSize = wndclass.size
wndclass.style = 0
wndclass.lpfnWndProc = LIBC::WNDPROC
wndclass.cbClsExtra = 0
wndclass.cbWndExtra = 0
wndclass.hInstance = nil
wndclass.hIcon = nil
wndclass.hCursor = nil
wndclass.hbrBackground = 5 # COLOR_WINDOW
wndclass.lpszMenuName = nil
wndclass.lpszClassName = "testclass"
wndclass.hIconSm = nil

LIBC.registerClassEx(wndclass.to_ptr)

# WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
LIBC.createWindowEx(0,"testclass", "testwindow", 
                    0x10000000 | 0x00000000 | 0x00C00000 | 0x00080000 | 0x00040000,
                    0, 0, 200, 200, nil, nil, nil, nil)

msg = LIBC::MSG.malloc
loop do
  if LIBC.peekMessage(msg, nil, 0, 0, 0x0001) != 0 then # PM_REMOVE
    if msg.message == 0x0012 then # WM_QUIT
      break
    end
    LIBC.translateMessage(msg)
    LIBC.dispatchMessage(msg)
  end
  sleep 0.001
end


うむ。
テキトーに作ったからいろいろ問題はありそうなソースだが、とりあえず動いた。
頑張ればRubyだけできちんとしたWindowsアプリが作れそうだ。
それに意味があるかどうかはちょっと疑問だが。