2012-06-18 18 views
2

我有以下代碼,如果我給無效參數(雖然,顯然不工作),但是每當我給出準確的參數,ruby段錯誤。我傾向於認爲這是我的代碼和/或ruby實際調用此API函數的能力的問題,但我想要更多的輸入。我試過Win32APIDL::Importer,結果相同。有什麼辦法讓這個工作?如何從Ruby調用CreateWindowEx?

對於好奇,there's full background available here,包括在不同分支上嘗試使用Win32APIDL::Importer。在這兩種情況下,您都在尋找examples/windows-test

編輯:我已經設法讓RegisterClassEx工作,但這仍然沒有幫助。紅寶石正悄然崩潰在CreateWindowEx

下面給出這樣的輸出:

的WndProc:4293787656
的hInstance:4194304
輸入RegisterClassEx
窗口類: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 
+0

嗯,你告訴窗戶不創建一個窗口。 CreateWindowEx的第二個參數是要創建的窗口的類名。對於預定義的控件(Windows),這可能是按鈕,編輯等...如果你想創建一個父窗口,你需要首先用RegisterWindowEx創建一個原子,然後將其作爲類名 – Gunner

+0

@Gunner:是我今天晚上的第一次嘗試,但如果是這樣,那麼爲什麼班級名稱在API文檔中作爲可選字段呈現? –

+0

因爲我們正在談論MS的文檔編寫者,他們似乎犯了很多錯誤/遺漏。無論如何,您應該檢查API調用的返回。 CreateWindowEx在錯誤時返回NULL,當它發生時,調用GetLastError來獲取原因 – Gunner

回答

1

解決方案:使用ffi。無論出於何種原因,它只是沒有在DL工作(Win32API使用DL引擎蓋下)

完全歸功於這裏,無論這是(我看不懂日文):http://www19.atwiki.jp/tmtbnc/m/pages/56.html

我的猜測是它的因爲DL似乎不支持stdcall,但我真的不知道足夠了解它。

13759我的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 
+0

「我的猜測是因爲DL似乎不支持stdcall,但我真的不知道它足夠了解它。「 >>看一下Win32API源代碼似乎支持stdcall(第11行):'def initialize(dllname,func,import,export =「0」,calltype =:stdcall)',或者更確切地說它默認使用stdcall。也許應該使用不同的calltype ...其他調用定義可以在這裏找到:https://msdn.microsoft.com/en-us/library/984x0h58.aspx – Sancarn