結果だけでなく過程も見てください

たい焼きさんの日々の奮闘を綴る日記です。

AutoItでDLLを呼び出す方法

つい先日からUWSCスマホゲーWindows上の作業を自動化していたのですが、
UWSCは最近公式サイトがリンク切れになったり、32-bitのバイナリしかなかったり、VMのゲストOSでの動作がうまくいかなかったりと、
将来的にいろいろ不安なので、AutoItに乗り換えられないか色々試してます。


AutoItについてはWikipediaでもみてください。
https://ja.wikipedia.org/wiki/AutoIt


こちらの環境です。

OS Windows 10
C++コンパイラ Visual Studio 2017 Community
AutoIt v3.3.14.5

AutoItは世界ではわりとメジャーだそうで、困ったことがあっても調べればすぐ解決方法が出てくるのも魅力ですね~。
今回は自作のDLL呼び出しでちょっと詰まったので、解決方法をご紹介します。

C++(DLL)のソースコード

サンプルで簡単な足し算の関数を定義します。

結果を戻り値で受け取るバージョンと、引数経由で受け取るバージョンの2つ。
これをVisualStudio等でビルド・dllを作成し、AutoItのソースコードと同じパスに配置しておいてください。

#define DllExport __declspec( dllexport )

extern "C"
{
    DllExport int Add(int a, int b)
    {
        return (a + b);
    }

    DllExport void AddRef(int a, int b, int* pResult)
    {
        *pResult = (a + b);
    }
}

AutoItのソースコード

Add関数の呼び方
Dim $result = DllCall("NinaImageSearch.dll", "int:cdecl", "Add", "int", 3, "int", 5)
If (@error <> 0) Then
	MsgBox(0, "error", "DllCall returned " & @error)
	Exit @error
Else
	MsgBox(0, "Result", "$result=" & $result[0])
EndIf
ポイント
  • 第一引数にはDLLのファイル名(またはDllOpenした結果(ハンドル))を渡す
  • 第二引数には関数の戻り値の型(※)を指定する
  • 呼び出す関数の呼び出し規約がcdeclの場合は「型:cdecl」と指定する
  • 第三引数に関数名を指定する
  • それ以降は型名(※)と値のペアを指定する
  • エラーが発生した場合はマクロ「@error」に0以外の数値が入る
  • 戻り値がintだろうと、結果は配列で返るので値を参照するときは$result[0]として参照する

ポイント多いですね!
この呼び出しを成功させるだけで、30分くらい格闘した覚えがあります…。

(※)型一覧はこのあたりをみてください。
https://open-shelf.appspot.com/AutoIt3.3.6.1j/html/functions/DllCall.htm

AddRef関数の呼び方

変数の参照(リファレンス)を渡して、そこに結果を格納する方法ですが、こいつがわかりづらい。

Dim $sum
Dim $ret = DllCall("NinaImageSearch.dll", "none:cdecl", "AddRef", "int", 3, "int", 20, "int*", $sum)
If (@error <> 0) Then
	MsgBox(0, "error", "DllCall returned " & @error)
	Exit @error
Else
	$sum = $ret[3]
	MsgBox(0, "Result", "$sum=" & $sum)
EndIf
ポイント
  • 戻り値voidの場合は「none」という識別子を使う。(第二引数)
  • 変数の参照(リファレンス)を渡すときは型の末尾に「*」を指定する(第八引数)
  • DllCallに成功しても、なんと$sumには値が入らない!
  • 結果は$retに格納されており、$retは以下のような配列構造になっている。
  • $ret[0] ←戻り値(noneの場合は空文字)
  • $ret[1] ←3 AddRef関数の第一引数に渡す値
  • $ret[2] ←20 AddRef関数の第二引数に渡す値
  • $ret[3] ←23 これがAddRef関数の戻り値!
  • つまり必要に応じて結果($ret[3])を変数に格納して使う。ってなんじゃこのわかりづらいのは~!

この呼び出しを成功させるだけで、1時間くらい格闘した覚えがあります…。

その他疑問

呼び出し規約をstdcallとかにすると、DllCallが3(関数が見つからない)が返ってくる。なぜだ。

プライバシーポリシー お問い合わせ