Newsgroup: it.comp.lang.visual-basic
Titolo: [?] comportamento differente tra compilato e sorgente nell'IDE

Salve,
il mio problema è questo:
ho un programma che calcola una serie di punti nello spazio e la routine che
esegue il calcolo accetta in input un vettore che con "redim preserve" viene
dimensionato ad ogni nuovo punto.
il programma all'interno dell'IDE funziona senza problemi  ma l'exe invece
mi da un error 10(matrice bloccata)
da cosa può dipendere? e perchè nell'IDE non succede?
Grazie
Davide

e perchè nell'IDE non succede?
Il debug nell' ide non e' affidabile, perche' in realta' viene
debuggato il processo di vb che esegue il nostro codice, non
il processo autonomo dell' applicazione che abbiamo scritto.
Per le cose "strane" occorre debuggare l' exe con debugger vero,
ad esempio quello del visual c++, caricando anche i sorgenti
vb, cosi' da impostare i breakpoint dove ti interessa e seguire
passo passo il codice vb, ma con visibilita' anche sul disassemblato.
-- 
ciao, hal
-- 
Posted via Mailgate.ORG Server - 
http://www.Mailgate.ORG

 passo passo il codice vb, ma con visibilita' anche sul disassemblato.
mi potresti spiegare come fare?
grazie per l'aiuto
Davide

 funzione che tenta di ridimensionarlo.
Non mi pare che le cose stiano esattamente cosě... la redim preserve, a
occhio, anche leggendo le info su SAFEARRAY si limita a "allungare" lo
spazio in coda all'array (ecco perchč solo l'ultima dimensione puň essere
ridimensionata!).
Paradossalmente č piů pesante la redim, che resetta l'array completamente.
Poi non ho ben capito il discorso del passaggio alle funzioni, cosa che io
faccio regolarmente, classico es. č passare un array non inizializzato a una
funzione di "init" che ridimensiona e riempie l'array.
E funziona anche in loop "critici", poichč fortunatamente la redim č
sincrona.
Non č molto chiaro a cosa serva il lock sugli array... forse proprio per
rendere le redim trhead-safe: mentra lo sta facendo uno non puň farlo
l'altro.
Ciao

 l'altro.
oppure serve a farmi tribolare con questi error 10!
cioa e grazie
Davide

 passo passo il codice vb, ma con visibilita' anche sul disassemblato.
mi spiegheresti come fare?
grazie
Davide

 Paradossalmente č piů pesante la redim, che resetta l'array
completamente.
Per quanto ne so non e' assolutamente cosi':
La velocita' di accesso alle matrici dipende dal fatto che esse sono
allocate in zone "contigue" di memoria. Tale tipo di allocazione
permette, avendo il riferimento al primo elemento della matrice, ed il
tipo di dato contenuto (ed il numero di elementi)  di accedere
immediatamente, a partire dall'indice, alla locazione esatta di memoria
in cui si trova l'elemento. La formula che restituisce l'indirizzo di
memoria dell'i-esimo elemento (Option Base 0) di una matrice
monodimensionale e' (i * dimensione_tipo_dato +
indirizzo_primo_elemento).
Per esempio se e' una matrice di 500 elementi di tipo Integer (2 byte) e
l'indirizzo di memoria del primo elemento e' 5600 l'indice del 46esimo
elemento e': (45*2 + 5600) = 5690.
Redim Preserve alloca fisicamente una nuova area di memoria della
dimensione della matrice incrementata di "uno" (*) o piu' (a seconda
della nuova dimensione passata), copia il contenuto della prima matrice
nella seconda ed assegna al campo/ai campi successivo/i 0 (zero). Cio'
significa che anche se la matrice contiene 50.000 riferimenti (e non
oggetti veri e propri) e quindi la dimensione del singolo elemento (8
byte ?) e' "ridotta" rispetto alla dimensione dell'oggetto "riferito",
facendo Redim Preserve Matrice(0 To 51000), avviene in ordine:
1) Allocazione di 51.000 * 8 byte contigui in memoria (oltre ai 50.000
gia' allocati, per un totale di 101.000 * 8 byte allocati
contemporanemente)
2) Copia in blocco della zona di memoria occupata dalla prima matrice
(50.000*8 byte) nella seconda
3) Deallocazione della prima matrice
4) "Puntamento" della variabile che indica la matrice sulla nuova zona
di memoria
In pratica Redim Preserve corrisponde a (passatemi lo pseudocodice):
Dim NuovaMatrice(Ubound(VecchiaMatrice) + QuantoTiPare)
CopyMem(VecchiaMatrice, NuovaMatrice)
Set VecchiaMatrice = Nothing
Lokar
--------------------
(*) Per "uno" intendo lo spazio necessario a contenere un nuovo
riferimento all'oggetto del tipo specificato, oppure, nel caso dei tipi
standard, lo spazio di memoria occupato da una variabile di quel tipo.
--------------------
--
Sito Comune: 
http://www.it-lang-vb.net/
Manifesto: 
http://www.it-lang-vb.net/docs/Manifesto.txt

 (45*2 + 5600) = 5690.
Per riassumere:
Detto i l'indice di un elemento generico della matrice,
Detto PE l'indirizzo di memoria del primo elemento
Detto S lo Spazio occupato da un elemento della matrice,
la formula per calcolare l'indirizzo dell'elemento m(i) a partire da i
e':
Indirizzo(i) = PE + (i)*S
Per quanto riguarda 2 indici la zona di memoria e' sempre *contigua* e
quindi esiste una formula che permette di accedere direttamente ad un
indirizzo di memoria a partire dagli indici. La formula per 2 indici e'
un "pelino" piu' complessa =):
Detto j il secondo indice di un elemento generico della matrice,
Detta N la dimensione massima del primo indice,
la formula per calcolare l'indirizzo dell'elemento m(i,j) a partire da i
e j e':
Indirizzo(i, j) = PE + (i*N + j)*S
Come vedi N (cioe' la dimensione del primo indice) e' *necessaria* al
fine di accedere "direttamente" all'indirizzo di memoria.
Questo e' il motivo per cui N non puo' cambiare, ne' si puo' passare una
matrice bidimensionale ad una funzione senza specificare la dimensione
del primo indice (almeno in C e' cosi'!).
hth
Lokar


 > ridimensionata!).
No, non mi torna.
Mi pare di ricordare (ma potrei sbagliarmi) che un array di n dimensioni sia
allocato nel seguente modo:
[elementi contigui dimensione 1][elementi contigui dimensione 2]...[elementi
contigui dimensione n] tant'è che appunto è possibile accedere a ogni
singolo elemento partendo dall'indirizzo del precedente + 1 *
SizeOf(elemento).
Quindi l'array è contiguo.
Questo spiega perchè l'ultima dimensione può essere dimensionata e le altre
no: l'ultima è l'unica allungabile, le altre andrebbero a sovrapporsi alle
seguenti, oppure necessiterebbero della "reallocazione" almeno della
dimensione, cosa che appunto non mi pare avvenga per la stessa struttura
dell'array.
Quindi, (ripeto posso ricordare male, ma mi almeno la logica mi da ragione)
non c'è nessuna copia dei dati, solo l'ultima dimensione viene "allungata"
(magari spostando quello che c'era) e riempita a 0 e il <count> della
dimensione aggiornato.
Può darsi che l'array venga "ricopiato" ma _solo_ se non c'è abbastanza
memoria contigua libera.
Ciao

 abbastanza memoria contigua libera.
Potrebbe darsi, ma non mi risulta che il funzionamento sia questo. Ho
spulciato un po' su MSDN e pare che MS mi da ragione ;-)
***
ReDim releases the existing array and creates a new array with the same
rank. The elements of the new array are initialized to the default value
for their data type unless you specify Preserve.
If you include the Preserve keyword, Visual Basic copies the elements
from the existing array to the new array. When you use Preserve, you can
resize only the last dimension of the array, and for every other
dimension you must specify the same size it already has in the existing
array.
***
tratto liberamente da:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vblr7/h
tml/vastmReDim.asp
Ciao
Lokar

 library/en-us/vblr7/html/vastmReDim.asp
OOPS! mi sono accorto solo ora che parla di .NET... mi sono lasciato
ingannare dal fatto che la dichiarazione con Dim la mostra sia in VB 6.0
che in 
VB.NET
.
In ogni caso sostengo che e' identico anche per VB6 (la convinzione
nasce dal fatto che conosco a fondo la gestione degli array in C/C++ ed
e' la medesima).


 spulciato un po' su MSDN e pare che MS mi da ragione ;-)
Questo č quello che ho trovato io semplicemente sulla SafeArrayRedim():
1) il parametro psaboundNew č:
Pointer to a new safearray bound structure that contains the new array
boundary. You can change only the least significant dimension of an array.
Quindi quello che cambia č il descrittore, non fa cenno dei dati.
Ma poi dice:
If you reduce the bound of an array, SafeArrayRedim deallocates the array
elements outside the new array boundary. If the bound of an array is
increased, SafeArrayRedim allocates and initializes the new array elements.
E questo sembrerebbe confermare quello che dicevo, ma continuando c'č una
frase sibillina :)
 The data is preserved for elements that exist in both the old and new
array.
Quindi forse hai ragione tu. :)
Penso che su un paio di punti si possa essere d'accordo:
1)  Tutto questo non c'entra niente con l'errore sui lock degli array, che
hanno sicuramente altro (e ancora oscuro) motivo.
2) La documentazione M$ č frammentaria, incompleta e spesso superficiale:
non mi servono 3/4 pagine uguali di un documento (SDK, API Reference, ecc)
ma una sola pagina dettagliata!
Ciao

ridimensionata!).
In effetti ho scritto poco chiaro per la fretta (due righe di codice sarebbero 
state piu' esaustive), comunque quanto segue genera il fatidico errore 10:
<codice>
Option Explicit
Dim t() As Long
Sub Main()
    ReDim t(0 To 9) As Long
    test t(3)
    ReDim Preserve t(0 To 35)
    ciccio t()
    MsgBox UBound(t())
 
End Sub
Sub test(ByRef a As Long)
    ReDim t(0 To 8)     ' <--- qui genera errore 10
End Sub
Sub ciccio(ByRef a() As Long)
    ReDim Preserve a(0 To 15)
End Sub
</codice>
Mi sono capito adesso? ;-)
-- 
ciao, hal

mi spiegheresti come fare?
Vale anche per gli exe:
HOWTO: Debug a Native Code Visual Basic Component in VC++
Q166275
-- 
hth, hal

 contigua libera.
Direi che nel caso di redim preserve non c'è (almeno in
generale) nessuna copia, mentre una semplice redim crea un
nuovo array.
Basta un sempice varptr(array(o)) per vedere che l'indirizzo
cambia in caso di una semplice redim, e rimane lo stesso nel
caso di una redim preserve.
Ciao
--
BSD is for UNIX-lovers -- linux is for Windows-haters.

 funzione che tenta di ridimensionarlo.
ho fatto unas erie di debug e ho scoperto che i redim non c'entrano per
nulla!
error 10 "scatta" sull'end sub!
tra l'altro ho riscritto la routine in modo da non salvare i punti ma
allocandoli in un array a diemnsione fissa e ho lo stesso
questo error 10.
la rouinr viene chiamata 9 volte, l'8° volta in uscita da error 10...
ma cosa può essere allora?
ciao
Davide

 ha scritto nel messaggio
news:QhiO8.42711$5i1.1...@news2.tin.it...

Riporto, per documentazione, quanto si trova sulla guida cercando "matrice
fissa", mi scuso per la lunghezza, ma leggendo tutto il topic, ho avuto la
sensazione che il problema venisse affrontato da un punto di vista troppo
generico. A me il problema (evidendemente avevo anch'io delle matrici
presenti) era nato quando da un popupmenù (modale per sua natura) aprivo una
finestra modale. Ho dovuto chiamare una routine intermedia (in questo modo
il popup si "sbloccava") che chiamava la form di destinazione.
Questa matrice è fissa o temporaneamente bloccata (errore 10)
Non tutte lematrici possono essere ridimensionate. Anche le matrici
dichiarate in modo specifico come dinamiche e le matrici divariabili Variant
a volte sono bloccate temporaneamente. Cause e soluzioni dell'errore:
  a.. Si è cercato di utilizzare ReDim per modificare il numero di elementi
di una matrice fissa. Nel codice seguente, ad esempio, la matrice fissa
FixedArr viene ricevuta da SomeArr nella routine NextOne e si cerca di
ridimensionare SomeArr:
Sub FirstOne
Dim FixedArr(25) As Integer    ' Crea una matrice fissa
NextOne FixedArr()    ' e la passa a un'altra routine.
End Sub
Sub NextOne(SomeArr() As Integer)
ReDim SomeArr(35)        ' Qui viene generato l'errore 10.
. . .
End Sub
  Impostare la matrice originale come dinamica anziché come fissa
dichiarandola con ReDim (se la matrice è dichiarata in una routine) oppure
dichiarandola senza specificare il numero di elementi (se la matrice è
dichiarata alivello di modulo).
  b.. Si è cercato di ridimensionare una matrice dinamica a livello di
modulo, in cui un elemento è stato passato comeargomento a una routine. Ad
esempio, nel codice seguente ModArray è una matrice dinamica a livello di
modulo, il cui quarantacinquesimo elemento viene passatoper riferimento alla
routine Test:
Dim ModArray () As Integer    ' Crea una matrice dinamica a livello di
modulo.
. . .
Sub AliasError()
ReDim ModArray (1 To 73) As Integer
Test ModArray (45)    ' Passa un elemento della matrice
' a livello di modulo alla routine Test.
End Sub
Sub Test(SomeInt As Integer)
ReDim ModArray (1 To 40) As Integer  ' Qui viene generato l'errore 10.
End Sub
  Non è necessario passare un elemento della matrice a livello di modulo in
questo caso, poiché è visibile in tutte le routine del modulo. Tuttavia, se
viene passato un elemento la matrice viene bloccata per evitare la
deallocazione di memoria per ilparametro di riferimento nella routine, con
conseguenze imprevedibili al termine della routine.
  c.. Si è cercato di assegnare un valore a una variabile Variant che
contiene una matrice, ma la variabile Variant è bloccata. Ad esempio, se il
codice utilizza un ciclo For Each...Next per iterare in una variabile
Variant che contiene una matrice, la matrice viene bloccata all'entrata nel
ciclo e quindi rilasciata al termine del ciclo:
SomeArray = Array(9,8,7,6,5,4,3,2,1)
For Each X In SomeArray
SomeArray = 301    ' Causa l'errore perché la matrice è bloccata.
Next X
  Utilizzare For...Next anziché un ciclo For Each...Next per eseguire
l'iterazione. Quando una matrice è l'oggetto di un ciclo For Each...Next è
possibile leggere la matrice ma non scrivere in essa.
Per ulteriori informazioni, selezionare l'elemento desiderato e premere F1.

 generico.
hai fattpo bene a riportare il tutto.. inutile dire chre avevo controllato
già..
la cosa che mi fa "impazzire" è che la routine in oggetto viene richiamata
per 9 volte
le prime 7 non da errori l'8 volt a da errore, ma la momento di uscire dalla
sub cioè su end sub, e la 9 volta non da errore...
sinceramente sono basito.
Davide

 caso di una redim preserve.
uh! intelligente verifica :)
Quindi questo conferma le mie impressioni, ma comferma anche che l'SDK è
scritto coi piedi.
Ciao

 scritto coi piedi.
In realta' "allunga" finche' la memoria contigua e' libera, se il blocco
contiguo non e' sufficientemente grande rialloca il tutto,
indipendentemente dal fatto che sia Preserve.
Insomma qualunque sia il caso la riallocazione/non riallocazione non e'
"controllabile", in quanto dipende dalla frammentazione della memoria in
fase di esecuzione...
Provare per credere (anche senza Preserve):
Private Sub Form_Load()
    Dim l As Long
    Dim m() As Integer
    Me.AutoRedraw = True
    ReDim Preserve m(1000)
    Me.Print VarPtr(m(0))
    ReDim Preserve m(10000)
    Me.Print VarPtr(m(0))
    ReDim Preserve m(100000)
    Me.Print VarPtr(m(0))
    ReDim Preserve m(1000000)
    Me.Print VarPtr(m(0))
    ReDim m(0)
End Sub


 indipendentemente dal fatto che sia Preserve.
Di questo ne sono convinto, come ti dicevo in un post precedente.
Ciao

ma cosa può essere allora?
Intanto, poiche' non sappiamo esattamente cosa faccia il tuo codice,
riporto ancora un po' di documentazione nel caso possa essere sfuggito,
pur potendo essere utile:
Articolo su msdn:
BUG: Error 10 Attempting to ReDim or Erase an Array 
Q187553
<Estratto da un articolo sul vba di office:>
Duplicate definition (Error 10)
This error usually occurs only when generated from code, as in the following example: 
Error 10 
However the error may also occur if you try to use ReDim to change the number of elements 
of a fixed-size array. 
For example, in the following code, the fixed array FixedArr is received by SomeArr in 
the procedure NextOne, then an attempt is made to resize SomeArr: 
   Sub FirstOne
   Static FixedArr(25) As Integer   ' Create a fixed-size array
      NextOne FixedArr()            ' and pass it to another sub.
   End Sub
   Sub NextOne(SomeArr() As Integer)
   ReDim SomeArr(35)   ' Duplicate definition occurs here.
   . . .
   End Sub 
</estratto>
<estratto da un articolo sul vba di excel 97>
This behavior will occur if the following conditions are all true: 
You create two macros, where one macro passes a variable to the other macro. 
-and- 
The variable that is passed to the other macro is an element of an array. 
-and- 
The second macro accepts the variable by reference, not by value. 
-and- 
The second macro uses the ReDim method to redimension the array. 
</estratto>
Purtroppo non conoscendo il tuo codice e' piuttosto difficile azzardare
delle altre risposte.
-- 
ciao, hal

 Preserve.
Sì, infatti avevo aggiunto un "almeno in generale" (anche se
poco chiaro stava a significare proprio questo..
Sarei curioso di sapere quale è il comportamento in caso ci
sia sufficiente memoria per contenere l'array, ma sia troppo
frammentata perché sia contiguo. Suppongo fallisca.
Ciao.
