Click to See Complete Forum and Search --> : How to get BYTE array allocated in Unmanaged DLL ???


sharong
January 4th, 2005, 06:41 AM
I’m using an unmanaged DLL wartime in C that exports the function:
void Get (BYTE** pByte);

This function fills the pByte with a BYTE buffer that is allocated inside the unmanaged DLL.


How do I use this function from a C# code?


I tried:

[DllImport("Unmanged.dll")]
public static extern void Get(out byte[] frame);


and


byte [] myByteArray = null ;
UnmangedDLL.Get(out myByteArray);

The trouble was that myByteArray returned with size of 1 while the unmanaged DLL set it to point byte array of 100 bytes.

darwen
January 4th, 2005, 08:16 AM
You can't. Or at least not easily.

Firstly, you don't know how big the byte array is.

Secondly, you always have to copy between unmanaged & managed memory and in this case it's impossible.

Returning pointers to memory allocated inside of DLLs like this is bad practice. You should always copy memory from the DLL into the calling code's memory.

You should also always include the size of the memory in the call.

Look at this thread : it shows you the correct way of passing memory between DLLs/client code.

http://www.codeguru.com/forum/showthread.php?p=1071912#post1071912

Now if you're really stuck and you can't change the method's definition then you can do this :


[DllImport("Unmanaged.dll")]
public static extern void Get(ref IntPtr rArray);

// in code
IntPtr pData = IntPtr.Zero;
UnmanagedDLL.Get(pData);

// here's where you need to know how big the array is !
int nSize = 200; // or how big it is

// we copy the memory into .NET memory
byte [] abData = new byte[nSize];
System.Runtime.InteropServices.Marshal.Copy(pData, abData, 0, nSize);


But again you need to know how much memory you need to copy.

Darwen.

sharong
January 4th, 2005, 08:47 AM
I must say it looks like it to me also as you said.

BUT, it’s making my work impossible.

I didn’t post the real code; I posted the minimum to make my question clear.

Allow me to describe the huge problem.

I developing a component for a project, this component should supply an API to developers and form the other hand it should interact with Frame Grabber.

The component will allocate a very large memory buffer (about 500 MByte or more) and pass it to the Frame Grabber by calling his unmanaged DLL (C code), the Frame Grabber takes frame and put them in the buffer one by one, each frame is 100 MByte.

The component should be able to point to each frame inside the buffer to prevent enormous memory copy of 100 MByte each time that is used many times.

Each frame (of 100 MByte) is then passed to image processing module (also unmanaged DLL in C) and to other managed component for display and something like that.

To fulfill all of these requirements I must mix managed and unmanaged code that will use same shared memory, I do not know how to do it in any other way unless I’ll drop the C# and move to C++ all together, and I must say that I hate the idea of dropping the C#.

Furthermore, I find it hard to believe that C# does not support this kind of things.

So if you have any kind of ideas, I’ll be more then happy to hear about it.

P.S. In the previous code I posted, the myByteArray does returns with the correct pointing, but it gets the size of only 1 element. Is there a way to tell him the size of it? Maybe through the DLL Importing using some kind of attribute???

darwen
January 4th, 2005, 10:41 AM
Why are you finding it hard to believe that C# doesn't support this ?

What you're doing is WRONG and bad programming practice.

.NET memory is garbage collected, C++ memory is not for starters.

And NO there's no way from a C++ pointer of determining the size of an array.

Secondly, I am really concerned that you feel it necessary to hold 500Mb of data in memory.

I really don't know what kind of specs your working to but that would mean that most XP machines will need at least 1024Mb of RAM otherwise your app is going to seriously slow down the machine.

You can get C# to interface with the frame grabber API directly : which is what I would do.

This would 'cut out the middle man' so to speak.

Although as I've said before I would seriously reconsider trying to allocate that amount of memory and see what optimisations you can do to bring the footprint down.

Darwen.

darwen
January 4th, 2005, 10:48 AM
You might be able to do this, but I'm not recommending it :


[DllImport("Unmanaged.dll")]
public static extern void Get(ref IntPtr pData);

unsafe public void Function()
{
IntPtr pData = IntPtr.Zero;
UnmanagedDLL.Get(ref pData);

fixed (byte *pbArray = (byte *)pData.ToPointer())
{
// do whatever
}
}


Darwen.

sharong
January 5th, 2005, 01:24 AM
I do agree with all you said, and believe me that I now it very well. I didn’t mention all of the requirements details as their are long and may be confusing.
Yet, I’ll try to clarify the issue.

The Frame Grabber must takes frame continually without me disturbing him, therefore I must give him a big buffer that can hold several frames, and each frame is in the size of 100 MByte.
The Frame Grabber interface given by an unmanaged DLL written in C.
The user of my component needs to work on a specific frame in that buffer. I do not allow the copy of the frame to prevent copying of hundreds of mega bytes (efficiently requirement).
As you can see, the user needs to use sub buffer of the allocated buffer.
As you can see, my code should interact with unmanaged code from one hand (Frame Grabber) and using managed C# for the other hand.
Furthermore, the supplied managed interface for the user need to use memory (point to) that was allocated by my managed code and currently used by unmanaged code (Frame Grabber).
The user takes this buffer (that is used by the unmanaged code) and use if for any king of reason.

Comment to user comments:
I do know the size of the buffer given to the user; it’s the size of a single frame the user in setting in the component initialization.

I find it hard to believe that C# doesn't support this because C# does support calling unmanaged code and passing it any kind of memory buffer.
C# class can hold data member as public so other users can use it – it’s like interfering with the class memory for outside.
And I find it hard to believe that Microsoft left some unhandled issues that the C# can not address, otherwise the assimilation of the language will be lesser then Microsoft may accept.

I’m not saying that the 500 MByte will be kept in memory, but please note that the project I’m developing will not be sold on CD, it will shipped to the customer installed on a complete system that will have any amount of necessary memory – Inspection System (Electro optic inspection system).

Cutting to the chase:
(a) Its known how to allocate buffer: byte [] byteBuff = new byte[10000...];
(b) Its known how to pass this buffer to the unmanaged DLL (Frame Grabber C code).
(c) I do not know how to give the user of my code/class sub buffer of the buffer allocated in section 1 above (also in managed C#).

So you see, the trouble is actually not with the managedßàunmanaged.
The trouble is how a class that holds byte buffer (byteBuff as shown in section 1 above) can have a method that return buffer ( of byte [] ) which is part of the bigger buffer byteBuff (as shown in section 1 above).
This method should look like: void GetFrame(int offset, out byte [] frame);

Any idea?

darwen
January 5th, 2005, 02:54 AM
I've already said you can't do this... and why you can't do this.

Yes, you can pass byte [] arrays INTO DllImported functions. Why ? Because the memory is 'pinned' first.

You can't do the reverse.

And no it's not a problem because for the third time - what you're doing is bad practice even in C++.

You're really barking up the wrong tree here. There's no point arguing with me about it. It's just the way that things are. You might as well argue for two hours about the fact the sky isn't pink with blue spots.

Darwen.