1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

PHPからWindowsAPIを呼び出してみる

Last updated at Posted at 2025-03-08

はじめに

PHPからWindowsAPIを呼び出すことはできるのだろうか?と、たまたま気になったので調べてみると
PHP FFI(Foreign Function Interface)で呼び出せるそうです

FFIのマニュアルのサンプルを確認すると、
Basic FFI usage

  • FFI::cdef()で、関数のプロトタイプ宣言(と、ライブラリファイル名)を渡す
  • $ffiオブジェクト経由で、動的に関数を呼び出すことができる
    という仕組みのようです
$ffi = FFI::cdef(
    "int printf(const char *format, ...);", // this is a regular C declaration
    "libc.so.6");
// call C's printf()
$ffi->printf("Hello %s!\n", "world");

FFIを有効にする

(PHP8.4.4で試しています)
php.iniでffiを読み込むように変更します

-;extension_dir = "ext"
+extension_dir = "ext"
;extension=bz2
;extension=curl
-;extension=ffi
+extension=ffi

MessageBoxを表示するサンプル

WindowsAPIを呼び出すサンプルを作ってみましたが、呼び出し規約(stdcall)を指定できませんでした
(WindowsでFFIを使うのは、厳しそう・・・)

  • WindowsAPIは文字がUFT16。そのまま文字を渡せないので$ffi->new("unsigned short[" . <文字列のながs> . "]");で配列を作ってそこへセット
  • 呼び出し規約の指定はできなかったので、多分__cdeclで呼び出しされている(実行はできるが、スタックポインタがずれてエラーになる可能性がある)

image.png

<?php
/**
 * PHPからFFIでWindowsAPI(MessageBoxW)を呼び出すサンプル
 * ・WindowsAPIはstdcall呼び出し規約に従う必要があるが、FFIで指定できない(詳細不明)
 */

$stdcall = ""; //  "__stdcall"; // 呼び出し規約を指定するとエラーになる
// MessageBoxW APIの定義
$ffi = FFI::cdef("int $stdcall MessageBoxW(void* hWnd, unsigned short* lpText, unsigned short* lpCaption, unsigned int uType);", 'user32.dll');

$hWnd = null; // 親ウィンドウハンドル無し
// 文字列をUTF16に変換
$lpText = utf16("PHPからWindowsAPI(MessageBoxW)を呼び出しました!"); // メッセージ
$lpCaption = utf16("FFI Example"); // タイトルバー
$uType = 0; // MB_OK (OKボタンのみ)

// APIの呼び出し
$result = $ffi->MessageBoxW($hWnd, $lpText, $lpCaption, $uType);

if ($result == 1) { // IDOK (OKボタンが押された場合)
    echo "MessageBoxW が表示されました。\n";
} else {
    echo "MessageBoxW の表示に失敗しました。\n";
}


/**
 * UTF16の文字列に変換
 */
function utf16(string $string): ?FFI\CData
{
    $ffi = FFI::cdef();
    $utf16le_string = iconv("UTF-8", "UTF-16BE", $string);
    $hexed_string = bin2hex($utf16le_string);
    $buffer = $ffi->new("unsigned short[" . (strlen($string) + 1) . "]");
    for ($i = 0; $i < strlen($string); $i++) {
        $buffer[$i] = hexdec(substr($hexed_string, $i * 4, 4));
    }
    return $buffer;
}

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?