【问题标题】:Call C++ dll methods/classes from C#从 C# 调用 C++ dll 方法/类
【发布时间】: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 只会以悲伤和自怜而告终。

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

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

我认为上面的第 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 比使用代理模式要容易得多,并且需要的维护也少得多。
  • 很遗憾,我无权访问源代码或开发人员。

标签: c# visual-c++ dll pinvoke


【解决方案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 分钟)“很遗憾,我无权访问源代码或开发人员”
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-12
  • 1970-01-01
  • 2012-02-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多