簡體   English   中英

按值為 C++ 結構 PInvoke 類

[英]PInvoke Class by value for c++ struct

我有一個關於 P/Invoke 的小問題。 目前,我正在為原始 C# 實現糟糕的硬件設備實現 C API 的包裝器。 我遇到的問題/不便如下:

API 實現了多個用於獲取/設置設備設置的結構。 它們具有相似的結構,因此我給出了一個示例實現:

typedef struct _Struct1
{
    bool b1;
    unsigned int ui1;
    unsigned int ui2;
    unsigned int ui3;
    unsigned int ui4;
    unsigned int ui5;
} Struct1;

getter 和 setter 實現如下:

unsigned int SetSetting(bool b1, Struct1 s1);
unsigned int GetSetting(bool b1, Struct1 &s1);

C# DllImport 是:

[DllImport("api.dll", EntryPoint = "GetSetting", CallingConvention = CallingConvention.StdCall]
public static extern uint GetStatus(bool b1, CStruct1 s1);

[DllImport("api.dll", EntryPoint = "SetSetting", CallingConvention = CallingConvention.StdCall]
public static extern uint SetStatus(bool b1, SStruct1 s1);

C# 結構體實現是使用 LayoutKind.Sequential 完成的,並准確地表示 C 結構體,並且 P/Invoke 調用工作得很好,除了: 正如您可能注意到的,getter 和 setter DllImports 略有不同,因為 setter 使用 C# 結構(SStruct1 ) 和 getter 一個 C# 類 (CStruct1):

[StructLayout(LayoutKind.Sequential)]
public struct SStruct1
{
    public bool b1;
    public uint ui1;
    public uint ui2;
    public uint ui3;
    public uint ui4;
    public uint ui5;
}

[StructLayout(LayoutKind.Sequential)]
public class CStruct1 { /* same as struct */ }

我無法僅使用一個類或結構來使 P/Invoke 工作。

對於這個問題的更方便的解決方案,您有什么建議嗎?

將結構更改為類(反之亦然)確實會產生 PInvokeStackImbalance 異常。

我猜這與 setter 期望一個 struct by value 和 getter by reference 的事實有關,因為它是 out-parameter-equivalent。 我已經嘗試過任何我能想到的 Marshal 屬性和參數定義,但我遇到了死胡同。 谷歌似乎沒有幫助。

非常感謝任何幫助。

編輯

我弄錯了:API 是 ANSI C,而不是 C++。

更新

我已經嘗試了建議的解決方案(用於 setter 的 SStruct,用於 getter 的 SStruct),盡管對於具有完全由 uint 組成的結構的函數工作正常,但它為所討論的結構產生了完整的垃圾:

| Name | correct value   | returned value |
| ---- | --------------- | -------------- |
| b1   | False           | True           |
| ui1  | 0               | 3355443223     |
| ui2  | 0               | 1677721600     |
| ui3  | 0               | 0              |
| ui4  | 0               | 0              |
| ui5  | 0               | 0              |

請記住:使用上述 DllImports 時,這工作得很好。

  1. 檢查 C# 項目的構建設置 x86 或 x64。
  2. 驗證調用約定。 我認為在 VC++ 中默認是cdecl ,嘗試在 DllImport 中指定它。

基於@HansPassant 的評論,您希望將out SStruct用於 getter 方法。 此外,您需要確保 dotnet 結構和編譯后的 api.dll 結構中 bool 的大小相同(結構打包可能是 1 個字節,但不太可能在這里看到 :)。

此外,您使用CallingConvention=StdCall 使用錯誤調用約定的症狀是堆棧不平衡異常。 如果您不知道,您想嘗試使用CallingConvention.Cdecl

大多數情況下,在打開 dll 時,如果符號沒有以@<some int>結尾,則約定是Cdecl ,但不能保證。

暫無
暫無

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

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