PInvoke、指针和数组复制

发布于 2024-10-15 20:35:41 字数 690 浏览 2 评论 0原文

我们正在 c#、.net 4.0、Win7 x64 上构建一个应用程序,目标为 x32。

我们在我们的应用程序中使用第三方库。我们知道这个库是用C++编写的。然而,为了让 c# 开发人员使用这个库,他们使用 P/Invoke 对其进行了包装,这就是我们调用 API 函数的方式。

其中一个 API 调用如下:

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

该函数从外部设备读取 numBytes 数据并将其放入 data[] 中。正如您所看到的,它期望看到 C# 字节数组作为第三个参数。现在,我们的问题是,我们想将数据读取到预先声明的数组中的任意位置。例如:

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

如果我们使用 C/C++,这将是微不足道的。鉴于底层 API 是用 C++ 编写的,我觉得我们也应该能够在 C# 中做到这一点,但是,我不知道如何在 C# 中做到这一点。也许我们可以以某种方式不通过提供的 P/Invoke 接口来调用底层库并编写自定义接口?

任何想法将不胜感激。

问候,

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,

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

戏舞 2024-10-22 20:35:41

虽然这里的其他答案很接近,但没有一个是完全完整的。

首先,您只需声明您自己的 p/invoke 声明。这就是 p/invoke 的美妙之处;从来没有只有一种方法可以做到这一点。

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

现在你可以用它来调用它

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

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);
    }
}
岁吢 2024-10-22 20:35:41

您可以使用指针,但需要在检查不安全模式的情况下进行构建。

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

但首先您需要将导出的方法签名更改为。

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

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);
魂牵梦绕锁你心扉 2024-10-22 20:35:41

您仍然可以在 C# 中执行指针算术。

如果您重新声明 dll 导入(针对 C++ 库)以使用 IntPtr 来传递字节数组,则可以使用 Add 方法将其增加 350(这实际上返回一个新的 intptr)

这里有一个类似的示例: http://msdn.microsoft.com/en-我们/library/system.intptr.add.aspx#Y811

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

木緿 2024-10-22 20:35:41

就这么简单:

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#

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#
薄荷→糖丶微凉 2024-10-22 20:35:41

这个问题的解决方案似乎很明显。

虽然确实可以简单地创建自己的包装器类和 DllImport 并编写自己的包装器类,但解决方案更容易。

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

在您的帖子数据的上下文中是一个输出参数。因此,解决方案是向其发送一个适当大小的空字节数组,然后将填充的数组放入现有数组中。

您所要做的就是确定返回数组的大小(您事先知道该大小),然后填充并替换。

我会直截了当地告诉你,你使用现有数组的想法可能只有在你发送数组中特定元素的地址时才有效(这当然是可能的),但你仅限于 C++ 库实际期望的内容,这很可能只是 Byte 数组本身的地址。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文