简体   繁体   中英

PInvoke, pointers and array copy

We're building an application on c#, .net 4.0, on Win7 x64, targeting x32.

We are using a 3rd party library in our application. We understand that this library is written using C++. However, to let c# developers use this library, they've wrapped it using P/Invoke, so that's how we call the API functions.

One of the API calls is as follows:

ReadFromDevice(int deviceAddress, int numBytes, Byte[] data);

This function reads numBytes of data from an external device and places it in data[]. As you can see, it expects to see a C# Byte array as the 3rd argument. Now, our problem is, we would like to read data to an arbitrary location in a predeclared array. For example:

Byte[] myData = new Byte[1024*1024*16];
ReadFromDevice(0x100, 20000, &myData[350]) // Obviously not possible in C#

If we were using C/C++, this would be trivial. Given that the underlying API is written in C++, I feel that we should be able to do this in c# as well, however, I can't figure out how to do this in c#. Maybe we can somehow call the underlying library not through the supplied P/Invoke interface and write a custom interface?

Any ideas would be appreciated.

Regards,

You can use pointers but requires to build with unsafe mode checked.

Byte[] myData = new Byte[1024*1024*16];
fixed( Byte * pB = &myData[350])
{
   ReadFromDevice(0x100, 20000,pB  ) 
} 

But first you need to change the exported method signature to.

ReadFromDevice(int deviceAddress, int numBytes, Byte * data);

While the other answers here are close, none are quite complete.

First you simply need to declare your own p/invoke declaration. This is the sweet thing about p/invoke; There's never just one way to do it.

[DllImport("whatever.dll")]
unsafe extern static void ReadFromDevice(int deviceAddress, int numBytes, byte* data);

Now you can call it with

unsafe static void ReadFromDevice(int deviceAddress, byte[] data, int offset, int numBytes)
{
    fixed (byte* p = data)
    {
        ReadFromDevice(deviceAddress, numBytes, p + offset);
    }
}

You are still able to perform pointer arithmetic in c#.

If you re-declare you dll import (against the C++ library) to use an IntPtr to pass the byte array , this can be incremented by 350 using the Add method (This actually returns a new intptr)

There is an example of something similar here: http://msdn.microsoft.com/en-us/library/system.intptr.add.aspx#Y811

As easy as this:

ReadFromDevice(int deviceAddress, int numBytes, ref byte data);

...


Byte[] myData = new Byte[1024*1024*16];
ReadFromDevice(0x100, 20000, ref myData[350]) // Obviously possible in C#

The solution to this problem seems sort of obvious.

While it is true you could simply make your own wrapper class and DllImport and write your own wrapper class the solution is easier then that.

ReadFromDevice(int deviceAddress, int numBytes, Byte[] data); 

In the context of your post data is an output paramater. So the solution would be to send it an empty Byte array of the appropriate size then place filled array into your existing array.

All you have to do is determine the size of the returned array, which you knew before hand, then fill and replace.

I will just flat out and tell you that your idea of using an existing array would likely only work if you sent the address of the specfic element within the array ( which certianly is possible ) but your limited to what the C++ library actually expects which likely is just the address of the Byte array itself.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM