【问题标题】:C# Calling C++ DLL Function which returns a structC#调用返回结构的C++ DLL函数
【发布时间】:2013-06-10 09:14:34
【问题描述】:

我有一个 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#端i使用动态加载:

    [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'”。我认为这意味着堆栈已损坏(不平衡)。

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

欢迎任何想法或建议!

【问题讨论】:

    标签: c# c++ dll call


    【解决方案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();
    
    1. 之后,我可以访问字符串,例如使用

    字符串 MyVersion = Marshal.PtrToStringAnsi(VersionInfos.Version);

    【讨论】:

      【解决方案2】:

      使用带有 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; }
      // ----------------------------------
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-02-10
        • 2015-02-14
        • 1970-01-01
        • 1970-01-01
        • 2018-11-07
        • 2016-08-03
        相关资源
        最近更新 更多