Marshal.PtrToStructure与Marshal.StructureToPtr 的使用

一、定义

MSDN:将数据从非托管内存块封送到托管对象。

重载的方法

二、实例

1、下面的示例创建一个托管结构,将其传输到非托管内存,然后使用 PtrToStructure 方法将其传输回托管内存。

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Runtime.InteropServices;

namespace 测试interlock
{


    public struct Point
    {
        public int x;
        public int y;
    }

    class Example
    {

        static void Main()
        {

            // Create a point struct.
            Point p;
            p.x = 1;
            p.y = 1;

            Console.WriteLine("The value of first point is " + p.x + " and " + p.y + ".");

            // 初始化一块非托管内存,大小为结构体所占的内存大小
            IntPtr pnt = Marshal.AllocHGlobal(Marshal.SizeOf(p));

            try
            {

                //将Point p的数据复制到非托管内存中去
                Marshal.StructureToPtr(p, pnt, false);

                // Create another point.
                Point anotherP;

                //将非托管内存的数据复制到新建的Point anotherP中
                anotherP = (Point)Marshal.PtrToStructure(pnt, typeof(Point));

                Console.WriteLine("The value of new point is " + anotherP.x + " and " + anotherP.y + ".");
                Console.ReadKey();
            }
            finally
            {
                // Free the unmanaged memory.
                Marshal.FreeHGlobal(pnt);
            }
        }
    }
}

 

2、结构体中包含字符串

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);
                Console.ReadKey();
            }
            catch (ArgumentException)
            {
                throw;
            }
            finally
            {
                Marshal.FreeHGlobal(intPtr);    //free tha memory
            }
        }
    }
}

 

参考:

 

https://docs.microsoft.com/zh-cn/dotnet/api/system.runtime.interopservices.marshal.ptrtostructure?f1url=https%3A%2F%2Fmsdn.microsoft.com%2Fquery%2Fdev15.query%3FappId%3DDev15IDEF1%26l%3DZH-CN%26k%3Dk(System.Runtime.InteropServices.Marshal.PtrToStructure);k(SolutionItemsProject);k(TargetFrameworkMoniker-.NETFramework,Version%3Dv4.5);k(DevLang-csharp)%26rd%3Dtrue&view=netcore-3.1

https://blog.csdn.net/livelylittlefish/article/details/2423764

在 VB.NET 环境中,`Marshal` 是一个用于进行互操作操作的类。它提供了一些方法和属性,用于在托管代码和非托管代码之间进行数据转换、内存分配和释放等操作。 下面是 `Marshal` 类的常用成员和使用方法: 1. `AllocCoTaskMem(size As Integer)`:分配指定大小的内存块,并返回指向该内存块的指针。 ```vb Dim ptr As IntPtr = Marshal.AllocCoTaskMem(100) ``` 2. `FreeCoTaskMem(ptr As IntPtr)`:释放由 `AllocCoTaskMem` 分配的内存块。 ```vb Marshal.FreeCoTaskMem(ptr) ``` 3. `Copy(source As Byte(), startIndex As Integer, destination As IntPtr, length As Integer)`:将字节数组的一部分复制到指定内存地址。 ```vb Dim data As Byte() = {1, 2, 3, 4, 5} Dim ptr As IntPtr = Marshal.AllocCoTaskMem(data.Length) Marshal.Copy(data, 0, ptr, data.Length) ``` 4. `StructureToPtr(structure As Object, ptr As IntPtr, fDeleteOld As Boolean)`:将结构体转换为指向非托管内存的指针。 ```vb Dim obj As MyStruct Dim ptr As IntPtr = Marshal.AllocCoTaskMem(Marshal.SizeOf(obj)) Marshal.StructureToPtr(obj, ptr, False) ``` 5. `PtrToStructure(ptr As IntPtr, structureType As Type)`:将指向非托管内存的指针转换为结构体。 ```vb Dim obj As MyStruct = Marshal.PtrToStructure(ptr, GetType(MyStruct)) ``` 6. `StringToHGlobalAnsi(s As String)`:将 ANSI 编码的字符串分配到非托管内存,并返回指向该内存的指针。 ```vb Dim str As String = "Hello" Dim ptr As IntPtr = Marshal.StringToHGlobalAnsi(str) ``` 7. `FreeHGlobal(ptr As IntPtr)`:释放由 `StringToHGlobalAnsi` 分配的内存。 ```vb Marshal.FreeHGlobal(ptr) ``` 这些是 `Marshal` 类的一些常用方法,可以根据需要选择合适的方法来进行数据转换、内存操作等操作。需要注意的是,在使用 `Marshal` 类时,需要引入 `System.Runtime.InteropServices` 命名空间。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值