代码之家  ›  专栏  ›  技术社区  ›  Paul Sasik

将.net p/invoke代码组织到win32api的最佳实践

  •  12
  • Paul Sasik  · 技术社区  · 14 年前

    我正在重构.net中一个庞大而复杂的代码库,它大量使用了win32api的p/invoke。这个项目的结构不是最好的,我发现到处都是dllimport语句,经常为同一个函数重复,而且还以各种方式声明:

    import指令和方法有时声明为public,有时声明为private,有时声明为static,有时声明为instance方法。我担心重构可能会产生意想不到的后果,但这可能是不可避免的。

    是否有记录在案的最佳实践可以帮助我?

    我的建议是组织一个静态/共享win32 p/invoke api类,该类在一个文件中列出所有这些方法和相关常量… 编辑 有70多个导入到user32 dll。

    (代码库由20多个项目组成,包含大量windows消息传递和跨线程调用。这也是一个从vb6升级的vb.net项目,如果这有区别的话。)

    6 回复  |  直到 9 年前
        1
  •  5
  •   Hans Passant    9 年前

    您可能会考虑在.NET框架中执行此操作的方式。它总是声明一个名为nativemethods的静态类(vb.net中的模块),该类包含p/invoke声明。你可以比微软的程序员更有条理,有很多重复的声明。在框架的不同部分工作的不同团队。

    但是,如果要在所有项目中共享此声明,则必须将这些声明声明声明为public而不是friend。这不太好,它应该是一个实现细节。我认为可以通过在每个需要的项目中重新使用源代码文件来解决这个问题。通常是忌讳的,但在这种情况下,我想是可以的。

    我个人根据需要在需要它们的源代码文件中声明它们,使它们成为私有的。这也确实有助于在参数类型上撒谎,特别是对于sendmessage。

        2
  •  3
  •   Mark Brackett Achilles Ram Nakirekanti    14 年前

    把它们组织成 [Safe|Unsafe]NativeMethods class . 将类标记为 internal static . 如果需要将它们公开到自己的程序集,可以使用 InternalsVisibleTo -不过,如果可以将相关的分组到每个程序集中,则更为合适。

    每种方法都应该是 static -我真的不知道你甚至可以用 DllImport .

    作为第一步-我可能会将所有内容移动到核心程序集(如果有),或者创建 Product.Native 装配。然后,您可以轻松地找到重复和重叠,并查找托管的等效项。如果您的p/invoke是一团混乱,我不怀疑您在指导分组的其他程序集中有太多的分层方式。

        3
  •  2
  •   t0mm13b    14 年前

    为什么不创建一个名为win32.vb的单独文件,并在该文件中逻辑地将pinvokes分组到单独的名称空间中,例如,gdi名称空间可以使用所有gdi pinvokes,user32名称空间可以使用位于user32内核中的所有pinvokes,等等….起初可能会很痛苦,但在l东方你会有一个集中的名称空间所有包含在那个文件中?看一看 here 看看我的意思…你觉得呢?

        4
  •  2
  •   Polyfun MicBehrens    14 年前

    您的p/invoke调用是从vb6迁移的工件吗?我已经将300000行代码从vb6迁移到c(windows.forms和system.enterpriseservices),并消除了所有的p/invoke调用——几乎总是有一个托管的等价调用。如果你正在重构,你可能会考虑做一些类似的事情。生成的代码应该更容易维护。

        5
  •  2
  •   munissor    14 年前

    建议的方法是为每个程序集提供一个nativemethods类,其中包含所有dllimported方法,并具有内部可见性。以这种方式,您总是知道导入的函数在哪里,并避免重复声明。

        6
  •  2
  •   Mitchel Sellers    14 年前

    在这种情况下,我通常尝试做的是按照您所说的做,创建各种类,不管是静态的还是非静态的,它们提供了功能,这样就可以根据需要重用。根据调用的性质,我会回避静态类实现,但这将取决于您的特定实现。

    按要求在上面展开。

    考虑到p/invoke的性质,特别是如果需要很多调用,而且这些调用的实现领域各不相同,我发现最好将类似的项组合在一起,这样就不会造成很多其他混乱,或者在不需要时导入其他dll。

    想要远离静态方法,是因为对非托管资源的调用和潜在的内存泄漏等。