从 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# DllImport 调用的 c++ dll?