C#调用返回结构体的C++ DLL函数

3

我有一个定义了结构体和dll调用的C ++ 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’”导致程序崩溃。我认为这意味着堆栈已被破坏(不平衡)。

我已经尝试了许多结构定义的变体,但没有结果。

欢迎任何想法或建议!

2个回答

1
感谢您的指引,但我找到了一个可行的解决方案:
  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();
4. 然后,我可以通过以下方式访问字符串,例如:

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


1

一个使用具有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; }
// ----------------------------------

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接