Windowsアプリその後
なんだかいじっていたら進化してしまったのでアップ。
Ruby1.8用。
DLのPtrDataオブジェクトのptrメソッドを呼ぶとなぜかコケるので、ウィンドウハンドルはポインタじゃなくint型にして強引に扱っている。
そんなもんか。
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 GetMessage(int*,int,int,int)" extern "int TranslateMessage(int*)" extern "int DispatchMessage(int*)" extern "void PostQuitMessage(int)" extern "void* GetWindowLong(int,int)" extern "int SetWindowText(int, char*)" 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" ] end class Form @@control = {} def initialize @@control[self.class] = {} wndProc = DL::callback("IIIII") do |a,msg,wparam,lparam| case msg when 0x0111 # WM_COMMAND if wparam >> 16 == 0 then # BN_CLICKED self.__send__(@@control[self.class][lparam][0]+"_OnClick") end 0 when 2 # WM_DESTROY LIBC::postQuitMessage(0) 0 else LIBC::defWindowProc(a,msg,wparam,lparam) end end wndclass = LIBC::WndClassEx.malloc wndclass.cbSize = wndclass.size wndclass.style = 0 wndclass.lpfnWndProc = 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) # WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU @hWnd = LIBC::createWindowEx(0,"testclass", "testwindow", 0x10000000 | 0x00000000 | 0x00C00000 | 0x00080000, 0, 0, 200, 200, 0, nil, nil, nil) init end def addControl(c, name, caption, x, y, w, h) temp = c.new(@hWnd, caption, x, y, w, h) @@control[self.class][temp.hWnd] = [name, temp] instance_eval("def #{name}\n @@control[self.class][#{temp.hWnd}][1]\n end") end def messageLoop msg = LIBC::MSG.malloc loop do if LIBC::getMessage(msg, 0, 0, 0) == 0 then break end LIBC.translateMessage(msg) LIBC.dispatchMessage(msg) end end end class Button attr_reader :hWnd def initialize(hWnd, caption, x, y, w, h) @hWnd = LIBC::createWindowEx(0,"BUTTON",caption, 0x10000000 | 0x40000000 | 0x00000001,# WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, x,y,w,h,hWnd,nil, nil,#LIBC::getWindowLong(@hWnd, -6) nil); end def caption=(str) LIBC::setWindowText(@hWnd, str) end end # ↑ライブラリのコード # ↓アプリケーションのコード class Form1 < Form def init addControl(Button, "button1", "OK", 10, 10, 100, 20) addControl(Button, "button2", "Cancel", 10, 50, 100, 20) end def button1_OnClick button1.caption = "おらー" end def button2_OnClick button2.caption = "ぎゃー" end end a = Form1.new a.messageLoop
こんな感じで使えるようにしていけば、なんだかWindowsアプリが簡単に作れそうな気がしてくる。
まあ、まともな開発環境になるまでには膨大なコードが必要で、そんな苦労するぐらいならVisualuRubyとかwxRubyとか使えよ、って話なんだけど。