如何将void*转换为可在C#中使用的类型?C-DLL与C的互操作性#

如何将void*转换为可在C#中使用的类型?C-DLL与C的互操作性#,c#,c++,dll,interop,void-pointers,C#,C++,Dll,Interop,Void Pointers,我是一名C/C++程序员,但我被要求更新一个用C#编写的程序,以便与设备通信。我的C#知识非常基础 以前的版本完全是用C#编写的,但现在实际上访问设备的API改为C。我发现我可以使用以下方法导入C函数API: [DllImport("myapi.dll")] public static extern int myfunct( [MarshalAs(UnmanagedType.LPTStr)] string lpDeviceNam

我是一名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 );
其中,句柄定义为:

typedef void *HANDLE;
但是,此功能无法按预期工作。事实上,在C#代码调用中,我应该声明并传递给C#方法的类型是什么


感谢您的帮助,对于任何愚蠢的问题,我深表歉意。

您传递的是IntPtr而不是ref IntPtr,定义应如下所示:

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

实际上,这是编组
句柄*
的错误方法。它可以工作,但在异常情况下不可靠

您发布的函数看起来像一个对象创建函数(它将
hpDevice
视为输出参数,并返回
int
状态结果)

封送它的正确方式取决于它创建的对象的类型和关闭方式。假设通过调用
CloseHandle
关闭
HANDLE
(对于大多数但并非所有
HANDLE
对象都是如此),则您可能可以使用继承自的类型之一。例如,如果对象是注册表项,则使用;如果是文件,则使用

如果某个类型没有现有的安全句柄类型(但确实使用了
CloseHandle
来关闭它),那么您必须定义从
safehandlezerorminusoneisinvalid
派生的自己的安全句柄类型。如果某个类型不使用
CloseHandle
来关闭它,那么您必须定义自己从
SafeHandle
派生的安全句柄类型

一旦确定了正确的
SafeHandle
派生类型,就可以在函数调用中使用它(以
SafeFileHandle
为例):


这是将句柄类型编组为CLR类型的正确方法。你的代码肯定有其他问题。你能告诉我们更多的细节吗?我同意维勒的观点。显示您从哪里获得通过的
hpDevice
。通常,我希望它来自同一库中的另一个函数;使用IntPtr.Zero作为默认值。但一般来说,您不会手动设置句柄-它们将由创建句柄的其他函数返回。除非这是设置句柄的函数,在这种情况下,传递
ref IntPtr
作为类型。我必须简单地将其声明为HANDLE myHandle,并将其作为类似于myfunc(&myHandle)的指针传递给函数。我尝试过这一点,但它编译的结果并不正常。此句柄用于连接到串行端口的设备,当我用C编写应用程序时,我刚刚将其声明为“HANDLE myHandle”,并将其地址传递给函数,在API中,此句柄已初始化。我也尝试过使用ref-InPtr,但没有任何运气。句柄是串行端口,还是用作连接到串行端口的“设备”的不透明句柄<代码>安全文件句柄只能在句柄是串行端口本身而不是不透明设备句柄时使用。另一个需要检查的是错误匹配:C++默认值是“代码> CDECL < /Cord>,C默认值是代码> STDCALL> /CODE。我没有办法知道如何使用这个句柄,第三方API只是简单地说,当调用这个函数时,它们会“封装串行或USB连接”。正如我所说,我在尝试将其集成到C#项目之前做了一个测试,我所需要做的就是将句柄声明为句柄h,并将其地址传递给函数,它只是返回了正确的句柄,没有任何抱怨。好吧,C#比这更安全。这就是为什么它不是那么简单的原因。:)即使您不知道
句柄
指的是什么,您也应该能够知道它是如何“关闭”的。您必须调用什么函数来关闭句柄;事实上,您的解决方案部分是正确的,我在另一个论坛上了解到,传递StringBuilder而不是编组LPTStr更好。这项工作只是使用StringBuilder而不是那样编组的字符串。
[DllImport("myapi.dll")]
public static extern int myFunct(
    [MarshalAs(UnmanagedType.LPTStr)] string lpDeviceName,
    out SafeFileHandle hpDevice);