I have the following code which is fine if I give invalid parameters (though, obviously doesn’t work), but whenever I give accurate parameters, ruby segfaults. I’m inclined to believe that this is a problem with my code and/or the ability of ruby to actually call this API function, but I’d like some more input. I’ve tried with both Win32API and DL::Importer with the same results. Is there any way to get this to work?
For the curious, there’s full background available here, including attempts with Win32API and DL::Importer on different branches. You are looking for examples/windows-test in both cases.
EDIT: I’ve managed to get RegisterClassEx to work, but this still isn’t helping. Ruby is silently crashing in CreateWindowEx.
The following gives output like this:
wndproc: 4293787656
hInstance: 4194304
Entering RegisterClassEx
Window Class: 49795
Entering CreateWindowEx
EDIT 2: My code in progress has grown a little large to be pasting it all into SE. If you want all the background, you can see it at the link above. I’ve tried to keep everything relevant included here though.
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
Solution: Use
ffi. For whatever reason, it just doesn’t work inDL(Win32APIusesDLunder the hood)Full credit goes here, wherever this is (I can’t read Japanese): http://www19.atwiki.jp/tmtbnc/m/pages/56.html
My guess is it’s because
DLdoesn’t seem to supportstdcall, but I honestly don’t know enough about it to know.The FFI solution as used by me is below: