2014-11-03 52 views
0

我有这样定义的结构:如何调用dll C++ func,它需要参数并返回C#中的struct?

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为什么会正确返回?

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

+0

似乎问题是从dll返回结构的C#。参数传递正常,但返回时,结构没有正确地从C++镜像到C#。 – toomyem 2014-11-05 09:02:58

回答

1

GetDelegateForFunctionPointer()假设__stdcall调用约定,但是你的函数有__cdecl(当你返回一些东西或者你传递了多个参数时,你会有意想不到的行为)。

更改本机API来:

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

装点您的委托指示框架使用权调用约定:

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

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

如果还clist_t.ptr那么一个函数指针穿上” t忘记装饰该代表了。

+0

感谢您的回答。但不幸的是,添加cdecl装饰并不能解决问题。返回的“列表”结构仍然不正确:( – toomyem 2014-11-03 12:36:57

+0

)同时检查你所调用的'GetFunc1'是否声明为'ArgsDelegate',但是你搜索'GetFunc1'(注意:代替'GetArgs1'),并且你转换了'ArgsStringDelegate '(其他功能反之亦然),它只是一个错字吗?因为它不应该编译。 – 2014-11-03 13:14:36

+0

是的,这是一个错字,我刚刚修复了这个问题 – toomyem 2014-11-03 13:22:15

相关问题