C# Marshal2024 年 8 月 29 日 | 5 分钟阅读 引言C# Marshal 是 .NET 框架提供的一项功能,它实现了托管代码和非托管代码之间的互操作。它允许托管代码访问非托管资源,例如本地库、COM 对象和 Win32 API。Marshal 类提供了一组方法来促进这种互操作。 在本文中,我们将深入探讨 C# Marshal 功能、其用法以及 Marshal 类提供的各种方法。 C# Marshal 概述C# Marshal 是一项实现托管代码和非托管代码之间通信的功能。非托管代码可以用 C++、Delphi 或任何其他编译成原生代码的语言编写。托管代码可以用 C#、VB.NET 或任何其他针对 .NET 框架的语言编写。 .NET 框架提供了一个运行时环境,用于管理托管代码的执行。该运行时提供了一个抽象层,使托管代码免受底层硬件和操作系统的影响。这种抽象提供了几个优点,例如自动内存管理、异常处理和跨平台兼容性。 然而,有时托管代码需要访问非托管资源,例如本地库、COM 对象和 Win32 API。例如,C# 应用程序可能需要调用一个 C++ 库,该库提供 .NET 中不可用的某些功能。在这种情况下,C# Marshal 功能就派上用场了。 C# Marshal 功能提供的方法允许托管代码与非托管资源进行交互。这些方法允许在托管和非托管代码之间封送数据、分配非托管内存以及调用非托管函数。 封送数据封送数据是在托管代码和非托管代码之间转换数据的过程。调用非托管函数时,作为参数传递的数据必须是非托管函数能够理解的格式。同样,从非托管函数接收数据时,必须将数据转换为托管代码可以理解的格式。 Marshal 类提供的方法可促进托管代码和非托管代码之间的数据封送。一些常用的方法是 Marshal.StructureToPtrMarshal.StructureToPtr 方法将托管结构的内容复制到非托管内存块中。当调用需要结构指针作为参数的非托管函数时,此方法非常有用。 以下是使用 Marshal.StructureToPtr 方法的示例 C# 代码 在此示例中,我们定义了一个名为 MyStruct 的托管结构。然后,我们定义了一个名为 MyFunction 的非托管函数,它接受 MyStruct 的指针作为参数。在 Main 方法中,我们创建 MyStruct 的一个实例并初始化其字段。然后,我们使用 Marshal.AllocHGlobal 方法分配一个非托管内存块,并使用 Marshal.StructureToPtr 方法将 myStruct 的内容复制到已分配的内存块中。最后,我们调用 MyFunction 方法,并将已分配的内存块作为参数传递。函数调用后,我们使用 Marshal.FreeHGlobal 方法释放已分配的内存块。 Marshal.PtrToStructureMarshal.PtrToStructure 方法将非托管内存块的内容复制到托管结构中。当接收来自返回结构指针的非托管函数的数据时,此方法非常有用。 以下是使用 Marshal.PtrToStructure 方法的示例 C# 代码 在此示例中,我们定义了一个名为 MyStruct 的托管结构。然后,我们定义了一个名为 MyFunction 的非托管函数,它返回 MyStruct 的指针。在 Main 方法中,我们调用 MyFunction 方法,该方法返回包含 MyStruct 的非托管内存块的指针。然后,我们使用 Marshal.PtrToStructure 方法将非托管内存块的内容复制到 MyStruct 的托管实例中。最后,我们打印 MyStruct 实例的 x 和 y 字段的值。 分配非托管内存 Marshal 类还提供用于分配和释放非托管内存的方法。当处理需要由托管代码操作的非托管数据时,这些方法非常有用。 Marshal.AllocHGlobal Marshal.AllocHGlobal 方法分配指定大小的非托管内存块。此方法返回已分配内存块的指针。 以下是使用 Marshal.AllocHGlobal 方法的示例 C# 代码 在此示例中,我们使用 Marshal.AllocHGlobal 方法分配一个大小为 1024 字节的非托管内存块。然后,我们使用已分配的内存块执行某些操作。最后,我们使用 Marshal.FreeHGlobal 方法释放已分配的内存块。 Marshal.FreeHGlobalMarshal.FreeHGlobal 方法释放使用 Marshal.AllocHGlobal 方法分配的非托管内存块。 以下是使用 Marshal.FreeHGlobal 方法的示例 C# 代码 在此示例中,我们使用 Marshal.AllocHGlobal 方法分配一个大小为 1024 字节的非托管内存块。然后,我们使用已分配的内存块执行某些操作。最后,我们使用 Marshal.FreeHGlobal 方法释放已分配的内存块。 调用非托管函数Marshal 类还提供用于从托管代码调用非托管函数的方法。这些方法提供了一种调用定义在非托管库或 DLL 中的函数的方法。 DllImport 属性DllImport 属性用于从 DLL 或共享库导入非托管函数。该属性将 DLL 或共享库的名称作为参数,并将要导入的函数名称作为参数。 结论C# Marshal 类提供了一套强大的方法,用于处理非托管内存以及从托管代码调用非托管函数。这些方法允许开发人员以安全高效的方式与非托管代码进行互操作。在处理非托管代码时,了解潜在的陷阱很重要,例如内存泄漏和数据损坏。通过遵循最佳实践并正确使用 Marshal 类,开发人员可以创建与非托管代码互操作的健壮且可靠的应用程序。 下一个主题C# 正则表达式测试器 |
我们请求您订阅我们的新闻通讯以获取最新更新。