首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何从Ruby调用CreateWindowEx?

如何从Ruby调用CreateWindowEx?
EN

Stack Overflow用户
提问于 2012-06-18 01:07:52
回答 1查看 1.6K关注 0票数 2

我有下面的代码,如果我给出无效的参数(虽然,显然不起作用),这是很好的,但是每当我给出精确的参数时,就会出现ruby分段错误。我倾向于认为这是我的代码和/或ruby实际上调用这个API函数的能力的问题,但是我想要更多的输入。我尝试过Win32APIDL::Importer都有相同的结果。有什么办法让这件事起作用吗?

对于好奇的人,这里有完整的背景资料,包括Win32APIDL::Importer在不同分支上的尝试。在这两种情况下,您都在寻找examples/windows-test

编辑:--我设法让RegisterClassEx工作了,但这仍然没有帮助。Ruby正在CreateWindowEx中悄然崩溃。

下面给出如下输出:

wndproc: 4293787656 hInstance: 4194304 加入RegisterClassEx 窗口类: 49795 加入CreateWindowEx

编辑2:我正在进行中的代码变得有点大,将其粘贴到SE中。如果你想要所有的背景,你可以在上面的链接看到它。不过,我试着把所有相关的东西都包括在这里。

代码语言:javascript
复制
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
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2012-06-18 11:28:30

解决方案:使用ffi。无论出于什么原因,它在DL中都不起作用(Win32API在引擎盖下使用DL )

所有的学分都在这里,不管它在哪里(我不会读日语):http://www19.atwiki.jp/tmtbnc/m/pages/56.html

我猜想这是因为DL似乎不支持stdcall,但我真的不太了解它。

我使用的FFI解决方案如下:

代码语言:javascript
复制
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
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/11076010

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档