[英]Passing a struct pointer in C# interop results in NULL
我正在構建一個用於非托管環境的托管 DLL(C/C++ 應用程序 - FreeRDP)。 互操作在大多數情況下都可以正常工作,但在一個特定情況下,我無法將指針傳遞給 struct。 在 API 中,我有一個結構:
typedef struct _IWTSListenerCallback IWTSListenerCallback;
struct _IWTSListenerCallback
{
UINT(*OnNewChannelConnection)(IWTSListenerCallback* pListenerCallback,
IWTSVirtualChannel* pChannel,
BYTE* Data,
BOOL* pbAccept,
IWTSVirtualChannelCallback** ppCallback);
};
以及我正在調用的函數:
UINT(*CreateListener)(IWTSVirtualChannelManager* pChannelMgr,
const char* pszChannelName,
ULONG ulFlags,
IWTSListenerCallback* pListenerCallback);
兩者都轉換為 C#:
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate uint ListenerCallbackNewConnectionDelegate(IntPtr listenerCallback, IntPtr channel, [MarshalAs(UnmanagedType.LPArray)] byte[] data, IntPtr accept, ref IntPtr channelCallback);
[StructLayout(LayoutKind.Sequential)]
public struct IWTSListenerCallback
{
[MarshalAs(UnmanagedType.FunctionPtr)]
public ListenerCallbackNewConnectionDelegate OnNewChannelConnection;
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate uint ChannelManagerCreateListenerDelegate(IntPtr channelManager, [MarshalAs(UnmanagedType.LPStr)] string channelName, ulong flags, IntPtr listenerCallback);
[MarshalAs(UnmanagedType.FunctionPtr)]
public ChannelManagerCreateListenerDelegate CreateListener;
和執行代碼:
var callback = new IWTSListenerCallback();
callback.OnNewChannelConnection = NewChannelConnection;
var pCallback = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(IWTSListenerCallback)));
Marshal.StructureToPtr(callback, pCallback, false);
var ret = channelManager.CreateListener(pChannelManager, "TestChannel", 0, pCallback);
雖然 pChannelManager(這是我從調用我的 DLL 的非托管代碼中獲得的指針)並且字符串被發送沒有任何問題,但我在此處創建的指針 (pCallback) 在 C# 中成功分配,但它導致非托管代碼中的 NULL .
我認為問題在於我如何定義結構,或者我如何定義函數(盡管在非托管代碼中成功調用了該函數)。 我使用該方法以與 DLL 的另一部分完全相同的方式創建指針,當傳遞給非托管函數時,它在那里工作得非常好。
編輯:@jdweng 建議:
[StructLayout(LayoutKind.Sequential)]
public struct TestCall
{
public IntPtr channelManager;
[MarshalAs(UnmanagedType.LPStr)]
public string channelName;
public ulong flags;
public IntPtr listenerCallback;
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate uint ChannelManagerCreateListenerDelegate(IntPtr testStructure);
var test = new TestCall();
test.channelManager = pChannelManager;
test.channelName = "TestChannel";
test.flags = 0;
test.listenerCallback = pCallback;
var pTest = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(FreeRDPTypes.TestCall)));
Marshal.StructureToPtr(test, pTest, false);
var ret = channelManager.CreateListener(pTest);
沒用。
EDIT2:解決方法! 僅當您有權訪問原始非托管代碼時。 我重新排列了函數參數,因此首先是結構指針,如下所示:
UINT(*CreateListener)(IWTSVirtualChannelManager* pChannelMgr,
IWTSListenerCallback* pListenerCallback,
const char* pszChannelName,
ULONG ulFlags);
它有效! 可能是偏移量的問題。
這是一個抵消問題。 C/C++ ULONG
是typedef unsigned long
,我錯誤地認為它對應於 C# ulong
,但實際上第一個在 Visual 中是 4 個字節,而另一個是 8 個字節,這導致了 4 個字節的偏移。 通過將ulong
更改為uint
並添加[MarshalAs(UnmanagedType.U4)]
以進行良好測量來修復。 我在 C# 中調用的函數的最終外觀:
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate uint ChannelManagerCreateListenerDelegate(IntPtr channelManager, [MarshalAs(UnmanagedType.LPStr)] string channelName, [MarshalAs(UnmanagedType.U4)] uint flags, IntPtr listenerCallback);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.