C#—EMguCV Marshal
### C#—EMguCV Marshal: StructureToPtr 方法详解 #### 概述 在C#与.NET Framework开发中,有时我们需要处理托管与非托管代码之间的交互。为了实现这一目标,.NET Framework提供了一系列用于处理此类操作的方法。其中,`Marshal.StructureToPtr`是一个重要的方法,用于将托管对象中的数据封送到非托管内存块。本文将详细介绍`Marshal.StructureToPtr`方法的功能、参数、异常处理以及注意事项,并通过一个示例帮助理解其实际应用。 #### 功能及位置 `Marshal.StructureToPtr`方法位于`.NET Framework`类库中,属于`System.Runtime.InteropServices`命名空间,可以在`mscorlib.dll`程序集中找到。它的主要功能是将托管对象中的数据复制到非托管内存块中,这对于实现与非托管代码的交互非常有用。 #### 语法 在C#中,`Marshal.StructureToPtr`方法的声明如下: ```csharp [ComVisibleAttribute(true)] public static void StructureToPtr( Object structure, IntPtr ptr, bool fDeleteOld ); ``` 在C++中,对应的声明如下: ```cpp [ComVisibleAttribute(true)] public: static void StructureToPtr( Object^ structure, IntPtr ptr, bool fDeleteOld ); ``` #### 参数说明 - `structure`: 托管对象,包含要封送的数据。该对象必须是格式化类的实例。 - `ptr`: 指向非托管内存块的指针,必须在调用此方法之前分配该指针。 - `fDeleteOld`: 设置为`true`可在执行`Marshal.DestroyStructure`方法前对`ptr`参数调用此方法。请注意,传递`false`可导致内存泄漏。 #### 异常 当`structure`参数是泛型类型时,会抛出`ArgumentException`异常。 #### 备注 - `StructureToPtr`将结构的内容复制到`ptr`参数指向的预分配内存块。如果`fDeleteOld`参数为`true`,则使用嵌入指针上适当的删除API来删除最初由`ptr`指向的缓冲区,但该缓冲区必须包含有效数据。 - 此方法为在镜像托管类中指定的每个引用字段执行清理工作。假设`ptr`指向非托管内存块。此内存块的布局由相应的托管类`structure`描述。 - `StructureToPtr`将字段值从结构封送到指针。假设`ptr`块包含引用字段,该字段指向当前包含“abc”的字符串缓冲区。假设托管端上相应的字段是包含“vwxyz”的字符串。如果不另行通知它,`StructureToPtr`将分配一个新的非托管缓冲区来保存“vwxyz”,并将它挂钩到`ptr`块。这将丢弃旧缓冲区“abc”使之漂移而不将其释放回非托管堆。您将得到一个孤立的缓冲区,它表示在代码中存在内存泄漏。 - 如果将`fDeleteOld`参数设置为真,则`StructureToPtr`在继续为“vwxyz”分配新缓冲区之前释放保存“abc”的缓冲区。 #### 示例 下面通过一个具体的示例来演示如何使用`Marshal.StructureToPtr`方法。本例中,我们定义了一个名为`PERSON`的结构,并将该结构的一个变量拷贝到非托管内存,再将该内存中的`PERSON`还原为`PERSON`对象,观察其内容的变化。 ```csharp using System; using System.Text; using System.Runtime.InteropServices; namespace testStructureToPtr { public static class define // defines some constant { public const int MAX_LENGTH_OF_IDENTICARDID = 20; // maximum length of identicardid public const int MAX_LENGTH_OF_NAME = 50; // maximum length of name public const int MAX_LENGTH_OF_COUNTRY = 50; // maximum length of country public const int MAX_LENGTH_OF_NATION = 50; // maximum length of nation public const int MAX_LENGTH_OF_BIRTHDAY = 8; // maximum length of birthday public const int MAX_LENGTH_OF_ADDRESS = 200; // maximum length of address } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] public struct PERSON // person structure { [MarshalAs(UnmanagedType.ByValArray, SizeConst = define.MAX_LENGTH_OF_IDENTICARDID)] public byte[] identicardid; [MarshalAs(UnmanagedType.ByValArray, SizeConst = define.MAX_LENGTH_OF_NAME)] public byte[] name; [MarshalAs(UnmanagedType.ByValArray, SizeConst = define.MAX_LENGTH_OF_COUNTRY)] public byte[] country; [MarshalAs(UnmanagedType.ByValArray, SizeConst = define.MAX_LENGTH_OF_NATION)] public byte[] nation; [MarshalAs(UnmanagedType.ByValArray, SizeConst = define.MAX_LENGTH_OF_BIRTHDAY)] public byte[] birthday; [MarshalAs(UnmanagedType.ByValArray, SizeConst = define.MAX_LENGTH_OF_ADDRESS)] public byte[] address; } public class Program { public static void Main(string[] args) { PERSON p = new PERSON(); // 初始化结构体 p.identicardid = Encoding.ASCII.GetBytes("12345678901234567890"); p.name = Encoding.ASCII.GetBytes("John Doe"); p.country = Encoding.ASCII.GetBytes("United States"); p.nation = Encoding.ASCII.GetBytes("American"); p.birthday = Encoding.ASCII.GetBytes("01011980"); p.address = Encoding.ASCII.GetBytes("1234 Main St, Anytown, USA"); // 分配非托管内存 IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(p)); try { // 将结构体数据复制到非托管内存 Marshal.StructureToPtr(p, ptr, false); // 读取非托管内存中的数据 PERSON pFromPtr = (PERSON)Marshal.PtrToStructure(ptr, typeof(PERSON)); // 输出结果 Console.WriteLine($"Identicard ID: {Encoding.ASCII.GetString(pFromPtr.identicardid)}"); Console.WriteLine($"Name: {Encoding.ASCII.GetString(pFromPtr.name)}"); Console.WriteLine($"Country: {Encoding.ASCII.GetString(pFromPtr.country)}"); Console.WriteLine($"Nation: {Encoding.ASCII.GetString(pFromPtr.nation)}"); Console.WriteLine($"Birthday: {Encoding.ASCII.GetString(pFromPtr.birthday)}"); Console.WriteLine($"Address: {Encoding.ASCII.GetString(pFromPtr.address)}"); } finally { // 释放非托管内存 Marshal.FreeHGlobal(ptr); } } } } ``` ### 结论 `Marshal.StructureToPtr`方法在处理托管与非托管代码交互时非常重要。通过合理设置参数并注意内存管理,可以有效地利用该方法实现数据的传输。在实际开发过程中,正确使用此方法不仅可以提高代码效率,还能避免潜在的内存泄漏问题。
剩余14页未读,继续阅读
- 粉丝: 47
- 资源: 156
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助