【问题标题】:Why Microsoft not provide for C# a static Win32 class with the most native functions and structures inside like windows.h?为什么微软不为 C# 提供一个静态 Win32 类,其中包含最原生的函数和结构,如 windows.h?
【发布时间】:2010-05-28 02:31:30
【问题描述】:

使用过 Windows API 的 P/Invoke 的每个人都知道一长串具有如下属性的静态函数声明

 [DllImport ("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]

从 WinNT.h 等 Windows 头文件或 www.pinvoke.net 等网站复制的结构声明在我们的程序中也占据了很多位置。

为什么我们都必须为此花时间?为什么微软不给我们一个简单的方法来在旧的非托管程序中包含一行

#include <windows.h>

我们将可以访问一个静态类Native,其中包含所有或大多数 Windows 函数和结构?

更新基于一些答案:

您对自己诚实一点,您的 .NET 程序的哪一部分不是在 Windows 下运行的? 5%? 1%?如果您在 .NET 中使用 WMIProcessRegistryServiceProcess.ServiceBase 类等,那么您的程序就是“平台无关”和更多“兼容”如果您不使用原生 API? Thread.ApartmentState 是否在 Windows 之外无处不在?

使用SafeHandletry {…} finally 是有必要的。我很乐意有任何这些形式的 Native API 的标准定义。

我知道windows.h 中的某些结构具有不同的版本 32/64 或 XP/Vista 等。我认为拥有不同版本的 Native 结构就足够了,例如 MIB_IPADDRROW_XPMIB_IPADDRROW_W2KIMAGE_NT_HEADERS32IMAGE_NT_HEADERS64(请参阅 Windows 标题中的相同名称)。

如果存在托管.NET 类和方法,则应该使用它。遗憾的是,Windows 的一些最强大的功能在托管 .NET 中的实现为时已晚,而且到目前为止,很多功能只能在非托管世界中访问。 10 年前,在第一次关于 .NET 的 Microsoft 会议上,我询问了我对 Memory Mapped Files 的青睐。现在只有 .NET 4 实现了 MemoryMappedFile 类(请参阅 http://blogs.msdn.com/salvapatuel/archive/2009/06/08/working-with-memory-mapped-files-in-net-4.aspx)。如果为了管理目的而编写实用程序,同样的问题会永久存在。例如,用CreateFile 和标志FILE_FLAG_BACKUP_SEMANTICSRegCreateKeyExREG_OPTION_BACKUP_RESTOREREG_OPTION_CREATE_LINK 打开文件。 硬链接Junctions(参见http://msdn.microsoft.com/en-us/library/aa365006(v=VS.85).aspx)是下一个示例。再举一个例子:使用 Job Objects 而不是 Process(参见 http://msdn.microsoft.com/en-us/library/ms684161(VS.85).aspxhttp://www.microsoft.com/msj/0399/jobkernelobj/jobkernelobj.aspx)。如果你想启动一个进程并等到这个进程,还要等到它的所有子进程结束,job 是非常有用的。可以使用CreateJobObjectAssignProcessToJobObject,然后使用TerminateJobObjectWaitHandle,例如.NET 版本的(WaitForSingleObject)。

仅在 .NET 4.0 System.IntPtrSystem.UIntPtr 类中支持 AddSubtract 方法。

我可以继续这些例子,但我希望你明白我的意思。所以我想用 .NET 编写一个程序,因为它有很多优点,但我并不总是可以在不使用本机 API 的情况下做到这一点。此外,有时客户对软件实现的语言有要求,我会选择需要的方式。

更新 2:Microsoft 改进了与 .NET 4.0 中的 COM 的互操作性,但没有改进与 C 类 Windows API 的互操作性。我看到了一些使使用 P/Invoke 更容易的方法。你看有什么办法做到这一点?我建议我看到的三个方向:

  1. 使用声明所有(或最重要的)尚未在 .NET Windows API 中完全实现的程序集。这个汇编只能(或几乎只有)具有静态函数和相应类/结构的静态 Native 类的元数据。这个程序集可以放在 GAC 中,每个人都可以使用它。 (这种方式我测试过。效果很好。)
  2. 实现了一组 sn-ps,其中包含使用不同原生 Windows API 的声明和示例。
  3. 在 www.codeplex.com 上启动一个开源项目,在该项目中创建 .NET 类和一些最重要的本机 Windows API 的扩展方法,这些 API 尚未在 .NET 中实现。

我确信存在更多方法可以让开发人员更轻松地使用本机 Windows API。欢迎提出其他建议。

【问题讨论】:

    标签: c# .net windows interop pinvoke


    【解决方案1】:

    我不知道为什么 MSFT 会做出这个决定,但以下是我认为这个决定是正确的几个原因:

    • Windows SDK 头文件 (windows.h 等) 广泛使用基于目标 Windows 版本和体系结构的条件编译来确定要声明的函数以及数据结构的布局方式。这在任何 .NET 语言中都不可能实现,因为它不针对 Windows 版本,而是针对框架版本,生成的二进制文件能够在 Windows 的许多版本和版本的 32 位和 64 位架构上本地运行

    • 许多 Windows API 调用和数据结构无法通过 P/Invoke 完全表达。立即想到的是DeviceIoControl。另一个是许多所谓的“可变长度”结构,其中包含具有未知(在编译时)数量的元素的数组

    • P/Invoke 随着时间的推移不断发展,特别是在暴露句柄的方式上(在框架的早期版本中为IntPtr;在以后的类中为SafeHandle);如果 MSFT 维护一个包含大多数或所有 Win32 API 函数的静态类,他们也有义务保持与此类的先前版本的兼容性,将自己锁定在 P/Invoke 最初实现的方式中

    • 甚至 MSFT 本身也不在框架内部维护单个 Native 类。现在 .NET Framework 3.5 源代码可用,您可以亲自了解 P/Invoke 的临时使用情况,即使在我们应该用来代替 P/Invoke 的框架内也是如此。例如,System.Net 和 System.IO 有自己独立的 P/Invoke 声明。

    • .NET Framework 和托管代码从一开始就被设计为一种为 Windows 构建软件的新方法。提供这种新方式,同时又要求在许多任务中使用旧方式,这有多愚蠢?

    我这样说是因为我广泛使用 P/Invoke 来处理 IOCTL 和卷级 I/O 操作。我使用 P/Invoke 的次数越多,我就越讨厌它。它很难使用,容易出错,而且速度很慢。每次我使用 P/Invoke 时,都是因为我已经用尽了所有其他选项。如果您发现自己遇到的问题需要大量直接 Windows API 调用才能解决,您可能:

    a) 框架中缺少一些可以满足您需求的功能

    b) 正在采取错误的方法来解决问题,特别是如果您习惯了原生 Windows API 并且仍然以这些术语思考

    c) 应该用 C++/CLI 编写你的低级代码,并为你的 .NET 代码提供大块的高级接口来使用

    【讨论】:

    • 我认为我从来没有在没有 P/Invoke 的情况下编写过 .Net 程序。
    • 那你有我的同情 ;)
    • 抱歉,DeviceIoControl 有误。您当然可以使用DeviceIoControl 函数与设备驱动程序直接通信。如果您愿意,我可以向您发布一个工作示例,您可以自己查看。但是我对我的问题想要什么有误解。请阅读问题的“更新 2”。
    • 我没有声称 DevioceIoControl 不能与 P/Invoke 一起使用,但我确实声称您不能生成一个适用于所有各种输入的 DeviceIoControl P/Invoke 声明并在不手动调用编组器的情况下输出数据结构。对于许多非常复杂的数据结构,我已经成功地 P/Invoke'd DeviceIoControl,但只需将输入和输出缓冲区声明为 IntPtr,您就可以手动编组输入和输出。当然,您可以创建一个功能更多的包装类,但这不是最初的目的。
    • 我只想补充一点,我并不是说使用 P/Invoke 没有任何价值,或者框架是如此完整,以至于 P/Invoke 是没有必要的。听起来你和我用 C# 做类似的低级工作,所以我们一直需要 P/Invoke。但是,我敢打赌,至少 80% 的 .NET 程序员(可能更多)从不需要 P/Invoke 方法,因此 MSFT 将努力为需要它的 20%(可能更少)改进 P/Invoke .对于我最喜欢的所有 Win32 API 调用,具有经过测试声明的开源 P/Invoke 项目会很棒。如果它存在,我会使用它。
    【解决方案2】:

    我相信你的脑海里闪过这个想法,但我认为应该有一个开源项目可以做到这一点。 与其等待 Microsoft 来做这件事,我们可以收集那些日复一日实际使用 P/Invoke 的人的所有知识,这样其他人就不必重新发明轮子。

    在人们使用和需要 API 时继续收集它们。

    有志愿者吗? :)

    pinvoke.net 不算数 - 它不容易插入您的解决方案。

    【讨论】:

      【解决方案3】:

      一种观点认为 PInvoke 是一种兼容性拐杖。您应该使用 100% 的 .Net 库和函数,而不是“旧版”Win32 调用。

      【讨论】:

      • 出于某种原因,每当我需要做一些特别的事情时(这种情况经常发生),我最终都会使用“旧版”Win32 调用来实现魔法。在我写这篇文章时,我正在研究如何让我的 WPF 窗口像 winamp 一样具有粘性……希望 .net 库为我做到这一点。
      猜你喜欢
      • 1970-01-01
      • 2017-03-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-20
      • 1970-01-01
      • 2011-10-21
      • 2019-09-04
      相关资源
      最近更新 更多