如何使用 PInvoke 传递图像
我有一个 C DLL,它对图像进行一些处理并返回结果。因此,我尝试从 .NET 端传递图像,但现在我陷入困境,并且我不确定这是否与类型、编组的复杂性或语法有关。因为我是菜鸟,所以这三个都可能是。
我可以调用相关 DLL 中的其他函数,因此至少有一些基础已经就位。例如,当我调用:时
IntPtr versionIntPtr = GetDLLVersionNumber();
string version = Marshal.PtrToStringAnsi(versionIntPtr);
Console.WriteLine("DLL version number reported as: " + version);
,这绝对可以正常工作,将 DLL 的当前版本打印到控制台。
当我查看使用相同函数的 C 代码示例时,它似乎使用了如下函数:(
unsigned char* ExtractImageInfo(const char* pixels, size_t width, size_t height)
我还有一个头文件,其中提到了相同的函数,如下所示:
... ExtractImageInformation(struct ImageData image, void* imageInformation);
但我真的不知道这意味着什么。)
因此,我尝试使用此函数的过程如下:
首先,我指定 DLL 的接口:
[DllImport("C:\\MyDLL", EntryPoint = "ExtractImageInfo", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr ExtractImageInfo(IntPtr image, UInt32 imageWidth, UInt32 imageHeight);
然后,我获得正确类型的图像并获取其尺寸:
Bitmap bitmap1 = (Bitmap)Image.FromFile("C:\\Images\\myImage.bmp");
UInt32 _imageWidth = Convert.ToUInt32(bitmap1.Width);
UInt32 _imageHeight = Convert.ToUInt32(bitmap1.Height);
然后,我获得指向该图像的指针(因为我认为这就是我想要的)需要通过):
IntPtr bitmap1Ptr = bitmap1.GetHbitmap();
然后我调用该函数...
IntPtr myProcessedImage;
myProcessedImage = ExtractImageInfo(bitmap1Ptr, _imageWidth, _imageHeight);
但是它不起作用 - 我没有返回指向我处理过的数据的指针。我在这里想知道的很大一部分是我是否以正确的方式传递图像,以及我的本机函数接口的语法是否正确。我想这两个问题的答案可能都是“否”!
我只阅读和试验了 PInvoke 几天,所以如果有人能向我指出我的方法的错误,我将永远感激不已:-)
I have a C DLL which does some processing on an image and returns the result. So I am trying to pass an image over from the .NET side, but right now I am stuck, and I'm not sure whether that's on the types, the intricacies of marshaling, or syntax. Since I am a noob it could be all three.
I can call other functions in the DLL in question, so at least some of the foundations are in place. For example, when I call:
IntPtr versionIntPtr = GetDLLVersionNumber();
string version = Marshal.PtrToStringAnsi(versionIntPtr);
Console.WriteLine("DLL version number reported as: " + version);
and this works absolutely fine, printing the current version of the DLL to the console.
When I look at C code sample which uses the same function, it appears to use the function as follows:
unsigned char* ExtractImageInfo(const char* pixels, size_t width, size_t height)
(I also have a header file where the same function is mentioned as follows:
... ExtractImageInformation(struct ImageData image, void* imageInformation);
but I don't really know what this means.)
So my attempt to use this function goes as follows:
First I specify the interface to the DLL:
[DllImport("C:\\MyDLL", EntryPoint = "ExtractImageInfo", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr ExtractImageInfo(IntPtr image, UInt32 imageWidth, UInt32 imageHeight);
Then, I get an image of the right type and get its dimensions:
Bitmap bitmap1 = (Bitmap)Image.FromFile("C:\\Images\\myImage.bmp");
UInt32 _imageWidth = Convert.ToUInt32(bitmap1.Width);
UInt32 _imageHeight = Convert.ToUInt32(bitmap1.Height);
Then I get a pointer to the image (since I think that's what I need to pass):
IntPtr bitmap1Ptr = bitmap1.GetHbitmap();
And then I call the function...
IntPtr myProcessedImage;
myProcessedImage = ExtractImageInfo(bitmap1Ptr, _imageWidth, _imageHeight);
But it doesn't work - I don't get back a pointer to my processed data. A big part of what I'm wondering here is whether I am passing the image in the right way, and whether the syntax for my interface to the native function is right. I think probably the answer to both could be NO!
I've only had a few days of reading and experimenting with PInvoke, so if anyone can point out to me the error of my ways I will be eternally grateful :-)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
参数的名称强烈表明它需要一个指向原始像素数据的指针。您可以从 Bitmap.LockBits()、BitmapData.Scan0 属性中获取一个。在函数返回之前不要调用 UnlockBits()。
函数的返回类型是一个重要的内存管理问题。无论返回什么缓冲区指针,几乎肯定都必须释放。您无法从托管代码执行此操作,您无权访问此 C 代码使用的分配器来调用正确版本的 free()。调用此函数一百万次,并仔细检查是否存在失控的内存泄漏。如果这样做,则无法调用它,因此需要 C++/CLI 包装器,尽管它正常工作的可能性也相当小。这是一个设计不佳的函数,很难在任何代码(包括 C 代码)中使用。
The name of the argument strongly suggests it wants a pointer to the raw pixel data. You can get one from Bitmap.LockBits(), BitmapData.Scan0 property. Don't call UnlockBits() until the function returns.
The return type of the function is a significant memory management problem. Whatever buffer pointer is returned is almost certainly going to have to be released. You cannot do so from managed code, you don't have access to the allocator used by this C code to call the proper version of free(). Call this function a million times and double-check that you don't have an out-of-control memory leak. If you do then you can't pinvoke it, a C++/CLI wrapper is required although the odds that it works correctly are fairly slim as well. This is a poorly designed function that's hard to use from any code, including C.