Click here to Skip to main content
15,036,145 members
Please Sign up or sign in to vote.
4.67/5 (3 votes)
I don't find some golden rules to handle a byte array of unmanaged Code from a dll in a C# application.
The more I read on different webpages, the more confused I became.

I would like to get a databyte-array given by a pointer (and another parameter which contains the length of the data array) within a DLL's callback function.
I got an unmanaged "C++" - DLL with a stdcall C-Wrapper-Interface.

The following line is the prototype declaration of the callback function in the header file:

typedef void (__stdcall *PFN_DATACALLBACK)(const tByte*, const tWord);

I specified a delegate and announced the Callback function of the DLL in the following way:

public delegate void PFN_DATACALLBACK([MarshalAs(UnmanagedType.LPArray)] byte[] data, Int16 length);  

[DllImport("MyDll.dll", CallingConvention = CallingConvention.StdCall),AllowReversePInvokeCalls]
  
public static extern void FUNC_DataReceived(PFN_DATACALLBACK MyCallback);


I tried several ways with IntPtr, with Stringbuilder, with different Marshalling mechanisms, but I didn't get it to work. The code above was my latest try.

At least I can put out the length of the data array.
But I don't know to pass the byte-array in a proper way to my higher design levels.

I got a lot of questions so far, and here I put some of them to show how confusing the stuff seems to me:
a) Did I take the right direction or am I completely wrong with my approach above ?
b) Which datatype could be the best to use for that ?
c) When do I have to use Marshal.copy instead of MarshalAs ?
d) I saw an example where the UnmanagedType.FctPointer was used for a data array. What is the idea behind that ?
e) I tried to use the AllowReversePInvokeCalls argument, even though I don't know if I necessarily have to use it for Callback functions and call-by-ref parameters.
f) Does it make sense to get rid off the byte array approach and use a string instead ?

To me it seems that there are many combinations to put it all together to make it work, but I didn't find the right one yet. Is there any simple way to do it ?
Posted
Comments
R. Hoffmann 24-May-11 15:02pm
   
Wow, a descriptive title, decent amount of info in the question, details of what has been tried already, clear questions in the end.. Oh, *and* the question is tagged nicely. Unfortunately I'm not able to help you with your queries, but I just want to say well done on formulating the question! It's so refreshing to come across something like this :)
Mr Nukealizer 25-May-11 22:58pm
   
Yeah same. I know almost nothing about managed code as the only language I use is C++, but 5* for a readable question.

1 solution

OK. Even I don't know if it is the best way, with the help of a colleague of mine I have got a solution, or at least a work-around.
I was not able to find answers to all of my questions, but there is some little progress in understanding the stuff.

I used an IntPtr to pass on the byte arraypointer, so the delegate definition is as follows:
public delegate void PFN_DATACALLBACK(IntPtr data, Int16 length);


The DLLImport section works as defined previously.

The Marshalling takes place in my Event (Callback) - Handler:

private static void MyCallback(IntPtr data, Int16 length)
{
            var rxbytes = new byte[length];
            Marshal.Copy(data, rxbytes, 0, length);
            DataEvent.Invoke(rxbytes);
}


The approach of using a string could lead to more or less severe troubles due to the string termination NULL characters (0x00, '\0'), which occasionally occur as usual data bytes.

However, it works, if somebody has got a more elegant solution, please don't hesitate to post it.
   

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)




CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900