![](/img/trans.png)
[英]How do I call a function defined in a C++ DLL that has a parameter of type int *, from inside C# code?
[英]How do I call a function in a C++ Dll from C# that has void* callback and object parameter
我正在嘗試創建一個C dll的包裝器,我試圖調用一個具有回調函數的函數,接收一個對象作為傳回的指針。
.h文件delares
extern int SetErrorHandler(void (*handler) (int, const char*, void*),
void *data_ptr);
處理程序是一個回調函數,在發生錯誤時調用,data_ptr是傳遞給你的任何對象(狀態),對於我的應用程序就是這個(當前對象)。
我能夠在一個dll中調用函數,它使用編組的常量類型,如簡單類型字符串,整數等。但我無法弄清楚如何編寫一個指向C#對象的指針作為狀態。
為了通過在這里搜索我已經找到的對象引用傳遞對象引用,否則似乎我需要一個結構類型來能夠編組該函數,所以我創建了一個結構來保存我的對象:
[StructLayout(LayoutKind.Sequential)]
struct MyObjectState
{
public object state;
}
編輯:我試圖在public object state
屬性上放置一個屬性: [MarshalAs(UnmanagedType.Struct, SizeConst = 4)]
,但這會產生相同的錯誤,所以我刪除了它,似乎它無論如何都不會起作用。
該struct包含一個對象屬性,用於保存回調函數的任何對象。
我在C#中聲明了委托如下:
delegate void ErrorHandler(int errorCode, IntPtr name, IntPtr data);
然后我在C#中聲明了導入函數,如下所示:
[DllImport("somedll.dll", CallingConvention = CallingConvention.Cdecl)]
static extern int SetErrorHandler handler, IntPtr data);
然后我在我的C#代碼中創建了一個回調函數:
void MyErrorHandler(int errorCode, IntPtr name, IntPtr data)
{
var strName = Marshal.PtrToStringAnsi(name);
var state = new MyObjectState();
Marshal.PtrToStructure(data, state);
Console.WriteLine(strName);
}
我可以調用庫函數如下:
var state = new MyObjectState()
{
state = this
};
IntPtr pStruct = Marshal.AllocHGlobal(Marshal.SizeOf(state));
Marshal.StructureToPtr(state, pStruct, true);
int ret = SetErrorHandler(MyErrorHandler, pStruct);
調用工作和回調函數被調用,但我無法訪問回調函數中的數據,當我嘗試Marshal.PtrToStructure
我收到一個錯誤:
結構不能是值類。
我在這里做了很多搜索,在Marshall上發現了各種各樣的東西,但是沒有任何東西可以幫助我實現這一目標
謝謝。
你使它變得比它需要的更復雜。 您的C#客戶端不需要使用data_ptr
參數,因為C#委托已經具有用於維護this
指針的內置機制。
因此,您只需將IntPtr.Zero
傳遞給委托即可。 在您的錯誤處理程序委托中,您只需忽略data_ptr
的值,因為this
將是可用的。
如果你不遵循這個描述,這里有一個簡短的程序來說明我的意思。 請注意MyErrorHandler
是一個充當錯誤處理程序的實例方法,並且可以修改實例數據。
class Wrapper
{
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate void ErrorHandler(int errorCode, string name, IntPtr data);
[DllImport("somedll.dll", CallingConvention = CallingConvention.Cdecl)]
static extern int SetErrorHandler(ErrorHandler handler, IntPtr data);
void MyErrorHandler(int errorCode, string name, IntPtr data)
{
lastError = errorCode;
lastErrorName = name;
}
public Wrapper()
{
SetErrorHandler(MyErrorHandler, IntPtr.Zero);
}
public int lastError { get; set; }
public string lastErrorName { get; set; }
}
class Program
{
static void Main(string[] args)
{
Wrapper wrapper = new Wrapper();
}
}
很可能有辦法做到這一點,但我很久以前就放棄了。 我提出的解決方案略顯苛刻,但它非常有效並適用於我拋出的所有內容:
C# - >托管C ++ - >本機調用
這樣做你最終在托管C ++中編寫一個小包裝器,這是一種痛苦,但我發現它比所有編組代碼更有能力,更少痛苦。
老實說雖然我有點希望有人給出一個不回避的答案,但我已經在這方面掙扎了很長一段時間。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.