C++で記述されたDLLがあります。C#コードでこのDLLを使用する必要があります。検索後、P/Invokeを使用すると必要な関数にアクセスできることがわかりましたが、これらの関数はクラスで定義され、非静的なプライベートメンバー変数を使用しています。したがって、関数を適切に使用するには、このクラスのインスタンスを作成できる必要があります。インスタンスを作成できるように、このクラスにアクセスするにはどうすればよいですか?これを行う方法を見つけることができませんでした。
C++ dllは私のコードではないことに注意する必要があると思います。
C#コードでC++クラスを直接使用する方法はありません。 PInvokeを間接的に使用して、タイプにアクセスできます。
基本的なパターンは、クラスFooのすべてのメンバー関数に対して、メンバー関数を呼び出す関連する非メンバー関数を作成することです。
class Foo {
public:
int Bar();
};
extern "C" Foo* Foo_Create() { return new Foo(); }
extern "C" int Foo_Bar(Foo* pFoo) { return pFoo->Bar(); }
extern "C" void Foo_Delete(Foo* pFoo) { delete pFoo; }
今では、これらのメソッドをC#コードにPInvokingするだけです。
[DllImport("Foo.dll")]
public static extern IntPtr Foo_Create();
[DllImport("Foo.dll")]
public static extern int Foo_Bar(IntPtr value);
[DllImport("Foo.dll")]
public static extern void Foo_Delete(IntPtr value);
欠点は、渡すべき扱いにくいIntPtrがありますが、このポインターの周りにC#ラッパークラスを作成して、より使いやすいモデルを作成するのは簡単なことです。
このコードを所有していない場合でも、元のDLLをラップして小さなPInvokeレイヤーを提供する別のDLLを作成できます。
C++コード、ClassName.h
class __declspec(dllexport) CClassName
{
public:
CClassName();
~CClassName();
void function();
};
C++コード、ClassName.cpp
CClassName::CClassName()
{
}
CClassName::~CClassName()
{
}
void CClassName::function()
{
std::cout << "Bla bla bla" << std::endl;
}
C++コード、呼び出し元関数のClassNameCaller.hファイル
#include "ClassName.h"
#ifdef __cplusplus
extern "C" {
#endif
extern __declspec(dllexport) CClassName* CreateClassName();
extern __declspec(dllexport) void DisposeClassName(CClassName* a_pObject);
extern __declspec(dllexport) void function(CClassName* a_pObject);
#ifdef __cplusplus
}
#endif
C++コード、呼び出し元関数のClassNameCaller.cppファイル
#include "ClassNameCaller.h"
CClassName* CreateClassName()
{
return new CClassName();
}
void DisposeClassName(CClassName* a_pObject)
{
if(a_pObject!= NULL)
{
delete a_pObject;
a_pObject= NULL;
}
}
void function(CClassName* a_pObject)
{
if(a_pObject!= NULL)
{
a_pObject->function();
}
}
C#コード
[DllImport("ClassNameDll.dll")]
static public extern IntPtr CreateClassName();
[DllImport("ClassNameDll.dll")]
static public extern void DisposeClassName(IntPtr pClassNameObject);
[DllImport("ClassNameDll.dll")]
static public extern void CallFunction(IntPtr pClassNameObject);
//use the functions
IntPtr pClassName = CreateClassName();
CallFunction(pClassName);
DisposeClassName(pClassName);
pClassName = IntPtr.Zero;
ここ は、C++クラスメソッドをVB-から呼び出す方法のサンプルです。C#の場合、手順4でサンプルプログラムを書き換えるだけで済みます。
myfile.i
%module learnaboutswig
class A
{
public:
void boringfunction(char *charstr);
};
swig.orgからSwigをダウンロードします
swig -c ++ -csharp myfile.i
出力を見て、うまくいくかどうかを確認してください。
これを行った方法は、アンマネージC++ DLLの周りに薄いマネージC++ラッパーを作成することです。マネージラッパーには、.NETアプリケーションに必要なインターフェイスを公開するアンマネージコードをラップする「プロキシ」クラスが含まれています。これは少し二重の作業ですが、通常の環境では非常にシームレスな操作が可能です。状況によっては(ASP.NETなど)依存関係によって物事が難しくなりますが、おそらくそれには遭遇しません。
これを処理し、必要なインターフェイスを公開する仲介者DLL(おそらくC++))を記述する必要があるかもしれません。あなたのDLLが担当しますサードパーティのDLLをロードし、このC++オブジェクトのインスタンスを作成し、設計したAPIを介して必要に応じてそのメンバー関数を公開します。その後、P/Invokeを使用してAPIを取得し、オブジェクトをクリーンに操作します。
注:DLLのAPIについては、データ型をプリミティブ(long、int、char *など)に制限して、モジュールの境界の問題を回避してください。
JaredParに同意します。マネージコードでアンマネージクラスのインスタンスを作成することはできません。
もう1つは、マネージC++でDLLを再コンパイルするか、それからCOMコンポーネントを作成できれば、はるかに簡単になります/