Oppure

Loading
12/12/09 12:00
xeeynamo
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:
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public class Test
{
    uint var1;
    byte var2;
    ushort var3;
    uint var4;
}

ed eseguendo la funzione
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:

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:

        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 12/12/09 12:01
aaa
13/12/09 20:24
Il Totem
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.
aaa
14/12/09 8:34
Thejuster
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
:k:

Ultima modifica effettuata da Thejuster 14/12/09 8:49
mire.forumfree.it/ - Mire Engine
C# UI Designer
14/12/09 15:09
Il Totem
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.
aaa
14/12/09 17:06
Thejuster
ah ecco.
chiedo scusa allora
avevo inteso io male cosa voleva fare 8-|
mire.forumfree.it/ - Mire Engine
C# UI Designer
14/12/09 21:10
xeeynamo
Ho trovato una soluzione temporanea... Ho fatto il codice così:
        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 :D l'unica cosa è che sarà scocciante fare tutti quei get e set, dato che il byte sarà grande 2048 bytes :S
aaa
15/12/09 16:26
Il Totem
Basta usare un for, ad esempio:
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:
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 15/12/09 16:27
aaa
15/12/09 19:05
xeeynamo
Postato originariamente da Il Totem:

Basta usare un for, ad esempio:
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:
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
aaa