2017-03-23 72 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? –