如何制作 PInvoke 友好的本机 API?

发布于 2024-08-19 02:49:57 字数 874 浏览 2 评论 0原文

如何使原生 API 对 PInvoke 友好?

此处提供了一些有关如何修改与 P/Invoke 一起使用的本机程序的提示。但在我编写本机程序之前,我应该注意哪些事项才能使我的程序/库 PInvoke 友好?

使用 C 或 C++ 都可以。


update:
if I write a C API, what are the things I have to do so that It is P/Invoke-able using C# syntax like the following:

[DLLimport("MyDLL.dll")]

是否可以对本机 C++ 代码/库执行相同操作?


Summary/Rephrase of Some Tips to make a P/Invoke friendly native-API:
+ the parameters should be of native types (int, char*, float, ...)
+ less parameters is better
+ if dynamic memory is allocated and passed to managed code, make sure to create a "cleaner" function which is also p/invoked
+ provide samples and/or unit tests that illustrate how to call the API from .NET
+ provide C++/CLI wrapper

How to make a native API to be PInvoke friendly?

there are some tips on how to modify native-programs to be used with P/Invoke here. But before I even write a native programs, what are the things I should look out to make my programs/library PInvoke friendly?

using C or C++ are fine.


update:
if I write a C API, what are the things I have to do so that It is P/Invoke-able using C# syntax like the following:

[DLLimport("MyDLL.dll")]

is it possible to do the same with native C++ code/library?


Summary/Rephrase of Some Tips to make a P/Invoke friendly native-API:
+ the parameters should be of native types (int, char*, float, ...)
+ less parameters is better
+ if dynamic memory is allocated and passed to managed code, make sure to create a "cleaner" function which is also p/invoked
+ provide samples and/or unit tests that illustrate how to call the API from .NET
+ provide C++/CLI wrapper

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

脸赞 2024-08-26 02:49:57

如果您自己控制本机库,则可以编写一组包装本机调用的 C++/CLI 类,而不是使用 P/Invoke。在许多情况下,这比使用平台调用的性能更好,并且您可以获得类型正确性的额外好处。例如,如果您有如下所示的某种 C API(它没有做任何有用的事情,我只是添加了指针和结构来强化它是本机代码的事实):

struct SomeStruct {
  int a, b;
  int* somePtr;
};

int foo(struct SomeStruct* a, int b) {
  *a->somePtr = a->a + a->b;
  return a->b * *a->somePtr + b;
}

您可以创建一个 C++/CLI 类来包装它:

public ref class MyNativeAPI {
  private:
    SomeStruct* x;
  public:
    MyNativeAPI() {
      x = new SomeStruct;
    }  
    ~MyNativeAPI() {
      delete x;
    }
    int Foo(int a) {
      pin_ptr<SomeStruct*> ptr = this->x;
      return foo(ptr, a);
    }
}

然后,您可以在 C# 中调用它:

MyNativeAPI a = new MyNativeAPI();
if(a.Foo(5) > 5) { ... };

您必须阅读有关 C++/CLI 的更多内容,以了解对托管堆和本机堆的新控制,以及混合两者的注意事项(例如 < code>pin_ptr 我在上面使用过),但总的来说,它是在 .NET 中实现本机互操作的更优雅的解决方案。

Instead of using P/Invoke, if you are controlling the native library yourself, you can write a set of C++/CLI classes that wrap the native calls. In many cases, this will perform better than using platform invoke, and you get the added benefit of type correctness. For example, if you have some sort of C API like the following (it doesn't do anything useful, I just added pointers and structs to reinforce the fact that it is native code):

struct SomeStruct {
  int a, b;
  int* somePtr;
};

int foo(struct SomeStruct* a, int b) {
  *a->somePtr = a->a + a->b;
  return a->b * *a->somePtr + b;
}

You can create a C++/CLI class to wrap it:

public ref class MyNativeAPI {
  private:
    SomeStruct* x;
  public:
    MyNativeAPI() {
      x = new SomeStruct;
    }  
    ~MyNativeAPI() {
      delete x;
    }
    int Foo(int a) {
      pin_ptr<SomeStruct*> ptr = this->x;
      return foo(ptr, a);
    }
}

Then, you can call this in C#:

MyNativeAPI a = new MyNativeAPI();
if(a.Foo(5) > 5) { ... };

You'll have to read more on C++/CLI to understand the new controls you have over both the managed heap and the native heap, and the caveats to mixing the two (like the pin_ptr I used above), but overall it's a much more elegant solution to accomplishing native interop in .NET.

染柒℉ 2024-08-26 02:49:57

根据定义,每个本机函数都可以从托管代码中 p/调用。但为了 p/invoke 友好,函数应该具有尽可能少的参数,这些参数应该是本机类型(int、char*、float,...)。此外,如果函数在返回到托管代码的某个指针上分配内存,请确保编写其对应部分来释放该指针,因为托管代码无法释放从非托管代码分配的内存。

By definition every native function can be p/invoked from managed code. But in order to be p/invoke friendly a function should have as few parameters as possible which should be of native types (int, char*, float, ...). Also if a function allocates memory on some pointer that is returned to managed code, make sure you write its counter part that will free the pointer as managed code cannot free memory allocated from unmanaged code.

泛泛之交 2024-08-26 02:49:57

提供一个从 C# 或 .NET 正确调用它的示例,最好提供一个包装所有方法的 .NET 类

使用 nunit 编写简单的单元测试
证明你的代码工作正常
当从 .Net 调用时会很棒
这样做的方法。

另请记住,可能调用您的代码的 .NET 开发人员不太可能了解 C++,或者不知道不同数据类型的大小等,也不知道这些类型如何映射到 PInvoke 属性。

首先考虑一下您希望客户代码的外观,然后设计一个允许它的 API。

Provide an example of correctly calling it from C# or .NET, even better provide a .NET class that wraps all your methods

Writing a simple unit test with nunit
that proves your code works correctly
when called from .Net would be a great
way of doing it.

Also remember that the .NET developers that are likely to be calling your code are unlikely to know much about C++, or don’t know the sizes of different data types etc or how these types map to the PInvoke attributes.

Above all think about how you wish your clients code to look and then design a API that allows it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文