C#Maeshal类——托管资源和非托管资源转换

C#——Marshal.StructureToPtr方法简介

http://blog.csdn.net/livelylittlefish/article/details/2423764
                                        
具体可以参考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对象
,观察其内容的变化。
                                           
源代码如下:

  
  
  1. using System;
  2. using System.Text;
  3. using System.Runtime.InteropServices;
  4. namespace testStructureToPtr
  5. {
  6. public static class define //define some constant
  7. {
  8. public const int MAX_LENGTH_OF_IDENTICARDID = 20; //maximum length of
  9. identicardid
  10. public const int MAX_LENGTH_OF_NAME = 50; //maximum length of name
  11. public const int MAX_LENGTH_OF_COUNTRY = 50; //maximum length of country
  12. public const int MAX_LENGTH_OF_NATION = 50; //maximum length of nation
  13. public const int MAX_LENGTH_OF_BIRTHDAY = 8; //maximum length of birthday
  14. public const int MAX_LENGTH_OF_ADDRESS = 200; //maximum length of address
  15. }
  16. public struct PERSON //person structure
  17. {
  18. //MarshalAs:指示如何在托管代码和非托管代码之间封送数据
  19. //UnmanagedType:指定如何将参数或字段封送到非托管内存块
  20. [ MarshalAs(UnmanagedType.ByValArray, SizeConst =
  21. define.MAX_LENGTH_OF_IDENTICARDID)]
  22. public byte[] identicardid;
  23. [ MarshalAs(UnmanagedType.ByValArray, SizeConst = define.MAX_LENGTH_OF_NAME)]
  24. public byte[] name;
  25. [ MarshalAs(UnmanagedType.ByValArray, SizeConst = define.MAX_LENGTH_OF_COUNTRY)]
  26. public byte[] country;
  27. [ MarshalAs(UnmanagedType.ByValArray, SizeConst = define.MAX_LENGTH_OF_NATION)]
  28. public byte[] nation;
  29. [ MarshalAs(UnmanagedType.ByValArray, SizeConst = define.MAX_LENGTH_OF_BIRTHDAY)]
  30. public byte[] birthday;
  31. [ MarshalAs(UnmanagedType.ByValArray, SizeConst = define.MAX_LENGTH_OF_ADDRESS)]
  32. public byte[] address;
  33. }
  34. class testProgram
  35. {
  36. private static byte _fillChar = 0; //the fill character
  37. //convert string to byte array in Ascii with length is len
  38. public static byte[] CodeBytes(string str, int len)
  39. {
  40. if ( string.IsNullOrEmpty(str))
  41. {
  42. str = string.Empty;
  43. }
  44. byte[] result = new byte[len];
  45. byte[] strBytes = Encoding.Default.GetBytes(str);
  46. //copy the array converted into result, and fill the remaining bytes with 0
  47. for ( int i = 0; i < len; i++)
  48. result[i] = ((i < strBytes.Length) ? strBytes[i] : _fillChar);
  49. return result;
  50. }
  51. //show the person information
  52. public static void ShowPerson(PERSON person)
  53. {
  54. Console.WriteLine( "cardid :" + Encoding.ASCII.GetString
  55. (person.identicardid));
  56. Console.WriteLine( "name :" + Encoding.ASCII.GetString(person.name));
  57. Console.WriteLine( "country :" + Encoding.ASCII.GetString(person.country));
  58. Console.WriteLine( "nation :" + Encoding.ASCII.GetString(person.nation));
  59. Console.WriteLine( "birthday :" + Encoding.ASCII.GetString(person.birthday));
  60. Console.WriteLine( "address :" + Encoding.ASCII.GetString(person.address));
  61. }
  62. static void Main(string[] args)
  63. {
  64. PERSON person;
  65. person.identicardid = CodeBytes( "123456198001011111",
  66. define.MAX_LENGTH_OF_IDENTICARDID);
  67. person.name = CodeBytes( "jackson", define.MAX_LENGTH_OF_NAME);
  68. person.country = CodeBytes( "China", define.MAX_LENGTH_OF_COUNTRY);
  69. person.nation = CodeBytes( "HanZu", define.MAX_LENGTH_OF_NATION);
  70. person.birthday = CodeBytes( "19800101", define.MAX_LENGTH_OF_BIRTHDAY);
  71. person.address = CodeBytes( "Luoshan Road, Shanghai",
  72. define.MAX_LENGTH_OF_ADDRESS);
  73. int nSizeOfPerson = Marshal.SizeOf(person);
  74. IntPtr intPtr = Marshal.AllocHGlobal(nSizeOfPerson);
  75. Console.WriteLine( "The person infomation is as follows:");
  76. ShowPerson(person);
  77. try
  78. {
  79. //将数据从托管对象封送到非托管内存块,该内存块开始地址为intPtr
  80. Marshal.StructureToPtr(person, intPtr, true);
  81. //将数据从非托管内存块封送到新分配的指定类型的托管对象anotherPerson
  82. PERSON anotherPerson = (PERSON)Marshal.PtrToStructure(intPtr, typeof
  83. (PERSON));
  84. Console.WriteLine( "The person after copied is as follows:");
  85. ShowPerson(anotherPerson);
  86. }
  87. catch (ArgumentException)
  88. {
  89. throw;
  90. }
  91. finally
  92. {
  93. Marshal.FreeHGlobal(intPtr); //free tha memory
  94. }
  95. }
  96. }
  97. }

运行过程中的对象地址及其内容如下:
intPtr指向的内存块的内容就是程序中对person对象所赋的初值,如下图所示,共计378个字节:
对象person和another的地址及其identicardid成员的地址:
对象person的identicardid成员的内容,即程序中的值123456198001011111,最后的2个字节为0,图中
显示的是20个元素的ASCII码的16进制数值:
运行结果如下:
========

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

http://blog.csdn.net/xiaobai1593/article/details/7065955

c#中Marshal.Copy方法的使用
Marshal.copy()方法用来在托管对象(数组)和非托管对象(IntPtr)之间进行内容的复制

函数有很多重载,如下所示:

Copy(array<Byte>[]()[], Int32, IntPtr, Int32) 将一维的托管 8 位无符号整数数组中的数据复制到

非托管内存指针。

Copy(array<Char>[]()[], Int32, IntPtr, Int32) 将数据从一维的托管字符数组复制到非托管内存指

针。

Copy(array<Double>[]()[], Int32, IntPtr, Int32) 将数据从一维的托管双精度浮点数组复制到非托

管内存指针。

Copy(array<Int16>[]()[], Int32, IntPtr, Int32) 将数据从一维的托管 16 位带符号整数数组复制到

非托管内存指针。

Copy(array<Int32>[]()[], Int32, IntPtr, Int32) 将数据从一维的托管 32 位带符号整数数组复制到

非托管内存指针。

Copy(array<Int64>[]()[], Int32, IntPtr, Int32) 将数据从一维的托管 64 位带符号整数数组复制到

非托管内存指针。

Copy(IntPtr, array<Byte>[]()[], Int32, Int32) 将数据从非托管内存指针复制到托管 8 位无符号整

数数组。

Copy(IntPtr, array<Char>[]()[], Int32, Int32) 将数据从非托管内存指针复制到托管字符数组。

Copy(IntPtr, array<Double>[]()[], Int32, Int32) 将数据从非托管内存指针复制到托管双精度浮点

数组。

Copy(IntPtr, array<Int16>[]()[], Int32, Int32) 将数据从非托管内存指针复制到托管 16 位带符号

整数数组。

Copy(IntPtr, array<Int32>[]()[], Int32, Int32) 将数据从非托管内存指针复制到托管 32 位带符号

整数数组。

Copy(IntPtr, array<Int64>[]()[], Int32, Int32) 将数据从非托管内存指针复制到托管 64 位带符号

整数数组。

Copy(IntPtr, array<IntPtr>[]()[], Int32, Int32) 将数据从非托管内存指针复制到托管 IntPtr 数

组。

Copy(IntPtr, array<Single>[]()[], Int32, Int32) 将数据从非托管内存指针复制到托管单精度浮点

数组。

Copy(array<IntPtr>[]()[], Int32, IntPtr, Int32) 将数据从一维托管 IntPtr 数组复制到非托管内

存指针。

Copy(array<Single>[]()[], Int32, IntPtr, Int32) 将数据从一维的托管单精度浮点数组复制到非托

管内存指针。

这里需要注意的是两个参数Int32类型的使用

Int32类型的两个参数都是用来限定数组的,其中一个限定开始位置,一个限定长度

注意:长度是指数组元素的个数,而不是指字节数

示例:

string name = "xuwei";  
IntPtr pName = Marshal.AllocHGlobal(2*name.Length);  
Marshal.Copy(name.ToCharArray(), 0, pName, name.Length);  
char[] cName = new char[name.Length];  
Marshal.Copy(pName, cName, 0, name.Length);  
易知name.Length=5

(1) 给pName指针分配了2*name.Length字节的空间
注意:Marshal.AllocHGlobal(Int32 cb)中的参数cb是分配的字节数

(2) 将name转换的char[]中的内容复制到pName所指的内存中,所取长度为char的个数,即name.Length

(3) 给cName分配name.Length个char位置

(4) 将pName中的内容复制到cName数组中,长度同样为name.Length
========

Marshal 类

https://msdn.microsoft.com/zh-cn/library/system.runtime.interopservices.marshal(VS.80).aspx
.NET Framework 2.0 其他版本 
提供了一个方法集,这些方法用于分配非托管内存、复制非托管内存块、将托管类型转换为非托管类型


,此外还提供了在与非托管代码交互时使用的其他杂项方法。
命名空间:System.Runtime.InteropServices
程序集:mscorlib(在 mscorlib.dll 中)
语法
C#C++VB
public static class Marshal
J#
public final class Marshal
JScript
public final class Marshal
备注
Marshal 类中定义的 static 方法对于处理非托管代码至关重要。此类中定义的大多数方法通常由需要


在托管和非托管编程模型之间提供桥梁的开发人员使用。例如,StringToHGlobalAnsi 方法将 ANSI 字


符从指定的字符串(在托管堆中)复制到非托管堆中的缓冲区。该方法还分配大小正确的目标堆。
公共语言运行库提供了特定的封送处理功能。有关封送处理行为的详细信息,请参见 互操作封送处理。
示例
下面的代码示例演示如何使用 Marshal 类所定义的各个方法。
C#C++
using System;
using System.Text;
using System.Runtime.InteropServices;


public struct Point
{
    public Int32 x, y;
}


public sealed class App
{
    static void Main()
    {
        // Demonstrate the use of public static fields of the Marshal class.
        Console.WriteLine("SystemDefaultCharSize={0}, SystemMaxDBCSCharSize={1}",
            Marshal.SystemDefaultCharSize, Marshal.SystemMaxDBCSCharSize);


        // Demonstrate the use of the SizeOf method of the Marshal class.
        Console.WriteLine("Number of bytes needed by a Point object: {0}", 
            Marshal.SizeOf(typeof(Point)));
        Point p = new Point();
        Console.WriteLine("Number of bytes needed by a Point object: {0}",
            Marshal.SizeOf(p));
        
        // Demonstrate how to call GlobalAlloc and 
        // GlobalFree using the Marshal class.
        IntPtr hglobal = Marshal.AllocHGlobal(100);
        Marshal.FreeHGlobal(hglobal);


        // Demonstrate how to use the Marshal class to get the Win32 error 
        // code when a Win32 method fails.
        Boolean f = CloseHandle(new IntPtr(-1));
        if (!f)
        {
            Console.WriteLine("CloseHandle call failed with an error code of: {0}", 
                Marshal.GetLastWin32Error());
        }  
    }


    // This is a platform invoke prototype. SetLastError is true, which allows 
    // the GetLastWin32Error method of the Marshal class to work correctly.    
    [DllImport("Kernel32", ExactSpelling = true, SetLastError = true)]
    static extern Boolean CloseHandle(IntPtr h);
    
}


// This code produces the following output.
// 
// SystemDefaultCharSize=2, SystemMaxDBCSCharSize=1
// Number of bytes needed by a Point object: 8
// Number of bytes needed by a Point object: 8
// CloseHandle call failed with an error code of: 6


继承层次结构
System.Object 
  System.Runtime.InteropServices.Marshal
线程安全
此类型的任何公共静态(Visual Basic 中的 Shared)成员都是线程安全的,但不保证所有实例成员都


是线程安全的。
平台
Windows 98、Windows 2000 SP4、Windows CE、Windows Millennium Edition、Windows Mobile for 


Pocket PC、Windows Mobile for Smartphone、Windows Server 2003、Windows XP Media Center 


Edition、Windows XP Professional x64 Edition、Windows XP SP2、Windows XP Starter Edition
.NET Framework 并不是对每个平台的所有版本都提供支持。有关受支持版本的列表,请参见系统要求。
版本信息
.NET Framework
受以下版本支持:2.0、1.1、1.0
.NET Compact Framework
受以下版本支持:2.0、1.0
请参见
参考
Marshal 成员
System.Runtime.InteropServices 命名空间
========

Marshal在C#中的应用(void *指针到IntPtr的转化)

http://www.cnblogs.com/zhongxg/archive/2013/03/18/2965301.html
  C#调用C语言的API时一般把void *指针转换成IntPtr,但这经常远远不够的。在C语言中void *是个万


金油,尤其是一些老的c语言程序,所有的参数就一个void*指针,里面包罗万象,然后在程序中来一个


switch,甚至多个switch来处理不同的参数。最近笔者就碰到了这个问题,不得不来研究一下怎么把void 


*指针转换成IntPtr。


1.void *指针到IntPtr的简单转化。


c语言函数原型:


int SetConfig(int type, void *p);


这里假设p的所传递的参数式是结构体A:


struct A            
{
    wchar_t osdbuffer[100];             
    unsigned short ix;                      
    unsigned short iy;                      
};
 那么在C#中原型可以定义如下:


int SetConfig(int type, IntPtr p);


结构体A 


[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        public struct A {
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
            public string osdbuffer;        
            public ushort ix;                       //显示坐标x
            public ushort iy;                       //显示坐标y
        }
  注意这里的CharSet,它由c中wchar_t决定的,如果c程序编译时使用Unicode,这里就用


CharSet.Unicode,否则使用CharSet.Ansi。关于字符串的编码问题如果不懂可以去网上查一下。至于怎


么知道C语言是用Unicode还是Ansi编译,我是经过调用它的API测试出来的,调用成功了就说明他的编码


和我的调用代码一致。


  这里还有一个很重要的问题,那就是内存在编译时的分配问题。一般默认情况下,内存的分配是


4byte的整数倍,在这里我省略了,但为了便于理解,补充一下。结构体A完整一点的定义:(注意Pack的


值)


[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode,Pack = 4)]
        public struct A {
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
            public string osdbuffer;        
            public ushort ix;                       //显示坐标x
            public ushort iy;                       //显示坐标y
        }
c语言是用的是非托管代码,c#使用的是托管代码,c#的调用代码如下:


复制代码
    A s_a = new A();
  int lenght = Marshal.SizeOf(s_a);
    IntPtr pA= Marshal.AllocHGlobal(lenght);
    Marshal.StructureToPtr(s_a, pA, true);
    int type = 1;
    int ret = SetConfig( type, pA);
    Marshal.FreeHGlobal(pA);
复制代码
2.void *指针到IntPtr的复杂转化。


在这里结构体A变得复杂一点,如果它内部包含一个指向另一个结构体B的指针


复制代码
struct A            
{
    wchar_t osdbuffer[100];            
    unsigned short ix;            
    unsigned short iy;、
    B *pB;            
};
struct B            
{
    wchar_t title[20];     
};
复制代码
在C#中你要做的也就稍微复杂一点,也就是说你不但要为A分配内存,也要为B分配内存


复制代码
  B s_b = new B();
  //赋值省略
  int lenght1 = Marshal.SizeOf(s_b);
    IntPtr pB= Marshal.AllocHGlobal(lenght1);
    Marshal.StructureToPtr(s_b, pB, true);
  A s_a = new A();
  s_a.pB = pB;
  //其他赋值
  //
  int lenght2 = Marshal.SizeOf(s_a);
  IntPtr pA= Marshal.AllocHGlobal(lenght2);
    Marshal.StructureToPtr(s_a, pA, true);
    int type = 1; 
    int ret = SetConfig( type, pA);
    Marshal.FreeHGlobal(pB);
    Marshal.FreeHGlobal(pA);
复制代码
万变不离其宗,只要掌握了原理,不管void *指针传递的参数有多么复杂,都可以搞定。
========

C# struct class 在Marshal.SizeOf 的区别

http://blog.csdn.net/norsd/article/details/7057049


struct 和 class 的区别


最重要的就是 value 和 object 区别了.


但是最近发现另外一个有趣的现象,但是很重要.


一个工程中,因为需要各种结构,于是在开始使用了 struct , 但是觉得有点麻烦,值传递的话,消耗很多,


又不喜欢 ref (因为我喜欢写泛型函数)


于是采用了 class , 接下来顺风顺水 , 直到.....


[csharp] view plain copy
[Serializable] // 指示可序列化  
 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)] //平铺结构;Ansi字


符;结构成员各按1字节对齐  
 [RdMsgId(RDMSGID.E_FID_MC_MARKETINFO)]  
 class MarketInfo  
 {  
     [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]  
     public MarketDataTick[] MarketDataTicks;  
 }  


照理说,Marshal.SizeOf( MarketInfo ) 应该是等于 sizeof(MarketDataTick) *5 
可是实际却是: 4*5 = 20 


为什么? 因为 MarketDataTick 这个结构被设置为class , 改成 struct 就好办了!
========
                        <li class="tool-item tool-active is-like "><a href="javascript:;"><svg class="icon" aria-hidden="true">
                            <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#csdnc-thumbsup"></use>
                        </svg><span class="name">点赞</span>
                        <span class="count">3</span>
                        </a></li>
                        <li class="tool-item tool-active is-collection "><a href="javascript:;" data-report-click="{&quot;mod&quot;:&quot;popu_824&quot;}"><svg class="icon" aria-hidden="true">
                            <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#icon-csdnc-Collection-G"></use>
                        </svg><span class="name">收藏</span></a></li>
                        <li class="tool-item tool-active is-share"><a href="javascript:;"><svg class="icon" aria-hidden="true">
                            <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#icon-csdnc-fenxiang"></use>
                        </svg>分享</a></li>
                        <!--打赏开始-->
                                                <!--打赏结束-->
                                                <li class="tool-item tool-more">
                            <a>
                            <svg t="1575545411852" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5717" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M179.176 499.222m-113.245 0a113.245 113.245 0 1 0 226.49 0 113.245 113.245 0 1 0-226.49 0Z" p-id="5718"></path><path d="M509.684 499.222m-113.245 0a113.245 113.245 0 1 0 226.49 0 113.245 113.245 0 1 0-226.49 0Z" p-id="5719"></path><path d="M846.175 499.222m-113.245 0a113.245 113.245 0 1 0 226.49 0 113.245 113.245 0 1 0-226.49 0Z" p-id="5720"></path></svg>
                            </a>
                            <ul class="more-box">
                                <li class="item"><a class="article-report">文章举报</a></li>
                            </ul>
                        </li>
                                            </ul>
                </div>
                            </div>
            <div class="person-messagebox">
                <div class="left-message"><a href="https://blog.csdn.net/bcbobo21cn">
                    <img src="https://profile.csdnimg.cn/F/4/1/3_bcbobo21cn" class="avatar_pic" username="bcbobo21cn">
                                            <img src="https://g.csdnimg.cn/static/user-reg-year/2x/13.png" class="user-years">
                                    </a></div>
                <div class="middle-message">
                                        <div class="title"><span class="tit"><a href="https://blog.csdn.net/bcbobo21cn" data-report-click="{&quot;mod&quot;:&quot;popu_379&quot;}" target="_blank">bcbobo21cn</a></span>
                                            </div>
                    <div class="text"><span>发布了441 篇原创文章</span> · <span>获赞 518</span> · <span>访问量 295万+</span></div>
                </div>
                                <div class="right-message">
                                            <a href="https://bbs.csdn.net/topics/395525942" target="_blank" class="btn btn-sm btn-red-hollow bt-button personal-messageboard">他的留言板
                        </a>
                                                            <a class="btn btn-sm  bt-button personal-watch" data-report-click="{&quot;mod&quot;:&quot;popu_379&quot;}">关注</a>
                                    </div>
                            </div>
                    </div>
    
发布了14 篇原创文章 · 获赞 5 · 访问量 6024

猜你喜欢

转载自blog.csdn.net/weixin_43277501/article/details/104291462