PInvoke and double* - c#

I apologize if this is a duplicate. I am writing a class that needs to interact with an old c++ unmanaged dll. There is one method that I am having a hard time mapping to managed code:
long DoSomething(int id, double* points, long numberOfPoints, bool useShaping)
I have been thus far unable to map that to an extern method that does not throw a stack unbalanced exception. The problem is with the double pointer. What would the method signature look for in managed code? Here's what I've tried that does not work as an example.
[DllImport("Something.Dll", EntryPoint = "DoSomething")]
public static extern long DoSomething(int id, double[] points, long numberOfPoints, bool useShaping)

There are likely two problems -
This most likely needs to specify the calling convention.
"long" in C++ maps to "int" in C#
Try the following:
[DllImport("Something.Dll", EntryPoint = "DoSomething", CallingConvention=CallingConvention.Cdecl)]
public static extern int DoSomething(int id, double[] points, int numberOfPoints, bool useShaping);

Related

Debug an imported dll with VS 2010

I have a problem while I trying to call WinAPI functions from C# code. I have lots of imports, many of them works fine, but some of them not and leading to unexpected break main program, without any message, exception type, nothing, just fell down all its windows and exit.
I have two ways in code: via my developed library, where is more of winapi calls and I'm lazy to code specific structures, pointers, etc, and direct import from user32.dll, like this:
[DllImport(#"tradeInterop.dll")]
public static extern void ChooseInstrumentByMouse(UInt32 hwnd, int baseX, int baseY, int idx, int _isDown);
[DllImport(#"tradeInterop.dll")]
public static extern void PutNumber(int num);
[DllImport(#"tradeInterop.dll")]
public static extern void PutRefresh();
[DllImport(#"user32.dll")]
public static extern UInt32 FindWindow(string sClass, string sWindow);
[DllImport(#"user32.dll")]
public static extern int GetWindowRect(uint hwnd, out RECT lpRect);
[DllImport(#"user32.dll")]
public static extern int SetWindowPos(uint hwnd, uint nouse, int x, int y, int cx, int cy, uint flags);
[DllImport(#"user32.dll")]
public static extern int LockSetForegroundWindow(uint uLockCode);
[DllImport(#"user32.dll")]
public static extern int SetForegroundWindow(uint hwnd);
[DllImport(#"user32.dll")]
public static extern int ShowWindow(uint hwnd, int cmdShow);
[DllImport(#"tradeInterop.dll")]
public static extern ulong PixelColor(uint hwnd, int winX, int winY); //tried (signed) long and both ints as return type, same result (WINAPI says DWORD as unsigned long, what about 64-bit assembly where compiled both lib and program?
public struct RECT
{
public int Left;
public int Top; ...
As I said, many of this calls works perfectly, but have problem of last two of them: ShowWindow() and PixelColor() with following code:
extern "C" __declspec(dllexport) COLORREF __stdcall PixelColor(unsigned hwnd, int winX, int winY)
{
LPPOINT point;
point->x = winX;
point->y = winY;
ClientToScreen((HWND) hwnd, point);
HDC dc = GetDC(NULL);
COLORREF colorPx = GetPixel(dc, point->x, point->y);
ReleaseDC(NULL, dc);
return colorPx;
}
So, while I try to call directly imported ShowWindow() function, or library which calls api function(s), I got a program crash
Is there any way how to debug external libraries and its results?
What I¨m doing wrong?
Thanks a lot
You have several options for debugging issues.
Enable unmanaged code debugging in Visual Studio. Note: VS 2010 Express does not support mixed managed/unmanaged debugging. (Instructions)
Use WinDbg. This would be my personal favorite option for debugging mixed applications. It is an incredibly powerful tool. Admittedly the learning curve is a little steep, but it's well worth the effort.
Use an external/third party debugger like OllyDbg. (As suggested by MrDywar)
The P/Invoke problems:
As IInspectable pointed out HWND should be passed to unmanaged code using IntPtr.
Windows API data types are well defined. DWORD is always 32 bit. Also, LONG (all caps) is not the same as long (lower case).
The C++ Problems:
As mentioned by IInspectable, the LPPOINT is never initialized, so when you call ClientToScreen() you're accessing uninitialized stack garbage as a pointer, and assigning values. To Fix it you could:
Allocate the memory (your favorite scheme here, LocalAlloc, GlobalAlloc, malloc, calloc.
Make the declaration POINT point;, assign values using point.x & point.y, and use it in the function call as &point.
Make the first parameter's type HWND. The API types, even though they are ultimately typedefs, carry extra meaning with them.

Call a C++ DLL in C#

The problem is that i've got a C++ DLL that I want to use in my C# project.
The problematic function has the prototype:
int MRK3LINK_Open(void (*pfLog)(const char* s),void (*pfErrorOut)(const char* s));
The documentation states that:
pfLog is a pointer to log handler function of type const char*.
pfErrorOut is a pointer to error out handler function of type const char*.
And an example of how to call the functions of the DLL from C++:
static void _LogHandler(const char* sLog) {
printf(sLog);
}
static void _ErrorOutHandler(const char* sError) {
MessageBox(NULL, sError, "2-Link", MB_OK);
}
MRK3LINK_Open(_LogHandler, _ErrorOutHandler);
I'm stuck on this for 2 days now. Could you provide me some tips ?
Thanks.
The two parameters are function pointers. They will map to delegates in C++. Like this:
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void LogHandlerDelegate(string str);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void ErrorOutHandlerDelegate(string error);
Then the function you import is:
[DllImport(dllname, CallingConvention = CallingConvention.Cdecl)]
public static extern int MRK3LINK_Open(
LogHandlerDelegate LogHandler,
ErrorOutHandlerDelegate ErrorOutHandler
);
Then you create delegates in the usual way and pass them to MRK3LINK_Open. Make sure that you store references to the delegates if the unmanaged code takes a reference to them and calls them after MRK3LINK_Open returns. Otherwise the garbage collector is liable to collect them.

C# app crashes on exit after using C++ function with delegates

My C# app needs to talk with a DLL written in C++. I don't have the code of this DLL, but I have the code for a demo app (also in C++) that uses the DLL and works.
Here's the interesting code from the C++ demo app. It has two functions, one of which accepts a callback set of 4 delegates.
typedef BOOL (CBAPI* OPENSCANNERSDK)(HWND hwnd, TCallBackSet* callbackSet, wchar_t* configPath);
typedef void (CBAPI* CLOSESCANNERSDK)();
typedef struct TCallBackSet
{
TOnScannerStatusEvent scannerStatusEvent;
TOnScannerNotifyEvent scannerNotifyEvent;
TOnRFIDStatusEvent rfidStatusEvent;
TOnRFIDNotifyEvent rfidNotifyEvent;
} TCallBackSet;
typedef void (cdecl* TOnScannerStatusEvent ) (int scannerStatus);
typedef void (cdecl* TOnScannerNotifyEvent) (int scannerNotify, int lParam);
typedef void (cdecl* TOnRFIDStatusEvent ) (int rfidStatus);
typedef void (cdecl* TOnRFIDNotifyEvent ) (int rfidnotify);
So, I have to call OpenScannerSDK, pass a callback set with pointers to some functions, do some stuff, and finally call CloseScannerSDK.
I have declared this in my C# app like so:
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "_OpenScannerSDK")]
extern public static bool OpenScannerSDK(IntPtr hwnd, TCallBackSet callbackSet,
[MarshalAs(UnmanagedType.LPWStr)]string configPath);
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "_CloseScannerSDK")]
extern public static void CloseScannerSDK();
[StructLayout(LayoutKind.Sequential)]
public class TCallBackSet
{
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void TOnScannerStatusEvent(int scannerStatus);
[MarshalAs(UnmanagedType.FunctionPtr)]
public TOnScannerStatusEvent ScannerStatusEvent;
(I have removed the other 3 callbacks for brevity)
}
Finally I use the library like so:
var callback = new TCallBackSet() { ... set the delegates ... }
OpenScannerSDK(IntPtr.Zero, callback, ".");
... do other stuff...
CloseScannerSDK();
All this seems to work - both OpenScannerSDK and CloseScannerSDK and all the others I use between them work correctly. The problem is that as soon as the application tries to exit, I get an APPCRASH in KERNELBASE.dll. I don't see any relevant information in the crash report file. I have noticed that if I do not call OpenScannerSDK, but just some other functions of the DLL that are not related to delegates, the APPCRASH doesn't happen.
I also tried GC.KeepAlive for the delegates, no effect.
I had a similar issue porting other C DLL to C# some years ago.
Function pointers in C# are represented as delegates. Internally, delegates are class instances and they're collected by GC the same way other objects are collected.
Probably in your DLL there's some method that "stops" the API, making it stopping invoking the C++ function pointers. You must call this before you close the application.
Probably your app collects the delegate objects and when the C++ DLL tries to invoke from unmanaged code, finds an invalid object reference.
It's interesting to keep the references in C# of these delegates in private fields, to avoid them to be collected when the application is running. The sympton of this issue is that the application crashes intermitently.
Hope this helps.
To anyone interested, here is the final working solution.
First, CallBackSet is defined like so:
[StructLayout(LayoutKind.Sequential)]
public class CallBackSet
{
public IntPtr ScannerStatusEvent;
public IntPtr ScannerNotifyEvent;
public IntPtr RfidStatusEvent;
public IntPtr RfidNotifyEvent;
}
And then:
OnScannerStatusEvent onScannerStatus = (ScannerStatus status) => {...};
OnScannerNotifyEvent onScannerNotify = (ScannerNotify notify, short lparam) => {...};
OnRfidStatusEvent onRfidStatus = (RfidStatus status) => {...};
OnRfidNotifyEvent onRfidNotify = (RfidNotify notify) => {...};
GCHandle.Alloc(onScannerStatus);
GCHandle.Alloc(onScannerNotify);
GCHandle.Alloc(onRfidStatus);
GCHandle.Alloc(onRfidNotify);
callbackSet = new CallBackSet()
{
RfidNotifyEvent = Marshal.GetFunctionPointerForDelegate(onRfidNotify),
RfidStatusEvent = Marshal.GetFunctionPointerForDelegate(onRfidStatus),
ScannerNotifyEvent = Marshal.GetFunctionPointerForDelegate(onScannerNotify),
ScannerStatusEvent = Marshal.GetFunctionPointerForDelegate(onScannerStatus)
};
callbackPtr = Marshal.AllocHGlobal(Marshal.SizeOf(callbackSet));
Marshal.StructureToPtr(callbackSet, callbackPtr, false);
OpenScannerSDK(IntPtr.Zero, callbackPtr, ".");
Upon further testing I found that actually OpenScannerSDK always returns True, which made me believe it was working correctly, but it may not be the case. I did several tests, including passing a TCallBackSet struct that does not have any members and OpenScannerSDK still returned True.
So it seems the problem is with TCallBackSet and these delegates. Something's wrong there. I tried passing the CallBackSet w and w/o ref, no difference. Noticed int in C++ is not the same as int in C#, so changed functions signatures to use short instead of int. None of these made any difference.

LoadLibrary and define callback to C DLL (function pointer)

I have a code like this one in a DLL:
int (*callback)(int a, int b);
void mainfunc()
{
callback(1, 2);
callback(3, 4);
}
To access this DLL from a C program, I used to do this:
#include <windows.h>
int callback(int a, int b) {return a+b;}
int main()
{
HANDLE dll = LoadLibrary("test.dll");
*(void**)GetProcAddress(dll, "callback") = (void*)callback;
((void(*))GetProcAddress(dll, "mainfunc"))();
FreeLibrary(dll);
}
The DLL is still C code, but the main program have switched to C#. How to deal with function pointer? How would that code be in C#?
callback is a global variable in the dll, so you can't[1] set it from c#.
You shouldn't be setting it from C either. What you should have, if callback really is shared, is a function like SetCallback( MyCallbackType callback ) to set it.
But probably, you want to pass the function to mainfunc.
In either case, this is easy to do in C#:
// C#
public delegate Int32 Callback( Int32 a, Int32 b );
[DllImport("test.dll")]
static extern void mainfunc( Callback callback );
// Or if you're setting the callback globally,
[DllImport("test.dll")]
static extern void SetCallback(Callback callback);
[DllImport("test.dll")]
static extern void mainfunc();
The take home message is that DllImport is smart enough to convert a delegate with a reasonably close signature to a C function pointer.
[1] Ok, so you can...dll injection sometimes uses one of a number of hacks along those lines, but it's all kinds of the wrong way to do it in any other situation.

C#. How to pass message from unsafe callback to managed code?

Is there a simple example of how to pass messages from unsafe callback to managed code?
I have a proprietary dll which receives some messages packed in structs and all is coming to a callback function.
The example of usage is as follows but it calls unsafe code too. I want to pass the messages into my application which is all managed code.
*P.S. I have no experience in interop or unsafe code. I used to develop in C++ 8 yrs ago but remember very little from that nightmarish times :)
P.P.S. The application is loaded as hell, the original devs claim it processes 2mil messages per sec.. I need a most efficient solution.*
static unsafe int OnCoreCallback(IntPtr pSys, IntPtr pMsg)
{
// Alias structure pointers to the pointers passed in.
CoreSystem* pCoreSys = (CoreSystem*)pSys;
CoreMessage* pCoreMsg = (CoreMessage*)pMsg;
// message handler function.
if (pCoreMsg->MessageType == Core.MSG_STATUS)
OnCoreStatus(pCoreSys, pCoreMsg);
// Continue running
return (int)Core.CALLBACKRETURN_CONTINUE;
}
Thank you.
You can use Marshal class to deal with interop code.
example:
C:
void someFunction(int msgId, void* funcCallback)
{
//do something
funcCallback(msgId); //assuming that function signature is "void func(int)"
}
C#
[DllImport("yourDllname.dll")]
static extern someFunction(int msgId, IntPtr funcCallbackPtr);
public delegate FunctionCallback(int msgId);
public FunctionCallback functionCallback;
public void SomeFunction(int msgId, out FunctionCallback functionCallback)
{
IntPtr callbackPtr;
someFunction(msgId, callbackPtr);
functionCallback = Marshal.DelegateToPointer(callbackPtr);
}
you can call as:
SomeFunction(0, (msgIdx) => Console.WriteLine("messageProcessed"));
I hope I did it right. I did not try to compile it :)

Categories

Resources