What Are the Ruby Win32API Parameters | How to Pass a Null Pointer

What are these extra parameters when calling SendInput via win32API

The function call takes a union of those structs, I would wager it has something to do with that.

Looks like MOUSEINPUT is larger than KEYBOARDINPUT:

typedef struct tagMOUSEINPUT {
LONG dx;
LONG dy;
DWORD mouseData;
DWORD dwFlags;
DWORD time;
ULONG_PTR dwExtraInfo;
} MOUSEINPUT, *PMOUSEINPUT;

Dunno for sure though, that seems like a pretty terrifying way to bridge those calls!

edit: Yeah, looks like using that MOUSEINPUT size, you end up w/28 bytes of data sent to the function, which is what pack('ISSIIIII') would net you.

How to call CreateWindowEx from Ruby?

Solution: Use ffi. For whatever reason, it just doesn't work in DL (Win32API uses DL under 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 DL doesn't seem to support stdcall, but I honestly don't know enough about it to know.

The FFI solution as used by me is below:

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

How to call a Windows DLL from within Ruby?

Try Ruby's FFI module.

Two examples to get you started:

  1. Calling a C function from a DLL that returns a pointer to a string

  2. Calling a Win32 function from within Ruby

The older DL module seems to be less used and not as easy.

Ruby's *args causing seg fault when no args supplied

The likely reason it's seg faulting is because somewhere underneath Win32API the lack of arguments is translating into one or more NULL pointer dereferences.

If you are going to create functions like this then you should consider adding a per-api-call, boolean-returning argument validation block (or lambda) as an argument to def_api which you would then invoke as the first part of your derived function. Something like this:

def self.def_api(function, parameters, return_value, &valid_args?)              
api = Win32API.new 'user32', function, parameters, return_value

define_method(function.snake_case) do |*args|
if valid_args? and valid_args?.call(*args)
api.call *args
else
// raise argument error, etc
end
end

end

Then

def_api 'FindWindow', ['P', 'P'], 'L', { |args| return true if // API specific checks succeed }

UPDATE: Adding more color at questioner's request

The &valid_args? is the name of a block parameter. The ampersand prefix (&) is how you tell ruby that you passing a block. You can only pass one block to a methodand it must be the last parameter in the argument list. The question mark suffix (?) is just a convention in Ruby programming for naming functions which return boolean values.

If a block is passed you invoke it with &block.call(args)

To call a method with a block argument you do something like this:

method { |args| // block implementation }

or

method do |args|
// block implementation
end

The args are passed to the block through the call method. Hope this helps.

How can I write a generic C function for calling a Win32 function?

No, I don't think its possible to do with without writing some assembly. The reason is you need precise control over what is on the stack before you call the target function, and there's no real way to do that in pure C. It is, of course, simple to do in Assembly though.

Also, you're using PCSTR for all of these arguments, which is really just const char *. But since all of these args aren't strings, what you actually want to use for return value and for Arguments[] is void * or LPVOID. This is the type you should use when you don't know the true type of the arguments, rather than casting them to char *.

How to pass by reference in Ruby?

Ruby is strictly pass-by-value, which means references in the caller's scope are immutable. Obviously they are mutable within the scope, since you can assign to them after all, but they don't mutate the caller's scope.

a = 'foo'

def bar(b)
b = 'bar'
end

bar(a)

a
# => 'foo'

Note, however, that the object can be mutated even if the reference cannot:

a = 'foo'

def bar(b)
b << 'bar' # the only change: mutate the object instead of the reference
b = 'baz'
end

bar(a)

a
# => 'foobar'

If the object you get passed is immutable, too, then there is nothing you can do. The only possibilities for mutation in Ruby are mutating the reference (by assignment) or asking an object to mutate itself (by calling methods on it).

You can return an updated value from your method and have the caller assign that to the reference:

a = :foo

def bar(b)
:"#{a}bar"
end

c = bar(a)

c
# => :foobar

Or you can wrap the immutable object in a mutable one and mutate that mutable wrapper:

a = [:foo]

def bar(b)
b[0] = :bar
end

bar(a)

a
# => [:bar]

[This is really the same thing as the second example above.]

But if you can't change anything, then you are stuck.



Related Topics



Leave a reply



Submit