簡體   English   中英

在 C# 互操作中傳遞結構指針導致 NULL

[英]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++ ULONGtypedef 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM