如何包装C++;在基于C的dll或基于CLI的dll中初始化? >我被告知将C++中的Wrand类导入到DLL中,然后在C++应用程序中使用该DLL。下面我创建了dll,但我不能简单地在C#应用程序中使用它,因为它存在一些问题:
我应该为工厂函数的返回类型放置什么如何包装C++;在基于C的dll或基于CLI的dll中初始化? >我被告知将C++中的Wrand类导入到DLL中,然后在C++应用程序中使用该DLL。下面我创建了dll,但我不能简单地在C#应用程序中使用它,因为它存在一些问题:,c++,c,dll,c++-cli,C++,C,Dll,C++ Cli,我应该为工厂函数的返回类型放置什么 什么是构造函数参数类型的常量wchar\u t*的等价物 如何检索和使用类型为vector的函数返回类型 这些问题阻碍了我在C++应用程序中使用C++ DLL。我被告知需要用C++/CLI创建一个包装器,然后在我的C#中使用它。但是我很难过,我不知道它,我不知道C++,.net。 目前对我来说,唯一更有意义的事情是让它与C兼容,然后创建一个C DLL并在我的C应用程序中使用它。我曾经读过,在C语言中,类对象指针可以通过HANDLEs访问,所以我认为在不做太多更
常量wchar\u t*
的等价物vector
的函数返回类型HANDLE
s访问,所以我认为在不做太多更改的情况下运行是个好主意
所以问题是如何使用句柄访问C中的类对象并使用它们?我怎样才能把向量转换成C对应的向量呢?
如果我想使用CLI来为我的C++ DLL创建包装器(DLL),在其他的dotnet应用程序中使用什么?我应该做什么?< /p> 使用来自C++的本地C++类在技术上是可能的,但是它不是微不足道的,而且它甚至不是一个好主意。对于初学者,您必须知道从DLL导入的名称,这将是C++名称修改后的名称。您也不能直接从C#访问诸如
vector
之类的内容
基本上有两个好的选择:
第一种方法是使用C接口编写DLL,该接口只使用可以封送到CLR类型中的类型。您可以将指针与IntPtr
类型一起使用,但不能真正取消对这些指针的引用。您几乎可以将它们存储在C代码中,然后在需要时将它们传递回本机DLL。您还可以使用简单的struct
类型,只要不需要深度复制即可。此选项涉及使用P/Invoke
第二个选项是编写一个混合模式C++/CLI程序集,该程序集实现访问本机代码所需的所有逻辑。这个程序集可以直接从C#代码中访问类和数据,也可以直接访问本机代码,不过应该预先警告您,有些令人讨厌的中断不能将两者混合使用。例如,C++/CLI中的ref类不能有shared_ptr
成员。但是,它可以有一个原始的C++指针作为成员。(混合模式)本机类还可以访问CLR句柄类型,并通过该类调用C#代码。这个选项涉及使用C++互操作。
值得注意的是,你也可以用C++互操作来另一种方式。您可以让您的C#代码访问混合模式C++/CLI程序集,该程序集为某些本机代码提供.NET接口。但是,在这种情况下,您仍然需要进行一些翻译,因此它并不比第一个选项好多少
关于C++互操作的完整教程将相当冗长。我建议你在谷歌上阅读并做一些关于C++互操作的进一步研究。 < P> C++ +CLI引入托管对象,指针指针*应该用A^替换,而“新”应该用“GCNEW”替换,不需要在完成这些对象时删除这些对象,它们将被垃圾收集,编辑。托管类在其定义[/edit]中有一个ref关键字
在C++ /CLI包装类中包装C++ <强> MyClass < /Stutial>类<强> WrapperCLass < /St>可以类似这样:
#include <stdio.h>
class MyClass
{
public:
void ShowStuff(const wchar_t *a)
{
wprintf(a);
}
};
public ref class WrapperClass
{
MyClass *wrapped;
public:
WrapperClass()
{
wrapped = new MyClass;
}
~WrapperClass()
{
delete wrapped;
}
void ShowStuff(IntPtr string)
{
wrapped->ShowStuff((const wchar_t *)string.ToPointer());
}
};
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Client
{
class Program
{
static void Main(string[] args)
{
WrapperClass w = new WrapperClass();
IntPtr tmp;
w.ShowStuff(tmp = System.Runtime.InteropServices.Marshal.StringToHGlobalUni("Test"));
System.Runtime.InteropServices.Marshal.FreeHGlobal(tmp);
}
}
}
(很可能有更好的方法来做到这一点……)
对于返回类型,必须在包装器类中进行转换。创建一些.net集合,遍历向量,将wstring转换为System::String,并将其添加到.net集合中,然后返回。为了为C++
类创建一个C包装器,以便在例如C#
应用程序中使用,您可以执行以下操作
在Visual Studio中选择Win32 Console应用程序
并输入名称,然后单击下一步,在下一窗格中选择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”块中,您可以在其中定义接口、函数以访问类成员函数。请注意函数原型之前的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#应用程序中使用。
但有几件事需要注意,更重要的是:
你需要理解你作为代理使用的代码-我的意思是
testdll.h
中的函数定义只能使用C
兼容类型,毕竟是C,不是C++。< /LI>
您希望能够分配新的对象
类,而不是仅使用一个全局对象来访问所有方法
为此,如果需要在成员函数之间传递类对象,则需要首先将其转换为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.
}
}
<
[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());
}