Upgrade to Pro — share decks privately, control downloads, hide ads and more …

PHPからWin32APIをいじってみた

taiko19xx
September 24, 2016

 PHPからWin32APIをいじってみた

2016/09/24の「第一回PHP勉強会@仙台(仮)」で発表した資料です。

taiko19xx

September 24, 2016
Tweet

More Decks by taiko19xx

Other Decks in Programming

Transcript

  1. PHPからWin32APIを
    いじってみた
    2016/09/24第一回PHP勉強会@仙台(仮)
    Taiko19xx / 木村俊彦

    View Slide

  2. こんにちは
    • 木村俊彦
    • Twitter / GitHub : taiko19xx
    • 株式会社SRIA エンジニア
    • 普段はもちろんPHP
    • たまにスマホアプリとかもやりたい
    • 趣味は旅行とカメラとバイク
    • 最近は大洗とか北海道へ

    View Slide

  3. 早速ですが
    アンケート

    View Slide

  4. 自宅か会社で
    Windowsを
    使ってる方は?

    View Slide

  5. 自宅も会社も
    Mac / *nixの方!

    View Slide

  6. View Slide

  7. 今回の話はタイトルの通り、
    「PHPからWindowsのAPIをいじる」
    という話です…

    View Slide

  8. Win32APIとは?

    View Slide

  9. Win32APIとは
    Windows API(ウィンドウズ エーピーアイ)とは、
    Microsoft WindowsのAPIのことである。
    特に32ビットプロセッサで動作するWindows 95
    以降やWindows NTで利用できるものはWin32
    APIと呼ばれる。また、それらのWindowsにおけ
    るWin32 APIの実装をWin32と呼ぶ。
    (https://ja.wikipedia.org/wiki/Windows_APIより)

    View Slide

  10. View Slide

  11. つまり
    • 意味合いとしてはよくご存じの「API」と同じで、Windowsが
    提供している各機能へのアクセス窓口
    • 「各機能」の範囲は幅広く…
    • ファイルの読み書き
    • ウィンドウの表示
    • GUIの制御 などなど
    • 例えば、ファイルの読み書きをする関数(ex. fopen/fwrite)は
    Win32APIを裏で呼び出している
    • PHPから呼べない機能を使いたい場合は直接呼ぶしかない

    View Slide

  12. 直接呼べるのか?
    • Windows APIに属する各APIは、主にDLLからの関数または
    COMインターフェイスとして機能を公開している。
    (Wikipediaより)
    • そのため、言語や環境を問わず、DLLを読んだりCOMへアクセ
    スする事で自由に呼び出す事ができます
    • PHPにはCOMを使えるようにするcom_dotnet拡張があるので、
    これを利用します

    View Slide

  13. View Slide

  14. 利用準備

    View Slide

  15. php_com_dotnet.dllの有効化
    • 普段からバリバリ使ってる方にはお馴染み
    • 標準で添付されていますが、5.3.15/5.4.5以降は手動で有効に
    する必要あり
    • php.iniに「extension=php_com_dotnet.dll」を追記するだけ
    • 「php –i」を実行して、com_dotnetが確認できればOK

    View Slide

  16. View Slide

  17. View Slide

  18. DynamicWrapperの導入
    • com_dotnetからWin32APIを呼び出そうとすると少し大変なの
    で、DynamicWrapperというWin32APIのラッパーも導入
    • http://www.borncity.com/web/WSHBazaar1/WSHDynaCall.htm
    • dynawrapnt.zipをダウンロードして解凍し、下記コマンドでシ
    ステムにDLLを登録
    • regsvr32.exe dynwrap.dll
    • PHP -> com_dotnet -> DynamicWrapper -> Win32APIという
    若干遠回りな呼び出しになるが、これで扱えるように

    View Slide

  19. View Slide

  20. ここで注意

    View Slide

  21. PHPは
    32bit版(x86)を
    使用しましょう!

    View Slide

  22. 何故か
    • DynamicWrapperが32bitのDLLのため
    • 32bitのDLLは64bitのアプリケーションからは呼べない制約がある
    • その逆も然り
    • DLLを調整すれば64bitからでも呼べるようになる、らしい
    • これに気付くまで2~3時間ハマってました…

    View Slide

  23. View Slide

  24. 動かしてみる

    View Slide

  25. 今回表示するもの

    View Slide

  26. やってみましょう
    • メッセージボックスを表示するだけ
    1. com_dotnetでDynamicWrapperを呼び出し
    2. 利用したいWin32APIを内包しているDLLと関数名をRegist()に渡し、
    呼び出しの準備をする
    • 今回はMessageBox()関数を呼び出します
    • https://msdn.microsoft.com/ja-jp/library/cc410914.aspx
    3. 実際に関数を呼び出す

    View Slide

  27. Register()
    • 利用したい関数とDLLを読み込む
    • 引数はこんな感じ
    • 呼び出すDLL名(必須)
    • 呼び出す関数名(必須)
    • 関数に渡す引数の型フラグ(オプション、i=に続けて指定)
    • 呼出規約の種類フラグ(オプション、f=に続けて指定)
    • 返り値の型フラグ(オプション、 r=に続けて指定)

    View Slide

  28. 引数/返り値の型
    指定するフラグ 型名
    a IDispatch
    c unsigined char
    d 8byte real
    f 4byte real
    k IUnknown
    h handle (4bytes)
    l long (4bytes)
    p pointer
    s string
    t short (2bytes)
    u unsigined int
    w wide string

    View Slide

  29. MessageBoxの場合
    • MessageBox(HWND, LPCSTR, LPCSTR, UNIT)
    • 100%一致する訳ではないので、ある程度予測して当てはめる
    • LPCSTR(const char*)に該当するのは無いので、stringを割り当てる
    • HWND = h, LPCSTR = s, UNIT = u とする
    • つまり、「i = hssu」となる

    View Slide

  30. 呼出規約
    プログラミングにおける呼出規約(よびだしきやく)ないし呼出
    慣例(よびだしかんれい)はサブルーチンを呼び出す際の標準的
    な手法を指す。サブルーチンにデータを渡し、戻るべきアドレス
    (リターンアドレス)を記録し、サブルーチンからデータを受け
    取るための規則である。一つのプログラムでは、(複数の言語処
    理系を用いて記述する場合も)同一の呼出規約を守る必要がある。
    さまざまな呼出規約があり、引数のコールスタック(以下単にス
    タックと呼ぶ)への格納法、サブルーチンにデータを渡す方法、
    サブルーチンからの復帰法、名前修飾が異なる。
    (https://ja.wikipedia.org/wiki/%E5%91%BC%E5%87%BA%E8%A6%8F%E7%B4%84より)

    View Slide

  31. 呼出規約の種類
    指定するフラグ 内容
    m Microsoft (bと排他的)
    b Borland (mと排他的)
    s _stdcall (cと排他的)
    c _cdeel (sと排他的)
    4 4 byte real value returned in ST(8と排他的)
    8 8 byte real value returned in ST(4と排他的)
    • デフォルトは「f=ms」
    • そのままでも問題なく利用できるので、特に指定のない場合は
    省略してもOK

    View Slide

  32. 関数の呼出
    • Register()で登録した関数は、上記のように呼び出す
    • なので、1回登録すればその後は複数回呼び出せる
    • 引数によってはnullを指定できる場合があるので、マニュアル
    を参照のこと
    • 呼出時の型は、PHP側も合わせる必要がある

    View Slide

  33. 日本語を渡す

    View Slide

  34. 日本語を渡す

    View Slide

  35. 日本語を渡す
    • 普通に何もせずに渡してしまうとエラーになる
    • mb_convert_encoding()でSJISやSJIS-winに変換すればOK

    View Slide

  36. 返り値
    • 返り値のある関数の場合、PHPでその返り値を受け取れます
    • Registerで「r=」のフラグを利用して、引数と同じように型を
    推測して登録しておく必要があります
    • MessageBox()の場合、押したボタンによって数値が返ってく
    るので、「r=u」を指定すればOK

    View Slide

  37. 返り値

    View Slide

  38. まとめ

    View Slide

  39. まとめ
    • PHPからWin32APIを扱うにはそれなりの準備が必要
    • 環境依存もあるし
    • 使いこなすのであれば、下記が必要そう
    • MSDNなどのドキュメントを隅から隅まで読む時間
    • Win32APIについての理解
    • 準備や調査に対してのリターンが大きくないので、積極的に使
    いこなす必要はあまりなさそう
    • PHPとは全然違う分野の理解も深まるので、「最近新しい知識
    仕入れてないな」という方は試してみるといいかもしれません
    • 温故知新

    View Slide

  40. 雑感
    • 調査前に考慮していたよりも手軽に扱えた
    • 個人の意見です
    • 本格的なGUIアプリケーションは厳しそう
    • やれなくはなさそうだが…
    • スクリプトを利用した作業を補助するくらいであれば手軽
    • 処理が終わったらアラートを出すとか
    • エラーを出すとか
    • 返り値で分岐もできるので、特定の選択肢の場合は再度走らせるとか
    • 少し勉強したCとかC++の知識が少し役立った瞬間でした

    View Slide

  41. 参考
    • PHP: COM関数 - Manual
    • http://php.net/manual/ja/ref.com.php
    • PHPでWin32APIを呼ぶ(Windows) - Qiita
    • http://qiita.com/joh/items/9f54c6876e356c51157
    • An Automation Object for Dynamic DLL Calls | Dr Dobb's
    • http://www.drdobbs.com/windows/an-automation-object-for-
    dynamic-dll-cal/210200078
    • Born's Windows Scripting Host
    • http://www.borncity.com/web/WSHBazaar1/WSHDynaCall.htm

    View Slide

  42. 参考
    • MessageBox 関数 (MSDN)
    • https://msdn.microsoft.com/ja-jp/library/cc410914.aspx
    • No.18 msgBoxのパラメータ(早見表)
    • http://www.niji.or.jp/home/toru/notes/18.html

    View Slide