らんたいむ ますこっと スクリプト


らんたいむ ますこっとのスクリプトの一部を、2〜3回に分けて公開したいと思います。
今回は、ウインドウハンドルを取得する部分。後で、このウインドウハンドルにWindows APIを使って色々します。


ウインドウハンドルを取得するメソッドです。
なお、実際には専用のクラス内で定義しておりますが、その部分は省略しております。

def getWindowHandle
  desktop = getDesktopWindow()
  hwnd = getWindow(desktop, GW_CHILD)
  current_process_id = getCurrentProcessId()

  while hwnd != 0
    return hwnd if getWindowThreadProcessId(hwnd) == current_process_id
    hwnd = getWindow(hwnd, GW_HWNDNEXT)
  end

  print "ウインドウハンドルの取得に失敗しました。"
  exit
end


内部で使っているWindows APIの定義は、次の通り。
GW_CHILDとかの定数は、適当に調べて使って下さい。

def getWindow(hwnd, cmd)
  api = Win32API.new('user32.dll', 'GetWindow', 'l l', 'l')
  return api.call(hwnd, cmd)
end

def getDesktopWindow
  api = Win32API.new('user32.dll', 'GetDesktopWindow', 'v', 'l')
  return api.call
end

def getWindowThreadProcessId(hwnd)
  api = Win32API.new('user32.dll', 'GetWindowThreadProcessId', 'l p', 'l')
  buf = [0].pack('l')
  api.call(hwnd, buf)
  return buf.unpack('l')[0]
end

def getCurrentProcessId
  api = Win32API.new('kernel32.dll', 'GetCurrentProcessId', 'v', 'l')
  return api.call
end


ウインドウハンドルを取得する部分のスクリプトスクリプト素材のサイトにもあるけれど、iniファイルをパースして、タイトルであるはずの文字列を得て、そのタイトルを持つウインドウハンドルを得るという手法なのですよね。
つまり、複数起動したら対応できないと。同じタイトルですからね。


という訳で、私の使った方法では、ウインドウを作ったプロセスのIDを使ってウインドウハンドルを取得しています。これなら、タイトルがどうなっていても関係ないですし、もし同じタイトルのものがあったりしても問題ないのです。


まぁ、この方法も実はGetWindowが全部のウインドウを確実になめてくれるという保障がなかったりするので、本当はEnumWindowsを使いたいのだけれど、コールバックが使えないという制約のせいでやむなくGetWindowを使っていたりします。コールバック使えないのは仕方ないよね、うん。Rubyのライブラリがフルセット使えたら良かったのだけれども。


複数起動ができないからと自作してみたけれども、実はウインドウが非アクティブだと止まるので、あまり意味がなかったりします。うん、盲点でした。


そして、複数起動するにしても、ウインドウハンドルを取った直後に、ウインドウタイトルを変えてしまえば、ウインドウハンドルをタイトル経由で取ってくる方法が使えたのですよね。最初だけ、起動中、とか付けるとかしておけば。
どちらの方法にせよ、タイミングによってはウインドウハンドルが取れなかったり、違うものを取ってしまったりする可能性がないとは言えないから、どっちの方法でも大差がなかったりします。
両方組み合わせて、タイトルから取ってきて、プロセスを確認、というのが一番安全確実かな。面倒だから修正はしませんが。