【问题标题】:Complicated (?) pinvoke situation - avoid function overloading复杂的 (?) pinvoke 情况 - 避免函数重载
【发布时间】:2009-06-10 18:24:16
【问题描述】:

总结:

我有一堆必须从 C# 调用的 C 函数。我目前的工作解决方案基于函数重载,我想知道是否有更优雅的解决方案。

C 的东西:

头文件中的某处

typedef struct _unknown_stuff * handle; // a opaque pointer

函数示例

func( uint      num_entries,
      handle *  objects,
      uint *    n)
{ ... }

在 C 语言中,该函数的使用应该与此类似:

// warning: i bet that the syntax is not correct but you should get the idea...

uint n;

func(0, null, &n);

handle * objects = malloc(n * sizeof(handle));

func(n, objects, null);

C# 的东西:

现在我在 C# 中执行以下操作:

public struct handle
{
    public IntPtr Pointer;
}

// version to get number of objects
[DllImport(dll, ...]
private static extern void
func(  uint        must_be_zero,
       object      must_be_null,
       out uint    n);

// version to get the actual data
[DllImport(dll, ...]
private static extern void
func(   uint           num_entries,
        [Out] handle[] objects,
        int            must_be_zero);

然后:

handle[] objects;

uint n = 42;

func(0, null, out n);

objects = new handle[n];

func(n, objects, 0);

问题

由于我是 C# 菜鸟,我想知道这是否是最好的方法。特别是我想知道是否有办法重载函数。

【问题讨论】:

    标签: c# pinvoke dllimport


    【解决方案1】:

    首先,您的代码是错误的,因为在第二个 C# 签名中,您的第三个参数是 int,而对应的 C 参数仍然是 int*。它适用于 32 位 Windows,因为 sizeof(int)==sizeof(int*) 在那里 - 所以当你传递一个 0 int 时,你最终会传递一个空指针 - 但它不是 64 位安全的。如果你仍然想这样做,你需要在那里使用IntPtr

    除此之外,您还可以尝试:

    [DllImport(dll, ...]
    private static extern void func(
      uint num_entries,
      [Out] handle[] objects,
      [Out] int[] num_devices);
    

    使第三个参数成为一个数组,以便您可以在那里传递 null。

    或者只是使用指针。没有什么不好的,不要害怕 unsafe 关键字 - 无论如何,任何类型的 P/Invoke 本质上都是不安全的,所以你最好明确一点。

    【讨论】:

    • 好吧,现在我有点尴尬……不知道 C# 支持指针。使用指针似乎有效,感谢您的提示 :) 去图书馆寻找一本 C# 书
    【解决方案2】:

    C dll 不会看 0 并将其处理为 null 吗?

    它只有一个功能,对吗?也就是说,C 函数被定义一次,而不是为 null 情况单独定义,并且会有一个

    if( objects == NULL )
    检查那里的某处。在大多数系统上(检查目标系统的 stdio.h)这是 0。 所以在这个地方用 0 值从 pinvoke 调用应该做你想让重载做的事情。

    【讨论】:

    • 是的,你是对的,但是我在类型转换方面遇到了严重的问题,所以我决定重载这些方法。
    • 如果他使用第一个 C# 签名(其中第三个参数是 out),那么传递 0 将无济于事 - 他必须声明一个变量并为其分配 0,然后传递它是out,然后C函数将实际获取该变量的地址,其中包含0。如果他使用第二个签名,那么他可以传递 0(尽管我已经在上面解释了为什么这样做是错误的),但是他不能使用它来传递实际的 int 变量以用于需要检索值的情况。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-10
    • 1970-01-01
    • 1970-01-01
    • 2023-04-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多