从 C# 调用 C++ dll 方法/类

Posted

技术标签:

【中文标题】从 C# 调用 C++ dll 方法/类【英文标题】:Call C++ dll methods/classes from C# 【发布时间】:2015-06-29 08:03:00 【问题描述】:

我编写了一些软件来自动化一些第 3 方软件,并发现有必要考虑调用该软件自己的 dll。


注意:很遗憾,我无权访问源代码或开发者


使用 PInvoke 调用 dll 的静态方法很容易,但据我所知,如果没有 C++/CLI 包装器,就无法实例化类。

答案似乎是围绕 dll 创建一个 C++/CLR 包装器,如 this answer 中所示。 虽然显然是一个很好的答案,但我以前从未创建过 C++ 应用程序,也不知道确切该做什么。

我已经使用dependency walker 来获取我想使用的函数名:sdk_string::sdk_string(const char *)(装饰:??0sdk_string@@QAE@XZ)。在那个入口点尝试 PInvoke 只会以悲伤和自怜而告终。

根据我收集到的信息,我需要:

    新建一个 Visual C++ CLR 类库。 在主 .h 头文件中写入如下内容:sdk_string* CreateSdkString(const char * chars) return new sdk_string(chars); 以某种方式让new sdk_string(chars) 调用调用第三方 dll? ?????? (我是否需要以任何特殊方式构建它,以便轻松 PInvoke 我的CreateSdkString 函数?) 支持并接受您的回答。 :-)

我认为上面的第 3 步是我的问题:我如何获得 new sdk_string(chars) 调用以调用第 3 方 dll? 但如果我对其他事情有误,那么其他事情我的问题是我错了。

更新:

仅供参考,以下是该类的整个 Dependency Walker 函数名称输出:

const sdk_string::`vftable' class sdk_string & sdk_string::append(class sdk_string const &) 类 sdk_string & sdk_string::append(char) 类 sdk_string & sdk_string::append(char *) 类 sdk_string & sdk_string::append(char const *) char const * sdk_string::c_str(void) bool sdk_string::contains(char const *) bool sdk_string::empty(void) bool sdk_string::endsWith(char const *) int sdk_string::equals(class sdk_string const &) int sdk_string::equals(char const *) int sdk_string::equalsIgnoreCase(class sdk_string const &) int sdk_string::equalsIgnoreCase(char const *) void sdk_string::erase(int,int) bool sdk_string::hasAlphaChars(void) int sdk_string::indexOf(class sdk_string const &) int sdk_string::indexOf(char) int sdk_string::indexOf(char,int) int sdk_string::indexOf(char const *) void sdk_string::insert(int,char const *) bool sdk_string::isAllDigits(void) bool sdk_string::isAllWhiteSpace(void) int sdk_string::length(void) class sdk_string & sdk_string::operator=(class sdk_string const &) 类 sdk_string & sdk_string::operator=(char *) void sdk_string::replace(int,int,class sdk_string const &) void sdk_string::replace(char const *) sdk_string::sdk_string(wchar_t * &) sdk_string::sdk_string(class sdk_string const &) sdk_string::sdk_string(char const *) sdk_string::sdk_string(void) void sdk_string::setData(char const *) bool sdk_string::startsWith(char const *) bool sdk_string::stretch(int) void sdk_string::stripLeadingSpaces(void) void sdk_string::stripSpaces(void) void sdk_string::stripTrailingSpaces(void) void sdk_string::substr(int,int,class sdk_string &) void sdk_string::toUpper(class sdk_string &) sdk_string::~sdk_string(void)

【问题讨论】:

我很好奇 DLL 甚至可以导出类。这是一件很不寻常的事情。它限制您使用与 DLL 目标相同的编译器和运行时。你能做到吗?但无论如何,您都可以按照您链接到的答案中的说明进行操作。我看不出是什么阻止了你。虽然,FWIW,Jared 的回答涉及将 C++ 类接口转换为通过 p/invoke 调用的扁平接口的非托管 C++ DLL。 Jared 没有描述 C++/CLI 方法,尽管 C++/CLI 可能是我解决这个问题的方式。 嗯,也许我在这里不想要一门课?我只是假设方法签名foo::foo() 等同于class foo public: foo() 。我想我错过了一些非常明显的难题......我如何将第 3 方 .dll 中的函数/类放入我的新 C++/CLR 包装器中以便我可以调用它?我读过有关使用 LoadLibrary 的信息,我在 C# 中没有问题,但只是不知道如何在 C++ 中执行。 创建包装器 c++/CLI dll 以代表您的 .NET 代码创建非托管对象是一回事;但是对于非托管代码然后调用非托管对象则完全不同。如果您打算直接调用该对象,则需要将 c++ 代码转换为 c++/CLI。当然,您将需要源代码。唯一的另一种方法是创建一个 c++/CLI proxy dll,其中包含您打算调用的 c++ 类方法的包装器方法。后者需要更多的工作,但它不需要需要更改原始 c++ 代码。 如果您可以访问 c++ 源代码,那么将其转换为 c++/CLI 比使用代理模式要容易得多,并且需要的维护也少得多。 很遗憾,我无权访问源代码或开发人员。 【参考方案1】:

我认为我错过了一些非常明显的难题...如何将函数/类从第 3 方 .dll 获取到我的新 C++/CLR 包装器中,以便我可以调用它

您使用非托管库提供的头文件和导入库,就像您将任何 DLL 导入非托管项目一样。在引用库的任何源文件中包含头文件,并将导入库传递给链接器。

然而,在 DLL 中实现的基于 C++ 类的已发布接口令人惊讶。它对您选择编译器施加了严格的限制。我怀疑您正在对私有库进行逆向工程,因此没有头文件或导入库。对它们进行逆向工程可能是一个无法追踪的问题。我建议联系库的开发人员以获得支持。

【讨论】:

我没有头文件或导入库。我只有dll。这是我正在尝试自动化的第 3 方软件。 是的。我猜的差不多。看我的更新。正在尝试的事情是难以处理的。您需要尝试调用的库的开发人员的帮助。 FWIW, ??0sdk_string@@QAE@XZ demangles 到 public: __thiscall sdk_string::sdk_string(void) __thiscall 是否意味着我已经需要创建一个实例? 那是构造函数,所以没有。如果你不知道它的声明,你怎么可能希望创建这个类并使用它?【参考方案2】:

显然你只需要几个方法/函数,所以在这种情况下你能做的最好的就是创建头文件(你的选项 2)。如果您需要更多(很多)类/方法,您可以检查http://www.swig.org/ 它可以创建 C# 的包装器,但它需要定义,例如,您可以创建一个头文件,将其命名为 myHeader.h,如下所示:

class A

public:
int intMethod(float param);

在您创建一个文件之后,我们将其命名为 myHeader.i,内容如下:

%module myHeader_wrapper
%
//Here could be the header file or directly the class/functions definition
    #include "myHeader.h"
%
%include "myHeader.h"

之后你运行:

swig -csharp myHeader.i

应该创建一个名为 myHeader_wrap.c 和 myHeader.cs 的文件。使用 .c 文件创建 C++ dll 并使用 C# 项目中的 .cs 文件访问类。当然,可以使用您的 IDE 工具自动执行 swig 操作(例如,让 Visual Studio 运行构建后操作)。

【讨论】:

我认为我们永远不会达到 SWIG,因为我们不知道什么类声明 OP 表示(遗憾地在您回答后 10 分钟)“很遗憾,我无权访问源代码或开发人员”

以上是关于从 C# 调用 C++ dll 方法/类的主要内容,如果未能解决你的问题,请参考以下文章

从 C++ 调用 C# dll(MSVC 编译器)

有啥方法可以调试从 C# DllImport 调用的 c++ dll?

从 C# 调用带有 C++ 标头的 dll

从 C# 调用 C++ dll 中的方法,没有任何信息,只有头文件

从 C# 调用 C++ 代码而不创建 dll?

如何从 c++ 项目中调用用 c# 创建的 dll 文件? [复制]