Topic 4: C++で作ったDLLをActiveBasicで使用する

ActiveBasicではDLLの呼び出しに対応しているので,他の言語で作成したDLLも使うことができます。
そこで,ここではVisual C++(VC.NET)で作成したDLLを使ってみることにします。
自分が試してみたところ少し面倒なところがあったので,そこを特に重点的に解説します。

それでは各コードの解説です。

※Visual Studio .NETの場合,DLLの作成は以下のような方法で始めます。

※DllMain関数の部分は省略しました。

C++(DLL)のソース

// 「extern "C"」は,内部コードが(C++ではなく)Cの関数の形式になることを示します。DLLの場合は通常これを付けます。
// 「__declspec(dllexport)」はDLLの外部から呼び出される関数であることを示します。
#define Export extern "C" __declspec(dllexport)

// 暗号化
Export void __stdcall charcrypt(char *buf, char key){
    int i=0, t;
    while(buf[i]!='\0'){
        if(buf[i]>=32 && buf[i]<=126){
            t=buf[i]-32;
            t+=key;
            if(t>=95) t-=95;
            buf[i]=t+32;
        }
        i++;
    }
}

// 復号化
Export void __cdecl chardecrypt(char *buf, char key){
    int i=0, t;
    while(buf[i]!='\0'){
        if(buf[i]>=32 && buf[i]<=126){
            t=buf[i]-32;
            t-=key;
            if(t<0) t+=95;
            buf[i]=t+32;
        }
        i++;
    }
}

ActiveBasic(DLL呼び出し側)のソース

#N88BASIC

Declare Sub charcrypt Lib "DLLTest" Alias "_charcrypt@8" (buf As BytePtr, key As Byte)
Declare Sub chardecrypt CDECL Lib "DLLTest" (buf As BytePtr, key As Byte)

Dim S As String
S="ActiveBasic"

' 暗号化
charcrypt(S, 50) ' "s6G<I8t4F<6"と表示
Print S

' 復号化
chardecrypt(S, 50) ' "ActiveBasic"と表示
Print S

内容としては,文字列中にASCIIの範囲の制御文字を除く文字コード(32〜126)があれば,それにkeyの数を足したものを暗号化された文とするものです。ただし126を超えた場合は126の次に32に戻るものとします。

ここで,DLLの呼び出しの部分が微妙に違うのに注目して下さい。C++側で「__stdcall」を付けるか「__cdecl」を付けるかで,ABでの呼び出し方が変わるのです。

1."__stdcall"を用いた場合

DLLに限らず,Windows上では関数を呼び出す時にメモリの利用方法が数種類あります。これを「呼び出し規約」と言います。(「__stdcall 呼び出し規約」なんかで検索すると詳細が分かるかと思います。)そのうち"__stdcall"は,VB(VB.NETは違ったかも?)やABで標準としている呼び出し方法です。
ところが,VC++で"__stdcall"の関数を作成すると,DLL内部での名称が「_[関数名]@[引数のバイト数]」となります。
この例であれば,「char *」の4バイト(ポインタ型は全て4バイト)と「char」の1バイトで合計5バイトとなりますが,実際には「8」が付きました。おそらく,4の倍数でない時には4の倍数に切り上げられるのでしょう。詳細な情報をお持ちの方いらっしゃったら教えて下さい。
ですので,その名称を「Alias」の部分で指定する必要があります。

2."__cdecl"を用いた場合

"__cdecl"は,Cで標準としている関数の呼び出し方法です。なおCでは呼び出し規約名を省略するとこれになります。

この場合,ABの(非公式な?)仕様として,「CDECL」を付ければこの仕様に従った関数を呼び出すことができます。
Windows APIは基本的に"__stdcall"が使用されていますが,wsprintf関数は例外的に"__cdecl"になっています(includeフォルダのapi_window.sbpを参照)。"__cdecl"では可変個の引数を扱うことも可能であるためこのようになっています。

※呼び出し規約の指定を間違うと("__cdecl"の関数をABで「CDECL」なしで呼び出そうとしたりすると),アクセス違反で落ちるので注意しましょう。

1つ前へ ActiveBasic Hall トップへ ActiveBasic Center トップへ Sinryow Game トップへ