2009-07-29 31 views
6

ruby​​でwin32ライブラリのいくつかの関数にアクセスする必要があります。私は、Win32APIクラスのオンラインで非常に疎な情報を発見したので、私はここで尋ねています。ruby​​ win32 api interface

私はあなたがこのような何かができることを知っている:

function = Win32API.new('user32','MessageBox',['L', 'P', 'P', 'L'],'I') 

をしかし、私は、現在のwin32バインディングでこの関数を呼び出すことができるように見えることはできません。

http://msdn.microsoft.com/en-us/library/bb762108%28VS.85%29.aspx

問題はそのプロトタイプにあります:

UINT_PTR SHAppBarMessage(  
    DWORD dwMessage, 
    PAPPBARDATA pData 
); 

私はablになりますwin32ルビバインディングを使用して戻り値の型と最初のパラメータを取得する方法ですが、2番目の方法では構造が必要です。次のように構造体の定義は次のとおり

typedef struct _AppBarData { 
    DWORD cbSize; 
    HWND hWnd; 
    UINT uCallbackMessage; 
    UINT uEdge; 
    RECT rc; 
    LPARAM lParam; 
} APPBARDATA, *PAPPBARDATA; 

私は両方を使用して、このAPIメソッドを定義しようとした:「通話中

api = Win32API.new('shell32','SHAppBarMessage',['L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L'],'I') 

api = Win32API.new('shell32','SHAppBarMessage',['L', 'LLLLLLLL'],'I') 

が、最初のセグメンテーション違反メソッド呼び出しで指定された引数の量が間違っているため、2番目の呼び出しが失敗します。 C++で外部モジュールを作成せずにこのapi関数を公開する方法はありますか?

ありがとうございました。 DWORDとAPPBARDATAへのポインタ、 は、それはこのように宣言することがshuold
:その後、呼ば

app_bar_msg = Win32API.new('shell32', 'SHAppBarMessage', ['L', 'P'], 'L')

msg_id = 1 
app_bar_data = "properly initalized binary string" #should have sizeof(APPBARDATA) bytes 
app_bar_msg.call(msg_id, app_bar_data)

しかし、私は知りません

答えて

0

SHAppBarMessageは、2つのパラメータを取りますRuby、だから多分私は間違っている...

0

私はあなたが得るためにString#packメソッドを調査する必要がありますAPPBARDATA structが正しく入力されています。

「Pickaxe」ブックsection on Win32 and Ruby(Win32APIクラス定義までスクロールダウン)を参照してください。

既に見つかっているように、あなたは 'P'引数を使用し、正しくパックされたString(またはString)を関数に渡します。

また、調査する時間が少しでもある場合は、FFIライブラリを参照することをお勧めします.FFIライブラリは、すべてをよりやりやすい方法で実行しているようです。私は直接の経験を持っていませんが、Cの構造体を宣言するための非常に良くな方法の例がありますJRubyのチームのチャールズ・ナッター、によって

4

トリックは、すべてのポインタ引数のフォーマット指定子として「P」を使用することです。あなたは指示された領域として文字列を提供する必要があります。

もちろん、これらの文字列が正しいサイズであることを確認する必要があります。そうしないと、悪いことが起こります。

あなたは、直接これらの文字列

# Mostly useful when the area will be totally overwritten 
pointed_to_area = "\0" * n 

以上の文明Array#pack

# Allows you to control how ruby values get encoded in the buffer 
pointed_to_area = [1, 2, 3, 4].pack('SsLI') 

は、この情報がお役に立てば幸い使用を作成することができます。


古いルビー1.8.2と私のXPボックスで、次の作品:

require 'Win32API' 


module Win32 
    # This method is only here for test purposes 
    # Be careful to use the ascii version 
    FindWindow = Win32API.new('user32', 'FindWindowA', ['P', 'P'], 'L') 
    def self.findWindow(lpClassName, lpWindowName) 
    h = FindWindow.call(lpClassName, lpWindowName) 
    raise "FindWindow failed" if h == 0 
    h 
    end 

    # From winddef.h 
    RECT = Struct.new(:left, :top, :right, :bottom) 
    RECT.class_eval do 
    def pack 
     [left, top, right, bottom].pack('l4') 
    end 
    def self.unpack(s) 
     new(*s.unpack('l4')) 
    end 
    end 

    # From shellapi.h 
    APPBARDATA = Struct.new(:cbSize, :hWnd, :uCallbackMessage, :uEdge, :rc, :lParam) 
    APPBARDATA.class_eval do 
    def pack 
     unless rc.is_a? RECT 
     raise ArgumentError, ":rc must be an instance of Win32::RECT, got #{rc.inspect}" 
     end 
     # DWORD + HWND + UINT + UINT + RECT + LPARAM 
     cbSize = 4 + 4 + 4 + 4 + 16 + 4 
     [cbSize, hWnd, uCallbackMessage, uEdge, rc.pack, lParam].pack('L2I2a16L') 
    end 
    def self.unpack(s) 
     tmp = self.new(*s.unpack('L2I2a16L')) 
     tmp.rc = RECT.unpack(tmp.rc) 
     tmp 
    end 
    end 
    SHAppBarMessage = Win32API.new('shell32', 'SHAppBarMessage', ['L', 'P'], 'L') 

    # Calls SHAppBarMessage and returns the altered APPBARDATA 
    def self.shAppBarMessage(dwMessage, appBarData) 
    s = appBarData.pack 
    ok = (SHAppBarMessage.call(dwMessage, s) != 0) 
    raise "SHAppBarMessage failed" unless ok 
    APPBARDATA.unpack(s) 
    end 

    ABM_NEW    = 0x00000000 
    ABM_REMOVE   = 0x00000001 
    ABM_QUERYPOS   = 0x00000002 
    ABM_SETPOS   = 0x00000003 
    ABM_GETSTATE   = 0x00000004 
    ABM_GETTASKBARPOS = 0x00000005 
    ABM_ACTIVATE   = 0x00000006 
    ABM_GETAUTOHIDEBAR = 0x00000007 
    ABM_SETAUTOHIDEBAR = 0x00000008 
    ABM_WINDOWPOSCHANGED = 0x00000009 
    ABM_SETSTATE   = 0x0000000a 

    ABE_LEFT = 0 
    ABE_TOP = 1 
    ABE_RIGHT = 2 
    ABE_BOTTOM = 3 
end 




if __FILE__ == $0 
    require 'test/unit' 
    class SHAppBarMessageTest < Test::Unit::TestCase 
    include Win32 

    def test_pack_unpack 
     a = APPBARDATA.new(-1, 0, 0, ABE_TOP, RECT.new(1, 2, 3, 4), 0) 
     b = APPBARDATA.unpack(a.pack) 
     a.cbSize = b.cbSize 
     assert_equal(a.values, b.values) 
    end 
    def test_simple_pos_query 
     h = Win32.findWindow("Shell_TrayWnd", nil) 
     a = APPBARDATA.new(-1, 0, 0, ABE_TOP, RECT.new(0, 0, 0, 0), 0) 
     result = Win32.shAppBarMessage(ABM_GETTASKBARPOS, a) 
     assert(result.rc.left < result.rc.right) 
     assert(result.rc.top < result.rc.bottom) 
     puts result.rc.inspect 
    end 
    end 
end 
関連する問題