如何将void *转换为可以在C#中使用的类型? C DLL和C#之间的互操作性 [英] How to convert a void* to a type that can be used in C#? Interoperability between C DLL and C#

查看:186
本文介绍了如何将void *转换为可以在C#中使用的类型? C DLL和C#之间的互操作性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述





我是一名C / C ++程序员,但我被要求更新用C#编写的程序来与设备通信。我对C#的了解非常基础。之前的版本完全是用C#编写的,但现在实际访问该设备的API已更改为C.我发现我可以使用以下命令导入C函数API:



 [DllImport(myapi.dll)] 
public static extern int myfunct(
[MarshalAs(UnmanagedType.LPTStr)] string lpDeviceName,
IntPtr hpDevice);





在C中这个函数原型是:



 int myFunct(LPTStr lpDeviceName,HANDLE * hpDevice); 





其中HANDLE定义为:



 typedef void * HANDLE; 





但是这个功能没有按预期工作。事实上,在C#代码调用中我应该声明什么样的类型并传递给C#方法?



//稍后编辑我为假答案aplogize。 br />


我现在面临一个新问题。我有一个C结构,如:



 struct MyStruct 
{unsigned char * ptr;
int ptr_size;}





这个指针由C API函数填充值,因此在CI中只传递给函数一个足以容纳数据的缓冲区。

要将其转换为C#方式,我可以这样做:



 [ StructLayout(LayoutKind.Sequential)] 
public class MyStruct
{IntPtr ptr; //这是指向
int size的缓冲区的指针; //由C API填充值
}; //接下来我实例化itMyStruct ms = new MyStruct();







现在,奇怪的部分进来。我有一个简单的C#数组:



 byte [ ] RESET = new byte [] {0x00,0x00,0x80,0x00}; 





好​​的,现在ptr必须指向RESET,所以怎么可以这样做? Ptr需要保留它自己的地址....

非常感谢你的帮助!

解决方案

你的代码看起来好像是正确的,我怀疑问题更可能是你传递给C例程的参数的实际值。尝试使用调试器或添加一些日志代码来验证您的参数。


在我的(有限)经验中,这里有三个潜在的问题。



1.正如理查德建议的那样 - 你是否使用正确的参数值?特别是 hpdevice 。这是您之前从另一个非托管函数调用中检索的指针吗?如果没有,那可能是你的问题。



2.使用P / Invoke的字符串可能很麻烦。尝试使用 System.Text.StringBuider ,因为它内置了编组功能。

 [DllImport(< span class =code-string>  myapi.dll)] 
public static extern int myfunct(
StringBuilder lpDeviceName,
IntPtr hpDevice);





3.不太可能但是 hpDevice 应该是指针的指针?这种情况在C / C ++中很常见,并且有时会弄清楚正在发生的事情。


问题2



问题使用 byte [] 它是否可以在内存中移动。要停止,你需要固定RESET。请特别关注GCHandle结构:

GCHandle.Alloc(object,GCHandleType.Pinned)并且不要忘记使用

GCHandle.Free()完成后,获取指针

GCHandle.AddrOfPinnedObject ()

Hi,

I am a C/C++ programmer, but I was asked to update a program that was written in C# to communicate with a device. My knowledge of C# is very basic. The previous version was totally written in C#, but now the API that in fact access the device was changed to C. I found out that I can import the C function APIs by using:

[DllImport("myapi.dll")]
public static extern int myfunct( 
                                 [MarshalAs(UnmanagedType.LPTStr)] string lpDeviceName,
                                 IntPtr hpDevice);



In C this function prototype is:

int myFunct( LPTStr lpDeviceName, HANDLE* hpDevice );



Where HANDLE is defined as :

typedef void *HANDLE;



However this function does not work as expected. In fact, in the C# code call what kind of type I should declare and pass to the C# method?

// Later edit I aplogize for the fake answer.

I am facing a new problem now. I have a C structure like:

struct MyStruct
{  unsigned char* ptr;  
int ptr_size;}



This pointer filled with values by a C API function, thus in C I only pass to the function a buffer large enough to hold the data.
To convert this to C# way I can do:

[StructLayout(LayoutKind.Sequential)]
public class MyStruct
{  IntPtr ptr;// this is a pointer to a buffer that will  
   int size;  // be filled with values by the C API
};// Next I instantiate itMyStruct ms = new MyStruct();




Now, the odd part comes in. I have a simple C# array as :

byte[] RESET = new byte[]{ 0x00, 0x00, 0x80, 0x00};



OK, now ptr must point to RESET, so how could this be done? Ptr needs to hold the address it self....
Thanks a lot for the help!

解决方案

Well your code would appear to be correct, I suspect the problem is more likely to be with the actual values of the parameters that you are passing to the C routine. Try using the debugger or add some logging code to verify your parameters.


In my (limited) experience there are three potential issues here.

1. As Richard suggested - are you using correct values for the parameters? Particularly hpdevice. Is this a pointer that you have previously retrieved from another unmanaged function call? If not, that could be your issue.

2. Strings with P/Invoke can be troublesome. Try using a System.Text.StringBuider instead as it has built in marshalling capabilities.

[DllImport("myapi.dll")]
public static extern int myfunct(
    StringBuilder lpDeviceName,
    IntPtr hpDevice);



3. Unlikely but is hpDevice supposed to be a pointer to a pointer? This happens alot in C/C++ and it's a pain sometimes to work out what's going on.


To question 2


The problem with your byte[] is it can be moved around in memory. To stop that you would need to pin RESET. Have a look at the GCHandle structure inparticular:
GCHandle.Alloc(object, GCHandleType.Pinned) and DON'T FORGET to use
GCHandle.Free() when done with it, and to get the pointer
GCHandle.AddrOfPinnedObject().


这篇关于如何将void *转换为可以在C#中使用的类型? C DLL和C#之间的互操作性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆