簡體   English   中英

C# 調用返回結構的 C++ DLL 函數

[英]C# Calling C++ DLL Function which returns a struct

我有一個 C++ dll,它定義了一個結構體和一個 dll 調用,如下所示:

typedef const char* FString;

typedef struct {
    FString version;
    FString build_no;
    FString build_type;
    FString build_date;
    FString build_info;
    FString comment;
} FVersionInfo;

extern "C" FAPI_EXPORT FVersionInfo CALLINGCONV fGetVersion(void);

在 C# 方面,我使用動態加載:

    [DllImport("kernel32.dll", EntryPoint = "LoadLibrary")]
    static extern int LoadLibrary(
        [MarshalAs(UnmanagedType.LPStr)] string lpLibFileName);

    [DllImport("kernel32.dll", EntryPoint = "GetProcAddress")]
    static extern IntPtr GetProcAddress(int hModule,
        [MarshalAs(UnmanagedType.LPStr)] string lpProcName);

    [DllImport("kernel32.dll", EntryPoint = "FreeLibrary")]
    static extern bool FreeLibrary(int hModule);

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
    public struct FVersionInfo
    {
        public string Version;
        public string Build_No;
        public string Build_Type;
        public string Build_Date;
        public string Build_Info;
        public string Comment;
    }

    [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Ansi)]
    public delegate FVersionInfo fGetVersion();

    public fGetVersion GetVersion;

    FHandle = LoadLibrary(@pName);
    IntPtr intPtr;
    intPtr = GetProcAddress(FHandle, "fGetVersion");
    GetVersion = (fGetVersion)Marshal.GetDelegateForFunctionPointer(intPtr, typeof(fGetVersion));

調用代碼應該是:

FVersionInfo version = new FVersionInfo();
version = GetVersion();

我的第一個問題是,我在 c# 加載部分調用 Marshal.GetDelegateForFunctionPointer 時變成了“System.Runtime.InteropServices.MarshalDirectiveException”。

然后我使用 IntPtr 作為結構返回參數進行了測試,如下所示:

[UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Ansi)]
public delegate IntPtr fGetVersion();

所以我讓 Marshal.GetDelegateForFunctionPointer 工作,但后來我在編組方面遇到了同樣的問題:

IntPtr DllValue = new IntPtr();
FVersionInfo version = new FVersionInfo();
DllValue = fGetVersion();
Marshal.PtrToStructure(DllValue, FVersionInfo);

在這里,它在 fGetVersion() 調用時崩潰,帶有“托管調試助手‘PInvokeStackImbalance’”。 我認為這意味着堆棧已損壞(不平衡)。

我已經用結構定義的許多變體進行了測試,但沒有結果。

歡迎任何想法或建議!

感謝您的指導,但我找到了一個可行的解決方案:

  1. 我將結構的聲明更改為
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] public struct FVersionInfo { public IntPtr Version; public IntPtr Build_No; public IntPtr Build_Type; public IntPtr Build_Date; public IntPtr Build_Info; public IntPtr Comment; }
  1. 所以我通過Marshal.GetDelegateForFunctionPointer沒有任何問題。

  2. 我將使用代碼更改為:

 GF.FVersionInfo vi = new GF.FVersionInfo(); vi = gf.GetVersion();
  1. 之后,我可以訪問字符串,例如

string MyVersion = Marshal.PtrToStringAnsi(VersionInfos.Version);

使用具有 const char * 成員的結構的示例。 在這種情況下,您可以使用自己的 C++ DLL 結構來回傳遞。

// CPP Source code
// ----------------------------------

// Struct definition
struct MyStruct_t {
    const char * sStr;
    size_t       iInt;
};
// ----------------------------------


// C# Source code
// ----------------------------------

// Struct definition
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]       
public struct MyStruct_t {
    public string sStr;
    public int    iInt;
};

// DLL prototype
[DllImport("Cpp.dll", CallingConvention = CallingConvention.StdCall)]
public static extern void MyFunctionCall(IntPtr MyStruct_t);

// Prepare a struct pointer to pass to DLL
MyStruct_t pMyStruct_t = new MyStruct_t();
IntPtr pMyStructPTR    = Marshal.AllocHGlobal(Marshal.SizeOf(pMyStruct_t));
Marshal.StructureToPtr(pMyStruct_t, pMyStructPTR, false);

// Call C++ DLL
MyFunctionCall(pMyStructPTR);

// The DLL updated struct, get the struct
MyStruct_t pMyStruct = (MyStruct_t)Marshal.PtrToStructure(pMyStructPTR, typeof(MyStruct_t));

// Show data
MessageBox.Show(pMyStruct.sStr);

// clean up
if (pMyStructPTR != IntPtr.Zero) { Marshal.FreeHGlobal(pMyStructPTR); pMyStructPTR = IntPtr.Zero; }
// ----------------------------------

暫無
暫無

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

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