ericwuhk 2009-08-20
C# 操作内存是如何实现的呢?让我们开始讲解吧:
我们先来看看C#中如何操作内存,也就是非托管的数据。这需要引用System.Runtime.InteropServices命名空间。该命名空间下的Marshal的一些静态方法提供了这样的功能:
Marshal.ReadInt32() //从指定内存地址读取4位 C#操作内存 Marshal.PtrToStringAnsi() //从指定内存地址读取字符串C#操作内存 Marshal.WriteInt32() //将整数写到指定内存地址 C#操作内存 Marshal.WriteByte() //将字符串写到指定内存地址我们来看看具体的代码: using System; using System.Text; using System.Runtime.InteropServices; internal sealed class RCEvent { public int Event; public int Flag; public string User; }; //C#操作内存 internal sealed class RCEventAgent { internal static RCEvent Read(IntPtr ptr){ RCEvent Event = new RCEvent(); Event.Event = ReadEvent(ptr); Event.Flag = ReadFlag(ptr); Event.User = ReadUser(ptr); return Event; } //C#操作内存 internal static int ReadEvent(IntPtr basePtr) { return Marshal.ReadInt32(basePtr); } internal static int ReadFlag(IntPtr basePtr) { return Marshal.ReadInt32(basePtr,4); } internal static string ReadUser(IntPtr basePtr) { return Marshal.PtrToStringAnsi( new IntPtr(basePtr.ToInt32() + 8)); } internal static void Write(ClientEvent Event,IntPtr ptr) { WriteEvent(ptr,Event.Event); WriteFlag(ptr,Event.Flag); WriteUser(ptr,Event.User); } //C#操作内存 internal static void WriteEvent( IntPtr basePtr,int value) { Marshal.WriteInt32(basePtr,value); } internal static void WriteFlag( IntPtr basePtr,int flag) { Marshal.WriteInt32(basePtr,4,flag); } internal static void WriteUser( IntPtr basePtr,string user) { WriteString(basePtr,user,8,40); } private static void WriteString( IntPtr basePtr,string value,int offset,int length) { int pos = 0; byte[] bytes = Encoding.Default.GetBytes(value); while(pos length) { if (pos bytes.Length) Marshal.WriteByte(basePtr,offset,bytes[pos]); else Marshal.WriteByte(basePtr,offset,0); pos ++; offset ++; } } //C#操作内存 }
这样我们就可以通过ReadEvent和WriteEvent直接在c#中处理该结构体。或者通过 ReadXXX() 和 WriteXXX() 直接修改其字段。
public void DoSomething(IntPtr ptr){ RCEvent Event = RCEventAgent.Read(ptr); Event.Flag ++; RCEventAgent.Write(ptr, Event); // 或者以下代码 // RCEventAgent.WriteFlag( ptr, RCEventAgent.ReadFlag(ptr) + 1 ); }
C++中则可以直接将结构体地址传给C#: