- PR -

2回目 VC++6.0で作られたDLLをVC++2005から呼び出し方

1
投稿者投稿内容
gen
会議室デビュー日: 2006/07/19
投稿数: 17
投稿日時: 2006-07-19 17:33
http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=32202&forum=7&4

のつづきです。
勉強不足でごめんなさい、やっぱり駄目でしたのでもう一回投稿させて頂きます。

VC++6.0で作られたDLLをVC++2005から呼び出し方がわからなくて困っています。
VC++6.0で作られたDLLは別の会社から提供されたDLLでソースなどはありません。
あるのは
ノーマルなWin32 DLLファイル"cpjapi.dll",
インポートライブラリ"cpjapi.lib",
ヘッダファイル"cpjagtp.h"と"cpjapi.h"
があります。

"cpjapi.h"の最後に以下のように書いてありました。
------------------------------------------------------------------------------
// **************************************************
// * 関数プロトタイプ *
// * [ご注意] *
// * LIB ファイルをリンクしてご使用の場合は, *
// * CPJ_LOAD_LIB を定義する必要はありません。 *
// **************************************************
#if !defined(CPJ_LOAD_LIB)
#ifdef __cplusplus
extern "C" {
#endif
BOOL WINAPI CPJConnectEx( HWND hWnd, int cpj_no, int rcv_evt_mode );
.......
#ifdef __cplusplus
}
#endif
#else
typedef BOOL (WINAPI *pfnCPJConnectEx)( HWND hWnd, int cpj_no, int rcv_evt_mode );
.......
#endif
------------------------------------------------------------------------------
で、ソースで
#pragma comment( lib, "C:\\cpJOINT\\cpjapi.lib" )
のようにLIB ファイルをリンクして使用してますので上のソースを全部コメントアウト化しました。

別の会社から提供されたDLLの中には
CPJConnectEx( HWND hWnd, int cpj_no, int rcv_evt_mode ) などの
複数の関数があるのでそれをVC++2005から呼び出して同じ関数で定義して.netのDLLを作成し、それをVB2005から参照して使おうとしています。

今はVC++2005のソリューションエクスプローラの"ヘッダー ファイル"に"cpjagtp.h"と"cpjapi.h"を入れ、KTcpJOINT.hファイルを新規作成し、以下のソースを書いてあります。
----------------------------------------------------------------------------
#include "cpjagtp.h"
#include "cpjapi.h"

#pragma comment( lib, "C:\\cpJOINT\\cpjapi.lib" )

namespace KTcpJOINT {

using namespace System;

public ref class clsKTcpJOINT
{
public :

bool KTCPJConnectEx(
IntPtr hWnd,
int cpj_no,
int rcv_evt_mode)
{
return CPJConnectEx(hWnd,cpj_no,rcv_evt_mode);
}
};
}
-----------------------------------------------------------------------------

"ソース ファイル"フォルダにはhoge.cppファイルを新規作成し、以下のソースが書いてあります。
---------------------------------------------------------------------------
// これは メイン DLL ファイルです。

#include "KTcpJOINT.h"
---------------------------------------------------------------------------

これでビルドすると以下のエラーが出ています。
---------------------------------------------------------------------------
エラー 2 error C3861: 'CPJConnectEx': 識別子が見つかりませんでした d:\visual studio 2005\ktcpjoint\KTcpJOINT.h 23
警告 1 warning C4103: 'd:\visual studio 2005\ktcpjoint\ktcpjoint.h' : ヘッダーを含めた後に配置が変更しました。#pragma pack(pop) がないためである可能性があります d:\visual studio 2005\ktcpjoint\KTcpJOINT.h 4
---------------------------------------------------------------------------

c/c++ のすべてのオプション:
---------------------------------------------------------------------------
/Od /D "WIN32" /D "_DEBUG" /D "_WINDLL" /D "_UNICODE" /D "UNICODE" /FD /EHa /MDd /Fo"Debug\\" /Fd"Debug\vc80.pdb" /W3 /nologo /c /Zi /clr /TP /errorReport:prompt /FU "c:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\System.dll" /FU "c:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\System.Data.dll" /FU "c:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\System.XML.dll"
---------------------------------------------------------------------------

リンカのオプション:
---------------------------------------------------------------------------
/OUT:"D:\Visual Studio 2005\KTcpJOINT\Debug\KTcpJOINT.dll" /INCREMENTAL /NOLOGO /DLL /MANIFEST /MANIFESTFILE:"Debug\KTcpJOINT.dll.intermediate.manifest" /DEBUG /ASSEMBLYDEBUG /PDB:"d:\Visual Studio 2005\KTcpJOINT\Debug\KTcpJOINT.pdb" /MACHINE:X86 /FIXED:No /ERRORREPORT:PROMPT
---------------------------------------------------------------------------

ほんとうによろしくお願いします、今週中に何とかならないと...
返事お待ちしております。

[ メッセージ編集済み 編集者: gen 編集日時 2006-07-19 17:47 ]
chack
常連さん
会議室デビュー日: 2002/11/18
投稿数: 48
お住まい・勤務地: 埼玉県
投稿日時: 2006-07-19 19:29
下記の様にして、試してみてください。
コード:
// アンマネージライブラリインポートクラス
namespace KTcpJOINT {

  using namespace System;
  using namespace System::Runtime::InteropServices;

  public ref class clsKTcpJOINT
  {
  public:
    [DllImport("cpjapi.dll",EntryPoint="CPJConnectEx",
    CharSet=CharSet::Auto,ExactSpelling=true,
    CallingConvention=CallingConvention::StdCall)]
    static bool KTCPJConnectEx(IntPtr hWnd, int cpj_no, int rcv_evt_mode); 
  }; 
}

// 呼び出しテスト
namespace TEST {

  public ref class hoge
  {
  public:
    void CallTest()
    {
      ...

      KTcpJOINT::clsKTcpJOINT::KTCPJConnectEx(hWnd, cpj_no, rcv_evt_mode);
    }
};
}


ちなみに下記は不要です。
-----------------------------------------------
//#include "cpjagtp.h"
//#include "cpjapi.h"
//#pragma comment( lib, "C:\\\\cpJOINT\\\\cpjapi.lib" )
-----------------------------------------------
Blue
大ベテラン
会議室デビュー日: 2005/09/12
投稿数: 230
お住まい・勤務地: 知っている人は知っている
投稿日時: 2006-07-20 01:22
引用:

genさんの書き込み (2006-07-19 17:33) より:
上のソースを全部コメントアウト化しました。


って、違うような。。

引用:

// * LIB ファイルをリンクしてご使用の場合は, *
// * CPJ_LOAD_LIB を定義する必要はありません。 *


コメントアウトでなく、

コード:

#define CPJ_LOAD_LIB


の記述はいらないということなのでは?
ということなので、libを使うならば、そのまま何もいじらなくてよいと思います。
gen
会議室デビュー日: 2006/07/19
投稿数: 17
投稿日時: 2006-07-20 11:50
chackさん,Blueさん 本当にありがとうございます!!!

家にまだインターネットがないので返事遅れました、すいません。

ご指摘のとおりに改修入れて見ましたけどビルド通りました。
テストして見たら、うまくFALSEが返って来たのでOKだと思います。
まだ実際に使うHOST側との環境ができていないので処理テストは
できないけど、DLLを呼ぶのはできたので本当に助かりました。
ありがとうございました。

後、CPJConnectExの以外にいくつかの変数と関数の定義で間違って
いますけど...

cpjapi.hの定義:
--------------------------------------------------------------------
typedef int CPJ_HANDLE;
typedef DWORD CPJ_RESULT;
............
#define CPJ_SUCCESS 0
............
#define CPJ_DEST_DOWN 0xE000000B /* EVENTで通知 */
............
BOOL WINAPI CPJConnectEx( HWND hWnd, int cpj_no, int rcv_evt_mode );
CPJ_HANDLE WINAPI CPJConnect( HWND hWnd, int cpj_no, int lpath_no, char * server_addr );
CPJ_RESULT WINAPI CPJGetLastError( void );
UINT WINAPI CPJGet_RcvLen( HGLOBAL hBuff);
HGLOBAL WINAPI CPJAllocBuffer( DWORD alloc_size );
LPSTR WINAPI CPJLockBuffer( HGLOBAL hBuff );
----------------------------------------------------------------------

やぱりこれ
----------------------------------------------------------------------
BOOL WINAPI CPJConnectEx( HWND hWnd, int cpj_no, int rcv_evt_mode );
↓ ↓ ↓
static bool KTCPJConnectEx(IntPtr hWnd, int cpj_no, int rcv_evt_mode);
-----------------------------------------------------------------------
のように
BOOL → bool
HWND → IntPtr
変換して定義しなければいけないとおもいますけど
CPJ_HANDLE → int
CPJ_RESULT → ?
UINT → ?
HGLOBAL → ?
LPSTR → ?
char * → ?
DWORD → ?

"CPJGetLastError"は"CPJ_DEST_DOWN"値などを返してくれますので以下のように定義して
---------------------------------------------------------------------
[DllImport("cpjapi.dll",EntryPoint="CPJGetLastError",CharSet=CharSet::Auto,ExactSpelling=true,CallingConvention=CallingConvention::StdCall)]
static String^ KTCPJGetLastError();
---------------------------------------------------------------------

VB2005のテスト画面でVC++2005で作ったDLLを参照し、テストして見たけど
---------------------------------------------------------------------
Dim KT As New KTcpJOINT.clsKTcpJOINT
Try
Dim ss1 As String
Dim ss2 As String
Dim ss3 As String

ss1 = KT.KTCPJConnectEx(1, 1, 1)

ss3 = KT.KTCPJGetLastError()

ss2 = KT.KTCPJDisconnectEx(11)


TextBox1.Text = ss1

Catch ex As Exception
TextBox1.Text = ex.Message.ToString()
End Try
---------------------------------------------------------------------

ss3 = KT.KTCPJGetLastError()のところでエラーが出ています。
----------------------------------------------------------------------
FatalExecutionEngineError が検出されました。
Message: ランタイムの重大なエラーが発生しました。エラーのアドレスは 0x79f608c0、スレッド 0x16c8 です。エラー コードは 0xc0000005 です。これは CLR のバグであるか、またはユーザー コードのアンセーフまたは確認不可能な部分にバグがある可能性があります。このバグの一般的な原因には、スタックが壊れる可能性のある COM-interop または PInvoke のユーザー マーシャリング エラーが含まれています。
----------------------------------------------------------------------
警告 1 インスタンスを経由する共有メンバ、定数メンバ、列挙型メンバ、または入れ子にされた型へのアクセスです。正規の式は評価されません。 D:\Visual Studio 2005\Tester\Tester\Form1.vb 12 19 Tester
----------------------------------------------------------------------

ネットで検索してもよく見つからないのでアドバイスお願いできないでしょうか?
VBC++2005って出たばかりのもので資料が本当に少ないですね...

お願いするばかりで申し訳ございませんが、どうかよろしくお願いします。


[ メッセージ編集済み 編集者: gen 編集日時 2006-07-20 12:02 ]

[ メッセージ編集済み 編集者: gen 編集日時 2006-07-20 12:03 ]
Hongliang
ぬし
会議室デビュー日: 2004/12/25
投稿数: 576
投稿日時: 2006-07-20 12:20
最終的に C/C++ におけるどんな型として定義されているかを調べて、
http://msdn2.microsoft.com/ja-jp/library/ms235282.aspx
この辺を参照して対応するマネージド型に変換してください。
LPSTR とかは一般には String^ が対応しますが、メモリの解放という点を考えると IntPtr を使った方がいい場合もあります(特に関数の返値になってたりする場合)。
ついでに言うと、GetLastError 系は普通文字列じゃなくてエラーコードを返すことが多いと思います。

もっと言うと、せっかく C++/CLI でラップするんだったら、その辺は C++/CLI のクラスで隠蔽して VB 側からは単純な形式で使えるようにする方がいいと思います。
// 具体的にどうするかはラッパ書く人のセンス次第ですが。
gen
会議室デビュー日: 2006/07/19
投稿数: 17
投稿日時: 2006-07-20 12:40
Hongliangさん、アドバイスありがとうございます。

やっぱりMSDNですね、MSDNで探してたけど、このページ見つかりませんでした。

googleよりMSDNの検索が苦手です。

まずDLLを呼ぶところまではできそうなので処理テストしてOKなら

VB 側からは単純な形式で使えるようにしようと思っていました、

VB側は一箇所じゃなくていろんなところで使うんだから毎回変換とか

するのが大変ですよね、アドバイスありがとうございました。
1

スキルアップ/キャリアアップ(JOB@IT)