1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
|
// RuntimeFieldHandle.cpp : main project file.
#include "stdafx.h"
using namespace System;
using namespace System::Reflection;
// Je définis un type .NET avec plein de champs,
// et je retrouve bien l'offset 28 (en 32bit) pour le champ String ^s
ref struct A {
Object ^h;
Int32 ^k,^l,^m,pp;
UInt32 a,b,c,d,e;
Object ^h2;
private :
Type ^t;
Boolean p;
UInt32 a2,b2,c2,d2,e2;
public:
String ^s;
};
generic <typename T> value struct FieldReference {
UInt32 offset;
Object ^obj;
value struct RuntimeFieldHandle_m_ptr {
UInt32 a,b,offset; // attention UInt32 est peut-être uniquement valable en 32bit
};
static UInt32 GetFieldOffset(FieldInfo ^f) {
RuntimeFieldHandle h = f->FieldHandle;
IntPtr value = h.Value;
RuntimeFieldHandle_m_ptr * m_ptr = (RuntimeFieldHandle_m_ptr *)(void*)value; // le type de value n'est pas communiqué par .NET : il faut le trouver soi-même
UInt32 res = m_ptr->offset;
// le premier bit est probablement un flag ?
res &= 0x7FFFFFF; // attention 0x7FFFFFF est peut-être uniquement valable en 32bit
return res + sizeof(void*); // ajout de la VMT
}
FieldReference(Object ^obj, UInt32 offset) : obj(obj), offset(offset) {}
FieldReference(Object ^obj, FieldInfo^ fi) : obj(obj) {
offset = GetFieldOffset(fi);
}
FieldReference(Object ^obj, String ^fieldName) : obj(obj) {
Type ^t = obj->GetType();
FieldInfo ^fi = t->GetField(fieldName);
offset = GetFieldOffset(fi);
}
property T Value {
T get() {
pin_ptr<Object^> tmp = &this->obj;
void *ptr = (void*)tmp;
char *objadr = *(char**)ptr;
void *fieldadr = objadr + this->offset;
return (T)*(Object^*)fieldadr;
}
void set(T t) {
pin_ptr<Object^> tmp = &this->obj;
void *ptr = (void*)tmp;
char *objadr = *(char**)ptr;
void *fieldadr = objadr + this->offset;
*(Object^*)fieldadr = t;
}
};
};
int main(array<System::String ^> ^args)
{
A ^a = gcnew A();
a->s = "avant";
FieldReference<String^> a_s(a,"s");
a_s.Value = "apres";
Console::WriteLine(a->s);
return 0;
} |
Partager