簡體   English   中英

C#將指向struct(包含非blittable類型)的指針傳遞給非托管C ++ DLL

[英]C# pass pointer to struct (containing non-blittable types) to unmanaged C++ DLL

我嘗試在我的C#代碼中使用C ++ DLL。
必須將讀取的所有數據作為指向結構的指針傳遞給dll。 我的第一個想法是只保留一些非托管內存,將指針傳遞給函數並隨后提取數據。 問題是函數只會返回一個錯誤代碼,轉換為“參數無效”。

從DLL標題(結果和BusPortId縮短)

typedef enum {
    BUS_COM1 = 0x01,  // 2 to 15 ommited
    BUS_COM16 = 0x10,
    BUS_USB1 = 0x101,  // 2 to 15 ommited
    BUS_USB16 = 0x110
} BusPortId;

typedef enum {
    BUS_SUCCESS    = 0,     //!< The operation was completed successfully
    BUS_ERROR      = 0x100,  //!< An error occured
    BUS_INVALIDARG = 0x1000, //!< An argument is not valid
} Result


struct BusPortInfo
{
    ULONG       portInfoSize;
    CHAR        portText[64];
    BOOL        portLocked;
    BusPortId   portId;
};

Result BUSDRV_API busGetAvailablePortCount( ULONG *retCount );

Result BUSDRV_API busGetAvailablePort( ULONG index, BusPortInfo *portInfo );

到目前為止我的C#程序的相關部分

enum BusPortId
{
    BUS_COM1 = 0x01,  // 2 to 15 ommited
    BUS_COM16 = 0x10,
    BUS_USB1 = 0x101,  // 2 to 15 ommited
    BUS_USB16 = 0x110
};

public enum Result
{
    BUS_SUCCESS = 0,       //!< The operation was completed successfully
    BUS_ERROR = 0x100,  //!< An error occured
    BUS_INVALIDARG = 0x1000, //!< An argument is not valid
};

struct BusPortInfo
{
    public ULONG portInfoSize;
    unsafe public fixed char portText[64];
    public BOOL portLocked;
    public BusPortId portId;
}

[DllImport(DLL_Path)]
unsafe static extern Result busGetAvailablePortCount(ULONG* retCount);
[DllImport(DLL_Path)]
unsafe static extern Result busGetAvailablePort(ULONG index, BusPortInfo* portInfo);

ulong count= 0;
Result res = busGetAvailablePortCount(&count);

ulong index = 0;
BusPortInfo info = new BusPortInfo();
Result res = busGetAvailablePort(0, &info);

對busGetAvailablePortCount(和其他類似函數)的調用沒有任何問題。 但是當我調用busGetAvailablePort時,我在控制台輸出中得到以下內容

Cannot marshal 'parameter #2': Pointers cannot reference marshaled structures. Use ByRef instead.

問題是我可以在C#中更改我的結構,以便我可以傳遞指針,但是DLL中的函數也會返回“參數無效”

我該怎么做我的結構,所以我可以將指針傳遞給一個函數,同時仍然被DLL接受?

PS抱歉英語不好,我不是母語人士。

這些聲明存在很多問題,當程序員不斷破解代碼以試圖使pinvoke調用工作時,往往會發生這些問題。 該結構最可能的正確聲明是:

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
    struct BusPortInfo {
        public int portInfoSize;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
        public string portText;
        public bool portLocked;
        public BusPortId portId;
    }

強調本機代碼中的ULONG是32位類型並且僅fixed不是必需的並且非常笨拙。 由於bool和string成員,這個結構不是blittable,沒什么可擔心的。

[DllImport]聲明需要正確聲明第二個參數。 CallingConvention屬性總是很重要,我們無法看到BUSDRV_API的含義。 划船:

    [DllImport(DLL_Path, CallingConvention = CallingConvention.StdCall)]
    static extern Result busGetAvailablePortCount(out int retCount );

    [DllImport(DLL_Path, CallingConvention = CallingConvention.StdCall)]
    static extern Result busGetAvailablePort(int index, 
                            [In, Out] ref BusPortInfo portInfo);

電話看起來不正確。 當struct具有“size”成員時,api契約通常要求在調用之前設置它。 這是一種安全措施,它確保當調用者使用錯誤的結構聲明時,api不會破壞內存。 如果設置錯誤,“無效參數”錯誤是預期結果。 所以寫它類似於:

int count;
Result res = busGetAvailablePortCount(out count);
if (res != Result.BUS_SUCCESS) throw new Exception("Api failure " + res.ToString());

for (int ix = 0; ix < count; ++ix) {
    BusPortInfo info;
    info.portInfoSize = Marshal.SizeOf(typeof(BusPortInfo));   // Important!
    res = busGetAvailablePort(ix, ref info);
    if (res != Result.BUS_SUCCESS) throw new Exception("Api failure " + res.ToString());
    // etc...
}

當然沒有經過測試,應該在球場。 如果仍有問題,請驗證本機代碼中的sizeof(BusPortInfo)是否與C#中的Marshal.SizeOf(typeof(BusPortInfo))的值匹配。 如果全部失敗則使用C ++ / CLI,這樣您就可以直接使用本機聲明。 並與DLL的所有者討論正確的使用說明,最好是他會為你編寫一個pinvoke樣本。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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