我有以下代码,如果我给出无效的参数(虽然显然不起作用),这很好,但是每当我给出准确的参数时,ruby 就会出现段错误。我倾向于认为这是我的代码和/或 ruby 实际调用此 API 函数的能力的问题,但我想要更多输入。我尝试过Win32API
和DL::Importer
,结果相同。有什么方法可以让它工作吗?
对于好奇的人来说,这里有完整的背景知识,包括尝试在不同分支上进行Win32API
和DL::Importer
。在这两种情况下,您都在寻找examples/windows-test
。
编辑:我已经设法让RegisterClassEx
工作,但这仍然没有帮助。露比在CreateWindowEx
默默地崩溃。
下面给出了如下输出:
WNDPROC: 4293787656
h实例:4194304
输入注册类Ex
窗户等级: 49795
进入 CreateWindowEx
编辑2:我正在进行的代码已经变得有点大,可以将其全部粘贴到SE中。如果你想要所有的背景,你可以在上面的链接中看到它。不过,我试图将所有相关内容都包含在此处。
class Windows
def initialize
puts "wndproc: #{Win32::User32::WNDPROC}"
hInstance = Win32::Kernel32::GetModuleHandle(DL::NULL)
puts "hInstance: #{hInstance}"
puts "Entering RegisterClassEx"
@window_class_struct = Win32::User32::WNDCLASSEX.malloc
@window_class_struct.cbSize = Win32::User32::WNDCLASSEX.size
@window_class_struct.style = Win32::User32::CS_HREDRAW | Win32::User32::CS_VREDRAW
@window_class_struct.lpfnWndProc = Win32::User32::WNDPROC
@window_class_struct.cbClsExtra = 0
@window_class_struct.cbWndExtra = 0
@window_class_struct.hInstance = hInstance
@window_class_struct.hIcon = 0
@window_class_struct.hCursor = 0
@window_class_struct.hbrBackground = Win32::User32::COLOR_WINDOWFRAME
@window_class_struct.lpszMenuName = DL::NULL
@window_class_struct.lpszClassName = 'ruby-skype'
@window_class_struct.hIconSm = 0
p @window_class_struct
@window_class = Win32::User32::RegisterClassEx(@window_class_struct.to_i)
puts "Window Class: #{@window_class}"
puts "Entering CreateWindowEx"
@window = Win32::User32::CreateWindowEx(0, 'ruby-skype', 'ruby-skype', Win32::User32::WS_OVERLAPPEDWINDOW,
0, 0, 200, 200, DL::NULL, DL::NULL, DL::NULL)
puts "Exited CreateWindowEx"
p @window
end
module Win32
module Types
def included(m)
m.module_eval {
include ::DL::Win32Types
# @see http://msdn.microsoft.com/en-us/library/windows/desktop/aa383751.aspx
typealias('HBRUSH', 'HANDLE')
typealias('HCURSOR', 'HANDLE')
typealias('HICON', 'HANDLE')
typealias('HMENU', 'HANDLE')
typealias('HMODULE', 'HANDLE')
typealias('LPCTSTR', 'unsigned char *')
typealias('LPVOID', 'void *')
typealias('WNDPROC', 'void *') # Actually a function pointer
typealias('WNDCLASSEX', 'void *') # struct
}
end
module_function :included
end
module User32
extend DL
extend DL::Importer
dlload 'user32'
include Types
extern 'HWND CreateWindowEx(DWORD, LPCTSTR, LPCTSTR, DWORD, int, int, int, int, HWND, HMENU, HINSTANCE)'
WNDPROC = set_callback DL::TYPE_LONG, 4 do |window_handle, message_id, wParam, lParam|
puts "WM: #{message_id}"
end
end
end
end
Windows.new
解决方案:使用 ffi
.无论出于何种原因,它只是在DL
中不起作用(Win32API
引擎盖下使用DL
)
全部功劳在这里,无论在哪里(我看不懂日语):http://www19.atwiki.jp/tmtbnc/m/pages/56.html
我的猜测是DL
似乎不支持stdcall
,但老实说,我对它的了解还不够多。
我使用的 FFI 解决方案如下:
class Windows
def initialize
hInstance = Win32::GetModuleHandle(nil)
@window_class = Win32::WNDCLASSEX.new
@window_class[:style] = Win32::CS_HREDRAW | Win32::CS_VREDRAW
@window_class[:lpfnWndProc] = method(:message_pump)
@window_class[:hInstance] = hInstance
@window_class[:hbrBackground] = Win32::COLOR_WINDOWFRAME
@window_class[:lpszClassName] = FFI::MemoryPointer.from_string 'ruby-skype'
@window = Win32::CreateWindowEx(Win32::WS_EX_LEFT, ::FFI::Pointer.new(@window_class.atom), 'ruby-skype', Win32::WS_OVERLAPPEDWINDOW,
0, 0, 0, 0, Win32::NULL, Win32::NULL, hInstance, nil)
end
def message_pump(window_handle, message_id, wParam, lParam)
puts "WM: #{message_id}"
Win32::DefWindowProc(window_handle, message_id, wParam, lParam)
end
module Win32
extend FFI::Library
ffi_lib('user32', 'kernel32')
ffi_convention(:stdcall)
private
def self._func(*args)
attach_function *args
case args.size
when 3
module_function args[0]
when 4
module_function args[0]
alias_method(args[1], args[0])
module_function args[1]
end
end
public
ULONG_PTR = FFI::TypeDefs[:ulong]
LONG_PTR = FFI::TypeDefs[:long]
ULONG = FFI::TypeDefs[:ulong]
LONG = FFI::TypeDefs[:long]
LPVOID = FFI::TypeDefs[:pointer]
INT = FFI::TypeDefs[:int]
BYTE = FFI::TypeDefs[:uint16]
DWORD = FFI::TypeDefs[:ulong]
BOOL = FFI::TypeDefs[:int]
UINT = FFI::TypeDefs[:uint]
POINTER = FFI::TypeDefs[:pointer]
VOID = FFI::TypeDefs[:void]
HWND = HICON = HCURSOR = HBRUSH = HINSTANCE = HGDIOBJ =
HMENU = HMODULE = HANDLE = ULONG_PTR
LPARAM = LONG_PTR
WPARAM = ULONG_PTR
LPCTSTR = LPMSG = LPVOID
LRESULT = LONG_PTR
ATOM = BYTE
NULL = 0
WNDPROC = callback(:WindowProc, [HWND, UINT, WPARAM, LPARAM], LRESULT)
class WNDCLASSEX < FFI::Struct
layout :cbSize, UINT,
:style, UINT,
:lpfnWndProc, WNDPROC,
:cbClsExtra, INT,
:cbWndExtra, INT,
:hInstance, HANDLE,
:hIcon, HICON,
:hCursor, HCURSOR,
:hbrBackground, HBRUSH,
:lpszMenuName, LPCTSTR,
:lpszClassName, LPCTSTR,
:hIconSm, HICON
def initialize(*args)
super
self[:cbSize] = self.size
@atom = 0
end
def register_class_ex
(@atom = Win32::RegisterClassEx(self)) != 0 ? @atom : raise("RegisterClassEx Error")
end
def atom
@atom != 0 ? @atom : register_class_ex
end
end # WNDCLASSEX
class POINT < FFI::Struct
layout :x, LONG,
:y, LONG
end
class MSG < FFI::Struct
layout :hwnd, HWND,
:message, UINT,
:wParam, WPARAM,
:lParam, LPARAM,
:time, DWORD,
:pt, POINT
end
_func(:RegisterWindowMessage, :RegisterWindowMessageA, [LPCTSTR], UINT)
_func(:GetModuleHandle, :GetModuleHandleA, [LPCTSTR], HMODULE)
_func(:RegisterClassEx, :RegisterClassExA, [LPVOID], ATOM)
_func(:CreateWindowEx, :CreateWindowExA, [DWORD, LPCTSTR, LPCTSTR, DWORD, INT, INT, INT, INT, HWND, HMENU, HINSTANCE, LPVOID], HWND)
_func(:GetMessage, :GetMessageA, [LPMSG, HWND, UINT, UINT], BOOL)
_func(:TranslateMessage, [LPVOID], BOOL)
_func(:DispatchMessage, :DispatchMessageA, [LPVOID], BOOL)
_func(:DefWindowProc, :DefWindowProcA, [HWND, UINT, WPARAM, LPARAM], LRESULT)
# @!group Predefined WindowHandle's
#
# These are WindowHandle's provided by the Win32 API for special purposes.
# Target for SendMessage(). Broadcast to all windows.
HWND_BROADCAST = 0xffff
# Used as a parent in CreateWindow(). Signifies that this should be a message-only window.
HWND_MESSAGE = -3
# @!endgroup
# CreateWindow Use Default Value
CW_USEDEFAULT = 0x80000000
COLOR_WINDOW = 5
COLOR_WINDOWFRAME = 6
# @!group Class Style contants.
CS_VREDRAW = 0x0001
CS_HREDRAW = 0x0002
# @!group Window Style constants
#
# This is only a subset.
# @see http://msdn.microsoft.com/en-us/library/windows/desktop/ms632600.aspx
WS_BORDER = 0x00800000
WS_CAPTION = 0x00C00000
WS_DISABLED = 0x08000000
WS_OVERLAPPED = 0x00000000
WS_POPUP = 0x80000000
WS_SIZEBOX = 0x00040000
WS_SYSMENU = 0x00080000
WS_THICKFRAME = 0x00040000
WS_MAXIMIZEBOX = 0x00010000
WS_MINIMIZEBOX = 0x00020000
WS_OVERLAPPEDWINDOW = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX
WS_POPUPWINDOW = WS_POPUP | WS_BORDER | WS_SYSMENU
# @!group Window Extended Style constants
#
# This is only a subset.
# @see http://msdn.microsoft.com/en-us/library/windows/desktop/ff700543.aspx
WS_EX_LEFT = 0
# @!endgroup
end
end