Borland C++でつくったDLLを使うには?

解決


火山屋  2001-09-07 12:22:56  No: 103623  IP: [192.*.*.*]

VB歴3週間の火山屋と申します

VB6.0で、BorlandC++5.5で作ったDLLを読み込んで
関数を使用するプログラムを作ろうと思いましたが、
実行すると「SubまたはFunctionが定義されていません」が
出て動きません。

DLL名はtestdll.dll
関数名はtestgで引数を100で割った余りを返す関数です

モジュールファイルでの宣言
Private Declare Function testg Lib "testdll"_
 Alias "_testg@8" (ByVal x As Long) As Byte
 
コードからの呼び出し
Dim b As Byte
・・・
b = testg(105)
・・・

どこが原因かお教えいただけないでしょうか?
よろしくお願いいたします。

編集 削除
通りすがり  2001-09-07 14:59:15  No: 103624  IP: [192.*.*.*]

VC++で作った時の記憶ですけど、参考になればと思い
書込みさせていただきます。

>
> モジュールファイルでの宣言
> Private Declare Function testg Lib "testdll"_
> Alias "_testg@8" (ByVal x As Long) As Byte
>

関数名が "_testg@8"となっていますが、@以降の数値って
引数のサイズではなかったでしたっけ?
Long型が1つの引数だと4Byteだから"_testg@4"では...
3年くらい前にやった話なので資料もなくあいまいな記憶なので
間違ってたらごめんなさい。

編集 削除
こころ  URL  2001-09-07 23:31:13  No: 103625  IP: [192.*.*.*]

> SubまたはFunctionが定義されていません
というエラーメッセージから推測すると
関数名がどうこうという問題ではないように思います。
(関数名が違うと、xxx.dllに〜が見つかりませんとかでるし
  引数が違うのなら、メモリ違反で強制終了が発生するはず)

> モジュールファイルでの宣言
> Private Declare Function testg Lib "testdll"_
モジュールでPrivate宣言すると、そのモジュールでしか
この関数は使用できませんが、フォームとか
別のモジュールから使用していたりしませんか?
その場合はPublicにすれば解決できますが・・・。

編集 削除
火山屋  2001-09-08 19:03:28  No: 103626  IP: [192.*.*.*]

publicですか?試してみます。
@の後の数は、Functionの返す数の大きさかなと
思ってました...

編集 削除
火山屋  2001-09-10 10:12:44  No: 103627  IP: [192.*.*.*]

火山屋です

VBから読もうとすると、
「testdll.dllの中でtestgが見つかりません」
というエラーメッセージがでて使えません。
DLLの作り方に問題があるのでしょうか?

------VB側での呼び出し--------------
Public Declare Function testg Lib "testdll" _
 Alias "testg@4" (ByVal x As Long) As Byte

又は 
 Public Declare Function testg Lib "testdll" _
 Alias "_testg@4" (ByVal x As Long) As Byte
 又は 
 Public Declare Function testg Lib "testdll" _
 Alias "_testg@8" (ByVal x As Long) As Byte
 又は 
 Public Declare Function testg Lib "testdll" _
 (ByVal x As Long) As Byte
 で試しました。

編集 削除
通りすがり  2001-09-10 13:29:06  No: 103628  IP: [192.*.*.*]

試しに自分の環境で VC++6.0、BC++5.5でそれぞれDLLを作成し、
VBから呼び出してみました。参考にしてください。
ちなみにCはオマケで知ってる程度なので、コーディングの仕方とか
「こんなコーディングしないよ!」とかいわれるかも知れませんが
参考までに...


DLLはVC,BC共に同じコーディングで問題ありませんでした。

#include <windows.h>

extern "C" _declspec( dllexport )int _stdcall tasu( int data1, int data2 );
extern "C" _declspec( dllexport )int _stdcall hiku( int data1, int data2 );

_declspec(dllexport)int _stdcall tasu( int data1, int data2 )
{
  return( data1 + data2 );
}

_declspec(dllexport)int _stdcall hiku( int data1, int data2 )
{
  return( data1 - data2 );
}

しかし、VBで呼ぶ場合の関数名に違いがありました。
クイックビューアと言うWindowsに標準添付されているアプリで
エクスポート関数名を確認したら、VCで作成したDLLには

  _tasu@8
  _hiku@8

と登録されていたのに、BCで作成したDLLには

  tasu
  hiku

と登録されていました。この点から、VBで読込むDeclare以降の
関数名をそれぞれ違ったものにしなければ関数が実行できない
(ちょっとエラーは違うが 「エントリ _tasu@8がDLLファイル
dlltest.dll内に見つかりません。」というエラーがでる)

テストしたVBのソースコードは次のとおりでした。

[コントロールの説明]
Text1 … 数値データ1
Text2 … 数値データ2
Text3 … 足し算の結果
Text4 … 引き算の結果
Command1 … 足し算の起動
Command2 … 引き算の起動


[ソースコード]
Option Explicit

' VC++でDLLを作成した場合
'Private Declare Function tasu Lib "dlltest.dll" Alias "_tasu@8" (ByVal data1 As Integer, ByVal data2 As Integer) As Long
'Private Declare Function hiku Lib "dlltest.dll" Alias "_hiku@8" (ByVal data1 As Integer, ByVal data2 As Integer) As Integer

' Boland C++ でDLLを作成した場合
Private Declare Function tasu Lib "dlltest.dll" (ByVal data1 As Integer, ByVal data2 As Integer) As Long
Private Declare Function hiku Lib "dlltest.dll" (ByVal data1 As Integer, ByVal data2 As Integer) As Integer

Private Sub Command1_Click()

 Dim iData1 As Integer
 Dim iData2 As Integer


    Text3.Text = CStr(tasu(CInt(Text1.Text), CInt(Text2.Text)))
    
End Sub
Private Sub Command2_Click()

 Dim iData1 As Integer
 Dim iData2 As Integer


    Text4.Text = CStr(hiku(CInt(Text1.Text), CInt(Text2.Text)))

End Sub

と、こんな感じでやればまとも?に動きました。
あと、DLLのパスは描いた方がいいかも。もしかして、同名のDLLが
System(System32)フォルダにあったら、嫌ですよね。

参考にしてみてください。

編集 削除
火山屋  2001-09-10 13:47:52  No: 103629  IP: [192.*.*.*]

火山屋です

通りすがりさんレスありがとうございます。
_stdcallをつかえばよかったんですね。
こちらも別の解決策をみつけました。
場違いですが、DLL用のCppファイルを載せます。

#define _WIN32_WINNT 0x0400
#define WINVER 0x400
#include <windows.h>

#define DllExport extern "C" __declspec(dllexport)

DllExport WINAPI short testg(int x);

int WINAPI DllMain(HINSTANCE hInst,DWORD fdwReason,PVOID pvReserved)
{
  return TRUE;
}

DllExport WINAPI short testg(int x)
{
  return (short)x%100;
}
testgの宣言にWINAPIを入れていなかったことが原因でした。
VBの宣言は「Public」と不要なAliasを消す以外は
問題無かったようです。通りすがりさんのご指摘通り、
Aliasは要りませんでした。
お騒がせしました。

編集 削除