貌似传统方法,只能到取结构类型的:
http://topic.csdn.net/u/20090825/16/725bc96a-33f9-4c63-85ef-01d22d6c1ed2_3.html
说明见:292楼~~using System;
namespace ConsoleApplication9
{
public struct BofStruct { }
public class BofClass { }
class Program
{
unsafe static void Main(string[] args)
{
//--准备
BofStruct bs = new BofStruct();
BofClass bc = new BofClass(); //--测试
//Console.WriteLine("BofStruct'sizeof:{0}", sizeof(BofClass));
//无法获取托管类型(“BofClass”)的地址和大小,或无法声明指向它的指针
Console.WriteLine("BofStruct'sizeof:{0}", sizeof(BofStruct));
//BofStruct'sizeof:4
//Console.WriteLine("bc'pointer:{0:X8}", (uint)&bc);
//无法获取托管类型(“BofClass”)的地址和大小,或无法声明指向它的指针
Console.WriteLine("bc'pointer:{0:x8}", (uint)&bs);
//bc'pointer:057fecd0 //--使用
int num;
int* p;
p = #
*p = 999;
System.Console.WriteLine("p:{0}", *p);
System.Console.WriteLine("p:{0}", p->ToString()); Console.ReadKey();
}
}
}也许也有别的方法吧~~
http://topic.csdn.net/u/20090825/16/725bc96a-33f9-4c63-85ef-01d22d6c1ed2_3.html
说明见:292楼~~using System;
namespace ConsoleApplication9
{
public struct BofStruct { }
public class BofClass { }
class Program
{
unsafe static void Main(string[] args)
{
//--准备
BofStruct bs = new BofStruct();
BofClass bc = new BofClass(); //--测试
//Console.WriteLine("BofStruct'sizeof:{0}", sizeof(BofClass));
//无法获取托管类型(“BofClass”)的地址和大小,或无法声明指向它的指针
Console.WriteLine("BofStruct'sizeof:{0}", sizeof(BofStruct));
//BofStruct'sizeof:4
//Console.WriteLine("bc'pointer:{0:X8}", (uint)&bc);
//无法获取托管类型(“BofClass”)的地址和大小,或无法声明指向它的指针
Console.WriteLine("bc'pointer:{0:x8}", (uint)&bs);
//bc'pointer:057fecd0 //--使用
int num;
int* p;
p = #
*p = 999;
System.Console.WriteLine("p:{0}", *p);
System.Console.WriteLine("p:{0}", p->ToString()); Console.ReadKey();
}
}
}也许也有别的方法吧~~
解决方案 »
- using System.Collections.Generic;弱弱的问下引用这个空间什么作用啊
- 判断类型的问题,急!急!急!
- IP地址转整数为什么会溢出错误,请教?
- 连excel提示找不到可安装的 ISAM。
- 设置Excel格式NumberFormatLocal="@ "设置了后日期格式就全成数字了,怎么办??
- 1000分求VS2005控件安装示例
- 001写入csv文件,变成了1,如果在前面加"'"也无效。
- 在winform中 关于刷新客户端数据
- 不是说struct可以不new吗?为什么Point就非要new呢?
- 一个关于Gridview的问题?
- 如何能让windows用户注销后仍然能运行有窗口操作的程序?或者用户永远不注销?
- 蛋疼的json解析问题~
指针类型不同于引用类型,
当中要架起一座桥梁才行.在.net框架中,能够实施指针操作的类举不胜举
包括引入一些特定的类也行,
只是我并不熟这部分内容...
请看这个问题,需要这样做
http://topic.csdn.net/u/20090904/21/639bdc71-16e8-48e8-9528-04c0b985dfdc.html?seed=2135148115&r=59581132#r_59581132
与引用(引用类型的值)不同,指针不受垃圾回收器跟踪(垃圾回收器并不知晓指针和它们指向的数据)。出于此原因,不允许指针指向引用或者包含引用的结构,并且指针的目标类型必须是 unmanaged-type。
unmanaged-type 是任何不是 reference-type 并且在任何嵌套级别都不包含 reference-type 字段的类型。换句话说,unmanaged-type 是下列类型之一:
• sbyte、byte、short、ushort、int、uint、long、ulong、char、float、double、decimal 或 bool。
• 任何 enum-type。
• 任何 pointer-type。
• 任何由用户定义的只包含 unmanaged-types 字段的 struct-type。
将指针和引用进行混合使用时的基本规则是;引用(对象)的目标可以包含指针,但指针的目标不能包含引用。
fixed类中的第一字段,然后取得该字段的地址但是我想这个类的内存布局不能是Auto,只能是按顺序或显式布局吧
fixed 语句中声明的局部变量类型必须是指针类型既然这样,又回到老问题上,针类型无法与class类型沟通
{
return MultiUseWord.GetHashCode(this);
}具体执行在辅助类中:
MultiUseWord
这个类太复杂了,
不好调式,
也看不明白.
(这个解决不了问题,只能用于分析)------------值的传递过程----------------
[1]传入对象,获得对象muw,在muw上调用GetPayload
MultiUseWord muw = GetForObject(obj);[2]获得muw
muw.GetPayload()
实际上来自于MultiUseWord的preHeader.muw
get { return this.preHeader.muw; }[2]GetPayload将对象的value进行掩码并返回
UIntPtr PAYLOAD_MASK = (UIntPtr)0xfffffff8;
UIntPtr result = (this.value & PAYLOAD_MASK);
result就是我们要的值,关键还是这个this的转换过程------------this的转换过程----------------
[1]传入对象obj
MultiUseWord muw = GetForObject(obj);[2]对象强制转换为ObjectPreMUW
MultiUseWord result = ((ObjectPreMUW)obj).muw;[3]ObjectPreMUW
ObjectPreMUW继承了ObjectMUW
internal class ObjectPreMUW : ObjectMUW
字段
internal new PreHeaderDefault preHeader;[4]PreHeaderDefault
internal MultiUseWord muw;[5]指针的值
internal UIntPtr value;翻遍Object也没有这个指针值,
鬼知道怎么传过去的,
又是编译器魔法吧-_-
[2]不使用unsafe语法,用Marshal.PtrToStructure也应该可以,不过需要Copy内存两次
[3]与引用(引用类型的值)不同,指针不受垃圾回收器跟踪(垃圾回收器不了解指针和它们指向的数据)。
出于此原因,不允许指针指向引用或者包含引用的结构,并且指针的目标类型必须是非托管类型。
[4]“非托管类型”是任何不是“引用类型”并且在任何嵌套级别都不包含“引用类型”字段的类型。
[A]sbyte、byte、short、ushort、int、uint、long、ulong、char、float、double、decimal 或 bool。
[B]任何“枚举类型”。
[C]任何“指针类型”。
[D]任何由用户定义的只包含“非托管类型”字段的“结构类型”。
[5]void* 类型表示指向未知类型的指针。
由于目标类型是未知的,间接寻址运算符不能应用于 void* 类型的指针,
也不能对这样的指针执行任何算术运算。
但是 void* 类型的指针可以强制转换为任何其他指针类型(反之亦然)。
[6]允许在不同指针类型之间以及指针类型与整型之间进行转换。
[7]指针类型可用作易失字段的类型
[8]方法可以返回某一类型的值,而该类型可以是指针。
[9]stackalloc 运算符可用于从调用堆栈中分配内存。
[10]fixed 语句可用于暂时固定一个变量,以便可以获取它的地址
using System.Collections;
using System.Runtime.InteropServices;public unsafe class Memory
{
// Handle for the process heap. This handle is used in all calls to the
// HeapXXX APIs in the methods below.
static int ph = GetProcessHeap();
// Private instance constructor to prevent instantiation.
private Memory() { }
// Allocates a memory block of the given size. The allocated memory is
// automatically initialized to zero.
public static void* Alloc(int size)
{
void* result = HeapAlloc(ph, HEAP_ZERO_MEMORY, size);
if (result == null) throw new OutOfMemoryException();
return result;
}
// Copies count bytes from src to dst. The source and destination
// blocks are permitted to overlap.
public static void Copy(void* src, void* dst, int count)
{
byte* ps = (byte*)src;
byte* pd = (byte*)dst;
if (ps > pd)
{
for (; count != 0; count--) *pd++ = *ps++;
}
else if (ps < pd)
{
for (ps += count, pd += count; count != 0; count--) *--pd = *--ps;
}
}
// Frees a memory block.
public static void Free(void* block)
{
if (!HeapFree(ph, 0, block)) throw new InvalidOperationException();
}
// Re-allocates a memory block. If the reallocation request is for a
// larger size, the additional region of memory is automatically
// initialized to zero.
public static void* ReAlloc(void* block, int size)
{
void* result = HeapReAlloc(ph, HEAP_ZERO_MEMORY, block, size);
if (result == null) throw new OutOfMemoryException();
return result;
}
// Returns the size of a memory block.
public static int SizeOf(void* block)
{
int result = HeapSize(ph, 0, block);
if (result == -1) throw new InvalidOperationException();
return result;
}
// Heap API flags
const int HEAP_ZERO_MEMORY = 0x00000008;
// Heap API functions
[DllImport("kernel32")]
static extern int GetProcessHeap();
[DllImport("kernel32")]
static extern void* HeapAlloc(int hHeap, int flags, int size);
[DllImport("kernel32")]
static extern bool HeapFree(int hHeap, int flags, void* block);
[DllImport("kernel32")]
static extern void* HeapReAlloc(int hHeap, int flags,
void* block, int size);
[DllImport("kernel32")]
static extern int HeapSize(int hHeap, int flags, void* block);
}class Test
{
unsafe static void Main()
{
byte[] array = new byte[256];
fixed (byte* p = array) Console.WriteLine("array'address :{0:X8}", (uint)p);
Console.WriteLine("array'hashcode:{0:X8}", array.GetHashCode());
byte* buffer = (byte*)Memory.Alloc(256);
for (int i = 0; i < 256; i++) buffer[i] = (byte)i;
fixed (byte* p = array) Memory.Copy(buffer, p, 256);
Memory.Free(buffer);
//for (int i = 0; i < 256; i++) Console.WriteLine(array[i]);
Console.ReadKey();
}
}
因为string是自定义引用类型,被特殊照顾了,
主要是看在类似于“字符数组”的结构上。using System;struct B
{
int i;
//int[] o;
//TODO:
}class MyClass
{
unsafe static void Main(string[] args)
{
B[] a = { new B(), new B(), new B() };
System.Console.WriteLine(sizeof(B));
string s = "12345";
fixed (char* p = s) System.Console.WriteLine("{0:X8}", (uint)p); int b = 100;
System.Console.WriteLine("{0:X8}", (uint)&b); System.Console.ReadKey();
}
}
[1]T
[2]T[]
[3]string而托管类型(除数组、string)以外的类型变量,
获到地址,不应该要指针的身上打主意了。以下的方法
[1]语言混合编程
[2]DllImport系统调用
[3]反推(从hashcode值反推也是一种思路)
[4]Marshal
class Test
{
static string IntToString(int value) {
int n = value >= 0? value: -value;
unsafe {
char* buffer = stackalloc char[16];
char* p = buffer + 16;
do {
*--p = (char)(n % 10 + '0');
n /= 10;
} while (n != 0);
if (value < 0) *--p = '-';
return new string(p, 0, (int)(buffer + 16 - p));
}
}
static void Main() {
Console.WriteLine(IntToString(12345));
Console.WriteLine(IntToString(-999));
}
}
虚拟内存通常是由固定大小的块来实现的,在win32中这些块称为“页”,每页大小为4,096字节。在intel cpu结构中,通过在一个控制寄存器中设置一位来启用分页。启用分页时cpu并不能直接访问内存,对每个地址要经过一个映射进程,通过一系列称作“页表” 的查找表把虚拟内存地址映射成实际内存地址。通过使用硬件地址映射和页表win32可使虚拟内存即有好的性能而且还提供保护。利用处理器的页映射能力,操作系统为每个进程提供独立的从逻辑地址到物理地址的映射,使每个进程的地址空间对另一个进程完全不可见。win32中也提供了一些访问进程内存空间的函数,但使用时要谨慎,一不小心就有可能破坏被访问的进程。virtualqueryex
函数功能描述:查询地址空间中内存地址的信息。函数原型:
dword virtualqueryex( handle hprocess, lpcvoid lpaddress, pmemory_basic_information lpbuffer, dword dwlength );
参数:
hprocess 进程句柄。
lpaddress 查询内存的地址。
lpbuffer 指向memory_basic_information结构的指针,用于接收内存信息。
dwlength memory_basic_information结构的大小。
返回值:
函数写入lpbuffer的字节数,如果不等于sizeof(memory_basic_information)表示失败。
备注:
memory_basic_information在winnt.h中定义如下:
typedef struct _memory_basic_information {
pvoid baseaddress; // 区域基地址。
pvoid allocationbase; // 分配基地址。
dword allocationprotect; // 区域被初次保留时赋予的保护属性。
size_t regionsize; // 区域大小(以字节为计量单位)。
dword state; // 状态(mem_free、mem_reserve或 mem_commit)。
dword protect; // 保护属性。
dword type; // 类型。
} memory_basic_information, *pmemory_basic_information;成员解释:
baseaddress 与lpaddress参数的值相同,但是四舍五入为页面的边界值。
allocationbase 指明用virtualalloc函数分配内存区域的基地址。lpaddress
在该区域之内。
allocationprotect 指明该地址空间区域被初次保留时赋予该区域的保护属性。
page_readonly 只读属性,如果试图进行写操作,将引发访问违规。如果系统
区分只读、执行两种属性,那么试图在该区域执行代码也将引
发访问违规。
page_readwrite 允许读写。
page_execute 只允许执行代码,对该区域试图进行读写操作将引发访问违规。
page_execute_read 允许执行和读取。
page_execute_readwrite 允许读写和执行代码。
page_execute_writecopy 对于该地址空间的区域,不管执行什么操作,都不会引发访问违
规。如果试图在该页面上的内存中进行写入操作,就会将它自己
的私有页面(受页文件的支持)拷贝赋予该进程。
page_guard 在页面上写入一个字节时使应用程序收到一个通知(通过一个异
常条件)。该标志有一些非常巧妙的用法。windows 2000在创建
线程堆栈时使用该标志。
page_noaccess 禁止一切访问。
page_nocache 停用已提交页面的高速缓存。一般情况下最好不要使用该标志,
因为它主要是供需要处理内存缓冲区的硬件设备驱动程序的开发
人员使用的。
regionsize 用于指明内存块从基地址即baseaddress开始的所有页面的大
小(以字节为计量单位)这些页面与含有用lpaddress参数设
定的地址的页面拥有相同的保护属性、状态和类型。
state 用于指明所有相邻页面的状态。
mem_commit 指明已分配物理内存或者系统页文件。
mem_free 空闲状态。该区域的虚拟地址不受任何内存的支持。该地址空间没
有被保留。改状态下allocationbase、allocationprotect、protect
和type等成员均未定义。
mem_reserve 指明页面被保留,但是没有分配任何物理内存。该状态下protect成
员未定。
protect 用于指明所有相邻页面(内存块)的保护属性。这些页面与含有
拥有相同的保属性、状态和类型。意义同allocationprotect。
type 用于指明支持所有相邻页面的物理存储器的类型(mem_image,
mem_mapped或mem_private)。这些相邻页面拥有相同的保护属
性、状态和类型。如果是windows 98,那么这个成员将总是
mem_private 。
mem_image 指明该区域的虚拟地址原先受内存映射的映像文件(如.exe或dll
文件)的支持,但也许不再受映像文件的支持。例如,当写入模块
映像中的全局变量时,“写入时拷贝”的机制将由页文件来支持特
定的页面,而不是受原始映像文件的支持。
mem_mapped 该区域的虚拟地址原先是受内存映射的数据文件的支持,但也许不
再受数据文件的支持。例如,数据文件可以使用“写入时拷贝”的
保护属性来映射。对文件的任何写入操作都将导致页文件而不是原
始数据支持特定的页面。
mem_private 指明该内存区域是私有的。不被其他进程共享。
c#怎样调用api不用 说了吧
更简单的方法:
每隔一定时间,抓取屏幕截屏,分析指定位置的颜色值,然后...
另外试下Marshal.GetComInterfaceForObject是否得到你需要的
using System.Runtime.InteropServices;
//换成struct正常
public class Point
{
public int x;
public int y;
}
class Example
{
static void Main()
{
Point p = new Point();
p.x = 1;
p.y = 1;
//未处理的异常: System.ArgumentException: 类型“Point”不能作为非托管结构进行封送
//处理;无法计算有意义的大小或偏移量。
IntPtr pnt = Marshal.AllocHGlobal(Marshal.SizeOf(p));
Marshal.StructureToPtr(p, pnt, false);
Point anotherP = new Point();
anotherP = (Point)Marshal.PtrToStructure(pnt, typeof(Point));
Console.WriteLine("The value of new point is " + anotherP.x + " and " + anotherP.y + ".");
Marshal.FreeHGlobal(pnt);
}
}现在的思路是,退一步,
[1]定义一个引用类型
[2]Marshal申请一个内存,保留指针
[3]将引用类型封送到该内存上把命题反过来,
己知地址,将引用类型放置到该地址上
using System.Runtime.InteropServices;
class Test
{
public static unsafe byte[] Struct2Bytes(Object obj)
{
int size = Marshal.SizeOf(obj);
byte[] bytes = new byte[size];
IntPtr arrPtr = Marshal.UnsafeAddrOfPinnedArrayElement(bytes, 0);
Marshal.StructureToPtr(obj, arrPtr, true);
return bytes;
} public static unsafe Object Bytes2Struct<T>(byte[] bytes)
//where T:struct
{
IntPtr arrPtr = Marshal.UnsafeAddrOfPinnedArrayElement(bytes, 0);
return Marshal.PtrToStructure(arrPtr, typeof(T));
}
}class TestA
{
static void Main(string[] args)
{
int s = 100;
byte[] bytes = Test.Struct2Bytes(s);
object o = Test.Bytes2Struct<int>(bytes);
Console.WriteLine(o.GetType());
Console.WriteLine(o);
}
}
using System.Runtime.InteropServices;[StructLayout(LayoutKind.Sequential, Pack = 1)]
public class Point
{
public int x;
public int y;
}class Example
{
static void Main()
{
//类型A
Point pointA = new Point();
pointA.x = 100;
pointA.y = 200;
//从进程的非托管内存中分配内存
int sizeOfPointA = Marshal.SizeOf(typeof(Point));
Console.WriteLine("size of Point:{0}", sizeOfPointA);
IntPtr ptr = Marshal.AllocHGlobal(sizeOfPointA);
Console.WriteLine("ptr:{0:X8}", (uint)ptr); //将数据从托管对象封送到非托管内存块
Marshal.StructureToPtr(pointA, ptr, false);
pointA.x = 300;
pointA.y = 400; //类型B
Point pointB;// = new Point();
//Console.WriteLine(pointB.GetHashCode());
//unsafe
//{
// System.Console.WriteLine("anp:{0:X8}", (uint)&pointB);
//} //将数据从非托管内存块封送到新分配的指定类型的托管对象
pointB = (Point)Marshal.PtrToStructure(ptr, typeof(Point)); //释放以前使用从进程的非托管内存中分配的内存
Marshal.FreeHGlobal(ptr); //验证
Console.WriteLine("hashcode of PointA:{0:X8}", pointA.GetHashCode());
Console.WriteLine("hashcode of PointB:{0:X8}", pointB.GetHashCode());
Console.WriteLine("The value of new pointA is " + pointA.x + " and " + pointA.y + ".");
Console.WriteLine("The value of new pointB is " + pointB.x + " and " + pointB.y + ".");
}
}
1)语法思考法阶段
穷尽语法,从语法的层面上去偿试。
比如,这里面需要解决指针的问题,
就把整个指针研究一遍。
反复对比可行性与不可行性。
在个CASE中,结构类型可以做到,引用类型就做不到。
比较严谨的提法应该是:委托类型与非委托类型(并不等同于结构类型)
重点放在做不到的根源上,为什么不行?!
我总结了一下,主要出于两个原因:
[A]委托类型的内存对齐是不确定的,由编译器决定的(从一些出错信息中得到提示)
[B]基于A,委托类型的大小很难取得(后来发现这个是需要一些技术手段来处理的,从C++.net中获得灵感)
[C]委托类型分配在堆上,受到GC的影响,并且地址本身就是不可靠的。(先考虑了为啥C#要设计出fixed来)2)语言对比阶段
主要研究了C++语法机制,
一编关于C#直接调用汇编给予了一些灵感
总结如下:
[A]委托类型的内存布局是关键
[B]解决了sizeof的问题,就能终绕过这个东西,就可以突破非委托类型的桎梏。C++的关键也在尺寸上。3)技术筛选阶段
设定包围圈
[1]语言混合编程
[2]DllImport系统调用
[3]反推(hashcode值/显存关系)
[4]Marshal
最后还是决定先从Marshal偿试突破
Marshal整个学习一遍,发现了几个关键点:
[A]内存布局StructLayout(在class上试了一下,竟然也行,信心大增)
[B]内存机制GC,发现GC存在地址转换机制
[C]Marshal本身包围圈己经缩的很小了,
因为需要再找一些验证手段,答案明天公布,
也并非100%的,但多少还有点价值。
简单测试代码:
using System;
using System.Runtime.InteropServices;public class BoxedObject : IDisposable
{
private object _boxedObject;
private GCHandle _memData; public BoxedObject(object boxObject)
{
if (boxObject == null)
{
throw new ArgumentNullException();
}
_boxedObject = boxObject;
} ~BoxedObject()
{
(this as IDisposable).Dispose();
} public object Value
{
get { return _boxedObject; }
set
{
if (value == null)
{
throw new ArgumentNullException();
}
if (value.GetType() != _boxedObject.GetType())
{
throw new NotSupportedException(string.Format("Can not set [{0}] value to [{1}] object",
value.GetType().Name,
_boxedObject.GetType().Name));
} if (!_memData.IsAllocated)
{
_memData = GCHandle.Alloc(_boxedObject);
}
IntPtr pMemData = GCHandle.ToIntPtr(_memData);
IntPtr pBox = new IntPtr((Marshal.ReadIntPtr(pMemData).ToInt64() + IntPtr.Size));
Marshal.StructureToPtr(value, pBox, false);
}
} void IDisposable.Dispose()
{
if (_memData.IsAllocated)
_memData.Free();
}
}class Program
{
static void Main1(string[] args)
{
object test = 100;
Console.WriteLine("original value=" + test.ToString() + ", hash=" + test.GetHashCode());
BoxedObject b = new BoxedObject(test);
b.Value = 1000;
Console.WriteLine("after edit value=" + test.ToString() + ", hash=" + test.GetHashCode()); Console.ReadKey();
}
}
using System;
using System.Runtime.InteropServices;[StructLayout(LayoutKind.Sequential, Pack = 1)]
class MyClass
{
public int x ;
public byte y ;
}struct MyStruct
{
public int x;
public int y;
}class Tools
{
public static IntPtr GetAddress<T>(object obj)
{
GCHandle gch = new GCHandle();
if (!gch.IsAllocated)
{
gch = GCHandle.Alloc(obj);
}
IntPtr ptr_ptr_obj = GCHandle.ToIntPtr(gch);
IntPtr ptr_obj = Marshal.ReadIntPtr(ptr_ptr_obj); return ptr_obj;
} public static int GetSizeOf<T>()
{
int size = Marshal.SizeOf(typeof(T));
return size;
}
}class ProgramA
{
static void Main(string[] args)
{
//Class Test
MyClass mc = new MyClass();
IntPtr mc_prt = Tools.GetAddress<MyClass>(mc);
int mc_size = Tools.GetSizeOf<MyClass>(); Console.WriteLine("==========Class Test==========");
Console.WriteLine("mc's sizeof:{0}", mc_size);
Console.WriteLine("mc's address :{0:X8}", mc_prt.ToString());
Console.WriteLine("mc's hashcode:{0:X8}", mc.GetHashCode()); //Struct Test
MyStruct ms = new MyStruct();
IntPtr ms_prt = Tools.GetAddress<MyStruct>(ms);
int ms_size = Tools.GetSizeOf<MyStruct>(); Console.WriteLine("==========Struct Test==========");
Console.WriteLine("ms's sizeof:{0}", ms_size);
Console.WriteLine("ms's address :{0:X8}", ms_prt.ToString());
Console.WriteLine("ms's hashcode:{0:X8}", ms.GetHashCode()); //string Test
string ss = "abc";
IntPtr ss_prt = Tools.GetAddress<string>(ss);
//int ss_size = Tools.GetSizeOf<string>(); Console.WriteLine("==========string Test==========");
//Console.WriteLine("ss's sizeof:{0}", ss_size);
Console.WriteLine("ss's address :{0:X8}", ss_prt.ToString());
Console.WriteLine("ss's hashcode:{0:X8}", ss.GetHashCode()); //Class Test
MyClass mc1 = new MyClass();
IntPtr mc1_prt = Tools.GetAddress<MyClass>(mc1);
int mc1_size = Tools.GetSizeOf<MyClass>(); Console.WriteLine("==========Class Test==========");
Console.WriteLine("mc1's sizeof:{0}", mc1_size);
Console.WriteLine("mc1's address :{0:X8}", mc1_prt.ToString());
Console.WriteLine("mc1's hashcode:{0:X8}", mc1.GetHashCode()); //Array Test
MyClass[] mcs = new MyClass[3] { new MyClass(), new MyClass(), new MyClass(), };
Console.WriteLine("==========Array Test==========");
Console.WriteLine("mcs[0]'s address :{0:X8}", Tools.GetAddress<MyClass>(mcs[0]).ToString());
Console.WriteLine("mcs[1]'s address :{0:X8}", Tools.GetAddress<MyClass>(mcs[1]).ToString());
Console.WriteLine("mcs[2]'s address :{0:X8}", Tools.GetAddress<MyClass>(mcs[2]).ToString()); //Marshal.StructureToPtr(value, pBox, false); //End
Console.ReadKey();
}
}完善这个过程,交给大家去完成吧,主体思路己经有了。还有许多问题有待解决~~~
先去了解一下指针,了解一下Marshal
也许你会换个看法。没有指针,C#只能做C++10%的事情。
有了指针,C#能够做C++90%的事情。如果你不打算与其它系统交互,引用类型也许足够了。
要是你打算涉足图像、游戏、视频、算法、密码、Shell的话,
看看引用类型还能帮得上忙嘛?
剩下的问题会相对容易些。
继续研究GC与内存布局...BTW:
unsafe并非不全完,而是要求安全(对安全性的配置)
相比C++,在C#中使用unsafe首先是提高了安全的要求,其次才是提示编程者要小心谨慎。交作业:
using System;
using System.Runtime.InteropServices;//32bit计算机
[StructLayout(LayoutKind.Explicit)]
class MyClass
{
[FieldOffset(0)]
public char c1 ;
[FieldOffset(4)]
public int i1 ;
[FieldOffset(8)]
public char c2;
}struct MyClassLayout
{
public ulong SyncblkIndex;//index @ -4
public ulong TypeHandle;//index @ 0
public char c1;//index @ 4
public int i1;//index @ 4
public char c2;//index @ 4
}class Tools
{
public static IntPtr GetAddress<T>(object obj)
{
GCHandle gch = new GCHandle();
if (!gch.IsAllocated)
{
gch = GCHandle.Alloc(obj);
}
IntPtr ptr_ptr_obj = GCHandle.ToIntPtr(gch);
IntPtr ptr_obj = Marshal.ReadIntPtr(ptr_ptr_obj); return ptr_obj;
} public static int GetSizeOf<T>()
{
int size = Marshal.SizeOf(typeof(T));
return size;
}
}class ProgramA
{
static void GetFields(MyClass obj,ref MyClassLayout layout)
{
IntPtr pTypeHandle = Tools.GetAddress<MyClass>(obj);
IntPtr pSyncblkIndex = new IntPtr(pTypeHandle.ToInt32() - IntPtr.Size);
IntPtr pC1 = new IntPtr(pTypeHandle.ToInt32() + IntPtr.Size + 0);
IntPtr pI1 = new IntPtr(pTypeHandle.ToInt32() + IntPtr.Size + 4);
IntPtr pC2 = new IntPtr(pTypeHandle.ToInt32() + IntPtr.Size + 8); layout.SyncblkIndex = (ulong)Marshal.PtrToStructure(pSyncblkIndex, typeof(ulong));
layout.TypeHandle = (ulong)Marshal.PtrToStructure(pTypeHandle,typeof(ulong));
layout.c1 = (char)Marshal.PtrToStructure(pC1, typeof(char));
layout.i1 = (int)Marshal.PtrToStructure(pI1, typeof(int));
layout.c2 = (char)Marshal.PtrToStructure(pC2, typeof(char));
} static void SetFields(MyClass obj, ref MyClassLayout layout)
{
IntPtr pTypeHandle = Tools.GetAddress<MyClass>(obj);
IntPtr pSyncblkIndex = new IntPtr(pTypeHandle.ToInt32() - IntPtr.Size);
IntPtr pC1 = new IntPtr(pTypeHandle.ToInt32() + IntPtr.Size + 0);
IntPtr pI1 = new IntPtr(pTypeHandle.ToInt32() + IntPtr.Size + 4);
IntPtr pC2 = new IntPtr(pTypeHandle.ToInt32() + IntPtr.Size + 8); Marshal.StructureToPtr(layout.SyncblkIndex, pSyncblkIndex, false);
Marshal.StructureToPtr(layout.TypeHandle, pTypeHandle, false);
Marshal.StructureToPtr(layout.c1, pC1, false);
Marshal.StructureToPtr(layout.i1, pI1, false);
Marshal.StructureToPtr(layout.c2, pC2, false);
} static void PrintFields(MyClass obj,string tips)
{
int size = Tools.GetSizeOf<MyClass>(); IntPtr pTypeHandle = Tools.GetAddress<MyClass>(obj);
IntPtr pSyncblkIndex = new IntPtr(pTypeHandle.ToInt32() - IntPtr.Size);
IntPtr pC1 = new IntPtr(pTypeHandle.ToInt32() + IntPtr.Size + 0);
IntPtr pI1 = new IntPtr(pTypeHandle.ToInt32() + IntPtr.Size + 4);
IntPtr pC2 = new IntPtr(pTypeHandle.ToInt32() + IntPtr.Size + 8); Console.WriteLine("========== " + tips + " ==========");
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("c1:{0:X8},i1:{1:X8},c2:{2:X8}", obj.c1, obj.i1, obj.c2);
Console.ResetColor();
Console.WriteLine("MyClass's size:{0}", size);
Console.Write("MyClass's hashcode:");
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine("{0:X8}", obj.GetHashCode());
Console.ResetColor();
Console.WriteLine("========== " + "address list" + " ==========");
Console.WriteLine("SyncblkIndex's address :{0:X8}", (uint)pSyncblkIndex);
Console.WriteLine("TypeHandle's address :{0:X8}", (uint)pTypeHandle);
Console.WriteLine("C1's address :{0:X8}", (uint)pC1);
Console.WriteLine("I1's address :{0:X8}", (uint)pI1);
Console.WriteLine("C2's address :{0:X8}", (uint)pC2);
Console.WriteLine();
} static void Main(string[] args)
{
//创建
MyClass obj = new MyClass();
MyClassLayout layout = new MyClassLayout(); //初始化
obj.c1='a';
obj.i1 = 100;
obj.c2='b';
//值-->结构副本
GetFields(obj, ref layout);
PrintFields(obj, "修改前"); //修改结构副本
layout.c1 = '!';
layout.i1 = 1024-1;
layout.c2 = '%';
//结构副本-->值
SetFields(obj, ref layout);
PrintFields(obj, "修改后"); //结束
Console.ReadKey();
}
}
c1:a,i1:00000064,c2:b
MyClass's size:12
MyClass's hashcode:033C0D9D
========== address list ==========
SyncblkIndex's address :01351730
TypeHandle's address :01351734
C1's address :01351738
I1's address :0135173C
C2's address :01351740========== 修改后 ==========
c1:!,i1:000003FF,c2:%
MyClass's size:12
MyClass's hashcode:011C7A8C
========== address list ==========
SyncblkIndex's address :01351730
TypeHandle's address :01351734
C1's address :01351738
I1's address :0135173C
C2's address :01351740
那你别在C#版混了,直接回去用C++得了, 图像,游戏,怎么了,C++能做,C#更容易..
引用本身就是个指针,只是 象指针那样还要去管内存释放... 你不用来故做高深了.
引用本身就是个指针,
这就代表你的水平,这并不代不表C#,
你也代表不了CSDN啊。
Class.forName("PackageName.ClassName");
因为内容比较多,代码我就不仔细看了。发现提到了一个Marshal 类,啊,好东西啊,有了那个类,类似指针的操作就不难做到了,其实也就是把地址传递给接口,C#本身不需要直接操作指针的,没有意义。至于楼主后来使用的GCHandle,在Marshal 类中也提到过,MSDN上真的很详细。Marshal 类复制托管资源到非托管资源,而GCHandle可以直接固定托管资源,使其作为非托管资源传递。
lz引用文章可是需要加出处说明的。
其实最简单的获得指针的办法是:object data = new object();
GCHandle handle = GCHandle.Alloc(data);
void* pVer = handle.AddrOfPinnedObject().ToPointer();
// do something.
handle.Free();
GCHandle handle = GCHandle.Alloc(data);
void* pVer = handle.AddrOfPinnedObject().ToPointer();
// do something.
handle.Free();
@lalac
你看一下48楼顶,我有一段说明的,因为觉得对装箱的值类型理解有帮助,并且重要技术点是一样的,有必要分享一下。(如果有私心的话,完全可以不贴,对不对。)上段代码是后来发现的,异曲同工,关于装箱的值类型,MARK一下: google 关键字:GCHandle StructureToPtr,
再搜,链接有多个,初始的那个文章作者:winkingz
内容不错,特别是“装箱的值类型”这个概念被表达清楚的。
你告诉我确切的链接地址,我会补上的。至于代码确实比较笨拙,这个我也意识到了,
因为是第一时间贴上来的,一来比较兴奋,二来没有做优化的事情(这个也提了),只要能先达到目标就行,
后来花点时间把GCH和Marshal整个看了一遍,现在比较清楚了。至于最原始的动机:
解决"引用类型"的hashcode算法(贴出来的只是一个讨巧做法)
而现在的目标是模似类似SOS的功能,
也就是实现:表达引用类型的对象图谱,指针是一个重要的开头,就象是登月上的一小步。当前研究点(net3.5下的布局有点不一样):
CGInfo
Flags
Basic Instance Size
EEClass
Interface Vtable Map
Num Interfaces
CoreElementType
Module
.cctor Slot
Default .ctor Slot
Interface Map
Delegate
Mum Method Solts希望能够共勉之