2017-03-23 39 views
0

我想暴露一个函数从一个DLL(我们将调用foo.dll)在C#中使用。但是,我没有访问源,所以我想我可能会写一个第二个 DLL(bar.dll),其中包含第一个,通过返回foo.dll的结果重新实现函数。我确实有.lib和.h文件,所以我希望我可以写一个小工具来浏览标题并生成我的'wrapper'dll(这是正确的词吗?)包装C++ DLL通过第二次加载在C#

我已经设置一个非常简单的测试,我自己实现foo.dll。我是非常对新的C++所以请温柔。

foo.h中

#pragma once 

double Add(double a, double b); 

Foo.cpp中

#include <stdio.h> 
#include "foo.h" 

double Add(double a, double b) 
{ 
    return a + b; 
} 

我建立这个和引用的.lib到我的项目吧,在foo.h.沿着复制

bar.h

#pragma once 

extern "C" 
{ 
    namespace foo { 
     #include "foo.h" 
    } 

    __declspec(dllexport) double Add(double a, double b); 
} 

bar.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#应用​​程序运行正常,输出: PRE 10.0 POST

我已经通过关于这个问题的好很多职位读,一些建议在声明我的变量时在名称前面添加__stdcall,但这会给我一个StackOverflow错误。

这是我的第一篇SO帖子(尽管当然我一直潜伏多年),所以请随时告诉我是否可以做任何事情来改善问题。

+1

有时使用P/Invoke是不可能的(例如导出的方法有std :: string),有时使用P/Invoke(只是编译或试图追踪奇怪的短时间失败)非常困难。在这些情况下,你必须编写用C++/CLI编写的中间层。使用此选项的另一个优点是可以将C++ API转换为一些管理友好的API。有关C++/CLI的建议,[有一本Marcus Heege出色的书](https://www.amazon.com/Expert-Visual-CLI-Programmers-Experts/dp/1590597567)。 –

+0

原始的Add()函数不在foo名称空间中。很不清楚你用什么大锤让酒吧项目链接。但它“不起作用”并不意外。 –

+0

感谢您的书推荐。我正在调查Dan int的建议,他在下面回答了C++/CLI,一旦我取得了一些进展,就会更新。 –

回答

0

既然你创建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组装。

-1

它可能是调用约定,但更新版本的.NET实际上很适合抛出大多数CC违例的异常。我建议在你的C++包装器中粘贴一些printf,看看你是否可以找出它挂起的位置。

选项B - 实际上有一个名为SWIG的包装生成器,它可以完成您为数十种不同语言所做的工作。它工作得很好。

+0

为什么downvote? –