Newsgroup: it.comp.lang.visual-basic
Titolo: Passare dati da stringa a UDT, come?

Se per esempio ho una stringa di 100 caratteri e voglio suddividerne
il contenuto all'inerno di un UDT, come devo fare?
Dim MyString as string * 100
Type MyType
	Campo1 as string * 20
	Campo2 as string * 30
	Campo3 as string * 50
EndType
Pensavo di usare una funzione come CopyMemory usando i puntatori ma
non ci riesco. Qualche suggerimento?
Grazie.

Guarda sulla guida in linea Left$, Mid$, Right$ ecc...
Ciao
Paolo Ardissone


Dim lpszBuff as String
Dim udtBuff As MyType
   lpszBuff = String(100, "A")
   CopyMemory udtBuff, ByVal lpszBuff, 100



Il mio grosso problema č che il tutto avviene in una funzione e non ho
a disposizione udbBuff ma bensě il puntatore ottenuto con la funzione:
udtBuffptr=VarPtr(udtBuff)
Le soluzioni sono due ma non le so implementare:
1- far capire alle CopyMemory che la destinazione che gli sto passando
č un puntatore e non un UDT (ho provato a ridefinire la Copymemory
indicando ByVal ma non funzia.).
2 - Capire come passare alla funzione un UDT diverso a seconda da chi
viene chiamata.
PLEASE HELP ME !!!!
Grazie a tutti.

 indicando ByVal ma non funzia.).
CopyMemory, come si evince dal nome, copia locazioni di memoria.
Alla funzione non interessa nulla cosa sta copiando, dato che tratta
solo puntatori. Indicando "CopyMemory udtBuff ..." quello che viene
passato alla funzione è il puntatore alla struttura, ossia la locazione di
memoria iniziale. CM non fa altro che copiare il numero di byte indicati,
iniziando dalla locazione di memoria definita come "source", nella
porzione di memoria definita come "destination".
Se hai invece
udtBuffptr=VarPtr(udtBuff)
udtBuffptr è un puntatore a un puntatore; in base alla definizione
normale di CopyMemory, si rischia un crash del programma.
Per capire quale è il problema, dovresti farmi vedere la funzione di
cui parli, con del codice che effettua la chiamata.

cui parli, con del codice che effettua la chiamata.
Il problema è questo, io sto convertendo un'applicazione da VB3 a VB6:
prima c'era la hmemcpy ma ora non va più e sono costretto ad usare la
CopyMemory.
C'è una funzione detta OpenData( BLA BLA BLA, AddrUtenti as Long) che
quando viene chiamata gli viene passato il puntatore ad una UDT
diversa ad ogni chiamata.
 
Nella funzione OpenData vengono letti dati da file (mediante BTRIEVE)
e messi in una variabile stringa chiamata DataBuf
Mediante hmemcpy i dati venivano inseriti nella UDT in oggetto:
St% = hmemcpy(BTRs(BTRFile).Address, GetAddr(ByVal
BTRs(BTRFile).DataBuf), CLng(BTRStat(BTRFile).RecLen)) 
Ora devo usare la CopyMemory, nella funzione non ho la struttura ma
solo il puntatore (fra l'altro la struttura BTRs..... non è la
struttura sulla quale saranno copiati i dati ma è una struttura
contentente i puntatori ed altri dati).
Io ho provato a usare:
CopyMemory BTRs(BTRFile).Address, VarPtr(ByVal BTRs(BTRFile).DataBuf),
CLng(BTRStat(BTRFile).RecLen)
ma mi manda giustamente in crash perchè gli passso un puntatore a
puntatore.
L'ideale sarebbe una funzione inversa a VarPtr che dato un indirizzo
mi ritorna l'oggetto a cui punta.
Aiutami perchè sto impazzendo!
P.S: ti trovo su IRC? Se si quando?

 non ci riesco. Qualche suggerimento?
CopyMemory e' sicuramente il sistema migliore e gia' ne state parlando;
vorrei sottoporre alla tua attenzione un metodo meno elegante, buono per i
momenti di crisi:
Option Explicit
Type TRecord
  Campo1  As String * 5
  Campo2  As String * 10
  Campo3  As String * 11
End Type
Type TString
  s       As String * 26
End Type
Sub Main()
Dim i     As Integer
Dim udtR  As TRecord
Dim udtS  As TString
  For i = Asc("A") To Asc("Z")
    Mid$(udtS.s, i - Asc("A") + 1, 1) = Chr$(i)
  Next
  LSet udtR = udtS
  Debug.Print udtS.s
  With udtR
    Debug.Print .Campo1
    Debug.Print .Campo2
    Debug.Print .Campo3
  End With
End Sub
--
Ciao.
Maurizio

 CLng(BTRStat(BTRFile).RecLen)
Questa cosa non funzionerà mai, indipendentemente dal tipo
di variabili usate.

per ottenere il risultato voluto.
BTRs(BTRFile).Address è un long e contiene l'indirizzo della UDT in
cui dovranno essere posti i dati (l'indirizzo viene ottenuto mediante
la VarPtr)
BTRs(BTRFile).DataBuf è una stringa di lunghezza 1013.
Da questa la CopyMemory dovrà copiare i  primi 101 bytes (che
corrispondono alla dimensione della UDT (questo valore cambia con il
variare della struttura in oggetto).
Il problema è che nella funzione non ho a disposizione direttamente la
mia UDT ma solo il suo puntatore (o il suo indirizzo).
Dunque o trovo un modo per adattare la CopyMemory ad accettare
direttamente puntatori oppure trovo un sistema per passare alla mia
funzione una UDT diversa ad ogni chiamata.
Non so più dove sbattere la testa.
PLEASE HELP!!!




 variare della struttura in oggetto).
Spero di avere finalmente capito
Tenendo buona la definizione di CopyMemory:
Public Declare Sub CopyMemory Lib "kernel32" _
        Alias "RtlMoveMemory" _
        (hpvDest As Any, _
        hpvSource As Any, _
        ByVal cbCopy As Long)
Prova con questa sintassi:
CopyMemory _
    BTRs(BTRFile).Address, _
    ByVal StrPtr(ByVal BTRs(BTRFile).DataBuf),_
    CLng(BTRStat(BTRFile).RecLen)
con StrPtr al posto di VarPtr. VarPtr non si adatta alle stringhe.
(Occhio alle stringhe Unicode)
Ciao

Ciao
A quanto pare non funziona perchè copia qualcosina, ma lo copia
sbagliato.
Ora non capisco se il problema è relativo alla CopyMemory oppure al
fatto che le stringhe in VB3 erano ANSI e ora sono UNICODE.
Fra l'altro posso convertire UNICODE in ANSI, oppure lavorare
esclusivamente in ANSI?
Io provo a postare il codice del modulo.
Non è l'originale ma ricrea le stesse condizioni che ho descritto nei
post precedenti.
Se qualcuno mi fa il piacere di risolvermi questo problema gli sarò
infintamente grato:
-----------------  INIZIO MODULO.BAS ----------------
Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory"
(Destination As Any, Source As Any, ByVal Length As Long)
Global AddrUtente As Long
Type PW
    Key As String * 15
    Sum As Long
End Type
Type Moduli
    Base As Integer
    Magazzino As Integer
    Vendite As Integer
    Ordini As Integer
    Canoni As Integer
    Contabilita As Integer
    ContiCorrente As Integer
    Commesse As Integer
    Vuoto2 As Integer
    Vuoto3 As Integer
End Type
Type Utente
    Codice As String * 3
    Descrizione As String * 40
    PW As PW
    Moduli As Moduli
    CodiceAzienda As String * 3
    CodiceEsercizioS As String * 3
    CodiceEsercizioC As String * 3
    CodiceEsercizioM As String * 3
    Logging As String * 1
    CambioNumero As String * 1
    CambioValuta As String * 1
    PortaComm As String * 1
    Disabilitato As String * 1
    Amministratore As String * 1
    PortaComm2 As String * 1
End Type
Global Utente As Utente
Global Moduli As Moduli
Global DataBuf As String * 1013
Private Function OpenData(FileName As String, BTRFile As Integer,
KeyMode As Integer, FileType As Integer, Address As Long) As Integer
 
    DataBuf = String$(1013, Chr$(0))
    'Codice
    Mid$(DataBuf, 1, 3) = "  1"
 
    'Descrizione
    Mid$(DataBuf, 4, 40) = "AMMINISTRATORE                          "
 
    'PW.Key
    Mid$(DataBuf, 44, 15) = "               "
 
    'PW.Sum (=0)
    Mid$(DataBuf, 59, 4) = Chr$(0)
 
    CopyMemory Address, ByVal StrPtr(ByVal DataBuf), 101
 
    Debug.Print Utente.Codice
    Debug.Print Utente.Descrizione
    Debug.Print Utente.PW.Key
    Debug.Print Utente.PW.Sum
End Function
Sub Main()
 
    AddrUtente = VarPtr(Utente)
    OpenData "PROVA", 1, 1, 1, AddrUtente
 
End Sub
------------ FINE MODULO.BAS --------------------

 Global DataBuf As String * 1013
[...]
101?
--
Ciao.
Maurizio



No, è 1013 perchè la stringa deve contenere dati variabili.
Nel caso di questa funzione il valore dei dati che mi interessa è 101
(infatti la copymemory in questo caso, deve copiare 101 bytes).

     CopyMemory Address, ByVal StrPtr(ByVal DataBuf), 101
Qui in realtà stai copiando 50 byte
devi poi cambiare la chiamata in
    CopyMemory Address, ByVal StrPtr(DataBuf), 101
    (non ByVal DataBuf)
Questa volta ho provato e funziona.

 wrote:
Io ho provato a vedere la lunghezza della stringa DataBuf con lenb e
mi dà sempre 2026 sia se la dichiaro con Dim (all'interno della
routine) che come Public all'esterno.
Poi devo dichiararla come Public perchè è condivisa da più funzioni
(il programma è già fatto, non posso modificare, devo solo adattare se
possibile).
Guarda cosa ho dovuto fare per farlo andare.
Le stringhe UNICODE hanno percaso un descrittore all'inizio di
lunghezza 2bytes?
Non posso più definire tipi nidificati perchè i dati vengono switchati
di una quantità pari a 2 bytes.
Se esiste un modo più elegante per svolgere questo compito?
Comunque riposto il modulo modificato.
Quello che mi hai dato tu non funziona.
P.S: uso Win2000 e l'applicazione DEVE girare su Win2000.
Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory"
(Destination As Any, Source As Any, ByVal Length As Long)
Global AddrUtente As Long
'Type PW
'    Key As String * 15
'    Sum As Long
'End Type
'Type Moduli
'    Base As Integer
'    Magazzino As Integer
'    Vendite As Integer
'    Ordini As Integer
'    Canoni As Integer
'    Contabilita As Integer
'    ContiCorrente As Integer
'    Commesse As Integer
'    Vuoto2 As Integer
'    Vuoto3 As Integer
'End Type
Type Utente
    Codice As String * 3
    Descrizione As String * 40
    'PW as PW
    Key As String * 15
    Sum As Long
    'Moduli as Moduli
    Base As Integer
    Magazzino As Integer
    Vendite As Integer
    Ordini As Integer
    Canoni As Integer
    Contabilita As Integer
    ContiCorrente As Integer
    Commesse As Integer
    Vuoto2 As Integer
    Vuoto3 As Integer
    CodiceAzienda As String * 3
    CodiceEsercizioS As String * 3
    CodiceEsercizioC As String * 3
    CodiceEsercizioM As String * 3
    Logging As String * 1
    CambioNumero As String * 1
    CambioValuta As String * 1
    PortaComm As String * 1
    Disabilitato As String * 1
    Amministratore As String * 1
    PortaComm2 As String * 1
End Type
Global Utente As Utente
'Global Moduli As Moduli
Public DataBuf As String * 1013
'public DataBuf As String * 1013
Private Function OpenData(FileName As String, BTRFile As Integer,
KeyMode As Integer, FileType As Integer, Address As Long) As Integer
 
    DataBuf = String$(1013, Chr$(0))
    Utente.Codice = ""
    Utente.Descrizione = ""
    Utente.Key = ""
    Utente.Sum = -1
 
    Debug.Print LenB(DataBuf)
 
    'Codice
    Mid$(DataBuf, 1, 3) = "111"
 
    'Descrizione
    Mid$(DataBuf, 4, 40) = "2222222222222222222222222222222222222222"
 
    'PW.Key
    Mid$(DataBuf, 44, 15) = "333333333333333"
    Dim ptr As Long
 
    ptr = StrPtr(DataBuf) - 4
    Utente.Codice = ""
    CopyMemory Address, ByVal ptr, 202
 
    Debug.Print Utente.Codice
    Debug.Print Utente.Descrizione
    Debug.Print Utente.Key
    Debug.Print Utente.Sum
End Function
 
Sub Main()
 
    AddrUtente = VarPtr(Utente)
    OpenData "PROVA", 1, 1, 1, AddrUtente
 
End Sub
GRAZIE INFINITE !!!!

     CopyMemory Address, ByVal ptr, 202
a questo punto, se funziona, dovrebbe essere
    CopyMemory Address, ByVal ptr, 102
non 101 :)



Effettivamente usando STRCONV la stringa diventa di lungezza 1013bytes
ma non appena la vado a riempire, mi ritorna di dimensioni doppie.
Poi non funziona perchè quando vado a usare la copymemory le variabili
stringa definite nella mia UDT sono tutte UNICODE.
Possibile che non esista un modo per far capire a VB di usare ANSI
nelle dichiarazioni stringa?
Io poi non sono costretto ad usare la copymemory, se esiste una
soluzione alternativa per copiare la stringa nella UDT (consideriamo
che ci sono anche campi long e integer), ben venga!
Grazie.

 che ci sono anche campi long e integer), ben venga!
Non mi viene in mente niente altro.
Ciao

Chiaro. La stringa la converti dopo averla riempita.
No, perchè se la converto dopo averla riempita mi ritorna un insieme
di caratteri senza alcun significato.....
Una soluzione potrebbe essere quella di non usare le stringhe ma le
matrici e poi eventualmente convertirle in stringhe ma non so se
questo si possa adattare al programma.
Cosa ne dici?
Con gli array non avrei più problemi di UNICODE giusto?
Ciao, e ancora grazie.

 wrote:
Come ho detto nel mio post precedente, una possibile strada era quella
di convertire tutte le stringhe nelle UDT in Array di caratteri.
Cosě sembra funzionare ma come faccio a convertire una matrice a
dimensione fissa in una stringa senza utilizzare lunghi e noiosi cicli
che vanno a leggere ogni singolo carattere della matrice, rallentando
notevolmente il programma?
Di seguito posto il codice con la nuova modifica.
Ne approfitto per augurare a tutti buona domenica.
Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory"
(Destination As Any, Source As Any, ByVal Length As Long)
Public AddrUtente As Long
Type PW
    Key(1 To 15) As Byte ' As String * 15
    Sum As Long
End Type
Type Moduli
    Base As Integer
    Magazzino As Integer
    Vendite As Integer
    Ordini As Integer
    Canoni As Integer
    Contabilita As Integer
    ContiCorrente As Integer
    Commesse As Integer
    Vuoto2 As Integer
    Vuoto3 As Integer
End Type
Type Utente
    Codice(1 To 3) As Byte 'As String * 3
    Descrizione(1 To 40) As Byte ' As String * 40
    PW As PW
    Moduli As Moduli
    CodiceAzienda As String * 3
    CodiceEsercizioS As String * 3
    CodiceEsercizioC As String * 3
    CodiceEsercizioM As String * 3
    Logging As String * 1
    CambioNumero As String * 1
    CambioValuta As String * 1
    PortaComm As String * 1
    Disabilitato As String * 1
    Amministratore As String * 1
    PortaComm2 As String * 1
End Type
Public Utente As Utente
Public Moduli As Moduli
Public DataBuf(1013) As Byte
Public BTRdata() As Byte
Private Function OpenData(FileName As String, BTRFile As Integer,
KeyMode As Integer, FileType As Integer, Address As Long) As Integer
 
    '-- SIMULAZIONE LETTURA DATI DA ARCHIVIO ---
    'Codice
    Dim strTmp As String
 
    strTmp = String(2, Chr$(0))
    BTRdata = "  1AMMINISTRATORE
" & strTmp
 
    'Eliminazione caratteri UNICODE
    a = 0
    For x = 0 To UBound(BTRdata)
    If x / 2 = Int(x / 2) Or x = 0 Then
        DataBuf(a) = BTRdata(x)
        a = a + 1
    End If
    Next x
 
    'Nella matrice DataBuf ci sono i dati che
    'nel programma originale sono letti da file
 
    'la copymemory a quanto pare va chiamata cosě....
    CopyMemory ByVal AddrUtente, ByVal VarPtr(DataBuf(0)), 63



wrote:
Visto che le soluzioni precedenti non funzionano, ripartiamo da zero.
Allora io ho una funzione alla quale passo il puntatore ad una UDT che
varia ad ogni chiamata.
Poi ho una stringa di lunghezza fissa (precisamente 1023bytes) nella
quale vengono letti dati tramite la BTRCALL del BTRieve.
Nella funzione devo copiare i dati, inseriti sequenzialmente nella
stringa, nella UDT in questione.
ho provato con la Copymemory ma forse non č la strada giusta.
Il problema principale sicuramente č caratterizzato dal fatto che le
stringhe sono rappresentate in formato UNICODE e un carattere non
occupa piů un byte bensě due.
Come posso fare per fare in modo che i dati vadano al loro posto nella
UDT.
P.S. Consideriamo che le UDT hanno dati misti (String, Long, Integer).
GRAZIE.