DLLでextern "C" でstdcall [プログラミング]
とあるソフトのプラグインを作る事にしました。
このプラグインは普通のDLLの拡張子を変更したものなので、普通にDLLを作ります。
DLLを作るには、Visual C++ならプロジェクト作成時にDLLを作る指定をするだけなので、何も問題ありません。
後は、普通にプログラムを書いて、外部に公開する関数に「_declspec(dllexport)
」と付けるだけです。
_declspec(dllexport) void func()
{
....
}
これで、外部からDLL内のfunc
関数を呼び出せるようになります。
ところが、C++の場合は関数のオーバーロード(引数が違えば同じ名前の関数を定義できる機能)がある所為で、内部では関数名が違う名前に置き換えられています。
ソースファイルにはfunc
と書いてあるのに、実はfunc
ではないという事態になるのです。
DLLの場合、関数名を頼りにアクセスするので、これはちょっと困り者です。
置き換え後の名前でアクセスすれば良いのですが、名前の変換ルールは決まってないし、これは単なるC++の勝手な都合なので、他に押し付けることも出来ません。
C++が周りに合わせる必要があります。
そのために、「extern "C"
」を付けます。
_declspec(dllexport) extern "C" void func()
{
....
}
これで、名前の置き換えは起こらなくなります。func
関数はfunc
関数として外部に公開されます。
普通にDLLを作るのなら、これでOK。
さて、
Windowsの都合なのかVisual C++の都合なのか知りませんが、Visual C++では、関数の呼び出し方法が2種類あります。
「stdcall
」と「cdecl
」です。
詳しい違いはこの際どうでも良いので置いておくとして、重要なのは、関数の呼び出しは、関数の定義に合わせないといけないと言う事です。
stdcall
として作った関数はstdcall
として呼び出さないと、大変なことになります。
関数の呼び出し方法を指定するには、関数の戻り値の後ろに「__stdcall
」か「__cdecl
」を付ければOK。
void __stdcall func(); void __cdecl func();
実は、いま作ろうとしているプラグインは関数はstdcall
として呼び出す事になっています。
なので、関数の定義もstdcall
としなければなりません。
_declspec(dllexport) extern "C" void __stdcall func() { .... }
これで、問題は無いはずなのですが………。
__stdcall
を付けると、extern "C"
の指定がキャンセルされました。
なんですと~~~っ!
(正確には、extern "C"
がキャンセルじゃなくて、stdcall
が持つ名前の変換ルールに従って名前が置き換えられる)
一体どうすれば………。
C++を使うのを止めてCを使えと、そういうことか?
結論。
DEFファイル(拡張子がDEFのファイル)に、外部に公開する関数の名前を書いておけばOK
LIBRARY DLLの名前 EXPORTS 公開する関数名
こうすると、_declspec(dllexport)の指定が不要になります。
extern "C" void __stdcall func() { .... }
今日の一冊 | |
|
コメント 0