
xeeynamo (Normal User)
Pro
    
Messaggi: 66
Iscritto: 14/03/2008
|
Si lo sò, ho rotto un pochetto le scatole con le strutture e con tutte queste operazioni a basso livello col C# XD ma per il lavoro che stò facendo purtroppo mi è obbligatorio usare questi sistemi e il linguaggio più semplice e flessibile per me è il C#.
Passando al problema... Ho una classe/struttura fatta in questo modo:
Codice sorgente - presumibilmente C# |
[StructLayout(LayoutKind.Sequential, Pack = 1)] public class Test { uint var1; byte var2; ushort var3; uint var4; }
|
ed eseguendo la funzione
Codice sorgente - presumibilmente Plain Text |
Test test;
System.Runtime.InteropServices.Marshal.SizeOf(test);
|
mi restituisce il valore 11 e sin qui è perfetto perchè posso ordinare classi e strutture come voglio io. Ora voglio metterci all'interno ad esempio un array:
Codice sorgente - presumibilmente C# |
public class Test { uint var1; byte var2; ushort var3; uint var4; byte[] var5 = new byte[6 ]; }
|
ora il valore restituito dovrebb'essere 17, ma mi restituisce 14. Quando vado a copiare dei dati usando le funzioni Marshal nella classe il programma mi restiuisce questa eccezione: AccessViolationException. Ovviamente se tolgo quell'array il programma va liscio come l'olio. Credo che quei 4 bytes che mi genera l'array non sono altro che un puntatore verso una parte di memoria dinamica e quindi non corrispondono al vero array o mi sbaglio? Quindi quando vado a copiare i dati non faccio altro che sostituire il puntatore con dati che non c'entrano niente causando quel tipo di eccezione vero?
Comunque la funzione che uso è questa:
Codice sorgente - presumibilmente C# |
public static object Byte2Struct(byte[] buf, object o) { IntPtr ptPoit = Marshal.AllocHGlobal(buf.Length); Marshal.Copy(buf, 0, ptPoit, buf.Length); o = Marshal.PtrToStructure(ptPoit, o.GetType()); Marshal.FreeHGlobal(ptPoit); return o; }
|
Come potrei risolvere? Ultima modifica effettuata da xeeynamo il 12/12/2009 alle 13:01 |
|

Il Totem (Admin)
Guru^2
    
Messaggi: 3635
Iscritto: 24/01/2006
|
Dato che gli array sono tipi reference, sì, si tratta di un puntatore. La dimensione, però, è 15 bytes (dato che gli indirizzi sono di 4 bytes, e 11+4=15: ho anche confermato sul mio computer che è esatto).
Non so proprio come risolvere, ma potresti provare ad applicare all'array un attributo del tipo FixedSizeArray. Non mi ricordo di preciso il nome ma se cerchi dovresti trovare qualcosa del genere.
|
|

Thejuster (Admin)
Guru^2
    
Messaggi: 2032
Iscritto: 04/05/2008
|
Non sò bene se questo potrebbe aiutarti,
hai provato il codice non gestito?
ha appunto la possibilità delle strutture o dei dati di non avere dimensioni fisse.
prova a fare qualche ricerca su google.
Real-time applications, we might need to use pointers to enhance performance in such applications.
External functions, in non-.net DLLs some functions requires a pointer as a parameter, such as Windows APIs that were written in C.
Debugging, sometimes we need to inspect the memory contents for debugging purposes, or you might need to write an application that analyzes another application process and memory.
Performance and flexibility, by using pointer you can access data and manipulate it in the most efficient way possible.
Compatibility, in most cases we still need to use old windows APIs, which use pointers extensively. Or third parties may supply DLLs that some of it’s functions need pointer parameters. Although this can be done by using DLLImport and System.IntPtr class, but in some cases it’s just much simpler to use pointer.
Memory Addresses, there is no way to know the memory address of some data without using pointers.
queste sono una delle tante cose che puoi fare
devi solo leggerti bene la documentazione,
magari scopri se va bene per ciò che vuoi fare o meno
Ultima modifica effettuata da Thejuster il 14/12/2009 alle 9:49
|
|

Il Totem (Admin)
Guru^2
    
Messaggi: 3635
Iscritto: 24/01/2006
|
Ma... cosa c'entra?
Lui voleva solo convertire un array di bytes in una variabile strutturata usando l'allocazione della memoria e il namespace Marshal (che offre supporti managed per risorse non gestite). Il problema è che gli oggetti vengono rappresentati come puntatori e non con il loro contenuto, nella fattispecie l'array è un puntatore al primo byte e non un array di bytes.
|
|

Thejuster (Admin)
Guru^2
    
Messaggi: 2032
Iscritto: 04/05/2008
|
ah ecco.
chiedo scusa allora
avevo inteso io male cosa voleva fare
|
|

xeeynamo (Normal User)
Pro
    
Messaggi: 66
Iscritto: 14/03/2008
|
Ho trovato una soluzione temporanea... Ho fatto il codice così:
Codice sorgente - presumibilmente C# |
internal byte[] savemap; private ushort Get16(int offset){ return (ushort)(savemap[offset] + (savemap[offset + 1] << 8)); } private void Set16(int offset, ushort value) { savemap[offset + 0] = (byte)(value >> 8 & 0xFF); savemap[offset + 1] = (byte)(value & 0xFF); } private uint Get32(int offset) { return (uint)(savemap[offset] + (savemap[offset + 1] << 8) + (savemap[offset + 2] << 16) + (savemap[offset + 3] << 24)); } private void Set32(int offset, uint value) { savemap[offset + 0] = (byte)(value >> 24 & 0xFF); savemap[offset + 1] = (byte)(value >> 16 & 0xFF); savemap[offset + 2] = (byte)(value >> 8 & 0xFF); savemap[offset + 3] = (byte)(value & 0xFF); } private byte[] GetB(int offset, int size) { byte[] ret = new byte[size ]; for (int i = 0; i < size; i++) ret[i] = savemap[offset + i]; return ret; } private void SetB(int offset, byte[] value) { for (int i = 0; i < value.Length; i++) savemap[offset + i] = value[i]; } public uint Checksum { get { return Get32(0x0000); } set { Set32(0x0000, value); } } public byte PreviewCharacterLeadLevel { get { return savemap[0x0004]; } set { savemap[0x0004] = value; } } public byte PreviewCharacterLeadPortrait { get { return savemap[0x0005]; } set { savemap[0x0004] = value; } } public byte PreviewCharacterSecondPortrait { get { return savemap[0x0006]; } set { savemap[0x0005] = value; } } public byte PreviewCharacterThirdPortrait { get { return savemap[0x0007]; } set { savemap[0x0006] = value; } }
|
e così via  l'unica cosa è che sarà scocciante fare tutti quei get e set, dato che il byte sarà grande 2048 bytes :S
|
|

Il Totem (Admin)
Guru^2
    
Messaggi: 3635
Iscritto: 24/01/2006
|
Basta usare un for, ad esempio:
Codice sorgente - presumibilmente C# / VB.NET |
private void Set32(int offset, uint value)
{
for(int i = 0; i < 4; i++)
savemap[offset + i] = (byte)(value >> (8 * (3 - i)));
}
|
Non capisco perchè fai & 0xFF, che x & 1 restituisce 1 solo se x è 1 e 0 altrimenti, ossia se x è 0. Quindi x & 1 = x e perciò n & 0xFF = n.
In generale:
Codice sorgente - presumibilmente C# / VB.NET |
private void SetInteger(int offset, UInt64 value, byte bits)
{
for(int i = 0; i < (int)(bits / 8); i++)
savemap[offset + i] = (byte)(value >> (8 * ((bits / 8) - 1 - i)));
}
|
Ultima modifica effettuata da Il Totem il 15/12/2009 alle 17:27 |
|

xeeynamo (Normal User)
Pro
    
Messaggi: 66
Iscritto: 14/03/2008
|
Postato originariamente da Il Totem:
Basta usare un for, ad esempio:
Codice sorgente - presumibilmente C# / VB.NET |
private void Set32(int offset, uint value)
{
for(int i = 0; i < 4; i++)
savemap[offset + i] = (byte)(value >> (8 * (3 - i)));
}
|
Non capisco perchè fai & 0xFF, che x & 1 restituisce 1 solo se x è 1 e 0 altrimenti, ossia se x è 0. Quindi x & 1 = x e perciò n & 0xFF = n.
In generale:
Codice sorgente - presumibilmente C# / VB.NET |
private void SetInteger(int offset, UInt64 value, byte bits)
{
for(int i = 0; i < (int)(bits / 8); i++)
savemap[offset + i] = (byte)(value >> (8 * ((bits / 8) - 1 - i)));
}
|
|
L'ho fatto perchè se ad esempio del numero N = 0x12345678 avrei voluto prendere solo 0x34, avrei dovuto fare N << 16 e sarebbe rimasto 0x1234, poi facevo N & 0xFF e mi usciva 0x34 |
|

Il Totem (Admin)
Guru^2
    
Messaggi: 3635
Iscritto: 24/01/2006
|
Ah giusto...
|
|