w32apis.rb
よくRubyから win32apiを呼び出して使用する。
しかし、その度に Win32API.newするのが面倒なので、下記の様なラッパーを使ってる。
こうやっとくと、「require 'w32apis';w=W32APIs.new」とかするだけで、w.MessageBoxA(0,"Hello, World.","",0) とかして APIを呼び出せるんで便利。
#!/usr/bin/ruby # -*- coding: utf-8 -*- require 'Win32API' class W32APIs attr_reader :apis def initialize @file = '/usr/include/w32api/winuser.h' @h = { 'int'=>'I', 'HWND'=>'L', 'WORD'=>'H', #だっけ? 'SHORT'=>'H', #だっけ? 'LPCSTR'=>'P', 'void'=>'V', 'HBRUSH'=>'L', 'HANDLE'=>'P', #だっけ? L? (void*)な筈だが… 'LPWSTR'=>'P', 'HHOOK'=>'L', 'HWINEVENTHOOK'=>'L', 'VOID'=>'V', 'LONG_PTR'=>'P', 'ULONG_PTR'=>'P', 'HBITMAP'=>'L', 'HWINSTA'=>'L', 'HDESK'=>'L', 'DWORD'=>'L',#だっけ? 'HDEVNOTIFY'=>'L', 'INT'=>'I', 'HACCEL'=>'L', 'LPARAM'=>'L', 'LPSTR'=>'P', 'LPCWSTR'=>'P', 'UINT'=>'L', 'HMENU'=>'L', 'HICON'=>'L', 'HDC'=>'L', 'HMONITOR'=>'L', 'LRESULT'=>'L', 'HPOWERNOTIFY'=>'L', 'LONG'=>'L', 'long'=>'L', 'HDWP'=>'L', 'HCURSOR'=>'L', 'HKL'=>'L', #だっけ? 'BOOL'=>'L', 'ATOM'=>'H', #だっけ? とりあえず WORD で typedef されてるけど。 'BYTE'=>'C', #だっけ? 'CHAR'=>'C', #だっけ? 'PALTTABINFO'=>'P', 'PBOOL'=>'P', #'PBSMINFO'=>'-', 'PBYTE'=>'P', 'PCOMBOBOXINFO'=>'P', 'PCRAWINPUTDEVICE'=>'P', 'PCURSORINFO'=>'P', 'PCVOID'=>'P', 'PDEVMODEA'=>'P', 'PDEVMODEW'=>'P', 'PDISPLAY_DEVICEA'=>'P', 'PDISPLAY_DEVICEW'=>'P', 'PDWORD'=>'P', 'PFLASHWINFO'=>'P', 'PICONINFO'=>'P', 'PLASTINPUTINFO'=>'P', 'PMENUBARINFO'=>'P', #'POINT'=>'-', 'PRAWINPUT'=>'P', 'PRAWINPUTDEVICE'=>'P', 'PRAWINPUTDEVICELIST'=>'P', #'PROPENUMPROCA'=>'-', #'PROPENUMPROCEXA'=>'-', #'PROPENUMPROCEXW'=>'-', #'PROPENUMPROCW'=>'-', 'PSCROLLBARINFO'=>'P', 'PSECURITY_DESCRIPTOR'=>'P', 'PSECURITY_INFORMATION'=>'P', 'PTITLEBARINFO'=>'P', 'PUINT'=>'P', 'PVOID'=>'P', 'PWINDOWINFO'=>'P', 'UINT_PTR'=>'P', 'WCHAR'=>'H', } @apis = { } open(@file) do |f| f.each do |l| if /^(\w.+)\((.+)\)\s*;\s*$/ =~ l ret, arg = $1, $2 next if /^typedef/ =~ ret ret.gsub!(/WIN[A-Z]*APIV?(\W)/){$1} ret.sub!(/^\s*(.+)\s*$/){$1} ret.sub!(/^extern\s*/,'') next if 'DECLARE_HANDLE' == ret rets = ret.split args = arg.split(/\s*,\s*/) arg_str = '' args.each do |e| e.gsub!(/^const/i,'') e.sub!(/^\s+/,'') e.sub!(/\s+\w+$/,'') unless @h.key?(e) if /\s*\*\s*$/ =~ e @h[e] = 'P' #FixMe elsif /^LP/ =~ e @h[e] = 'P' #FixMe else @h[e] = '-' end end arg_str << @h[e] end @apis[rets[1].to_sym] = [nil, 'user32', arg_str, @h[rets[0]], l] # FixMe (user32?) end end end end def method_missing(name, *arg) a = @apis[name] unless a[0] a[0] = Win32API.new(a[1], name.to_s, a[2], a[3]) end a[0].call(*arg) end end if $0 == __FILE__ w = W32APIs.new w.MessageBoxA(0, "Hello, World!", "Title", 0) end
私の使用するPCには cygwin やら VisualC++2008 ExpressEdition やらが入っているので、そのヘッダファイルを利用して、半自動で Win32API をコールしてやろうという…