Marshal void** c# - c#

I try to use C dll in C#
typedef enum M_STATUS
{
// Unknown error. Should not be returned.
M_UNKNOWN = -1,
// Successful.
M_OK = 0
} M_STATUS;
M_STATUS WINAPI M_Create(LPVOID pTarget, LPVOID pDetour, LPVOID *ppOriginal);
In C# I have
[DllImport("Y:\\libs\\Min.x86.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern M_STATUS M_Create(IntPtr pTarget, IntPtr pDetour, ref IntPtr ppOriginal);
But I always get PinvokeStackImbalance Exception
Where is mistake?

Adding as an actual answer so it won't get lost.
The C function is declared as WINAPI, but the calling convention specified in the DllImport attribute is Cdecl. The conventions must match, so change it to either StdCall or Winapi.

Related

Second value not getting passed to C++ function during pinvoke

I have a c++ function which I am calling from c# using pinInvoke. Following is my cpp method-
int test(DWORD verb,DWORD verb2 )
{
return verb2 *100;
}
My function is exposed as -
extern "C" {
__declspec(dllexport) int test(DWORD verb, DWORD verb2);
}
Following is my c# code where I am calling the above method:
public class API
{
[DllImport("mydll.dll", EntryPoint = "test", SetLastError = true, CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.U4)]
public static extern uint test(
[MarshalAs(UnmanagedType.U8)]ulong verb,
[MarshalAs(UnmanagedType.U8)]ulong verb2);
static void Main(string[] args)
{
uint x = DPAPI.test(26,10);
Console.Write("result is-"+x);
}
}
Here the second value is getting passed as 0,so wrong result is coming. Am I doing something wrong while passing the value?
What I have tried:
I am relatively new to Pinvoke. So I tried debugging to see whether the value is not getting passed to c++ code or whether the c++ code is not returning proper values.I found that the value getting passed itself was wrong.
DWORD is a 32 but unsigned integer. You are mapping that to a 64 bit type. That is the problem. Your p/invoke should be:
[DllImport("mydll.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int test(uint verb, uint verb2);
Note that I removed the needless EntryPoint and the erroneous SetLastError from the DllImport attribute.
I also wonder why you have selected DWORD. Unless you are passing those values onto Win32 functions it would likely make more sense to use intrinsic types. Why not use int or unsigned int in your C++ code?

How to PInvoke CMark's cmark_markdown_to_html

I'm trying to PInvoke the following function from GitHub's fork of CMark
char *cmark_markdown_to_html(const char *text, size_t len, int options)
and here's my PInvoke signature:
[DllImport("cmark.dll")]
public static extern IntPtr cmark_markdown_to_html(
[In()] [MarshalAs(UnmanagedType.LPStr)] string text,
[MarshalAs(UnmanagedType.SysUInt)] uint len,
[MarshalAs(UnmanagedType.SysInt)] int options);
I call it as follows:
var retValue = cmark_markdown_to_html(markdown, 0, 0);
However, it throws a Marshaling exception the with the message:
Cannot marshal 'parameter #2':
Invalid managed/unmanaged type combination
(Int32/UInt32 must be paired with I4, U4, or Error).
OK, so I change the signature to:
[DllImport("cmark.dll")]
public static extern IntPtr cmark_markdown_to_html(
[In, MarshalAs(UnmanagedType.LPStr)] string text,
[MarshalAs(UnmanagedType.U4)] uint len,
[MarshalAs(UnmanagedType.I4)] int options);
Now it throws a PInvokeStackImbalance error
The name '$exception' does not exist in the current context
Native stuff is a mystery to me. Can someone help?
Stack imbalance
The reason for stack imbalance is described in Why are Cdecl calls often mismatched in the "standard" P/Invoke Convention?.
Basically you need to specify proper calling convention in the DllImport that will probably be cdecl:
[DllImport("cmark.dll", CallingConvention = CallingConvention.Cdecl)]
Marshalling size_t
That one is discussed in what is equal to the c++ size_t in c# .
Assuming that CMark will always be native (32 bit on x86, 64 bit on x64), you should use (U)IntPtr.
If it is always 32 bit, then Int32 should be used.
PInvokeStackImbalance
Presumably CMark is using the default calling convention. The default calling convention for C code is "Cdecl", while the default used for P/invoke calls is "StdCall". The calling convention specifies how the arguments and return value are placed on the call stack. A mismatch between the used calling convention causes the stack to become imbalanced.
You can specify the calling convention to use from C# code in the DllImport attribute.
[DllImport("cmark.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr cmark_markdown_to_html(
[In, MarshalAs(UnmanagedType.LPStr)] string text,
[MarshalAs(UnmanagedType.U4)] uint len,
[MarshalAs(UnmanagedType.I4)] int options);
Marshalling
In case you want your code to be compatible with architectures other than 32-bit, you would want to marshall size_t with UIntPtr. (Read #Eugene Podskal answer)
[DllImport("cmark.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr cmark_markdown_to_html(
[In, MarshalAs(UnmanagedType.LPStr)] string text,
[MarshalAs(UnmanagedType.U4)] UIntPtr len,
[MarshalAs(UnmanagedType.I4)] int options);
Then you can call the method like so
var retValue = cmark_markdown_to_html(markdown, UIntPtr.Zero, 0);

Calling non-managed DLL

I am going mad trying to call a DLL function for days from a C# application.
Here is the definition of the DLL call:
phStatus_t phbalReg_Rd70xUsbWin_Init
( phbalReg_Rd70xUsbWin_DataParams_t * pDataParams,
uint16_t wSizeOfDataParams )
Here is the definition of phbalReg_Rd70xUsbWin_DataParams_t:
And here is my C# code for calling the DLL:
public static data_params parameters;
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct data_params
{
internal ushort wId; //Layer ID for this BAL component, NEVER MODIFY!
internal byte ucTxSeq; //Sequence counter for packets.
[MarshalAs(UnmanagedType.LPStr)]
String pDeviceName;
internal IntPtr pDeviceHandle; //Handle to the USB device.
internal IntPtr pPipeOut; //Handle to Usb Out-pipe.
internal IntPtr pPipeIn; //Handle to Usb In-pipe.
internal ushort wTimeoutWrMs; //TO value for Usb Write pipe transfer.
internal ushort wTimeoutRdMs; //TO value for Usb Read pipe transfer.
}
[DllImport("NxpRdlib.dll", EntryPoint = "phbalReg_Rd70xUsbWin_Init")]
public static extern uint phbalReg_Rd70xUsbWin_Init(ref data_params data_parameters,
public static unsafe uint connectToPegoda()
{
parameters = new data_params();
parameters.wId = 0x05;
parameters.ucTxSeq = 0;
parameters.pDeviceHandle = IntPtr.Zero;
parameters.pPipeOut = IntPtr.Zero;
parameters.pPipeIn = IntPtr.Zero;
parameters.wTimeoutWrMs = 0xFFFF;
parameters.wTimeoutRdMs = 0xFFFF;
return phbalReg_Rd70xUsbWin_Init(ref parameters, (uint)Marshal.SizeOf(parameters));
}
The problem is that I receive a PInvokeStackImbalance exception.
I tried to change type of paramaters with different things and never achieved to get this work. I am sure I am doing something wrong with types, but can't find what. Can someone help me?
The most common explanation is a calling convention mis-match. As written, the unmanaged function declaration uses cdecl. You did not specify a calling convention in your p/invoke and so the default of stdcall is used.
To fix this, specify cdecl in your p/invoke:
[DllImport("NxpRdlib.dll", CallingConvention = CallingConvention.Cdecl)]
You also specified only part of the p/invoke declaration. You missed the second parameter. The full declaration should be:
[DllImport("NxpRdlib.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern uint phbalReg_Rd70xUsbWin_Init(
ref data_params data_parameters,
ushort wSizeOfDataParams
);
The other unknown here is phStatus_t. You've translated that as uint, an unsigned 32 bit integer. We can only take your word that the translation is correct.
Update: From your comment to the question, phStatus_t should be translated as ushort. So, finally, we have:
[DllImport("NxpRdlib.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern ushort phbalReg_Rd70xUsbWin_Init(
ref data_params data_parameters,
ushort wSizeOfDataParams
);

A call to PInvoke function has unbalanced the stack

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.
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 be uint.
Other things to check include the calling convention. Are you sure it is cdecl? Are you sure that SetLastError should be true?
As for the callback, you make the same error with ulong. And the abort parameter is LPBOOL. That is a pointer to BOOL. So you should declare the C# parameter as a ref parameter. And the callback is declared with CALLBACK which is stdcall.
So the delegate should be:
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
internal delegate void dlgDownloadingCB(
uint elapsedSec,
IntPtr lParam,
ref bool abort
);
Or simply delete the UnmanagedFunctionPointer attribute since the default is stdcall.
I think it exceptionally likely that since the callback is stdcall, so will the function. I expect that the FETCH_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:
[DllImport(dllPath, CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern FETCH HttpFetchW(
string url,
out System.Runtime.InteropServices.ComTypes.IStream retval,
string usrname,
string pwd,
bool unzip,
dlgDownloadingCB cb,
IntPtr cb_param,
string ctype,
uint ctypelen
);
Source : MSDN
In the .NET Framework version 3.5, the pInvokeStackImbalance MDA is disabled by default. When you use the .NET Framework version 3.5 with Visual Studio 2005, the pInvokeStackImbalance MDA will appear in the Managed Debugging Assistants list in the Exceptions dialog box (which is displayed when you click Exceptions on the Debug menu). However, selecting or clearing the Thrown check box for pInvokeStackImbalance does not enable or disable the MDA; it only controls whether Visual Studio throws an exception when the MDA is activated.
https://msdn.microsoft.com/en-us/library/0htdy0k3(v=vs.110).aspx

PInvoke with pointers - C++ to C#

The following is a PInvoke block in C++ that I'm trying to convert to C#:
typedef PVOID JHANDLE ;
typedef UINT32 JRET ;
#define JEXPORT __declspec(dllimport) JRET
JEXPORT
JInitialize (
OUT JHANDLE* ppHandle,
IN PVOID context,
IN UINT32 flags
) ;
I tried the following call, but it threw a PInvokeStackImbalance exception saying that the signatures don't match:
[DllImport("jhi.dll")]
public static extern UInt32 JHI_Initialize(out IntPtr ppHandle, IntPtr context, UInt32 flags);
Obviously a pointer of a pointer is handled different, but I'm not exactly sure how it translates.
You are missing the CallingConvention in your [DllImport] declaration, it is Cdecl.

Categories