2012-05-31 55 views
5

我最近一直在使用C#到C++ interop,尤其是設置一個從C++ DLL調用的回調函數。C#C++ Interop回調

namespace TomCSharpDLLImport 
{ 
    class Program 
    { 
     public delegate void TomDelegate(int a, int b); 

     [DllImport("TomDllNative.dll", CallingConvention = CallingConvention.Cdecl)] 
     public static extern void GetData(); 

     [DllImport("TomDllNative.dll", CallingConvention = CallingConvention.Cdecl)] 
     public static extern void SetCallback(TomDelegate aCallback); 

     static void Main(string[] args) 
     { 
      TomDelegate lTD = new TomDelegate(Program.TomCallback); 

      SetCallback(lTD); //Sets up the callback 

      int thread = Thread.CurrentThread.ManagedThreadId; 

      GetData(); //This calls the callback in unmanaged code 

      while (true) ; 
     } 

     //Callback function which is called from the unmanaged code 
     public static void TomCallback(int a, int b) 
     { 
      Console.WriteLine("A: {0} B: {1}", a, b); 
      int thread = Thread.CurrentThread.ManagedThreadId; 
     } 
    } 
} 

我的問題是,當程序控制進入了TomCallback功能,我期待它然後打在主要的,而(真)循環。然而,該程序只是退出。我不能完全理解這種行爲,我認爲這是預期的一部分,但我的一部分人會認爲它會繼續下去。

我期待......

  1. 的的GetData()函數被調用
  2. 該功能的GetData調用回調
  3. 回調函數返回到的GetData
  4. 的GetData返回到main()

但是,這不是很正確。

有人會友好地解釋發生了什麼。

爲了節省空間,我還沒有張貼的非託管代碼,但如果需要的話我很高興地張貼

編輯: 我打開非託管調試(完全忘了要做到這一點)現在我看到了崩潰..

運行時檢查失敗#0 - ESP的值未正確保存在函數調用中。這通常是調用一個調用約定的函數聲明的結果,其中函數指針聲明的調用約定不同。

原生代碼,這是在撞車

#include "stdafx.h" 
typedef void (*callback_function)(int, int); 

extern "C" __declspec(dllexport) void SetCallback(callback_function aCallback); 
extern "C" __declspec(dllexport) void GetData(); 

callback_function gCBF; 

__declspec(dllexport) void SetCallback(callback_function aCallback) 
{ 
    gCBF = aCallback; 
} 

__declspec(dllexport) void GetData() 
{ 
    gCBF(1, 2); 
} 

回答

11

您必須使用

IntPtr Marshal.GetFunctionPointerForDelegate(Delegate d) 

方法託管回調轉換爲本地函數指針(IntPtr的在C#)。

您將SetCallback()與System.Delegate作爲參數的用法是錯誤的。

讓它

SetCallback(Marshal.GetFunctionPointerForDelegate(lTD)); 

,並再次聲明SetCallback作爲

/// StdCall is crucial here 
[DllImport("TomDllNative.dll", CallingConvention = CallingConvention.StdCall)] 
public static extern void SetCallback(IntPtr aCallback); 
+0

嗨維克多,感謝您的答覆。我按照您的建議進行了更改,但它仍然表現出完全相同的行爲。 – TomP89

+0

程序「退出」 - 這意味着崩潰。你會如此善良,以顯示崩潰轉儲?這可以在「應用程序錯誤」列表中的「事件查看器」工具中完成。或者只是複製你的程序的控制檯輸出。 –

+0

謝謝Viktor,我已更新問題 – TomP89