简体   繁体   English

将C ++ DLL包装一秒以加载到C#中

[英]Wrap C++ DLL through a second to load in C#

I'm trying to expose a function from a DLL (we'll call foo.dll) to use in C#. 我正在尝试从DLL(我们称为foo.dll)公开一个函数,以在C#中使用。 However, I don't have access to the source so I thought I might be able to write a second DLL (bar.dll) which includes the first, reimplements the functions by returning the results from foo.dll. 但是,我没有访问源的权限,因此我认为我可以写第二个 DLL(bar.dll),其中包括第一个DLL,并通过从foo.dll返回结果来重新实现功能。 I do have the .lib and .h files so I'm hoping I can write a little tool to walk through the headers and generate my 'wrapper' dlls (is that the right term?) 我确实有.lib和.h文件,所以我希望我可以编写一个小工具来浏览标题并生成我的“包装器” dll(这是正确的说法吗?)

I've set up a very simple test for this, implementing foo.dll myself. 我为此设置了一个非常简单的测试,自己实现了foo.dll。 I'm very new to C++ so please be gentle. 新的C ++所以请温柔。

foo.h foo.h

#pragma once

double Add(double a, double b);

foo.cpp foo.cpp

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

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

I build this and reference the .lib into my project for bar, along with copying in foo.h. 我将其构建,然后将.lib引用到我的bar项目中,并在foo.h中进行复制。

bar.h bar.h

#pragma once

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

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

bar.cpp bar.cpp

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

__declspec(dllexport) double Add(double a, double b)
{
    return foo::Add(a, b);
}

So far so simple. 到目前为止很简单。 I'm then trying to use DllImport to bring this into C# thusly: 然后,我尝试使用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();
        }
    }
}

However, when I run this I just get "PRE" output and the program just waits. 但是,当我运行此程序时,我只会得到“ PRE”输出,程序将等待。 I've troubleshooted through error messages up to this stage, but I'm not really sure how to work out what's happening in this situation. 到目前为止,我已经通过错误消息进行了故障排除,但是我不确定如何弄清楚这种情况下的情况。

If I reimplement bar.cpp to return a + b the C# application runs as expected, outputting: PRE 10.0 POST 如果我重新实现bar.cpp以返回a + b,则C#应用程序将按预期运行,输出:PRE 10.0 POST

I've had a read through a good many posts on the subject, some suggest adding __stdcall before the name when declaring my variable, but that gives me a StackOverflow error. 我已经阅读了许多有关该主题的文章,有人建议在声明变量时在名称前添加__stdcall,但这会给我一个StackOverflow错误。

It's my first SO post (though of course I've been lurking for years) so feel free to let me know if I can do anything to improve the question. 这是我的第一篇SO帖子(尽管我已经潜伏了很多年),所以请随时告诉我是否可以采取任何措施来改善问题。

Since you're creating bar.dll anyway , use C++/CLI to wrap foo.dll ; 既然你创建bar.dll 无论如何 ,使用C ++ / CLI包装foo.dll; if your P/Invokes become non-trivial (as is likely dealing with legacy C++ code), you'll be glad you went in this direction. 如果您的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);
      }
   }
}

Your C# code is now simply 您的C#代码现在很简单

    static void Main(string[] args)
    {
        Console.WriteLine("PRE");
        Console.WriteLine(BarAssembly.Bar.Add(1.5, 8.5));
        Console.WriteLine("POST");
        Console.ReadKey();
    }

No need for [DllImport] although you will have to add a reference to the bar.dll assembly. 尽管您必须添加对bar.dll程序集的引用,但不需要[DllImport]

It could be the calling convention, but newer versions of .NET are actually pretty good about throwing an exception for most CC violations. 这可能是调用约定,但是.NET的较新版本实际上对于抛出大多数CC违例而言非常好。 I'd recommend sticking some printf's in your C++ wrapper to see if you can figure out where it hangs. 我建议在您的C ++包装器中粘贴一些printf,以查看是否可以将其挂起。

Option B - there's actually a wrapper generator called SWIG which does exactly what you're doing for dozens of different languages. 选项B-实际上有一个名为SWIG的包装器生成器,它可以为您使用数十种不同语言所做的事情。 It works quite well. 效果很好。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM