我有一个像这样定义的结构:
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"
。
答案 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
也是函数指针,那么也不要忘记装饰该委托。
子>