Wrong overload method called - c#

I have written COM component in C#. Interface methods are declared in following manner:
[ComImport,
Guid("7D37EE00-143E-40DF-B177-BF091D7CD36A"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IMonogramServiceHost
{
void Send(
[In, MarshalAs(UnmanagedType.BStr)] string text);
void Send([In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)]byte[] data,
[In, MarshalAs(UnmanagedType.I4)] int length);
}
These methods are called from C++ code. This same interface declared in C++ is:
DECLARE_INTERFACE_(IMonogramServiceHost, IUnknown)
{
STDMETHOD(Send)(BSTR text);
STDMETHOD(Send)(uint8 *buf, int length);
};
I am calling second method. Its parameter is simply unsigned char array whose length is defined by parameter 'length'. By some unknown reason code steps into method 'void Send(string text)'. After returning from COM method debugger displays following error message:
Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call. This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention.
When I rename method to ASend correct version is called. Why is this happening? I dont see logic in this.

COM doesn't support function overloading. It isn't that clear how you are making the call, but late binding will certainly fail. IDispatch::GetIDsOfNames() is going to return the wrong dispid when asked for "Send". That's not strongly indicated in this case since you derive from IUnknown. But in itself is enough reasons to give these methods distinct names.
I'd suggest SendText vs SendBytes. Quite justified in itself, bytes and characters are not at all equivalent in Unicode.

A C# char array is a C++ uint16 array, not a uint8 array. The second signature is a mismatch.

Related

Marshalling C++ .dll in C#

I am developing a C# application that uses a dll written in C++. I am able to call most of the functions in .dll from C# application, but only one function cause problem. I think it is about marshalling types.
This is the C++ prototype of the function:
int GetProgressInfo(
int *state,
double *progress,
char* stateInfo,
int infoStringMaxLen
);
This is my C# delegate:
delegate int GET_PROGRESS_INFO(
ref int state,
ref double progress,
[MarshalAs(UnmanagedType.LPStr)]
string stateInfo,
int infoStringMaxLen
);
Can you please help me? I can not find what is wrong
One very important lesson that you must learn is that the signature of a function is not enough information to fully specify the semantics for that function. In this case, a C++ int* could be the address of a single int, or an array. Likewise for double*. And char* could be a string being passed to the function, or a pointer to a buffer in which the function returns a string to the caller.
I'm going to take my best guess, but you do need to check the actual semantics.
My best guess is that the function returns three things to the caller: an int with the state int, a double with the progress value, and a string giving info on the state. The latter information is encoded in the final two parameters. The caller allocates a buffer and passes the pointer to the beginning, together with the length. So the C# should look like this:
delegate int GET_PROGRESS_INFO(
out int state,
out double progress,
StringBuilder stateInfo,
int infoStringMaxLen
);
I'm assuming that you are using the default charset of CharSet.Ansi, and so the third parameter does not need a MarshalAs attribute.
Call the function like this:
int state;
double progress;
StringBuilder stateInfoSb = new StringBuilder(256);
int retval = GetProgressInfo(
out state,
out progress,
stateInfoSb,
stateInfoSb.Capacity
);
if (retval == 0) // guessing that 0 means OK
{
string stateInfo = stateInfoSb.ToString();
....
}
Another possible cause for mismatch is the calling convention. As written, there are no calling conventions specified. The default for C++ code is cdecl, the default for C# is stdcall. You need to check what calling convention is used by the C++ and make sure the C# code matches.
And once again, you do need to check with the documentation that my guesswork above is accurate.

Understanding Piece of C# code

I have been coding in c# for a bit but I came across some piece of code which does not make any sense to me at all. It looks something like below:
[DllImport(DllName, SetLastError = true,
CallingConvention=CallingConvention.Cdecl)]
static extern byte QLIB_UploadCEFS_File(UInt32 handle, string sFileName,
string sPartitionFileName);
I have no idea how to interpret this code. Can anyone explain me what are they trying to achieve here?
The is a P/Invoke declaration. It declares a function, external to this module, implemented in an unmanaged DLL.
The DllImport attribute specifies the name of the unmanaged DLL, DllName in this instance. The other properties of the DllImport attribute specify, in this instance, the calling convention, and that the function sets the Win32 last error variable.
The function declaration itself specifies the signature of the unmanaged function. In this case the parameters mean that the function has the following unmanaged declaration:
unsigned char QLIB_UploadCEFS_File(
unsigned int handle,
const char *sFileName,
const char *sPartitionFileName
);
From the perspective of the managed code that calls the function, it's just like any other function. You call it passing parameters as specified in the code in your question.
For what it is worth, I do suspect that the declaration is incorrect. The first parameter is a handle and these are almost always pointer sized. So, whilst the code is probably just fine under 32 bit, it is likely to break under 64 bit. I would expect to see that first parameter declared as IntPtr. Of course, this is speculation because I cannot see the actual unmanaged function declaration.

Set C Function Pointer to C# Function

I need to set a callback function in a C library equal to a C# function, and can't figure out a way to do it without either dlopen or kernel32, which seems windows/unix specific. Does anyone know of a way to do this?
The problem: C shared library exposes function pointers, whose values should be set by over-writing them. E.g.
//C Code
extern void (*ptr_R_ShowMessage) (const char *)
The current c# code creates a delegate to a function that matches this signature, uses the marshal class to get a pointer to that delegate, and then overwrites the C pointer with this value.
//call to libdl or kernel32.dll
IntPtr showPointer = GetFunctionAddress(hndl,"ptr_R_ShowMessage");
IntPtr newShowPointer = Marshal.GetFunctionPointerForDelegate(matchingDelegate);
Marshal.WriteIntPtr(showPointer, newShowPointer);
The requirement on libdl and kernel32.dll causes all kinds of problems... and ideally would be avoided.
Does anyone know how I can make the C libraries pointer point to the C# code, without modifying the C code or using the GetFunctionAddress dynamic loading? I think this might be impossible, but it seems like it could be.
I'm not 100% sure if this is what you're looking for.
In our case, we have a third party C Sdk that provides several hooks for callback messages. The callback call is initiated in C code and expects to invoke a C function, but we are able to hook it to a C# method using the following steps. (This code is kind of old and probably there are more succint and modern methods to accomplish the same in newer iterations of C#).
First we declare inside a C# class a Callback delegate, compatible with the signature of the C function pointer the SDK is expecting.
For example, if the C code is expecting to call back a function having the following signature:
void DecCallBack(int nPort, void* pBuf, int nSize, FRAME_INFO *pInfo, int nReserved1, int reserved 2);
Here's the matching C# delegate definition. Note that the "magic" happens thanks to the UnmanagedFunctionPointer attribute:
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
delegate void DecCallBack(int nPort, IntPtr pBuf, int nSize, ref FRAME_INFO frameInfo, int nReserved1, int nReserved2);
Once we have this, we declare a class member of type DecCallBack that will hold a delegate instance in our class.
static DecCallBack _decodeCallBack = null;
Next we code a handler method compatible with the delegate signature. In this case we name it HandleDecData()
private static void HandleDecData(int nPort, IntPtr pBuf, int nSize, ref FRAME_INFO frameInfo, int nReserved1, int nReserved2) {
// Here we handle the callback, this code is being called from an external C library
}
Next, somewhere in the C# class, we need to initialize the delegate member and hook our callback Handler (In this case it is the static method HandleDecData()
_decodeCallBack += new DecCallBack(HandleDecData);
Finally, we pass the delegate member as if it were a function pointer to C.
In our case, the third party SDK has a C PlayM4_SetDecCallBack() function that expects the function pointer to call when the callback is invoked - we can safely pass the delegate member of our class instead.
if( !PlayM4_SetDecCallBack(channel, _decodeCallBack) )
throw new InvalidOperationException("Error setting DecCallBack");
I hope this is helpful.
C shared library DO NOT exposes function pointers in that way, extern means that this function is defined in another C file and linker during creation of binary object will use actual code from the function in final executable
to fix this you need to include C# file somehow in C project in way the C compiler will link both into binary object, but it is impossible
what current code is trying to do is called "hack", if you want to achieve similar functionality without hacks you need:
In C code provide function which will accept pointer to function to execute
In C code where ptr_R_ShowMessage is called use pointer from p1
In C# code call function from P1 and provide method to call as argument
Here is sample I've found which executes function from external library and provide it C# function as callback: http://tutorials.csharp-online.net/CSharp_Delegates_and_Events%E2%80%94Win32_callbacks
I confirmed that this is not possible in C# directly, so interfacing with the libary load function is required. Thanks to both for answers though, definitely useful.

Passing delegate to a unmanaged method which expects a delegate method with an int array pointer

I am working on a C# application which uses an unmanaged dll which as a method that takes in a function pointer as one of it's parameters. As I do not have access to the actual C++ source code for the unmanaged dll I can only rely on a snippet I have from a C++ sample which uses that the same dll. The problem I am having is that the delegate I have made to pass into the unmanaged method is not working.
Below is the DllImport of the method I am trying to use which takes the delegate I've created:
[DllImport("pos_tk.dll")]
static internal extern ErrorCode AddSIGHandle([MarshalAs(UnmanagedType.FunctionPtr)] SIG_Callback func);
Here is the delegate signature I currently have:
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate void SIG_Callback ([MarshalAs(UnmanagedType.LPArray)] ref int[] buf, int rev, object sender);
And this is the function the C++ sample snippet uses in which I based my delegate off of:
void __stdcall point_handle (int *buf, int rev, LPVOID pParam)
Now, before you tell me to change the ref int[] buf parameter of my delegate to ref int buf the program will throw an InvalidVariant error once the callback is attempted. The code snippet uses int *buf as an array of size rev.
Using the code I have above, the application throws an AccessViolationException when the callback is attempted. My hunch is that I should be using a different type for the ref int[] buf parameter, but I've tried everything I can think of. I've also been searching Google, SO, and MSDN all day but with no luck.
Anyone have any ideas?
As a final note, is this any way similar to how you can use a StringBuilder as a parameter for a unmanaged method that takes a char* parameter to retrieve a variable length string?
Passing arrays back and forth is always a PITA...try this signature, it seems applicable:
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate void point_handle(
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)]
int[] buf,
int rev,
IntPtr pParam);
EDIT: just to elaborate, when you've got a "C style" array (that is a T*) as well as the length both specified in the arguments, SizeParamIndex is your salvation; basically it says "Hey, there's an unknown-length array coming in, but the parameter at this index will tell you how many of them there are. Use both that and the type to help marshal"

C# - Calling unmanaged C++ function passing LPVARIANT

I want to call the following function from my managed code:
short LS_LoadConfig(LS_ID SensorID,LPVARIANT varConfigPathFile,BOOL bInit)
Here is how I declare the extern function in my C# class:
[DllImport("LineSensor.dll", EntryPoint = "#16")]
private static extern Int16 LS_LoadConfig(
Int16 deviceId,
IntPtr variantFilePath,
int init);
And here is how I create the VARIANT instance and I obtain a pointer to it. Then I call the C# function:
string filepath = #"C:\Windows\ ...";
IntPtr variantFilePath = Marshal.AllocCoTaskMem(200);
Marshal.GetNativeVariantForObject(filepath, variantFilePath);
LS_LoadConfig(device.Id, variantFilePath, initLineSensor);
The problem is that I keep receiving error messages such as "calling the LS_LoadConfig function has unbalanced the stack, check that parameters match the unmanaged signature".
It seems that the problem is caused by the second argument "variantFilePath", like it is not properly marshaled and its size on the unmanaged heap doesn't correspond to the one of an address (32-bit in my case). I tried to change the type in the C# function signature from IntPtr to int as follows:
[DllImport("LineSensor.dll", EntryPoint = "#16")]
private static extern Int16 LS_LoadConfig(
Int16 deviceId,
int variantFilePath,
int init);
I tried to call the function passing a random number and it got slightly better, I have just received an error "memory access violation". Obviously because the random number wasn't a valid address.
Does anybody knows the solution to this problem?
Thank you for any helpful information.
The access violation you created is not better. It also prevents the MDA warning from being generated. Short from the argument types being wrong, the int16 looks pretty weird, the most likely trouble is caused by the CallingConvention. Try StdCall.
And declare the 2nd argument as "object", its default marshaling is to a VARIANT. Declare it with the "ref" keyword to get an LPVARIANT.
"calling the LS_LoadConfig function has unbalanced the stack, check that parameters match the unmanaged signature".
This usually means that you're using conflicting calling conventions between your native and managed code. C# by default uses stdcall, and c/c++ uses cdecl. Try specifying CallingConvention = CallingConvention.Cdecl.

Categories