C#将结构体和指针互转的方法
- . 功能及位置
- 将数据从托管对象封送到非托管内存块,属于.NET Framework 类库
- 命名空间:System.Runtime.InteropServices
- 程序集:mscorlib(在 mscorlib.dll 中)
- . 语法
- 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);
- . 参数说明
- structure:托管对象,包含要封送的数据。该对象必须是格式化类的实例。
- ptr:指向非托管内存块的指针,必须在调用此方法之前分配该指针。
- fDeleteOld:设置为 true 可在执行Marshal.DestroyStructure方法前对 ptr 参数调用此方法。请注意,传递 false 可导致内存泄漏。
- . 异常
- 异常类型:ArgumentException
- 条件:structrue参数是泛型类型
- . 备注
- StructureToPtr将结构的内容复制到 ptr 参数指向的预分配内存块。如果 fDeleteOld 参数为 true,则使用嵌入指
- 针上适当的删除 API 来删除最初由 ptr 指向的缓冲区,但该缓冲区必须包含有效数据。此方法为在镜像托管类中指
- 定的每个引用字段执行清理工作。
- 假设 ptr 指向非托管内存块。此内存块的布局由相应的托管类 structure 描述。StructureToPtr将字段值从结构封
- 送到指针。假设 ptr 块包含引用字段,该字段指向当前包含“abc”的字符串缓冲区。假设托管端上相应的字段是包含“vwxyz”的字符串。如果不另行通知它,StructureToPtr将分配一个新的非托管缓冲区来保存“vwxyz”,并将它挂钩到 ptr 块。这将丢弃旧缓冲区“abc”使之漂移而不将其释放回非托管堆。最后,您将得到一个孤立的缓冲区,它表示在代码中存在内存泄漏。如果将 fDeleteOld 参数设置为真,则 StructureToPtr 在继续为“vwxyz”分配新缓冲区之前释放保存“abc”的缓冲区。
- . 举例
- 定义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 = ; //maximum length of identicardid
- public const int MAX_LENGTH_OF_NAME = ; //maximum length of name
- public const int MAX_LENGTH_OF_COUNTRY = ; //maximum length of country
- public const int MAX_LENGTH_OF_NATION = ; //maximum length of nation
- public const int MAX_LENGTH_OF_BIRTHDAY = ; //maximum length of birthday
- public const int MAX_LENGTH_OF_ADDRESS = ; //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 = ; //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 = ; 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("", 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("", 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
- }
- }
- }
- }
- . 分析及扩展
- 结构体:
- 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;
- }
- A. 通过获取Person信息的函数返回的指针,再将该指针转换为结构体,并显示结构体中的内容
- a. 获取Person信息的函数
- //获取 Person信息
- [DllImport("person.dll", CallingConvention = CallingConvention.Cdecl)]
- public static extern IntPtr GetPerson(IntPtr pEngine);
- b. 使用指针定义一个变量,来获取一个返回值为该指针的函数
- IntPtr Person = GetPerson(pEngine);
- c. 将指针变量装换为结构体,操作如下:
- PERSON anotherPerson = (PERSON)Marshal.PtrToStructure(intPtr, typeof(PERSON));
- d. 通过ShowPerson(PERSON person)函数,用来打印输出信息
- Console.WriteLine("cardid :" + Encoding.ASCII.GetString(anotherPerson.identicardid));
- B. 通过定义结构体,并赋值结构体中的数据,再将结构体转为指针数据,并将指针传入到SetPerson信息的函数中
- a. 设置Person信息的函数
- //获取 Person信息
- [DllImport("person.dll", CallingConvention = CallingConvention.Cdecl)]
- public static extern int SetPerson(IntPtr pEngine);
- b. 定义结构体,并赋值结构体中的数据
- PERSON person = new PERSON();
- person.identicardid = CodeBytes("", 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("", define.MAX_LENGTH_OF_BIRTHDAY);
- person.address = CodeBytes("Luoshan Road, Shanghai", define.MAX_LENGTH_OF_ADDRESS);
- c. 将结构体转为指针数据
- int nSizeOfPerson = Marshal.SizeOf(person); //定义指针长度
- IntPtr personX = Marshal.AllocHGlobal(nSizeOfPerson); //定义指针
- Marshal.StructureToPtr(person, personX, true); //将结构体person转为personX指针
- d. 将指针传入到SetPerson函数中
- SetPerson(personX);
C#将结构体和指针互转的方法的更多相关文章
- 【学习笔记】【C语言】指向结构体的指针
1.指向结构体的指针的定义 struct Student *p; 2.利用指针访问结构体的成员 1> (*p).成员名称 2> p->成员名称 3.代码 #include < ...
- c语言中较常见的由内存分配引起的错误_内存越界_内存未初始化_内存太小_结构体隐含指针
1.指针没有指向一块合法的内存 定义了指针变量,但是没有为指针分配内存,即指针没有指向一块合法的内浅显的例子就不举了,这里举几个比较隐蔽的例子. 1.1结构体成员指针未初始化 struct stude ...
- C语言结构体和指针
指针也可以指向一个结构体,定义的形式一般为: struct 结构体名 *变量名; 下面是一个定义结构体指针的实例: struct stu{ char *name; //姓名 int num; //学号 ...
- 37深入理解C指针之---结构体与指针
一.结构体与指针 1.结构体的高级初始化.结构体的销毁.结构体池的应用 2.特征: 1).为了避免含有指针成员的结构体指针的初始化复杂操作,将所有初始化动作使用函数封装: 2).封装函数主要实现内存的 ...
- 深入了解Windows句柄到底是什么(句柄是逻辑指针,或者是指向结构体的指针,图文并茂,非常清楚)good
总是有新入门的Windows程序员问我Windows的句柄到底是什么,我说你把它看做一种类似指针的标识就行了,但是显然这一答案不能让他们满意,然后我说去问问度娘吧,他们说不行网上的说法太多还难以理解. ...
- 关于C语言结构体,指针,声明的详细讲解。——Arvin
关于结构体的详细分析 只定义结构体 struct Student { int age; char* name; char sex;//结构体成员 };//(不要忘记分号) Student是结构体的名字 ...
- c语言结构体&常指针和常量指针的区别
结构体: 关系密切但数据类型不尽相同, 常指针和常量指针的区别: char * const cp : 定义一个指向字符的指针常数,即const指针,常指针. const char* p : 定义一个指 ...
- C#调用c++Dll 结构体数组指针的问题
参考文章http://blog.csdn.net/jadeflute/article/details/5684687 但是这里面第一个方案我没有测试成功,第二个方案我感觉有点复杂. 然后自己写啦一个: ...
- Delphi结构体数组指针的问题
//这段代码在Delphi 2007和delphi 7下是可以执行的,所以正确使用结构体数组和指针应该是这样的,已验证 unit Unit1; interface uses Windows, Mess ...
随机推荐
- 8Linux磁盘划分、RAID
磁盘划分fdisk 1.磁盘分区 fdisk 2.格式化 mkfs.ext4 mkfs.xfs 3.挂载 mount 路径 挂载路径 fdisk命令中的参数以及作用 参数 作用m 查看全部可用的参数n ...
- 1024程序员节宅男节日快乐 -- JAVA快速开发平台,JEECG 3.8宅男优化版本发布
JEECG 3.8 版本发布,系统全面升级,重构上传组件.优化代码生成器机制! 导读 ⊙平台性能优化,系统更稳定,速度闪电般提升 ⊙系统上传组件全面重构,使用plupload组件,解决flash的 ...
- Maven打包后的文件存在中文乱码
发现打包的js文件虽然是UTF-8格式的编码,但是有中文有乱码 可设置jvm的编码,两种方法: 在系统的环境变量中添加一个变量,名为: JAVA_TOOL_OPTIONS, 值为:-Dfile.enc ...
- centos下删除MYSQL 和重新安装MYSQL
centos下彻底删除MYSQL 和重新安装MYSQL 因centos系统自带的mysql版本比较低5.1,所以想卸载重新安装较新版本,下面是过程 1 删除Mysql yum remove mysql ...
- html和css问题?
1.说说你对语义化的理解?答,去掉或者丢失样式的时候能够让页面呈现出清晰的结构方便其他设备解析(如屏幕阅读器.盲人阅读器.移动设备)以意义的方式来渲染网页:便于团队开发和维护,语义化更具可读性,是下一 ...
- HATEOAS
HATEOAS(Hypermedia as the engine of application state)是 REST 架构风格中最复杂的约束,也是构建成熟 REST 服务的核心.它的重要性在于打破 ...
- java itext替换PDF中的文本
itext没有提供直接替换PDF文本的接口,我们可以通过在原有的文本区域覆盖一个遮挡层,再在上面加上文本来实现. 所需jar包: 1.先在PDF需要替换的位置覆盖一个白色遮挡层(颜色可根据PDF文字背 ...
- java第六章异常
异常: 程序运行一旦出现异常程序就会立刻结束不在向下运行 处理异常:在程序执行代码时,万一发生了异常,程序会按照处理的方法对一场进行处理办法,程序将继续执行 try-catch-finally-thr ...
- vue 存取、设置、清除cookie
步骤: 第一步:assets目录下添加cookie.js文件 export function setCookie(c_name,value,expire) { var date=new Date() ...
- Wordpress 后台更改网址
在 `wp_options` 数据库执行下面两条命令 ```sql update wp_options set option_value = 'your_new_url' where option_n ...