通过一秒钟包装C ++ DLL来加载C#

时间:2017-03-23 18:01:00

标签: c# visual-c++ pinvoke dllimport dllexport

我试图从DLL(我们调用foo.dll)中公开函数以在C#中使用。但是,我无法访问源代码,所以我想我可以编写一个第二个 DLL(bar.dll),其中包含第一个,通过返回结果重新实现这些函数foo.dll。我确实有.lib和.h文件,所以我希望我可以编写一个小工具来浏览标题并生成我的包装' dlls(这是正确的术语吗?)

我为此设置了一个非常简单的测试,我自己实现了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引用到我的bar项目中,同时在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();
        }
    }
}

然而,当我运行这个时,我只是得到了#34; PRE&#34;输出和程序只是等待。到目前为止,我已经通过错误消息进行了问题排查,但我不确定如何解决在这种情况下发生的事情。

如果我重新实现bar.cpp以返回+ b,则C#应用程序按预期运行,输出: PRE 10.0 POST

我已经阅读了很多关于这个主题的帖子,有些人建议在声明我的变量时在名称前添加__stdcall,但这会给我一个StackOverflow错误。

这是我的第一篇SO帖子(虽然我当然潜伏了多年),如果我能做任何事情来改善这个问题,请随时告诉我。

2 个答案:

答案 0 :(得分: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 :(得分:-1)

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

选项B - 实际上是一个名为SWIG的包装器生成器,它完全符合您为数十种不同语言所做的事情。它运作得很好。