C#——Marshal.StructureToPtr方法简介

目录

  1. MarshalStructureToPtr方法简介
  2. 功能及位置
  3. 语法
  4. 参数说明
  5. 异常
  6. 备注
  7. 举例

本博客(http://blog.csdn.net/livelylittlefish)贴出作者(三二一、小鱼)相关研究、学习内容所做的笔记,欢

迎广大朋友指正!

具体可以参考http://msdn.microsoft.com

Marshal.StructureToPtr方法简介

1. 功能及位置

将数据从托管对象封送到非托管内存块,属于.NET Framework 类库
命名空间:System.Runtime.InteropServices
程序集:mscorlib(在 mscorlib.dll 中)

2. 语法

C#:

[ComVisibleAttribute(true)] public static void StructureToPtr (Object structure,IntPtr ptr,bool fDeleteOld);
C++:

[ComVisibleAttribute(true)]public: static void StructureToPtr (Object^ structure, IntPtr ptr, bool fDeleteOld);

3. 参数说明

structure:托管对象,包含要封送的数据。该对象必须是格式化类的实例。
ptr:指向非托管内存块的指针,必须在调用此方法之前分配该指针。
fDeleteOld:设置为 true 可在执行Marshal.DestroyStructure方法前对 ptr 参数调用此方法。请注意,传递 false 可导致内存泄漏。

4. 异常

异常类型:ArgumentException
条件:structrue参数是泛型类型

5. 备注

StructureToPtr将结构的内容复制到 ptr 参数指向的预分配内存块。如果 fDeleteOld 参数为 true,则使用嵌入指

针上适当的删除 API 来删除最初由 ptr 指向的缓冲区,但该缓冲区必须包含有效数据。此方法为在镜像托管类中指

定的每个引用字段执行清理工作。

假设 ptr 指向非托管内存块。此内存块的布局由相应的托管类 structure 描述。StructureToPtr将字段值从结构封

送到指针。假设 ptr 块包含引用字段,该字段指向当前包含“abc”的字符串缓冲区。假设托管端上相应的字段是包含“vwxyz”的字符串。如果不另行通知它,StructureToPtr将分配一个新的非托管缓冲区来保存“vwxyz”,并将它挂钩到 ptr 块。这将丢弃旧缓冲区“abc”使之漂移而不将其释放回非托管堆。最后,您将得到一个孤立的缓冲区,它表示在代码中存在内存泄漏。如果将 fDeleteOld 参数设置为真,则 StructureToPtr 在继续为“vwxyz”分配新缓冲区之前释放保存“abc”的缓冲区。

6. 举例

定义PERSON结构,并将该结构的一个变量拷贝到非托管内存,再将该内存中的PERSON还原为PERSON对象,观察其内容的变化。

源代码如下:

using System;
using System.Text;
using System.Runtime.InteropServices;

namespace testStructureToPtr
{
    public static class define  //define 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
    }

    public struct PERSON    //person structure
    {
        //MarshalAs:指示如何在托管代码和非托管代码之间封送数据
        //UnmanagedType:指定如何将参数或字段封送到非托管内存块
        [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;
    }

    class testProgram
    {
        private static byte _fillChar = 0;      //the fill character

        //convert string to byte array in Ascii with length is len
        public static byte[] CodeBytes(string str, int len)
        {
            if (string.IsNullOrEmpty(str))
            {
                str = string.Empty;
            }

            byte[] result = new byte[len];
            byte[] strBytes = Encoding.Default.GetBytes(str);

            //copy the array converted into result, and fill the remaining bytes with 0
            for (int i = 0; i < len; i++)
                result[i] = ((i < strBytes.Length) ? strBytes[i] : _fillChar);

            return result;
        }

        //show the person information
        public static void ShowPerson(PERSON person)
        {
            Console.WriteLine("cardid   :" + Encoding.ASCII.GetString(person.identicardid));
            Console.WriteLine("name     :" + Encoding.ASCII.GetString(person.name));
            Console.WriteLine("country  :" + Encoding.ASCII.GetString(person.country));
            Console.WriteLine("nation   :" + Encoding.ASCII.GetString(person.nation));
            Console.WriteLine("birthday :" + Encoding.ASCII.GetString(person.birthday));
            Console.WriteLine("address  :" + Encoding.ASCII.GetString(person.address));
        }

        static void Main(string[] args)
        {
            PERSON person;
            person.identicardid = CodeBytes("123456198001011111", define.MAX_LENGTH_OF_IDENTICARDID);
            person.name = CodeBytes("jackson", define.MAX_LENGTH_OF_NAME);
            person.country = CodeBytes("China", define.MAX_LENGTH_OF_COUNTRY);
            person.nation = CodeBytes("HanZu", define.MAX_LENGTH_OF_NATION);
            person.birthday = CodeBytes("19800101", define.MAX_LENGTH_OF_BIRTHDAY);
            person.address = CodeBytes("Luoshan Road, Shanghai", define.MAX_LENGTH_OF_ADDRESS);

            int nSizeOfPerson = Marshal.SizeOf(person);
            IntPtr intPtr = Marshal.AllocHGlobal(nSizeOfPerson);

            Console.WriteLine("The person infomation is as follows:");
            ShowPerson(person);

            try
            {
                //将数据从托管对象封送到非托管内存块,该内存块开始地址为intPtr
                Marshal.StructureToPtr(person, intPtr, true);

                //将数据从非托管内存块封送到新分配的指定类型的托管对象anotherPerson
                PERSON anotherPerson = (PERSON)Marshal.PtrToStructure(intPtr, typeof(PERSON));

                Console.WriteLine("The person after copied is as follows:");
                ShowPerson(anotherPerson);
            }
            catch (ArgumentException)
            {
                throw;
            }
            finally
            {
                Marshal.FreeHGlobal(intPtr);    //free tha memory
            }
        }
    }
}

运行过程中的对象地址及其内容如下:

intPtr指向的内存块的内容就是程序中对person对象所赋的初值,如下图所示,共计378个字节:

对象person和another的地址及其identicardid成员的地址:

对象person的identicardid成员的内容,即程序中的值123456198001011111,最后的2个字节为0,图中显示的是20个元素的ASCII码的16进制数值:

运行结果如下:

参考文献:C#——Marshal.StructureToPtr方法简介

时间: 2024-08-07 21:20:14

C#——Marshal.StructureToPtr方法简介的相关文章

Datatable的Select()方法简介

DataTable是我们在进行开发时经常用到的一个类,并且经常需要对DataTable中的数据进行筛选等操作,下面就介绍一下Datatable中经常用到的一个方法——Select,微软提供了四个函数的重载,分别是 Select() Select(string filterExpression) Select(string filterExpression, string sort) Select(string filterExpression,string sort, DataViewRowSt

$.getJSON( )的使用方法简介

JSON(JavaScript Object Notation)即JavaScript对象表示法,是一种轻量级的数据交换格式.它非常便于编程人员对数据的处理,也便于机器对数据的解析和生成,应用非常广泛. json文件可以保存为"test.json"这样的文件,json数据的一般格式如下("{ }"中的为对象,"[ ]"中的为数组): {"total":3,"rows":[{"userId"

Level Set方法简介

originate from: http://www.cnblogs.com/tabatabaye/articles/891232.html Level Set方法简介: Level Set方法是由Sethian和Osher于1988年提出,最近十几年得到广泛的推广与应用.简单的说来,Level Set方法把低维的一些计算上升到更高一维,把N维的描述看成是N+1维的一个水平.举个例子来说,一个二维平面的圆,如x^2+y^2=1可以看成是二元函数f(x,y)=x^2+y^2的1水平,因此,计算这个

iOS中常用的四种数据持久化方法简介

iOS中常用的四种数据持久化方法简介 iOS中的数据持久化方式,基本上有以下四种:属性列表.对象归档.SQLite3和Core Data 1.属性列表涉及到的主要类:NSUserDefaults,一般 [NSUserDefaults standardUserDefaults]就够用了 @interface User : NSObject <NSCoding>@property (nonatomic, assign) NSInteger userID;@property (nonatomic,

苍狼敏捷需求用例分析方法简介并讲义下载

作者:张克强    作者微博:张克强-敏捷307 用例分析方法已经有不短的历史,发展出了多种用例分析方法.笔者花费了大量时间,对用例分析的各个方面进行实践和分析,得到如下系列文章: 需求用例分析之一:异常流 需求用例分析之二:级别设置需求用例分析之三:补充规约 需求用例分析之四:业务规则 需求用例分析之五:业务用例之Rational系 需求用例分析之六:业务用例之科伯恩系 需求用例分析之七:业务用例之小结 需求用例分析之八:用例颗粒度 在这些分析的基础上与及笔者的实践,总结整理得到"苍狼敏捷需求

ATAM 方法简介

ATAM  方法简介 1.ATAM 是啥 ATAM 是一种基于场景评估方式,英文全称 Architecture TradeOff Analysis Method ATAM(架构权衡分析法) 2.ATAM评估方法 ATAM 方法对软件架构进行评估的目的主要是 根据系统质量属性和业务需求评估决策结果,ATAM希望揭示出架构满足质量目标,架构设计者能够更清楚的认识到质量目标之间的联系.即如何权衡多个目标 3.ATAM的参与者 开发人员,领域专家,测试人员,客户代表,用户等 4.如何展开评估活动 这里将

xtrabackup使用方法简介

关于xtrabackup的简介就不再赘述,百度一堆,使用方法也说明也很多.感觉还是只有自己试过之后才能有更深刻的认识,以下的使用说明基于官方文档及自己试验过程,记录下备查. 安装: 去percona-xtrabackup官网上下载,有rpm包.tar包,也有解压直接可用的二进制包.我试验采用的二进制包. 由于里面的innobackupx命令实际上是用perl语言封装了xtrabackupx而成,所以使用innobackupx命令要先检查perl包以及其依赖包的安装情况. 可以执行yum inst

delphi fastMM 使用方法简介

delphi fastMM 使用方法简介 在 http://sourceforge.net/projects/fastmm 中可以下载到最新 stable 的 FastMM,当前推荐的是 4.62,主要特点包括: 1.彻底实现了 Borland 的内存管理器,可以完全取代现有的内存管理器("取代"就是第一个 uses FastMM4,that is all ...) 2.实现了内存管理器共享机制,Exe 和 Dll 间共享内存管理器不需要任何 Dll 支持 3.集成了内存泄漏检测功能

c#中Marshal.Copy()方法的使用

c#中Marshal.Copy方法的使用 Marshal.copy()方法用来在托管对象(数组)和非托管对象(IntPtr)之间进行内容的复制 函数有很多重载,如下所示: Copy(array<Byte>[]()[], Int32, IntPtr, Int32) 将一维的托管 8 位无符号整数数组中的数据复制到非托管内存指针. Copy(array<Char>[]()[], Int32, IntPtr, Int32) 将数据从一维的托管字符数组复制到非托管内存指针. Copy(ar