Making a function call to .NET 4 to native code is resulting in the following exception:
A call to PInvoke function has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the calling convention and parameters of the PInvoke signature match the target unmanaged signature.
Here is my definition in Native Code:
typedef void ( CALLBACK* CB_DOWNLOADING )
(
ULONG, // secs elapsed
LPARAM, // custom callback param
LPBOOL // abort?
);
FETCH_API HttpFetchW
(
LPCWSTR url,
IStream** retval,
LPCWSTR usrname = NULL,
LPCWSTR pwd = NULL,
BOOL unzip = TRUE,
CB_DOWNLOADING cb = NULL,
LPARAM cb_param = 0,
LPWSTR ctype = NULL,
ULONG ctypelen = 0
);
Here is the .NET counterpart:
[DllImport(dllPath, CharSet = CharSet.Unicode, SetLastError = true, CallingConvention = CallingConvention.Cdecl)]
internal static extern FETCH HttpFetchW
(
[MarshalAs(UnmanagedType.LPWStr)]
string url,
out System.Runtime.InteropServices.ComTypes.IStream retval,
[MarshalAs(UnmanagedType.LPWStr)]
string usrname,
[MarshalAs(UnmanagedType.LPWStr)]
string pwd,
bool unzip,
dlgDownloadingCB cb,
IntPtr cb_param,
[MarshalAs(UnmanagedType.LPWStr)]
string ctype,
ulong ctypelen
);
Where FETCH is an enum.
[UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)]
internal delegate void dlgDownloadingCB(ulong elapsedSec, IntPtr lParam, bool abort);
internal static void DownloadingCB(ulong elapsedSec, IntPtr lParam, bool abort)
{
// Console.WriteLine("elapsedSec = " + elapsedSec.ToString());
}
Can anyone suggest an alternative within the .NET 4?
Thank you very much for your help.
Best Answer
The only clear error in
HttpFetchW
that I can see is that C#ulong
is 64 bits wide, by C++ULONG
is 32 bits wide. The C# code for the final parameter should beuint
.Other things to check include the calling convention. Are you sure it is
cdecl
? Are you sure thatSetLastError
should betrue
?As for the callback, you make the same error with
ulong
. And theabort
parameter isLPBOOL
. That is a pointer toBOOL
. So you should declare the C# parameter as aref
parameter. And the callback is declared withCALLBACK
which isstdcall
.So the delegate should be:
Or simply delete the
UnmanagedFunctionPointer
attribute since the default isstdcall
.I think it exceptionally likely that since the callback is
stdcall
, so will the function. I expect that theFETCH_API
macro expands to both the return enum and the calling convention. Since you did not supply those details, I can only guess. You'll need to check.The other thing that we cannot check is
CB_DOWNLOADING
.Anyway, with those assumptions, the function becomes: