2012-08-09 62 views
3

我在C++文件中編譯了該代碼,並將其編譯爲dll。如何在運行時在C#應用程序中加載Dll(C++)

#include "stdafx.h" 

#include "WHUU.h" 

#include "stdafx.h" 

typedef int (__stdcall * Callback)(const int text); 

static int x , y= 0; 

Callback Handler = 0; 

int getX() 
{ 
    return x; 
} 

void setX(int i) 
{ 
    x = i; 
} 

void setY(int i) 
{ 
    y = i; 
} 
int getY() 
{ 
    return y; 
} 
extern "C" __declspec(dllexport) 
void __stdcall SetCallback(Callback handler) { 
    Handler = handler; 
} 


extern "C" __declspec(dllexport) 
void __stdcall addX(int x) { 
    setX(x); 
} 

extern "C" __declspec(dllexport) 
void __stdcall addY(int y) { 
    setY(y); 


} 


extern "C" __declspec(dllexport) 
void __stdcall TestCallback() { 
    int z = getX() + getY(); 
    int retval = Handler(z); 
} 

我的c#應用程序現在必須在運行時加載此dll。添加到回調並調用函數。我不想使用一個類。我可以加載類和

Type[] types = moduleAssembly.GetTypes(); 

但這個矯枉過正!另外C++不受管理。

我的意思是它很小! (是的,這只是一個例子,但「真實」和這個例子一樣大)。

我該怎麼做?

謝謝你的幫助!

地址:

  • 我不喜歡的框架(如PInvoke的/組裝)

  • 函數名稱/類型是固定的,不會改變(認爲driver.dll讀寫的)

  • 這個DLL是由客戶編寫的,所以它應該儘可能的簡單!

+0

http://www.pinvoke.net/ – deltree 2012-08-09 12:18:18

+0

要求是相當荒謬的。沒有人要求最艱難的方式來做到這一點。你真的*想要利用pinvoke。要求客戶編寫這段代碼的COM版本,這樣你就不必再努力工作了,可能會變得很糟糕。 – 2012-08-09 12:43:24

回答

0

我使用了P/Invoke,發佈了我自己的原因,回調未被其他人包括在內。但他們是很好的答案! C#應用程序使用這個GUI

的代碼應用程序是這樣的:(介意它是一個原型回答技術問題)

 public partial class Form1 : Form 
     { 

     private delegate int Callback(int text); 
     private Callback mInstance; // Ensure it doesn't get garbage collected 

     [DllImport(@"C:\Visual Studio 2010\Projects\kalkulatorius\Debug\WHUU1.dll")] 
     private static extern void SetCallback(Callback fn); 
     [DllImport(@"C:\Visual Studio 2010\Projects\kalkulatorius\Debug\WHUU1.dll")] 
     private static extern void addX(int x); 
     [DllImport(@"C:\Visual Studio 2010\Projects\kalkulatorius\Debug\WHUU1.dll")] 
     private static extern void addY(int y); 
     [DllImport(@"C:\\Visual Studio 2010\Projects\kalkulatorius\Debug\WHUU1.dll")] 

     private static extern void TestCallback(); 

     private int Handler(int text) 
     { 
      textBox3.Text = text.ToString(); 
      return 42;      
     } 


     private void button1_Click(object sender, System.EventArgs e) 
     { 
      mInstance = new Callback(Handler); // to set the callback in lib 
      SetCallback(mInstance);   // could also be withhin constructor! 

      addX(int.Parse(textBox1.Text)); // other people in this thread posted this correct answer 
      addY(int.Parse(textBox2.Text)); 
      TestCallback(); 
     } 

     public Form1() 
     { 
      InitializeComponent(); 
     } 

所以,如果你想使用C++的lib與功能和回調(如你問題發佈)你可以使用這個。

但如何更改lib?

  • lib的路徑是硬編碼的(參見[dllImport ......])。但你 可以swop文件系統中的庫。這可能會發生後,你建立這個 應用程序。
  • 如果lib不在給定路徑上,則拋出異常。因此,如果你的程序想要使用這個庫,首先檢查該文件系統是否存在lib。因此,要切換功能(swop驅動程序庫),請將不同的庫與
    同名複製到給定路徑中。 (複製粘貼 - 也許更改名稱)

此解決方案的開銷最小,並且如果在應用程序構建後永遠不會更改dll的界面,那麼這個解決方案很好!

0

這樣做的一種方法是通過API。從上面的示例中查找下​​面的setX和getX方法的示例。

[DllImport("kernel32.dll", CallingConvention = CallingConvention.StdCall)] 
    internal static extern IntPtr LoadLibraryEx(string libraryPath, IntPtr fileHandle, int actionFlag); 

    [DllImport("kernel32.dll", CallingConvention = CallingConvention.StdCall)] 
    internal static extern bool FreeLibrary(IntPtr libraryHandle); 

    [DllImport("kernel32.dll", CallingConvention = CallingConvention.StdCall)] 
    internal static extern IntPtr GetProcAddress(IntPtr dllPointer, string functionName); 

    IntPtr ptr = IntPtr.Zero; 
    private delegate void setX (int i); 
    private delegate int getX(); 

    private setX setXDel; 
    private getX getXDel; 

    public Constructor() 
    { 
     loadLib(); 
    } 

    public void YourMethod() 
    { 
     setXDel(100); 
     int y = getXDel(); 
     Console.WriteLine(y.ToString()); 
    } 

    private void loadLib() 
    { 
     string path = "your dll path"; 
     ptr = LoadLibraryEx(path, IntPtr.Zero, 0); 

     if (ptr == IntPtr.Zero) 
      throw new Exception("Cannot load dll."); 

     IntPtr addressPtr = GetProcAddress(ptr, "setX"); 
     setXDel = (setX)Marshal.GetDelegateForFunctionPointer(addressPtr, typeof(setX)); 

     addressPtr = GetProcAddress(unrarPtr, "getX"); 
     getXDel = (getX)Marshal.GetDelegateForFunctionPointer(addressPtr, typeof(getX)); 

    } 

    public void Dispose() 
    { 
     if (ptr != IntPtr.Zero) 
     { 
      FreeLibrary(ptr); 
     } 
    } 
+2

您正在使用P/Invoke來提供您自己的與P/Invoke類似的實現。只需使用P/Invoke即可。 – 2012-08-09 12:44:42

1

你也可以做過來的P/Invoke,作爲例子:

[DllImport("unmanaged.dll", CharSet = CharSet.Ansi)] 
private extern static int yourFunction(int var1, int var2); 
1

我不喜歡的框架(如PInvoke的/組裝)

我會建議P /無論如何調用。我不認爲有任何合理的選擇。也許在託管的C++中編寫託管包裝,但是真的嗎?

當您使用P/Invoke時,.NET運行時將動態加載您指定的DLL(並在您首次調用該函數時完成此操作)。沒有理由先使用P/Invoke調用LoadLibrary

+0

這個問題是因爲一個激烈的討論,你可以調用沒有任何框架的.net lib函數發佈。 – Thomas 2012-08-10 07:38:16

1

您可以使用P/Invoke直接調用dll,也可以爲它創建一個C++/CLI包裝器。

這裏是你如何使用P/Invoke做到這一點:
將編譯後的dll添加到C#項目中,將其「複製到輸出目錄」屬性設置爲「始終複製」。並且這樣稱呼它:

class Program 
{ 
    [DllImport("cppdll.dll")] 
    private static extern void addX(int x); 

    [DllImport("cppdll.dll")] 
    private static extern void addY(int y); 

    static void Main(string[] args) 
    { 
     addX(5); 
     addY(7); 
    } 
} 
相關問題