Using Managed Class Method as Callback - c#

I'm currently working on a little Midi Project and just now I'm writing a little "SharpMidi" Library in C++/Cli to make it easier for me to use native Midi functions from Managed code.
I'm now stuck on the midiInOpen Function:
http://msdn.microsoft.com/en-us/library/windows/desktop/dd798458%28v=vs.85%29.aspx
As you can see from the documentation, this function requires an unmanaged function as Callback and optional instance data.
I managed to convert a Managed Function Pointer to an unmanaged Function Pointer using
System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate
but I now have problems converting the this Pointer from my managed class to an unmanaged Pointer, I don't even know if its possibly they way I want it to work.
HMIDIIN _midiInDevice;
void MidiInProcNative(HMIDIIN midiInDevice, UINT msg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2);
delegate void MidiInProc(HMIDIIN midiInDevice, UINT msg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2);
MidiInProc^ _midiInProc;
...
_midiInProc = gcnew MidiInDevice::MidiInProc(this, &MidiInDevice::MidiInProcNative);
cli::pin_ptr<HMIDIIN> midiInDevPtr = &_midiInDevice;
pin_ptr<???> thisPtr = this; // This is the line I'm struggling with
MMRESULT result = midiInOpen(midiInDevPtr, devId, (DWORD_PTR)System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(_midiInProc).ToPointer(), thisPtr, CALLBACK_FUNCTION);
As you can see I have experimented with pin_ptrs but I don't think this will work as the this pointer can't be used to initialize any pin_ptr.
I hope I could make clear what I want to try to achieve and maybe somebody can help me out.
Regards,
Xaser

I now have problems converting the this Pointer from my managed class to an unmanaged Pointer
Just don't, there's no need for it. The dwCallbackInstance argument of miniInOpen() is a convenience argument for native C++. You get it back in the static callback function, let's you call an instance method of a C++ class.
But delegates are far more powerful than member function pointers, they already encapsulate this. A delegate constructor takes two arguments, the target object and the target method. So that it can automatically call an instance method. You already took advantage of that, you indeed passed this as the first argument. So you can be sure that your MidiInProcNative() instance method uses the proper object reference.
Just pass nullptr for the argument.

Related

Marshal a variable from C# to void* in native C++ and change the variable value in Managed/C# inside native program

I have this C++ code :
void ReleaseHandle(void* handle){
Machine.motor motor =static_cast<Machine.IMotor*> (handle)
if (motor == 0) throw;
delete motor;
handle = nullptr;
}
so far I can pass a variable into Releasehandle using PInvoke in Managed using uint as data type, problem is the value of passed variable doesn't change. This method is not the whole package, but i think this is enough to illustrate what i want to do. I need the value to change since if the pointer doesn't change in managed side and i decide to call releaseHandle again from managed, it will throw stacktrace since the releaseHandle is called and machine is not found (released).
I have tried a lot of methods of passing datatype as ref from managed including but not limited to :
void*
[In, Out] void*
uint
ref/out uint
ref/out void*
UintPtr
ref/out UintPtr
I expect when i call ReleaseHandle in managed like
uint managedHandle = 123213124;
ReleaseHandle(managedHandle);
Console.WriteLine(managedHandle); // this outputs to 0
Thank you for your help.
Your basic problem is, that you are intending to change the a variable you pass by value.
That having said, as Matthew Watson pointed out in the comment to your question, you have to adjust the interface of the method you are calling in the DLL to take a pointer pointing to the location of the pointer you want to modify.
In your example you need to pass the pointer to managedHandle to ReleaseHandle.
Hence your code should look like this in your DLL:
void ReleaseHandle(void** handle) {
*handle = nullptr; /* Note that here we dereference one level
to modify the content of the location
pointed at */
}
In your C# program on the other hand, you should import the function with something like that:
[DllImport("YourLibrary.dll")]
static extern void ReleaseHandle(ref IntPtr handle);
and invoke it by using the ref keyword:
IntPtr value = IntPtr.Add(IntPtr.Zero, 123456789);
ReleaseHandle(ref managedHandle);
Console.WriteLine(managedHandle); // this outputs to 0

Delegate on instance method passed by P/Invoke

To my surprise I have discovered a powerful feature today. Since it looks too good to be true I want to make sure that it is not just working due to some weird coincidence.
I have always thought that when my p/invoke (to c/c++ library) call expects a (callback) function pointer, I would have to pass a delegate on a static c# function. For example in the following I would always reference a delegate of KINSysFn to a static function of that signature.
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int KINSysFn(IntPtr uu, IntPtr fval, IntPtr user_data );
and call my P/Invoke with this delegate argument:
[DllImport("some.dll", EntryPoint = "KINInit", ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
public static extern int KINInit(IntPtr kinmem, KINSysFn func, IntPtr tmpl);
But now I just tried and passed a delegate on an instance method and it worked also! For example:
public class MySystemFunctor
{
double c = 3.0;
public int SystemFunction(IntPtr u, IntPtr v, IntPtr userData) {}
}
// ...
var myFunctor = new MySystemFunctor();
KINInit(kinmem, myFunctor.SystemFunction, IntPtr.Zero);
Of course, I understand that inside managed code there is no technical problem at all with packaging a "this" object together with an instance method to form the respective delegate.
But what surprises me about it, is the fact that the "this" object of MySystemFunctor.SystemFunction finds its way also to the native dll, which only accepts a static function and does not incorporate any facility for a "this" object or packaging it together with the function.
Does this mean that any such delegate is translated (marshalled?) individually to a static function where the reference to the respective "this" object is somehow hard coded inside the function definition? How else could be distinguished between the different delegate instances, for example if I have
var myFunctor01 = new MySystemFunctor();
// ...
var myFunctor99 = new MySystemFunctor();
KINInit(kinmem, myFunctor01.SystemFunction, IntPtr.Zero);
// ...
KINInit(kinmem, myFunctor99.SystemFunction, IntPtr.Zero);
These can't all point to the same function. And what if I create an indefinite number of MySystemFunctor objects dynamically? Is every such delegate "unrolled"/compiled to its own static function definition at runtime?
Does this mean that any such delegate is translated (marshalled?) individually to a static function...
Yes, you guessed at this correctly. Not exactly a "static function", there is a mountain of code inside the CLR that performs this magic. It auto-generates machine code for a thunk that adapts the call from native code to managed code. The native code gets a function pointer to that thunk. The argument values may have to be converted, a standard pinvoke marshaller duty. And always shuffled around to match the call to the managed method. Digging up the stored delegate's Target property to provide this is part of that. And it jiggers the stack frame, tying a link to the previous managed frame, so the GC can see that it again needs to look for object roots.
There is however one nasty little detail that gets just about everybody in trouble. These thunks are automatically cleaned-up again when the callback is not necessary anymore. The CLR gets no help from the native code to determine this, it happens when the delegate object gets garbage-collected. Maybe you smell the rat, what determines in your program when that happens?
var myFunctor = new MySystemFunctor();
That is a local variable of a method. It is not going to survive for very long, the next collection will destroy it. Bad news if the native code keeps making callbacks through the thunk, it won't be around anymore and that's a hard crash. Not so easy to see when you are experimenting with code since it takes a while.
You have to ensure this can't happen. Storing the delegate objects in your class might work, but then you have to make sure your class object survives long enough. Whatever it takes, no guess from the snippet. It tends to solve itself when you also ensure that you unregister these callbacks again since that requires storing the object reference for use later. You can also store them in a static variable or use GCHandle.Alloc(), but that of course loses the benefit of having an instance callback in a hurry. Feel good about having this done correctly by testing it, call GC.Collect() in the caller.
Worth noting is that you did it right by new-ing the delegate explicitly. C# syntax sugar does not require that, makes it harder to get this right. If the callbacks only occur while you make the pinvoke call into the native code, not uncommon (like EnumWindows), then you don't have to worry about it since the pinvoke marshaller ensures the delegate object stays referenced.
For the records: I have walked right into the trap, Hans Passant has mentioned. Forced garbage collection has led to a null reference exception because the delegate was transient:
KINInit(kinmem, myFunctor.SystemFunction, IntPtr.Zero);
// BTW: same with:
// KINInit(kinmem, new KINSysFn(myFunctor.SystemFunction), IntPtr.Zero);
GC.Collect();
GC.WaitForPendingFinalizers();
KINSol(/*...*); // BAAM! NullReferenceException
Luckily I had already wrapped the critical two P/Invokes, KINInit (which sets the callback delegate) and KINSolve (which actually uses the callback) into a dedicated managed class. The solution was, as already discussed, to keep the delegate referenced by a class member:
// ksf is a class member of delegate type KINSysFn that keeps ref to delegate instance
ksf = new KINSysFn(myFunctor.SystemFunction);
KINInit(kinmem, ksf, IntPtr.Zero);
GC.Collect();
GC.WaitForPendingFinalizers();
KINSol(/*...*);
Thanks again, Hans, I'd never have noticed this flaw because it works as long as no GC happens!

How to pass C# class object to managed c++ without unsafe modifier?

I am passing a C# object (PSObject) to managed C++ in the following way. But it crashes in the commented statement. Am I missing something?
Am I passing PSObject correctly to managed C++?
or am I accessing it wrongly?
I am using clr:oldsyntax.
Actually C# will pass a PSObject to managed C++,
in managed C++ I want to examine the properties present in PSObject. (An object returned by running PowerShell commands)
In C#, using delegate concept I am calling managed C++ method to pass PSObject.
The delegate is declared as below:
delegate bool CFuncDelegate(PSObject Arg);
funcObj (a IntPtr) is a pointer to addData function in C++ (I didn't write that code here, since it is not relevant) and I am calling addData in csharp as:
CFuncDelegate func = (CFuncDelegate)Marshal.GetDelegateForFunctionPointer(funcObj, typeof(CFuncDelegate));
bool isCompleted = func(psoObject); //psoObject is a PSObject
and in managed C++,
static bool __clrcall addData(System::Management::Automation::PSObject* curPsObj)
{
log(Marshal::StringToHGlobalUni(curPsObj->AdaptedMemberSetName));
//prints psadapted
System::Object* value = curPsObj->Properties->get_Item("DisplayName");
//crashes
}
It would be better if someone just post two lines of code to pass object from C# and accessing it in managed C++. Thanks in advance.
I think it's really time that you abandoned oldsyntax and moved to C++/CLI. Anyway, even doing that is not going to solve your problem. You define a delegate like this:
delegate bool CFuncDelegate(PSObject Arg);
And then you assign a delegate variable like this:
CFuncDelegate func = (CFuncDelegate)Marshal.GetDelegateForFunctionPointer(
funcObj, typeof(CFuncDelegate));
The documentation for Marshal.GetDelegateForFunctionPointer says:
Converts an unmanaged function pointer to a delegate.
So, your code can only work if funcObj is an unmanaged function. And your addData method is certainly not that. You need to stop using GetDelegateForFunctionPointer here. It is simply not compatible with calling the managed function addData.
I've no idea where funcObj comes from. You said:
funcObj (a IntPtr) is a pointer to addData function in cpp (i didnt write that code here, since it is not relevant)
In fact it is not only relevant to the problem, it is the root cause of the problem. What I would expect to see here would be for you to add the C++ assembly to your C# project as a reference, at which point addData could be referenced directly.
Of course, none of this even mentions the fact that your calling conventions are mis-matched. The managed code uses clrcall and your unmanaged function pointer is taken to be stdcall.
Update
There's some more information in the comments. Pass addData as a delegate. You'll need to declare the delegate type in the C# code which I believe you reference from your C++ assembly.

What C# datatype should I use to interface with unmanaged type "char* &sResult"

I am writing a C# code, and there is a code that needs calling an unmanaged C++ library.
The signature in the library's header is like this
bool GetValueFromFile(char* sPathToFile, char* &sResult);
What signature should I translate this in C#? I tried:
bool GetValueFromFile(string filePath, ref string result)
But it does not work. There is no exception and the return value is true. But the string result stays null. It is the same for out string result or StringBuilder result.
I use Marshal.GetDelegateForFunctionPointer to get the function pointer as delegate.
You can handle a reference to a pointer pretty much like a pointer to a pointer, at least as far as P/Invoke is concerned.
I think you will probably need to use an IntPtr for the sResult parameter, along with either Marshal.PtrToStringAnsi() or Marshal.PtrToStringAuto(), but it's a bit difficult to say without knowing whether the C/C++ function allocates the string memory or not.
If it works, you will probably still need to free the memory (after getting the string) using Marshal.FreeCoTaskMem() or Marshal.FreeHGlobal(), but again this is impossible to know for sure without knowing what the C/C++ function does.
NOTE: If using an IntPtr to get an output value, you will need to use out result or ref result.
You'll need to pass a pointer by reference. Assuming that sResult is passed from native to managed, i.e. that it has out semantics, here's the signature:
bool GetValueFromFile(string filePath, out IntPtr result);
Once you've called this you will need to convert it to a string:
IntPtr resultPtr;
if (GetValueFromFile(filePath, out resultPtr))
string result = Marshal.PtrToStringAnsi(resultPtr);
It's not clear who is responsible for freeing the memory that the native code allocates. Presumably that is documented somewhere and you already know how to handle that issue.

C# delegate with string reference to c++ callback

I wrote a C# application that uses an unmanaged c++ dll via managed c++ dll.
In the unmanaged dll, there's a callback that one of its params is std::string&.
I can't seem to find the right way to wrap this with the managed dll.
When I use String^, the callback works, but the C# application does not get anything in the string.
When I used String^%, things started to crash in other places that does not seem to be related (maybe memory corruption).
So my question is, what's the right way to do this?
Thanks
I can't copy-paste code here, but I'll try to explain again.
I can't use marshaling in the managed c++ section because I'm not calling a function, but passing a c# delegate for a callback.
In the unmanaged dll, I have a callback that requires a function like this: void Func(unsigned int, int, std:string &).
My goal is to pass a c# delegate from my program to that callback, so in the unmanaged code,
I made a delegate like this: delegate void DEL(unsigned int a, int b, String ^ c) and a function like: void mFunc(DEL ^ del), and that function marshal's the delegate into a cb that the unmanaged callback subscribe function accepts. The unsigned int and int works fine, but the string is always "" when the C# function is triggered.
Posting some code would help me understand better and give a better answer; but there is no automatic conversion or marshalling of String^ to std::string. You would need to do to marshalling yourself to get the string back to the C# code. A quick search can provide with details on how to do this.
http://msdn.microsoft.com/en-us/library/42zy2z41.aspx
I don't believe that the marshalling can deal with std::string. I think you need to make your own callback that passes char * and then write the glue code between the two.
Also, once the delegate is marshalled into a callback, that callback does not count as a reference to the object that the delegate might have been made from. So if the delegate is not a static method, you need to stuff it somewhere for the lifetime of the unmanaged callback.

Categories

Resources