Skip to content

Instantly share code, notes, and snippets.

@mirichi
Created November 27, 2016 03:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mirichi/96eeee34c85677592bd1b0733ccb0f3d to your computer and use it in GitHub Desktop.
Save mirichi/96eeee34c85677592bd1b0733ccb0f3d to your computer and use it in GitHub Desktop.
なんとか呼べたっぽい
require 'ffi'
width = 320
height = 240
# 構造体にアクセサを生やす拡張
class << FFI::Struct
def layout_ex *args
layout *args
args.each_slice(2) do |member, type|
define_method(member) do
self[member]
end
define_method("#{member}=".to_sym) do |v|
self[member] = v
end
end
end
end
# enum時についでに定数を定義する拡張
module FFI::Library
def enum_ex *args
args.each do |member|
self.const_set(member, member) if member.is_a?(Symbol)
end
enum args
end
end
module WinAPI
extend FFI::Library
ffi_lib 'gdi32', 'ole32', 'user32', 'kernel32'
ffi_convention(:stdcall)
ULONG_PTR = FFI::TypeDefs[:uintptr_t]
LONG_PTR = FFI::TypeDefs[:intptr_t]
ULONG = FFI::TypeDefs[:ulong]
LONG = FFI::TypeDefs[:long]
UINT = FFI::TypeDefs[:uint]
INT = FFI::TypeDefs[:int]
BYTE = FFI::TypeDefs[:uchar]
WORD = FFI::TypeDefs[:ushort]
DWORD = FFI::TypeDefs[:uint]
BOOL = FFI::TypeDefs[:int]
POINTER = FFI::TypeDefs[:pointer]
VOID = FFI::TypeDefs[:void]
LPVOID = FFI::TypeDefs[:pointer]
LPCSTR = FFI::TypeDefs[:pointer]
LPCTSTR = FFI::TypeDefs[:pointer]
HWND = HICON = HCURSOR = HBRUSH = HINSTANCE = HMENU = HMODULE = HANDLE = ULONG_PTR
LPARAM = LONG_PTR
WPARAM = ULONG_PTR
LRESULT = LONG_PTR
HRESULT = LONG
ATOM = WORD
WINBOOL = BOOL
WNDPROC = callback(:WindowProc, [HWND, UINT, WPARAM, LPARAM], LRESULT)
class WNDCLASSEX < FFI::Struct
layout_ex :cbSize, UINT,
:style, UINT,
:lpfnWndProc, WNDPROC,
:cbClsExtra, INT,
:cbWndExtra, INT,
:hInstance, HINSTANCE,
:hIcon, HICON,
:hCursor, HCURSOR,
:hbrBackground, HBRUSH,
:lpszMenuName, LPCSTR,
:lpszClassName, LPCSTR,
:hIconSm, HICON
end
class POINT < FFI::Struct
layout_ex :x, LONG,
:y, LONG
end
class MSG < FFI::Struct
layout_ex :hwnd, HWND,
:message, UINT,
:wParam, WPARAM,
:lParam, LPARAM,
:time, DWORD,
:pt, POINT
end
class RECT < FFI::Struct
layout_ex :left, LONG,
:top, LONG,
:right, LONG,
:bottom, LONG
end
LPRECT = RECT.ptr
attach_function :GetModuleHandle, :GetModuleHandleA, [ LPCSTR ], HMODULE
attach_function :RegisterClassEx, :RegisterClassExA, [ WNDCLASSEX.ptr ], ATOM
attach_function :AdjustWindowRect, [ LPRECT, DWORD, WINBOOL ], WINBOOL
attach_function :CreateWindowEx, :CreateWindowExA, [ DWORD, LPCTSTR, LPCTSTR, DWORD, UINT, UINT, INT, INT, HWND, HMENU, HINSTANCE, LPVOID ], HWND
attach_function :DefWindowProc, :DefWindowProcA, [ HWND, UINT, WPARAM, LPARAM ], LRESULT
attach_function :DestroyWindow, [ HWND ], BOOL
attach_function :PostQuitMessage, [ INT ], VOID
attach_function :GetMessage, :GetMessageA, [ MSG.ptr, HWND, UINT, UINT ], BOOL
attach_function :TranslateMessage, [ MSG.ptr ], BOOL
attach_function :DispatchMessage, :DispatchMessageA, [ MSG.ptr ], BOOL
attach_function :SetCursor, [ HCURSOR ], HCURSOR
attach_function :LoadCursor, :LoadCursorA, [ HINSTANCE, LPCSTR ], HCURSOR
# 使いそうな定数の定義
CS_VREDRAW = 0x0001
CS_HREDRAW = 0x0002
CS_DBLCLKS = 0x0008
CS_OWNDC = 0x0020
CS_CLASSDC = 0x0040
CS_PARENTDC = 0x0080
CS_NOCLOSE = 0x0200
CS_SAVEBITS = 0x0800
CS_BYTEALIGNCLIENT = 0x1000
CS_BYTEALIGNWINDOW = 0x2000
CS_GLOBALCLASS = 0x4000
CS_IME = 0x00010000
CS_DROPSHADOW = 0x00020000
COLOR_SCROLLBAR = 0
COLOR_BACKGROUND = 1
COLOR_ACTIVECAPTION = 2
COLOR_INACTIVECAPTION = 3
COLOR_MENU = 4
COLOR_WINDOW = 5
COLOR_WINDOWFRAME = 6
COLOR_MENUTEXT = 7
COLOR_WINDOWTEXT = 8
COLOR_CAPTIONTEXT = 9
COLOR_ACTIVEBORDER = 10
COLOR_INACTIVEBORDER = 11
COLOR_APPWORKSPACE = 12
COLOR_HIGHLIGHT = 13
COLOR_HIGHLIGHTTEXT = 14
COLOR_BTNFACE = 15
COLOR_BTNSHADOW = 16
COLOR_GRAYTEXT = 17
COLOR_BTNTEXT = 18
COLOR_INACTIVECAPTIONTEXT = 19
COLOR_BTNHIGHLIGHT = 20
COLOR_3DDKSHADOW = 21
COLOR_3DLIGHT = 22
COLOR_INFOTEXT = 23
COLOR_INFOBK = 24
COLOR_HOTLIGHT = 26
COLOR_GRADIENTACTIVECAPTION = 27
COLOR_GRADIENTINACTIVECAPTION = 28
COLOR_MENUHILIGHT = 29
COLOR_MENUBAR = 30
COLOR_DESKTOP = COLOR_BACKGROUND
COLOR_3DFACE = COLOR_BTNFACE
COLOR_3DSHADOW = COLOR_BTNSHADOW
COLOR_3DHIGHLIGHT = COLOR_BTNHIGHLIGHT
COLOR_3DHILIGHT = COLOR_BTNHIGHLIGHT
COLOR_BTNHILIGHT = COLOR_BTNHIGHLIGHT
WS_OVERLAPPED = 0x00000000
WS_POPUP = 0x80000000
WS_CHILD = 0x40000000
WS_MINIMIZE = 0x20000000
WS_VISIBLE = 0x10000000
WS_DISABLED = 0x08000000
WS_CLIPSIBLINGS = 0x04000000
WS_CLIPCHILDREN = 0x02000000
WS_MAXIMIZE = 0x01000000
WS_CAPTION = 0x00C00000
WS_BORDER = 0x00800000
WS_DLGFRAME = 0x00400000
WS_VSCROLL = 0x00200000
WS_HSCROLL = 0x00100000
WS_SYSMENU = 0x00080000
WS_THICKFRAME = 0x00040000
WS_GROUP = 0x00020000
WS_TABSTOP = 0x00010000
WS_MINIMIZEBOX = 0x00020000
WS_MAXIMIZEBOX = 0x00010000
WS_TILED = WS_OVERLAPPED
WS_ICONIC = WS_MINIMIZE
WS_SIZEBOX = WS_THICKFRAME
WS_OVERLAPPEDWINDOW = (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX)
WS_TILEDWINDOW = WS_OVERLAPPEDWINDOW
WS_POPUPWINDOW = (WS_POPUP | WS_BORDER | WS_SYSMENU)
WS_CHILDWINDOW = (WS_CHILD)
CW_USEDEFAULT = 0x80000000
WM_NULL = 0x0000
WM_CREATE = 0x0001
WM_DESTROY = 0x0002
WM_MOVE = 0x0003
WM_SIZE = 0x0005
WM_ACTIVATE = 0x0006
WA_INACTIVE = 0
WA_ACTIVE = 1
WA_CLICKACTIVE = 2
WM_SETFOCUS = 0x0007
WM_KILLFOCUS = 0x0008
WM_ENABLE = 0x000A
WM_SETREDRAW = 0x000B
WM_SETTEXT = 0x000C
WM_GETTEXT = 0x000D
WM_GETTEXTLENGTH = 0x000E
WM_PAINT = 0x000F
WM_CLOSE = 0x0010
WM_QUIT = 0x0012
WM_ERASEBKGND = 0x0014
WM_SYSCOLORCHANGE = 0x0015
WM_SHOWWINDOW = 0x0018
WM_WININICHANGE = 0x001A
WM_SETTINGCHANGE = WM_WININICHANGE
WM_DEVMODECHANGE = 0x001B
WM_ACTIVATEAPP = 0x001C
WM_FONTCHANGE = 0x001D
WM_TIMECHANGE = 0x001E
WM_CANCELMODE = 0x001F
WM_SETCURSOR = 0x0020
WM_MOUSEACTIVATE = 0x0021
WM_CHILDACTIVATE = 0x0022
WM_QUEUESYNC = 0x0023
IDC_ARROW = 32512
IDC_IBEAM = 32513
IDC_WAIT = 32514
IDC_CROSS = 32515
IDC_UPARROW = 32516
IDC_SIZE = 32640
IDC_ICON = 32641
IDC_SIZENWSE = 32642
IDC_SIZENESW = 32643
IDC_SIZEWE = 32644
IDC_SIZENS = 32645
IDC_SIZEALL = 32646
IDC_NO = 32648
IDC_HAND = 32649
IDC_APPSTARTING = 32650
IDC_HELP = 32651
end
hInstance = WinAPI::GetModuleHandle(nil)
def wndproc(hWnd, msg, wParam, lParam)
case msg
when WinAPI::WM_CLOSE
WinAPI::DestroyWindow(hWnd)
when WinAPI::WM_DESTROY
WinAPI::PostQuitMessage(0)
else
return WinAPI::DefWindowProc(hWnd, msg, wParam, lParam)
end
return 0
end
wcex = WinAPI::WNDCLASSEX.new
wcex.cbSize = WinAPI::WNDCLASSEX.size
wcex.style = WinAPI::CS_HREDRAW | WinAPI::CS_VREDRAW
wcex.lpfnWndProc = method(:wndproc)
wcex.cbClsExtra = 0
wcex.cbWndExtra = 0
wcex.hInstance = hInstance
wcex.hIcon = 0
wcex.hIconSm = 0
wcex.hCursor = 0
wcex.hbrBackground = WinAPI::COLOR_WINDOW
wcex.lpszMenuName = nil
wcex.lpszClassName = FFI::MemoryPointer.from_string("test")
atom = WinAPI::RegisterClassEx(wcex)
rect = WinAPI::RECT.new
rect.top = 0
rect.left = 0
rect.right = width
rect.bottom = height
WinAPI::AdjustWindowRect(rect, WinAPI::WS_OVERLAPPED | WinAPI::WS_CAPTION | WinAPI::WS_SYSMENU | WinAPI::WS_MINIMIZEBOX, 0)
# ウィンドウ作成
hWnd = WinAPI::CreateWindowEx(0, "test", "Test Window",
WinAPI::WS_OVERLAPPED | WinAPI::WS_CAPTION | WinAPI::WS_SYSMENU | WinAPI::WS_MINIMIZEBOX | WinAPI::WS_VISIBLE,
WinAPI::CW_USEDEFAULT, WinAPI::CW_USEDEFAULT,
rect.right - rect.left, rect.bottom - rect.top,
0, 0, hInstance, nil );
# カーソル設定
WinAPI::SetCursor(WinAPI::LoadCursor(0, FFI::Pointer.new(WinAPI::IDC_ARROW)))
module D3D9
extend FFI::Library
ffi_lib 'd3d9', 'ole32'
ffi_convention(:stdcall)
ULONG_PTR = FFI::TypeDefs[:uintptr_t]
LONG_PTR = FFI::TypeDefs[:intptr_t]
ULONG = FFI::TypeDefs[:ulong]
LONG = FFI::TypeDefs[:long]
UINT = FFI::TypeDefs[:uint]
INT = FFI::TypeDefs[:int]
BYTE = FFI::TypeDefs[:uchar]
WORD = FFI::TypeDefs[:ushort]
DWORD = FFI::TypeDefs[:uint]
BOOL = FFI::TypeDefs[:int]
POINTER = FFI::TypeDefs[:pointer]
VOID = FFI::TypeDefs[:void]
LPVOID = FFI::TypeDefs[:pointer]
LPCSTR = FFI::TypeDefs[:pointer]
LPCTSTR = FFI::TypeDefs[:pointer]
HWND = HICON = HCURSOR = HBRUSH = HINSTANCE = HMENU = HMODULE = HANDLE = ULONG_PTR
LPARAM = LONG_PTR
WPARAM = ULONG_PTR
LRESULT = LONG_PTR
HRESULT = LONG
ATOM = WORD
WINBOOL = BOOL
D3DMULTISAMPLE_TYPE = enum_ex(
:D3DMULTISAMPLE_NONE , 0,
:D3DMULTISAMPLE_NONMASKABLE , 1,
:D3DMULTISAMPLE_2_SAMPLES , 2,
:D3DMULTISAMPLE_3_SAMPLES , 3,
:D3DMULTISAMPLE_4_SAMPLES , 4,
:D3DMULTISAMPLE_5_SAMPLES , 5,
:D3DMULTISAMPLE_6_SAMPLES , 6,
:D3DMULTISAMPLE_7_SAMPLES , 7,
:D3DMULTISAMPLE_8_SAMPLES , 8,
:D3DMULTISAMPLE_9_SAMPLES , 9,
:D3DMULTISAMPLE_10_SAMPLES , 10,
:D3DMULTISAMPLE_11_SAMPLES , 11,
:D3DMULTISAMPLE_12_SAMPLES , 12,
:D3DMULTISAMPLE_13_SAMPLES , 13,
:D3DMULTISAMPLE_14_SAMPLES , 14,
:D3DMULTISAMPLE_15_SAMPLES , 15,
:D3DMULTISAMPLE_16_SAMPLES , 16,
:D3DMULTISAMPLE_FORCE_DWORD , 0x7fffffff
)
# 定数
D3D_SDK_VERSION = 32
D3DFMT_UNKNOWN = 0
D3DFMT_D24S8 = 75
D3DSWAPEFFECT_DISCARD = 1
D3DPRESENT_INTERVAL_IMMEDIATE = 0x80000000
D3DADAPTER_DEFAULT = 0
D3DDEVTYPE_HAL = 1
D3DCREATE_MIXED_VERTEXPROCESSING = 0x00000080
D3DCLEAR_TARGET = 0x00000001
D3DCLEAR_ZBUFFER = 0x00000002
D3DCLEAR_STENCIL = 0x00000004
# COMインターフェイス基本クラス
class COM < FFI::Struct
class << self
# 自身の構造体レイアウトを設定し、VTableクラスを参照してメソッドを定義する
def init
vtbl = self.const_get(:VTable)
layout_ex :lpVtbl, vtbl.ptr
vtbl.members.each do |member|
define_method(member) do |*args|
self[:lpVtbl][member].call(self, *args)
end
end
end
end
end
# IDirect3D9インターフェイス
class IDirect3D9 < COM
# Idirect3D9のメンバ定義
class VTable < FFI::Struct
layout_ex :QueryInterface, callback([ IDirect3D9.ptr ], HRESULT), # できてないので呼ぶとコケる
:AddRef, callback([ IDirect3D9.ptr ], ULONG),
:Release, callback([ IDirect3D9.ptr ], ULONG)
end
# VTable構造体を定義してからinitを呼ぶとメソッドが定義される
init
end
attach_function :Direct3DCreate9, [ UINT ], IDirect3D9.ptr
attach_function :CoInitialize, [ LPVOID ], HRESULT
end
D3D9::CoInitialize(nil)
d3d9 = D3D9::Direct3DCreate9(D3D9::D3D_SDK_VERSION) # IDirect3D9インターフェイスが返る
p d3d9.Release # こんな感じに呼べる
# ウィンドウメッセージ構造体作成
msg = WinAPI::MSG.new
# メッセージループ
loop do
if WinAPI::GetMessage(msg, 0, 0, 0) == 0
break
end
WinAPI::TranslateMessage(msg)
WinAPI::DispatchMessage(msg)
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment