我正在尝试公开来自DLL(我们称之为foo.dll)的函数以在C#中使用。但是,我无法访问源代码,所以我想我可能能够编写第二个DLL (bar.dll),其中包括第一个,通过从 foo.dll 返回结果来重新实现函数。我确实有 .lib 和 .h 文件,所以我希望我可以写一个小工具来浏览标头并生成我的"包装器"dll(这是正确的术语吗?
我为此设置了一个非常简单的测试,自己实现 foo.dll。我对C++很陌生,所以请温柔一点。
福.H
#pragma once
double Add(double a, double b);
傅.cpp
#include <stdio.h>
#include "foo.h"
double Add(double a, double b)
{
return a + b;
}
我构建了这个并将 .lib 引用到我的 bar 项目中,并在 foo.h 中复制。
酒吧.H
#pragma once
extern "C"
{
namespace foo {
#include "foo.h"
}
__declspec(dllexport) double Add(double a, double b);
}
酒吧.cpp
#include <stdio.h>
#include "bar.h"
__declspec(dllexport) double Add(double a, double b)
{
return foo::Add(a, b);
}
到目前为止如此简单。然后,我尝试使用 DllImport 将其引入 C# 中:
using System;
using System.Runtime.InteropServices;
namespace ConsoleApplication1
{
class Program
{
[DllImport("bar.dll", CallingConvention = CallingConvention.StdCall)]
private static extern double Add(double a, double b);
static void Main(string[] args)
{
Console.WriteLine("PRE");
Console.WriteLine(Add(1.5, 8.5));
Console.WriteLine("POST");
Console.ReadKey();
}
}
}
但是,当我运行它时,我只会得到"PRE"输出,程序只是等待。到目前为止,我已经通过错误消息进行了故障排除,但我不确定如何弄清楚在这种情况下发生了什么。
如果我重新实现 bar.cpp 返回 a + b,C# 应用程序按预期运行,输出: 前 10.0 发布
我已经阅读了很多关于这个主题的文章,有些人建议在声明我的变量时在名称前添加__stdcall,但这给了我一个 StackOverflow 错误。
这是我的第一篇SO帖子(当然我已经潜伏了多年),所以如果我能做些什么来改进这个问题,请随时告诉我。
既然你正在创建bar.dll无论如何,使用 C++/CLI 来包装foo.dll; 如果你的 P/Invokes 变得不平凡(就像处理遗留C++代码一样),你会很高兴你朝着这个方向前进。
namespace BarAssembly
{
public ref struct Bar abstract sealed // "abstract sealed" == C#'s "static"
{
static double Add(double a, double b) {
return foo::Add(a, b);
}
}
}
您的 C# 代码现在很简单
static void Main(string[] args)
{
Console.WriteLine("PRE");
Console.WriteLine(BarAssembly.Bar.Add(1.5, 8.5));
Console.WriteLine("POST");
Console.ReadKey();
}
无需[DllImport]
,尽管您必须添加对bar.dll程序集的引用。
这可能是调用约定,但较新版本的 .NET 实际上非常适合为大多数 CC 违规引发异常。我建议在你的C++包装器中贴一些printf,看看你是否能弄清楚它挂在哪里。
选项 B - 实际上有一个名为 SWIG 的包装生成器,它完全可以执行您正在为数十种不同语言所做的工作。效果很好。