たとえばアプリケーションで使用されるクラスを作成するには、次のようにしC wrapper
ます。C++
C#
Visual StudioWin32 Console Application
で名前を選択して入力し、[次へ] をクリックして、次のペインで選択DLL
して [完了] をクリックします。完了すると、3 つのファイルを含む DLL プロジェクトが表示されます。
testdll.h
testdll.cpp
dllmain
testdll.h
およびファイル内に存在するすべてを削除しtestdll.cpp
、次の内容をそれぞれにコピーします。これらの行を testdll.h に追加します
// Our C wrapper for creating a dll to be used in C# apps
// The following ifdef block is the standard way of creating macros which make exporting
// from a DLL simpler. All files within this DLL are compiled with the TESTDLL_EXPORTS
// symbol defined on the command line. This symbol should not be defined on any project
// that uses this DLL. This way any other project whose source files include this file see
// TESTDLL_API functions as being imported from a DLL, whereas this DLL sees symbols
// defined with this macro as being exported.
#ifdef TESTDLL_EXPORTS
#define TESTDLL_API __declspec(dllexport)
#else
#define TESTDLL_API __declspec(dllimport)
#endif
extern "C"
{
TESTDLL_API int OurTestFunction(int x, int y);
}
この extern "C" ブロック内で、インターフェイス、クラス メンバー関数にアクセスするための関数を定義しますTESTDLL
。関数プロトタイプの前に注意してください。あなたのすべての機能はそれによって進められなければなりません。
これらを testdll.cpp ファイルに追加します。
#include "testdll.h"
#include "ourClass.h"
#define DLL_EXPORT
extern "C"
{
OurClass ourObject;
TESTDLL_API int OurTestFunction(int x, int y)
{
return ourObject.Add(x,y);
}
}
これをコンパイルして、C# アプリケーションで使用できる C ベースの dll を取得します。
注意すべき点がいくつかありますが、より重要なものは次のとおりです。
- プロキシとして使用するコード、つまり 内の関数定義を意味することを理解する必要があります
testdll.h
。C と互換性のある型のみを使用する必要があります。C++ ではなく C です。
- 1 つのグローバル オブジェクトを使用してすべてのメソッドにアクセスするのではなく、クラスの新しいオブジェクトを割り当てられるようにしたいということです。
このため、メンバー関数間でクラス オブジェクトを渡す必要がある場合は、まずそれvoid*
を C が理解できる に変換してから渡し、それを使用して任意のメンバー関数にアクセスする必要があります。
たとえば、testdll.h
ユーザーがオブジェクトを間接的に管理できるようにするために、内部に次のようなものがあります。
#ifdef TESTDLL_EXPORTS
#define TESTDLL_API __declspec(dllexport)
#else
#define TESTDLL_API __declspec(dllimport)
#endif
extern "C"
{
TESTDLL_API int OurTestFunction(int x, int y);
TESTDLL_API void* CreateHandle();
TESTDLL_API void* GetCurrentHandle();
TESTDLL_API void DisposeCurrentHandle();
TESTDLL_API void SetCurrentHandle(void* handle);
TESTDLL_API void* GetHandle();
TESTDLL_API void DisposeHandle(void*);
TESTDLL_API void DisposeArrayBuffers(void);
}
そして、testdll.cpp 内で、次のように定義します。
#include "testdll.h"
#include "ourClass.h"
#define DLL_EXPORT
extern "C"
{
OurClass *ourObject;
TESTDLL_API int OurTestFunction(int x, int y)
{
//return ourObject.Add(x,y); -- not any more !!
ourObject = reinterpret_cast<OurClass *>(GetHandle());
}
//Handle operations
TESTDLL_API void* CreateHandle()
{
if (ourObject == nullptr)
{
ourObject = new OurClass ;
}
else
{
delete ourObject ;
ourObject = new OurClass ;
}
return reinterpret_cast<void*>(ourObject);
}
TESTDLL_API void* GetCurrentHandle()
{
return reinterpret_cast<void*>(ourObject );
}
TESTDLL_API void DisposeCurrentHandle()
{
delete ourObject ;
ourObject = nullptr;
}
TESTDLL_API void SetCurrentHandle(void* handle)
{
if (handle != nullptr)
{
ourObject = reinterpret_cast<OurClass *>(handle);
}
else
{
ourObject = new OurClass ;
}
}
//factory utility function
TESTDLL_API void* GetHandle()
{
void* handle = GetCurrentHandle();
if (handle != nullptr)
{
return handle;
}
else
{
ourObject = new OurClass ;
handle = reinterpret_cast <void*>(ourObject );
}
return handle;
}
CDLL_API void DisposeHandle(void* handle)
{
OurClass * tmp = reinterpret_cast<OurClass *>(handle);
delete tmp;
}
TESTDLL_API void DisposeArrayBuffers(void)
{
ourObject = reinterpret_cast<OurClass *>(GetHandle());
return ourObject ->DisposeBuffers();//This is a member function defined solely for this purpose of being used inside this wrapper to delete any allocated resources by our class object.
}
}
これをコンパイルするDll
と、C# アプリケーション内で簡単に操作できます。この dll で定義された関数を使用する前に、適切な[ImportDll()]
. したがって、TestDll の場合、次のように記述します。
[DllImport(@"TestDll.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int OurTestFunction(int firstNumber,int secondNumber);
そして最後に次のように使用します。
private void btnReadBigram_Click(object sender, EventArgs e)
{
int x = OurTestFunction(10,50);
MessageBox.Show(x.ToString());
}
これで、C# アプリケーション内で C++ クラス メンバー関数に簡単にアクセスできるようになりました。
注: C# アプリケーションをコンパイルするときは、プロジェクトをコンパイルするため
のプラットフォームを選択していないことを確認してください。プロパティを使用してプラットフォームを変更できます。 x86
AnyCpu
注 2 :
ネイティブ C++ クラス用の C++/CLI ラッパーを作成する方法については、次を参照してください: ネイティブ C++ クラス用の C++/CLI ラッパー.