3

我是一名 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# 方法?

感谢您的帮助,并对任何愚蠢的问题感到抱歉。

4

2 回答 2

4

实际上,这是错误的编组方式HANDLE *。它会起作用,但在遇到异常时并不可靠。

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

编组它的正确方法取决于它正在创建的对象类型以及它是如何关闭的。假设HANDLE是通过调用关闭的CloseHandle(对于大多数但不是所有 HANDLE对象都是如此),那么您可能可以使用继承自SafeHandleZeroOrMinusOneIsInvalid. 例如,如果对象是注册表项,则使用SafeRegistryHandle; 如果是文件,则使用SafeFileHandle.

如果它是某种类型,没有现有的安全句柄类型(但确实用于CloseHandle关闭它),那么您必须定义自己的安全句柄类型,从SafeHandleZeroOrMinusOneIsInvalid. 如果它是某种不CloseHandle用于关闭它的类型,那么您必须定义自己的安全句柄类型,该类型从SafeHandle.

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

[DllImport("myapi.dll")]
public static extern int myFunct(
    [MarshalAs(UnmanagedType.LPTStr)] string lpDeviceName,
    out SafeFileHandle hpDevice);
于 2010-07-16T13:04:38.497 回答
1

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

[DllImport("myapi.dll")]
public static extern int myfunct( 
    [MarshalAs(UnmanagedType.LPTStr)] string lpDeviceName,
    ref IntPtr hpDevice);
于 2010-07-16T13:00:58.937 回答