如何调用带有参数的dll C ++ func并在C#中返回struct?

时间:2014-11-03 11:21:40

标签: c# dll struct interop

我有一个像这样定义的结构:

typedef struct
{
  int number;
  void *ptr;
}clist_t;

和dll中的两个函数:

DLL_API clist_t GetArgs1(const wchar_t* const name)
{
  static clist_t arg;
  arg.number = 1;
  arg.ptr = sth(name);
  return arg;
}

DLL_API clist_t GetArgs2()
{
  static clist_t arg;
  arg.number = 1;
  arg.ptr = sth2();
  return arg;
}

接下来我在C#中有一个包装器,用dll名称初始化:

public class DllWrapper
{
  private int m_dllHndl;

  [UnmanagedFunctionPointer(CallingConvention.Cdecl)] // <-- added as suggested in comment
  private delegate ArgsList ArgsDelegate();
  [UnmanagedFunctionPointer(CallingConvention.Cdecl)] // <-- added as suggested in comment
  private delegate ArgsList ArgsStringDelegate([MarshalAs(UnmanagedType.LPWStr)] string name);

  private ArgsStringDelegate GetFunc1 = null;
  private ArgsDelegate GetFunc2 = null;

  public DllWrapper(string dllPathName)
  {
    m_dllHndl = Win32APIWrapper.LoadLibrary(dllPathName);

    if(m_dllHndl == 0)
    {
      throw new Exception("Could not load the library: " + dllPathName);
    }

    GetFunc1 = (ArgsStringDelegate)findFunc("GetArgs1", typeof(ArgsStringDelegate));
    GetFunc2 = (ArgsDelegate)findFunc("GetArgs2", typeof(ArgsDelegate));
  }

  private Delegate findFunc(string name, Type t)
  {
    int func = Win32APIWrapper.GetProcAddress(m_dllHndl, name);
    if (func == 0)
    {
       throw new Exception("Function not found in the library: " + name);
    }
    return Marshal.GetDelegateForFunctionPointer((IntPtr)func, t);
  }

  public ArgsList Get1(string name)
  {
    ArgsList list = GetFunc1(name);
    return list; // <-- here list is corrupted
  }

  public ArgsList Get2()
  {
    ArgsList list = GetFunc2();
    return list; // <-- here list is correct
  }
}

ArgsList定义如下:

[StructLayout(LayoutKind.Sequential)]
public struct ArgsList
{
    public int number;
    public IntPtr ptr;
};

当我调用Get2()然后结果是正确的时,list.number为1并且指针可以被解组。但是在Get1()之后返回的结构就像:list.number = 0,list.ptr = 48,这显然是错误的。

这两种方法只有在Get2缺乏参数时才有所不同。我在调试器中检查了字符串参数是否正确传递给dll。然后struct clist_t在dll中正确填充,但是在返回时,当控件从dll传递回C#时,返回的struct会以某种方式被破坏。

你可以给我一些暗示出了什么问题吗? 为什么只有在没有参数的情况下才能正确返回struct?

编辑:我在dll中声明函数时使用extern "C"

1 个答案:

答案 0 :(得分:1)

GetDelegateForFunctionPointer()假设__stdcall调用约定,但您的函数有__cdecl(当您返回某些内容或传递多个参数时,您将遇到意外行为)。

将原生API更改为:

DLL_API clist_t __stdcall GetArgs1(const wchar_t* const name);
DLL_API clist_t __stdcall GetArgs2();

OR 装饰你的委托以指示框架使用正确的调用约定:

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate ArgsList ArgsDelegate();

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate ArgsList ArgsStringDelegate(
    [MarshalAs(UnmanagedType.LPWStr)] string name);

<子> 如果clist_t.ptr也是函数指针,那么也不要忘记装饰该委托。