C# Calling C++ DLL Function which returns a struct

蹲街弑〆低调 提交于 2019-12-21 22:42:31

问题


I have an C++ dll which defines a struct and an dll call like this:

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);

On the c# side i using an dynamic loading:

    [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));

The calling code should be:

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

My first problem is, that i become an "System.Runtime.InteropServices.MarshalDirectiveException" on the call of Marshal.GetDelegateForFunctionPointer in the c# loading part.

I have then tested using IntPtr as struct return parameter like that:

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

So i got the Marshal.GetDelegateForFunctionPointer to work, but later i've got the same problems with marshaling:

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

Here it crashes at the fGetVersion() call with "Managed Debugging Assistant 'PInvokeStackImbalance'". I think it means, that the stack is corrupted (imbalanced).

I have tested with many variants of the structure definition, but no result.

Any ideas or suggestions would be welcome!


回答1:


Thanks for the direction, but i found an working solution:

  1. I changed the declaration of the struct to
[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. So i passed the Marshal.GetDelegateForFunctionPointer without any problems.

  2. I changed my using code to:

GF.FVersionInfo vi = new GF.FVersionInfo();
vi = gf.GetVersion();
  1. After that, i could access the strings for example with

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



来源:https://stackoverflow.com/questions/17020464/c-sharp-calling-c-dll-function-which-returns-a-struct

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!