Sincronizza Indice |
Scarica il progetto |
Testo dell'articolo |
Stampa l'articolo |
In Visual Basic, come in altri linguaggi, esistono determinati tipi
di dati semplici che, mettendo assieme più bytes, formano un
unico valore quale ad esempio i numeri Integer o i Long.
Tutti gli altri tipi di dati si compongono di due o più bytes
concatenati tra loro. Così, ad esempio il tipo Integer (che permette
il conteggio fino a 2^16, ovvero da -32.768 a +32.767) si compone di due
bytes, uniti tra loro in una singola entità. In alcuni casi di programmazione a basso livello come ad esempio la manipolazione di immagini, può essere necessario estrarre i singoli bytes di cui si compone un dato di tipo multibyte, ovvero composto da più bytes. I bytes di un valore sono consecutivi tra loro, così dato l'indirizzo
inziale di un dato di un certo tipo, i bytes di cui si compone sono consecutivi
tra loro. Tuttavia, nelle architetture Intel x86 i dati non sono
memorizzati in maniera continua (Big-Endian)
ma l'ordine dei bytes è invertito; così il primo byte di
un tipo multibyte si trova all'ultima posizione. Questo processo di memorizzazione
invertita è detto Little-Endian. Per effettuare tale separazione di bytes o unione in un tipo multibyte
è necessario sfruttare la funzione API
CopyMemory, in realtà alias di un'altra funzione:
RtlMoveMemory. Il nostro semplice form si compone di pochi controlli: innanzitutto sulla prima riga abbiamo una Labeldi LongHEXLabel con la proprietà Caption impostata a "Numero Long Esadecimale". A fianco d'essa abbiamo la corrispondente TextBox di nome LongHEX, con la proprietà MaxLength impostata ad 8 (permettendo quindi l'inserimento fino a 8 cifre esadecimali). Segue a questa un'altra Labeldi nome LongDECLabel, con la proprietà AutoSize impostata a True, che verrà utilizzata per mostrare il risultato decimale del numero esadecimale inserito. La seconda riga di controlli contiene un'altra Labeldi nome HEXArrayLabel con il solo scopo descrittivo. Segue a questa una matrice di 4 TextBox di nome HEXArray con proprietà Index da 0 a 3, tutte con proprietà MaxLength impostata a 2. Completiamo il form con due CommandButtondi nome PulsanteLongBytes e PulsanteBytesLong e Caption impostate a "Long -> Bytes" e "Bytes -> Long". Il funzionamento del form è semplice. L'utente immette un numero
esadecimale nella casella di testo più grande, preme il pulsante
"Long -> Bytes" ed ottiene i singoli bytes
del numero inserito, ovviamente però in ordine inverso per i motivi
accennati in precedenza.
Definiamo subito il codice delle due funzioni di conversione:
Alla riga 2 abbiamo innanzitutto definito la funzione API CopyMemory, alias della vera funzione, RtlMoveMemory. Essa richiede tre parametri: due d'essi sono puntatori mentre il terzo è un numero semplice. Il primo parametro (Destination) è il puntatore all'indirizzo di memoria di destinazione, in cui verranno scritti i dati; il secondo parametro (Source) è un puntatore all'area di memoria da cui leggere i dati; il terzo parametro (numbytes) definisce il numero di bytes da copiare dall'indirizzo Source all'indirizzo Destination. Alla riga 3 abbiamo definito una variabile di nome CARATTERIHEX che utilizzeremo più avanti per controllare che i dati immessi dall'utente siano effettivamente validi come numero esadecimale.
La prima funzione che vedremo è la LongToBytes che,
estrae i singoli bytes dal numero Long e li scrive in un array
di bytes. Possiamo notare una strana scrittura: Tale matrice sarà il contenitore per i 4 bytes letti a partire dall'indirizzo del puntatore TheLong.
La seconda funzione effettuerà l'operazione inversa della prima, ovvero leggerà i dati da un array di bytes ed otterrà con essi un numero Long che riporterà come risultato della funzione. La chiamata alla funzione CopyMemory è quasi identica alla precedente.
Ciò che cambia è l'ordine dei parametri; infatti questa
volta la destinazione sarà una variabile temporanea di nome TempLong
e l'origine sarà la matrice di bytes passata alla funzione. Seguono quattro routines dedicate esclusivamente al controllo dei dati inseriti dall'utente. Ciò per evitare di passare alle funzioni API devi valori errati.
Durante il caricamento del form inizializziamo la variabile CARATTERIHEX con i sedici simboli del sistema numerico esadecimale. Ad essa aggiungiamo il simbolo ASCII del tasto BackSpace. Infatti la variabile CARATTERIHEX servirà per controllare se l'input inserito dall'utente è valido. Se non avessimo inserito il simbolo del BackSpace l'utente non avrebbe potuto cancellare i numeri precedenti se non utilizzando il tasto Canc. Sarebbe stato più conveniente dichiarare la variabile CARATTERIHEX come costante ma non è stato possibile a causa della funzione Chr da concatenare.
Al cambiamento del contenuto della casella di testo LongHEX il valore nella Label LongDECLabel viene aggiornato calcolando il valore decimale del numero esadecimale inserito.
La funzione di conversione da esadecimale è la notissima Format con l'appoggio della stringa "&H0" che assicura che il numero non sia nullo e richiede la conversione da esadecimale.
Alla pressione di un tasto nelle varie caselle di testo deve essere controllato se il tasto premuto è effettivamente una cifra del sistema esadecimale. Pertanto, alle righe 25 e 30 viene portata l'eventuale lettera in maiuscolo
(non è obbligatorio ma migliora l'estetica del programma) ed in
seguito viene controllato se tale valore compare all'interno della stringa
CARATTERIHEX che conterrà tutti i simboli esadecimali. Se
il simbolo compare, l'istruzione Instr restituirà la posizione
in cui tale carattere compare, quindi un numero maggiore di 0. Segue il codice dei due pulsanti di estrazione ed unione.
La pressione del pulsante PulsanteLongBytes richiede l'estrazione dei singoli bytes contenuti nel numero specificato nella casella di testo LongHEX. Pertanto dichiariamo una nuova matrice di tipo Byte (riga 35), richiamiamo la funzione LongToBytes che si occuperà di riempirla, passandole come parametri la matrice ed il numero, convertito a Long decimale, contenuto nella casella LongHEX (riga 36). Fatto questo potremo andare a leggere i valori dalla matrice e scriverli nella matrice di caselle di testo (righe 37-40).
L'operazione inversa è gestita dal click sul pulsante PulsanteBytesLong. Il nostro esempio è completo. Il progetto leggerà i dati dalle caselle di testo e li convertirà da un formato all'altro. L'esecuzione del progetto mostrerà molto chiaramente la strana
struttura Little-Endian dei
dati nelle macchine Intel x86. |
Naturalmente esistevano tantissime altre soluzioni per effettuare quest'operazione ma questa è quella più veloce e flessibile ai possibili cambiamenti. Fibia
FBI
|
Torna all'indice degli HowTo |