├── README.md ├── MarshalHelper ├── App.config ├── Properties │ └── AssemblyInfo.cs ├── MarshalHelper.csproj ├── Program.cs ├── ByteHelper.cs └── MarshalHelper.cs └── MarshalHelper.sln /README.md: -------------------------------------------------------------------------------- 1 | # MarshalHelper 2 | C#内存管理—职场生存的必修课 https://www.cnblogs.com/kiba/p/10971744.html 3 | -------------------------------------------------------------------------------- /MarshalHelper/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /MarshalHelper/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // 有关程序集的一般信息由以下 6 | // 控制。更改这些特性值可修改 7 | // 与程序集关联的信息。 8 | [assembly: AssemblyTitle("MarshalHelper")] 9 | [assembly: AssemblyDescription("https://www.cnblogs.com/kiba/")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("MarshalHelper")] 13 | [assembly: AssemblyCopyright("Copyright © 2019")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // 将 ComVisible 设置为 false 会使此程序集中的类型 18 | //对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型 19 | //请将此类型的 ComVisible 特性设置为 true。 20 | [assembly: ComVisible(false)] 21 | 22 | // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID 23 | [assembly: Guid("f93c4a05-ec2c-499d-bcb7-5aa6a250516d")] 24 | 25 | // 程序集的版本信息由下列四个值组成: 26 | // 27 | // 主版本 28 | // 次版本 29 | // 生成号 30 | // 修订号 31 | // 32 | // 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号 33 | // 方法是按如下所示使用“*”: : 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /MarshalHelper.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.28307.645 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MarshalHelper", "MarshalHelper\MarshalHelper.csproj", "{F93C4A05-EC2C-499D-BCB7-5AA6A250516D}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {F93C4A05-EC2C-499D-BCB7-5AA6A250516D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {F93C4A05-EC2C-499D-BCB7-5AA6A250516D}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {F93C4A05-EC2C-499D-BCB7-5AA6A250516D}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {F93C4A05-EC2C-499D-BCB7-5AA6A250516D}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {78721864-05F6-4AA8-8A56-CAEC0B62D7DB} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /MarshalHelper/MarshalHelper.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {F93C4A05-EC2C-499D-BCB7-5AA6A250516D} 8 | Exe 9 | MarshalHelper 10 | MarshalHelper 11 | v4.6.1 12 | 512 13 | true 14 | true 15 | 16 | 17 | AnyCPU 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | true 26 | 27 | 28 | AnyCPU 29 | pdbonly 30 | true 31 | bin\Release\ 32 | TRACE 33 | prompt 34 | 4 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /MarshalHelper/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace MarshalHelper 8 | { 9 | class Program 10 | { 11 | static void Main(string[] args) 12 | { 13 | PointerUsage(); 14 | 15 | IntPtr unsafePI = new IntPtr(); 16 | int testint = 518; 17 | unsafePI = MarshalHelper.Int32ToIntPtr(testint); 18 | int UnsaferetNoFree = Unsafe_Int32ToIntPtr_NoFree(unsafePI); 19 | Console.WriteLine("Unsafe_Int32ToIntPtr_Free-取IntPtr的值" + UnsaferetNoFree); 20 | new Task(() => 21 | { 22 | int unsafeafterNoFree = MarshalHelper.IntPtrToInt32(unsafePI); 23 | Console.WriteLine("Int32ToIntPtr_NoFree-未释放Intptr的线程取值" + unsafeafterNoFree); 24 | }).Start(); 25 | Console.ReadKey(); 26 | 27 | int retNoFree = Int32ToIntPtr_NoFree(); 28 | IntPtr retNoFreeIP = new IntPtr(retNoFree); 29 | int retFree = Int32ToIntPtr_Free(); 30 | IntPtr retFreeIP = new IntPtr(retFree); 31 | 32 | new Task(() => 33 | { 34 | int afterNoFree = MarshalHelper.IntPtrToInt32(retNoFreeIP); 35 | Console.WriteLine("Int32ToIntPtr_NoFree-未释放Intptr的线程取值" + afterNoFree); 36 | int afterFree = MarshalHelper.IntPtrToInt32(retFreeIP); 37 | Console.WriteLine("Int32ToIntPtr_Free-已释放Intptr的线程取值" + afterFree); 38 | 39 | }).Start(); 40 | 41 | Console.ReadKey(); 42 | 43 | } 44 | #region SafeCode 安全代码 45 | static int Int32ToIntPtr_Free() 46 | { 47 | IntPtr pointerInt = new IntPtr(); 48 | int testint = 518; 49 | pointerInt = MarshalHelper.Int32ToIntPtr(testint); 50 | int testintT = MarshalHelper.IntPtrToInt32(pointerInt); 51 | Console.WriteLine("Int32ToIntPtr_Free-取IntPtr的值" + testintT); 52 | MarshalHelper.Free(pointerInt); 53 | int testintT2 = (int)pointerInt; 54 | return testintT2; 55 | } 56 | static int Int32ToIntPtr_NoFree() 57 | { 58 | IntPtr pointerInt = new IntPtr(); 59 | int testint = 518; 60 | pointerInt = MarshalHelper.Int32ToIntPtr(testint); 61 | int testintT = MarshalHelper.IntPtrToInt32(pointerInt); 62 | Console.WriteLine("Int32ToIntPtr_NoFree-取IntPtr的值" + testintT); 63 | int testintT2 = (int)pointerInt; 64 | return testintT2; 65 | 66 | } 67 | #endregion 68 | 69 | #region UnsafeCode 不安全代码 70 | static int Unsafe_Int32ToIntPtr_NoFree(IntPtr pointerInt) 71 | { 72 | unsafe 73 | { 74 | int *pi = (int*)pointerInt.ToPointer(); 75 | return *pi; 76 | } 77 | } 78 | #endregion 79 | 80 | public static void PointerUsage() 81 | { 82 | string str = "I am Kiba518!"; 83 | int strlen = str.Length; 84 | IntPtr sptr = MarshalHelper.StringToIntPtr(str); 85 | unsafe 86 | { 87 | char* src = (char*)sptr.ToPointer(); 88 | //Console.WriteLine("地址" + (&src)); //这样写会报错,C#并不支持这样取指针地址 89 | for (int i = 0; i <= strlen; i++) 90 | { 91 | Console.Write(src[i]); 92 | src[i] = '0'; 93 | } 94 | Console.WriteLine(); 95 | Console.WriteLine("========不安全代码改值========="); 96 | for (int i = 0; i <= strlen; i++) 97 | { 98 | Console.Write(src[i]); 99 | } 100 | } 101 | Console.ReadKey(); 102 | } 103 | 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /MarshalHelper/ByteHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Runtime.InteropServices; 6 | using System.Runtime.Serialization; 7 | using System.Runtime.Serialization.Formatters.Binary; 8 | using System.Text; 9 | 10 | namespace Utility.Tool 11 | { 12 | public class ByteHelper 13 | { 14 | /// 15 | /// 将文件转换成byte[]数组 16 | /// 17 | /// 文件路径文件名称 18 | /// byte[]数组 19 | public static byte[] FileToByte(string fileUrl) 20 | { 21 | try 22 | { 23 | using (FileStream fs = new FileStream(fileUrl, FileMode.Open, FileAccess.Read)) 24 | { 25 | byte[] byteArray = new byte[fs.Length]; 26 | fs.Read(byteArray, 0, byteArray.Length); 27 | return byteArray; 28 | } 29 | } 30 | catch 31 | { 32 | return null; 33 | } 34 | } 35 | 36 | /// 37 | /// 将byte[]数组保存成文件 38 | /// 39 | /// byte[]数组 40 | /// 保存至硬盘的文件路径 41 | /// 42 | public static bool ByteToFile(byte[] byteArray, string fileName) 43 | { 44 | bool result = false; 45 | try 46 | { 47 | using (FileStream fs = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.Write)) 48 | { 49 | fs.Write(byteArray, 0, byteArray.Length); 50 | result = true; 51 | } 52 | } 53 | catch 54 | { 55 | result = false; 56 | } 57 | return result; 58 | } 59 | 60 | public static byte[] IntToByte(int source) 61 | { 62 | byte[] intBuff = BitConverter.GetBytes(source); 63 | return intBuff; 64 | } 65 | 66 | public static byte[] StringToBytebyEncoding(string source) 67 | { 68 | byte[] Stringbyte = Encoding.Default.GetBytes(source); 69 | return Stringbyte; 70 | } 71 | public static string ByteToStringbyEncoding(byte[] source) 72 | { 73 | string str = System.Text.Encoding.Default.GetString(source); 74 | return str; 75 | } 76 | /// 77 | /// 使用方法 ByteHelper.ByteToInt(pByte.Skip(0).Take(4).ToArray()); 78 | /// 79 | /// 80 | /// 81 | public static int ByteToInt32(byte[] source) 82 | { 83 | int intBuff = BitConverter.ToInt32(source, 0); 84 | return intBuff; 85 | } 86 | 87 | public static short ByteToInt16(byte[] source) 88 | { 89 | short intBuff = BitConverter.ToInt16(source, 0); 90 | return intBuff; 91 | } 92 | public static bool ByteToBool(byte[] source) 93 | { 94 | bool booBuff = BitConverter.ToBoolean(source, 0); 95 | return booBuff; 96 | } 97 | public static char ByteToChar(byte[] source) 98 | { 99 | char charBuff = BitConverter.ToChar(source, 0); 100 | return charBuff; 101 | } 102 | public static String ByteToString(byte[] source) 103 | { 104 | String strBuff = BitConverter.ToString(source, 0); 105 | return strBuff; 106 | } 107 | 108 | public static byte[] StructToBytes(T obj) 109 | { 110 | int size = Marshal.SizeOf(typeof(T)); 111 | IntPtr bufferPtr = Marshal.AllocHGlobal(size); 112 | try 113 | { 114 | Marshal.StructureToPtr(obj, bufferPtr, false); 115 | byte[] bytes = new byte[size]; 116 | Marshal.Copy(bufferPtr, bytes, 0, size); 117 | return bytes; 118 | } 119 | catch (Exception ex) 120 | { 121 | throw new Exception("Error in StructToBytes ! " + ex.Message); 122 | } 123 | finally 124 | { 125 | Marshal.FreeHGlobal(bufferPtr); 126 | } 127 | } 128 | 129 | 130 | //将一个结构序列化为字节数组 131 | private IFormatter formatter = new BinaryFormatter(); 132 | private ValueType DeserializeByteArrayToInfoObj(byte[] bytes) 133 | { 134 | ValueType vt; 135 | if (bytes == null || bytes.Length == 0) 136 | { 137 | return null; 138 | } 139 | 140 | try 141 | { 142 | MemoryStream stream = new MemoryStream(bytes); 143 | stream.Position = 0; 144 | stream.Seek(0, SeekOrigin.Begin); 145 | vt = (ValueType)formatter.Deserialize(stream); 146 | stream.Close(); 147 | return vt; 148 | } 149 | catch (Exception ex) 150 | { 151 | return null; 152 | } 153 | } 154 | //将一个结构序列化为字节数组 155 | private byte[] SerializeInfoObjToByteArray(ValueType infoStruct) 156 | { 157 | if (infoStruct == null) 158 | { 159 | return null; 160 | } 161 | 162 | try 163 | { 164 | MemoryStream stream = new MemoryStream(); 165 | formatter.Serialize(stream, infoStruct); 166 | 167 | byte[] bytes = new byte[(int)stream.Length]; 168 | stream.Position = 0; 169 | int count = stream.Read(bytes, 0, (int)stream.Length); 170 | stream.Close(); 171 | return bytes; 172 | } 173 | catch (Exception ex) 174 | { 175 | return null; 176 | } 177 | } 178 | 179 | } 180 | } 181 | -------------------------------------------------------------------------------- /MarshalHelper/MarshalHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Runtime.InteropServices; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using Utility.Tool; 8 | 9 | namespace MarshalHelper 10 | { 11 | public class MarshalHelper 12 | { 13 | #region unsafe 不安全代码 IntPtr to byte[] 14 | public static byte[] Unsafe_IntPtrToByte(IntPtr source, Int32 byteLength) 15 | { 16 | unsafe 17 | { 18 | byte[] data = new byte[byteLength]; 19 | void* tempData = source.ToPointer(); 20 | using (System.IO.UnmanagedMemoryStream tempUMS = new System.IO.UnmanagedMemoryStream((byte*)tempData, byteLength)) 21 | { 22 | tempUMS.Read(data, 0, byteLength); 23 | } 24 | return data; 25 | } 26 | } 27 | #endregion 28 | 29 | #region IntPtr to byte[] 30 | public static byte[] IntPtrToByte(IntPtr pointerInt, Int32 byteLength) 31 | { 32 | try 33 | { 34 | byte[] destinationData = new byte[byteLength]; 35 | Marshal.Copy(pointerInt, destinationData, 0, byteLength);//将数据从非托管内存指针复制到托管 8 位无符号整数数组。 36 | return destinationData; 37 | } 38 | catch 39 | { 40 | return null; 41 | } 42 | } 43 | /// 44 | /// 将bytelist复制到非托管内存指针IntPtr里 45 | /// 46 | /// 47 | public static IntPtr ByteToIntPtr(byte[] source) 48 | { 49 | try 50 | { 51 | IntPtr destpointer = Marshal.AllocHGlobal(source.Length); 52 | Marshal.Copy(source, 0, destpointer, source.Length); 53 | return destpointer; 54 | } 55 | catch 56 | { 57 | return IntPtr.Zero; 58 | } 59 | } 60 | 61 | #endregion 62 | 63 | #region string to IntPtr / IntPtr to string 64 | /// 65 | /// 使用Marshal提取[句柄/C++指针]指向的值,并转换成String 66 | /// 67 | public static string IntPtrToString(IntPtr pointer, int byteLength = byte.MaxValue) 68 | { 69 | byte[] destinationData = new byte[byteLength]; 70 | Marshal.Copy(pointer, destinationData, 0, byteLength);//将数据从非托管内存指针复制到托管 8 位无符号整数数组。 71 | string strData = Encoding.ASCII.GetString(destinationData); 72 | return strData; 73 | } 74 | /// 75 | /// 使用Marshal将String封装成[句柄/C++指针],形成IntPtr 76 | /// 77 | public static IntPtr StringToIntPtr(string source, Encoding type = null) 78 | { 79 | IntPtr destpointer = IntPtr.Zero; 80 | if (type == null) 81 | { 82 | type = Encoding.Default; 83 | } 84 | switch (type.ToString()) 85 | { 86 | case "Default": 87 | destpointer = Marshal.StringToHGlobalAnsi(source); 88 | break; 89 | default: 90 | destpointer = Marshal.StringToHGlobalUni(source); 91 | break; 92 | 93 | } 94 | return destpointer; 95 | } 96 | #endregion 97 | 98 | #region Int32 to IntPtr / IntPtr to Int32 99 | public static IntPtr Int32ToIntPtr(Int32 source) 100 | { 101 | IntPtr destpointer = Marshal.AllocHGlobal(4); 102 | byte[] sourceData = ByteHelper.IntToByte(source); 103 | Marshal.Copy(sourceData, 0, destpointer, sourceData.Length);// 将数据从一维托管 8 位无符号整数数组复制到非托管内存指针。 104 | return destpointer; 105 | } 106 | public static int IntPtrToInt32(IntPtr pointerInt, int byteLength = 4) 107 | { 108 | byte[] destinationData = new byte[byteLength]; 109 | Marshal.Copy(pointerInt, destinationData, 0, byteLength);//将数据从非托管内存指针复制到托管 8 位无符号整数数组。 110 | int ret = ByteHelper.ByteToInt32(destinationData); 111 | return ret; 112 | } 113 | #endregion 114 | 115 | #region Int16 to IntPtr / IntPtr to Int16 116 | public static IntPtr Int16ToIntPtr(Int16 source) 117 | { 118 | IntPtr destpointer = Marshal.AllocHGlobal(4); 119 | byte[] sourceData = ByteHelper.IntToByte(source); 120 | Marshal.Copy(sourceData, 0, destpointer, sourceData.Length);// 将数据从一维托管 8 位无符号整数数组复制到非托管内存指针。 121 | return destpointer; 122 | } 123 | public static int IntPtrToInt16(IntPtr pointerInt, int byteLength = 2) 124 | { 125 | byte[] destinationData = new byte[byteLength]; 126 | Marshal.Copy(pointerInt, destinationData, 0, byteLength);//将数据从非托管内存指针复制到托管 8 位无符号整数数组。 127 | int ret = ByteHelper.ByteToInt32(destinationData); 128 | return ret; 129 | } 130 | #endregion 131 | 132 | #region struct to IntPtr / IntPtr to struct 133 | public static IntPtr StructToIntPtr(object source) 134 | { 135 | Type type = source.GetType(); 136 | int size = Marshal.SizeOf(type); 137 | IntPtr destpointer = Marshal.AllocHGlobal(size); 138 | try 139 | { 140 | Marshal.StructureToPtr(source, destpointer, false); 141 | return destpointer; 142 | } 143 | catch (Exception ex) 144 | { 145 | FreeStruct(destpointer, type); 146 | return IntPtr.Zero; 147 | } 148 | } 149 | public static T IntPtrToStruct(IntPtr source) 150 | { 151 | return (T)Marshal.PtrToStructure(source, typeof(T)); 152 | } 153 | public static object IntPtrToStruct(IntPtr source, Type type) 154 | { 155 | return Marshal.PtrToStructure(source, type); 156 | } 157 | #endregion 158 | 159 | #region 释放IntPtr 160 | public static void Free(IntPtr pointer) 161 | { 162 | Marshal.FreeHGlobal(pointer); 163 | } 164 | public static void FreeStruct(IntPtr pointer, Type type) 165 | { 166 | Marshal.DestroyStructure(pointer, type); 167 | } 168 | #endregion 169 | 170 | #region 委托 to IntPtr 171 | public static IntPtr GetFunctionPointer(Delegate pointer) 172 | { 173 | IntPtr ret = Marshal.GetFunctionPointerForDelegate(pointer); 174 | return ret; 175 | 176 | } 177 | #endregion 178 | 179 | #region byte to struct 180 | public static StructType BytesToStruct(byte[] bytesBuffer) 181 | { 182 | // 检查长度。 183 | if (bytesBuffer.Length != Marshal.SizeOf(typeof(StructType))) 184 | { 185 | throw new ArgumentException("bytesBuffer参数和structObject参数字节长度不一致。"); 186 | } 187 | 188 | IntPtr bufferHandler = Marshal.AllocHGlobal(bytesBuffer.Length); 189 | for (int index = 0; index < bytesBuffer.Length; index++) 190 | { 191 | Marshal.WriteByte(bufferHandler, index, bytesBuffer[index]); 192 | } 193 | StructType structObject = (StructType)Marshal.PtrToStructure(bufferHandler, typeof(StructType)); 194 | Marshal.FreeHGlobal(bufferHandler); 195 | return structObject; 196 | } 197 | #endregion 198 | 199 | 200 | 201 | } 202 | } 203 | --------------------------------------------------------------------------------