Reputation: 139
I have a struct defined like this:
typedef struct
{
int number;
void *ptr;
}clist_t;
and a two functions in 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;
}
Next I have a wrapper in C# which is initialized with dll name:
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 is defined as follows:
[StructLayout(LayoutKind.Sequential)]
public struct ArgsList
{
public int number;
public IntPtr ptr;
};
When I call Get2() then the result is correct, list.number is 1 and pointer can be unmarshaled. But after Get1() the returned struct is sth like: list.number = 0, list.ptr = 48, which is obviously wrong.
Both methods are different only in lack of argument for Get2. I checked in debugger that string parameter is passed correctly to dll. Then struct clist_t is correctly filled in dll, but upon return, when control is passed back from dll to C#, the returned struct is somehow corrupted.
Could you give me some hint what is going wrong? Why struct is returned correctly only if there are no parameters?
EDIT: I'm using extern "C"
when declaring functions in dll.
Upvotes: 0
Views: 1048
Reputation: 67128
GetDelegateForFunctionPointer()
assumes __stdcall
calling convention but your functions have __cdecl
(and you'll have unexpected behaviors when you return something or you pass more than one parameter).
Change native API to:
DLL_API clist_t __stdcall GetArgs1(const wchar_t* const name);
DLL_API clist_t __stdcall GetArgs2();
OR decorate your delegate to instruct framework to use right calling convention:
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate ArgsList ArgsDelegate();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate ArgsList ArgsStringDelegate(
[MarshalAs(UnmanagedType.LPWStr)] string name);
If also clist_t.ptr
is a function pointer then don't forget to decorate that delegate too.
Upvotes: 1