爲了使C wrapper
爲C++
類可用於在例如C#
應用程序,您可以執行以下操作。
在Visual Studio中選擇Win32 Console Application
並輸入名稱,然後單擊下一步並在下一個窗格中選擇DLL
。
並單擊完成。
當你完成你代表一個DLL項目包括3個文件。
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」塊,你定義的接口,功能來訪問你的類的成員函數原型之前functions.Note的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的DLL可以在C#應用程序中使用。
有幾件事情雖然注意到,其中比較重要的有:
- 你要明白,你作爲一個的Proxy-使用的代碼我的意思是你
testdll.h
內 函數定義,只能用C 兼容類型,它畢竟不是C++。
- 是你希望能夠分配你的 類的新對象,而不是僅僅使用一個全局對象來訪問所有的方法。
對於這一點,你,如果你需要傳遞成員函數之間的類的對象,則需要先將其轉換爲一個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++/CLI包裝爲您的本地C++類閱讀:
C++/CLI wrapper for your native C++ class
希望這是任何人在那裏誰具有相同的問題,因爲我的幫助:)
窗口'HANDLE'類型只是'void *'s – Pruyque
'const wchar_t *'是一個非常模糊的參數說明。也許這是一個UTF-16LE編碼的Unicode字符串,它帶有一個被傳遞給構造函數的NUL終結符。如果是這樣,它接近.NET的'System :: String',這是一個代碼單元計數UTF-16LE編碼的Unicode字符串。 (至少它有'const',所以我們知道它是不可變的,因此不是一個輸入參數。) –
.NET'char'編組到'wchar_t'。 – Joel