[英]C# C++ Interop callback
我最近一直在修補C#到C ++的互操作,特別是設置一個從C ++ DLL調用的回調函數。
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函數時,我期待它然后在Main中點擊while(true)循環。 然而,程序只是退出。 我不能完全理解這種行為,我想象這是預期的,但我的一部分會期望它繼續在主要方面。
我所期待的......
然而,這不太對。
有人會善意地解釋會發生什么。
為了節省空間,我沒有發布非托管代碼,但如果需要,我很樂意發布
編輯:我打開非托管調試(完全忘了這樣做),現在我看到了崩潰..
運行時檢查失敗#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);
}
您必須使用以下命令將托管回調轉換為本機函數指針(C#中的IntPtr)
IntPtr Marshal.GetFunctionPointerForDelegate(Delegate d)
方法。
您使用System.Delegate作為參數的SetCallback()是錯誤的。
做了
SetCallback(Marshal.GetFunctionPointerForDelegate(lTD));
並重新聲明SetCallback為
/// StdCall is crucial here
[DllImport("TomDllNative.dll", CallingConvention = CallingConvention.StdCall)]
public static extern void SetCallback(IntPtr aCallback);
我遇到了與OP完全相同的問題(相同的錯誤消息)。 接受的答案根本沒有幫助,甚至@ TomP89也在評論中承認。
這並不奇怪,因為錯誤消息表明傳遞的回調函數的調用約定是錯誤的,而假設的解決方案更改了傳遞回調的函數的調用約定,如果庫導出的是cdecl,則會導致堆棧不平衡-functions(這是Win32 API之外的所有函數的默認情況)。
事實證明,.Net默認采用任何委托的調用約定“stdcall”。 通常,非托管代碼將采用與其導出函數相同的調用約定(在本例中為mine:“cdecl”)。
所以真正的解決方案(最終對我有用)是將回調的調用約定改為“cdecl”。 這個問題說明了這是如何實現的,簡而言之:
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void TomDelegate(int a, int b);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.