DOBON.NET DOBON.NETプログラミング掲示板過去ログ

DLLの文字列渡しについて

環境/言語:[XP/VB.NET,C]
分類:[.NET]

はじめまして。

CでDLLを作成して、VBでコールしたのですが、
文字列が1バイトしか取得できません。
以下にサンプルプログラムを掲示します。
よろしくお願いします。

[C]
#ifdef __cplusplus
extern "C" {
#endif

__declspec(dllexport) int __cdecl subtest3(int iDat, char *cDat1, char *cDat2);

#ifdef __cplusplus
}
#endif

__declspec(dllexport) int __cdecl subtest3(int iDat, char *cDat1, char *cDat2)
{
int i1;
int iLen;
int iRet;

iLen = strlen(cDat1);

以下省略

return(iLen);
}

[VB.NET]
Declare Auto Function subtest3 Lib "dlltest3.dll" _
Alias "subtest3" (ByVal iDat As Integer, ByVal cDat1 As String, ByVal cDat2 As String) As Integer


Private Sub Button5_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button5.Click
Dim iRet As Integer
Dim cDat1 As String
Dim cDat2 As String

cDat1 = "abcde"
cDat2 = "fghei"

iRet = subtest3(iDat, cDat1, cDat2)

以下省略

End Sub
> CでDLLを作成して、VBでコールしたのですが、
> 文字列が1バイトしか取得できません。

VBのDeclare文の場合、呼び出し規約が、stdCallになります。
CのDLLをstdCall規約にしましょう。
どうしてもcdeclを使うということなら、Declareステートメントではなく、
DllImport属性を使ってP/Invokeする必要があると思います。

また、DeclareでAuto指定をされていますが、これは文字列のCharSet指定に影響し、
これはWinNT系ではUnicode、Win9x系ではAnsi指定したことになります。
Declareステートメントを使う場合、Ansiを指定しましょう。
DllImport属性を使う場合は、CharSetにAnsiを指定して下さい。

後、CのDLLのchar*で指定された引数で文字列を返す必要がある場合は、
VB.NETでの宣言をAs Stringではなく、As System.Text.StringBuilderを使いましょう。
#VB.NETではAs Stringでも一応受け取ることはできますが。
よねKENさん
ご回答ありがとうございます。

■No2803に返信(よねKENさんの記事)
>
> VBのDeclare文の場合、呼び出し規約が、stdCallになります。
> CのDLLをstdCall規約にしましょう。

>
> また、DeclareでAuto指定をされていますが、これは文字列のCharSet指定に影響し、
> これはWinNT系ではUnicode、Win9x系ではAnsi指定したことになります。
> Declareステートメントを使う場合、Ansiを指定しましょう。


[C]
#ifdef __cplusplus
extern "C" {
#endif

__declspec(dllexport) int __stdcall subtest3(int iDat, char *cDat1, char *cDat2);

#ifdef __cplusplus
}
#endif


__declspec(dllexport) int __stdcall subtest3(int iDat, char *cDat1, char *cDat2)
{
省略
}

[VB.NET]
Declare Ansi Function subtest3 Lib "dlltest3.dll" _
Alias "subtest3" (ByVal iDat As Integer, ByVal cDat1 As String, ByVal cDat2 As String) As Integer

上記のように変更しましたが、以下のエラーとなりました。

----- エラー内容 -----
'System.EntryPointNotFoundException' のハンドルされていない例外が WindowsApplication1.exe で発生しました。

追加情報 : DLL dlltest3.dll の subtest3 というエントリ ポイントが見つかりません。
----------------------

VB.NETのAnsiをAutoに戻すとエラーにはなりませんでしが、
文字列が1バイトしか返却されません。
何か変更が足りないのでしょうか?
> ----- エラー内容 -----
> 'System.EntryPointNotFoundException' のハンドルされていない例外が WindowsApplication1.exe で発生しました。
>
> 追加情報 : DLL dlltest3.dll の subtest3 というエントリ ポイントが見つかりません。
> ----------------------

subtest3という名前で関数をエクスポートするには、
.defファイルで定義する必要があると思います。

私はCのDLL作成には詳しくないので、
http://homepage2.nifty.com/sak/w_sak3/doc/syspc/vc_net02.htm
をご覧下さい。
よねKENさん
ご回答ありがとうございます。

defファイルの追加で正常に動作するようになりました。

整理いたしますと

[C]
1.defファイルを以下の様に記述しました。
LIBRARY dlltest3
EXPORTS
subtest3 = subtest3

2.stdCall規約については、cdeclにしても動作しましたので
   どちらでも問題ないかと思いますが、
   一応、stdCall(標準呼び出し名前付け規則)にしました。
[VB]
1.DeclareのAuto指定をAnsiに変更しました。

以上です。

よねKENさん、本当にありがとうございました。
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板