我被告知将我在C++中的writen类导入一个dll,然后在C#应用程序中使用该dll。在this guide之后,我创建了dll,但由于存在一些与之相关的问题,因此我不能在C#应用程序中简单地使用它:
const wchar_t*
等效项,它是我的构造函数参数类型? vector< wstring>
类型的函数返回类型? 这些问题使我无法在C#应用程序中使用C++ DLL。有人告诉我,我需要使用C++/CLI创建包装器,然后在我的C#中使用该包装器。但是可悲的是,我对此一无所知,我不知道C++。net。
目前,对我来说似乎唯一更引起轰动的事情是使其与C兼容,然后创建一个C DLL并在我的C#应用程序中使用它。我已经读过在C语言中,可以通过
HANDLE
访问类对象指针,所以我认为这是个好主意,无需做太多更改就可以使事情顺利进行。所以问题是我该如何使用Handles在C语言中访问我的类对象并使用它们?以及如何将
vector<wstring>
转换为其C拷贝?如果我想使用CLI为我的C++ DLL创建包装器(DLL?),要在其他dotnet应用程序中使用,我该怎么办?
最佳答案
为了为要在例如C wrapper
应用程序中使用的C++
类创建C#
,您可以执行以下操作。
在Visual Studio中,选择Win32 Console Application
并输入一个名称,然后单击“下一步”,然后在下一个 Pane 中选择“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);
}
它位于此外部“C”块中,您可以在其中定义接口(interface)以及访问类成员函数的函数。请注意函数原型(prototype)之前的
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。
类,而不是仅使用一个全局对象来访问所有方法。
为此,如果需要在成员函数之间传递类对象,则需要先将其转换为C可以理解的
void*
,然后将其传递并使用它来访问任何成员函数。例如,为了使用户能够间接管理对象,我的
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++/CLI wrapper for your native C++ class。