開発環境はVS2005です。
MFCを使いダイアログベースのアプリケーションを作成しています。
VBで作られている、イーサネットにアクセスしてデバイスと通信を行うDLLを使う
アプリケーションを作成しています。
そのDLLの初期化関数(引数なし)は呼び出すことができ、正常終了が返ってくることが
確認できました。
その後、デバイスとのコネクションを確立する関数を呼ぶ必要があるのですが、そこで
詰まってしまいました。
コネクションを確立する関数の引数にIPアドレスを文字列で指定するのですが、
VC++側でどのように呼び出してもコネクションが確立されません。
DLLのソースはなく、与えられているのはDLLとそれを使用しているVBアプリだけです。
初期化関数(引数なし)はうまく動作するため、引数の扱いに問題があるのではと考え
ております。
なにか、ご存じのかたがいらっしゃいましたら、アドバイスをお願いいたします。
DLLを使用しているVBアプリでは次のように宣言されています。
Public Declare Function com_open Lib control (ByVal flag As Long, ByVal str
As String, ByVal port As Long, ByVal addr As String) As Boolean
VBアプリではstr,addrともにダブルクォーテーションでくくられた文字列を直接
与えて呼び出していました。
VBアプリではコネクションの確立に成功することは確認済みです。
VBで作られたDLLを利用するのにVC++側では下記のようなコードを使っています。
typedef short int (__stdcall *FUNC )( LONG flag,BSTR str, LONG port, BSTR
addr );
hDLL = LoadLibrary( dllName );
if (hDLL != NULL){
Func = ( FUNC ) GetProcAddress( hDLL, com_open );
if (!Func){
// error
FreeLibrary( hDLL );
goto Error;
}
_bstr_t bstr(_T(E));
_bstr_t bstrAddr(_T(192.168.100.223));
BSTR bs;
BSTR bsAddr;
bs = bstr.copy();
bsAddr = bstrAddr.copy();
uReturnVal = Func( 0, bs, 1000, bsAddr );
}
手元にあるVBソースコードを見ると、
以下のWindows-APIに対して、
DWORD GetTempPath(
DWORD nBufferLength, // バッファのサイズ
LPTSTR lpBuffer // パスを格納するバッファ
);
以下の定義です。
Public Declare Function GetTempPath Lib kernel32 Alias GetTempPathA
(ByVal nSize As Long, ByVal lpBuffer As String) As Long
そこから察するに、
以下のように変えても駄目ですか?
typedef short int (__stdcall *FUNC )( LONG flag, BSTR str, LONG port,
BSTR addr );
↓
typedef short int (__stdcall *FUNC )( LONG flag, LPTSTR str, LONG port,
LPTSTR addr );
>typedef short int (__stdcall *FUNC )( LONG flag, LPTSTR str, LONG port,
>LPTSTR addr );
LPTSTR→LPCSTRの方がいいかも?
LPCWSTRの方はVB側はLong型の対応になったと思います。
ちなみにそのDLLはVBで作成されたものではありません。
#DLL側の定義がわかってないと、VBアプリ側でも宣言書けません。
bun様
返信ありがとうございます。
>typedef short int (__stdcall *FUNC )( LONG flag, BSTR str, LONG port,
>BSTR addr );
>
> ↓
>
>typedef short int (__stdcall *FUNC )( LONG flag, LPTSTR str, LONG port,
>LPTSTR addr );
上記の変更をして動作させましたが、コネクションの確立はできませんでした。
subaru様
返信ありがとうございます。
>LPTSTR→LPCSTRの方がいいかも?
typedef short int (__stdcall *FUNC )( LONG flag, LPTSTR str, LONG port,
LPTSTR addr );
↓
typedef short int (__stdcall *FUNC )( LONG flag, LPCSTR str, LONG port,
LPCSTR addr );
に変更し、コンパイルエラーが出たため呼び出し側を下記のように変更しました。
uReturnVal = Func( 0, bs, 1000, bsAddr );
↓
uReturnVal = Func( 0, (LPCSTR)bs, 1000, (LPCSTR)bsAddr );
上記の変更をして動作させましたが、コネクションの確立はできませんでした。
VC++で作られたDLLをVBから呼び出す例はたくさん発見できるのですが、
逆の例は少なくこれといった解決策が見つけられていません。
下記のページにあるVBとC,C++言語での文字列の扱いが異なる点が今回の問題の原因だと
考えております。
http://japan.internet.com/developer/20051004/27.html
subaru様
>ちなみにそのDLLはVBで作成されたものではありません。
>#DLL側の定義がわかってないと、VBアプリ側でも宣言書けません。
DLLがVBで作成されていることは、人づてに聞いただけですので確信はありません。
確認してみます。
ただ、このDLLにはドキュメントが付属されており、そのドキュメント内に
VBでの使用方法の説明が書かれています。
ですので、そこからDLL側の定義がわかったのではないかと考えます。
bun様
subaru様
自己解決しました。
結論は、下記のとおりです。
型定義
typedef short int (__stdcall *FUNC )( LONG flag, LPTSTR str, LONG port,
LPTSTR addr );
呼び出し
uReturnVal = Func( 0, _T(E), 0x1000, _T(192.168.100.223) );
上記の通りに変更することによりコネクションが確立できました。
正常にコネクションが張る場合と失敗する場合とで、Wireshark で出力するパケットを
比較したところポート番号が異なっていました。
文字列引数の問題ではありませんでした。
subaru様
DLLの作成言語について再確認してみたところ、実際のところ不明とのことでした。
bun様、subaru様 お手数おかけしました。
ありがとうございました。
>型定義
>typedef short int (__stdcall *FUNC )( LONG flag, LPTSTR str, LONG port,
>LPTSTR addr );
>
>呼び出し
>uReturnVal = Func( 0, _T(E), 0x1000, _T(192.168.100.223) );
LPTSTRは文字セットがマルチバイトかUnicodeかによって
LPSTRかLPWSTRのいずれかにコンパイルされます。
入力のみの場合はconstがつくことが多いです。
#VS2005ということを考えるとLPWSTR/LPCWSTRで合ってたのだろうか・・・
>subaru様
>DLLの作成言語について再確認してみたところ、実際のところ不明とのことでした。
VBで作成されるDLLはActiveXDLLです。その場合はCOMの操作になります。
http://support.microsoft.com/kb/194873/ja
だからといって今回のDLLがVC++で作成されているとも限りませんが。