Newsgroup: it.comp.lang.visual-basic
Titolo: Merge di array con CopyMemory

Ciao,
Vorrei scrivere una funzione che unisca due array (se possibile in
maniera indipendente dal tipo di variabile) senza ciclare gli array
stessi. Ho pensato di utilizzare l'api copymemory ma ho qualche
difficoltà. Il codice:
Public Function ArrayMerge2(vArrayFirst As Variant, vArraySecond As
Variant) As Variant
    Dim arrTmp
    Dim sFBound As Single, sSBound As Single
    sFBound = UBound(vArrayFirst) - LBound(vArrayFirst)
    sSBound = UBound(vArraySecond) - LBound(vArraySecond)
    ReDim arrTmp(sFBound + sSBound)
    CopyMemory arrTmp(0), _
               vArrayFirst(LBound(vArrayFirst)), _
               (sFBound + 1) * LenB(vArrayFirst(UBound(vArrayFirst)))
    CopyMemory arrTmp(UBound(vArrayFirst) + 1), _
               vArraySecond(LBound(vArraySecond)), _
               (sSBound + 1) * LenB(vArraySecond(UBound(vArraySecond)))
    Dim sPnt As Single
    For sPnt = 0 To UBound(arrTmp)
        Debug.Print arrTmp(sPnt)
    Next
    Erase arrTmp
End Function
Quando arriva al debug.print si produce un errore (458: 'Variable uses
an Automation type not supported in Visual Basic').
Inoltre questa funzione potrebbe funzionare solo per array
zero-based...cosa affatto bella.
Qualcuno saprebbe darmi una mano?
Grazie
griflet

 difficoltà.
Le variabili array del VB non sono puntatori alla prima locazione di
memoria di un'area contigua di memoria (come in c per intenderci), ma
puntano ad una struttura SAFEARRAY (puoi dare un'occhiata qui
http://www.vbadvance.com/arrays.htm
)
Quindi trattarle così con il CopyMemory non credo sia una buona idea.
Sopratutto se gli array contengono stringhe o Variant!
Oltretutto tu passi attraverso dei Variant, che ti possono complicare la
vita.
Non vorrei dire una baggianata, ma per fare quello che vuoi fare tu
(sempre VB non si arrabbi) credo che dovrai passare per le API SafeArray*
-- 
Tnx a lot!
Daniele.
Free As In Freedom
www.fsf.org

 Qualcuno saprebbe darmi una mano?
Ripescando nella memoria mi ricordo di aver fatto un modulo che tra le altre 
cosine lavorava con i SAFEARRAY.
Ad es. er sapere la dimensione degli item in un array:
Private Declare Function ArrayPtr Lib "msvbvm60" Alias "VarPtr" (ptr() As 
Any) As Long
Private Declare Function CopyMemoryA Lib "kernel32" Alias "RtlMoveMemory" 
(pDst As Any, pSrc As Any, ByVal BytesLen As Long) As Long
'Use like this:  admArrayItemSize(ArrayPtr(p()))
Function admArrayItemSize(ByVal lpA As Long) As Long
    ' Test: passed
    Dim Size As Long
    Dim lpA2 As Long
    lpA2 = lpA
    Call CopyMemoryA(lpA2, ByVal lpA, 4)
    Call CopyMemoryA(Size, ByVal lpA2 + 4, 4)
    admArrayItemSize = Size
End Function
Oppure
Type SAFEARRAY
    cDims As Integer
    fFeatures As Integer
    cbElements As Long
    cLocks As Long
    pvData As Long
End Type
Private Declare Function SafeArrayGetElemSize Lib "oleaut32.dll" (psa As 
SAFEARRAY) As Long
Ciao
Prova a vedere se questo basta per correggere la tua.

Fabio ha scritto:

Ciao,
ottimo! grazie davvero. Ho ridotto la complessità utilizzando tipi
base (e i vs consigli naturalmente), direi che sono arrivato a un buon
punto. Adesso però mi sono imbattuto in un ulteriore magagna. Il mio
codice funziona per tutti i tipi base eccetto gli array di stringhe
che hanno una struttura differente (mi sembra di aver letto da qualche
parte....).
Utilizzando admArrayItemSize nell'array finale finisce solo il primo
item del primo array... il resto va perduto.
Pensate che utilizzare SafeArrayGetElemSize potrebbe risolvere? Direte:
"basta che provi"... Già! ma non mi è chiaro come utilizzare
quest'API. Fabio; potresti farmi un esempio?
grazie ancora.
griflet

 item del primo array... il resto va perduto.
Ma gli array di VB contengono tutti elementi dello stesso tipo ;)
Ciao 

Fabio ha scritto:

Ecco il codice:
'Le api....
Private Declare Function ArrayPtr Lib "msvbvm60" Alias "VarPtr" (ptr()
As Any) As Long
Private Declare Function CopyMemoryA Lib "kernel32" Alias
"RtlMoveMemory" (pDst As Any, pSrc As Any, ByVal BytesLen As Long) As
Long
'...come da tuo suggerimento...
Function lngArrayItemSize(ByVal lpA As Long) As Long
    ' Test: passed
    Dim Size As Long
    Dim lpA2 As Long
    lpA2 = lpA
    Call CopyMemoryA(lpA2, ByVal lpA, 4)
    Call CopyMemoryA(Size, ByVal lpA2 + 4, 4)
    lngArrayItemSize = Size
End Function
'Una funzione che semplicemente copia un array di long col copymem e lo
restituisce...
Private Function CopiaArrayLng(LngArr() As Long) As Long()
    Dim LngArr_Tmp(0 To 2) As Long
    Call CopyMemoryA(LngArr_Tmp(0), _
                     LngArr(0), _
                     lngArrayItemSize(ArrayPtr(LngArr)) * _
                     (UBound(LngArr) - LBound(LngArr) + 1))
    CopiaArrayLng = LngArr_Tmp
End Function
'La MEDESIMA funzione. Solo che qui usiamo array di stringhe...
Private Function CopiaArrayStr(StrArr() As String) As String()
    Dim StrArr_Tmp(0 To 2) As String
    Call CopyMemoryA(StrArr_Tmp(0), _
                     StrArr(0), _
                     lngArrayItemSize(ArrayPtr(StrArr)) * _
                     (UBound(StrArr) - LBound(StrArr) + 1))
    CopiaArrayStr = StrArr_Tmp
End Function
'E qui il brutale codice per provare quanto sopra...
    Dim LngArr(0 To 2) As Long, DstLngArr() As Long
    Dim StrArr(0 To 2) As String, DstStrArr() As String
    Dim Clc As Integer
    LngArr(0) = 1: LngArr(1) = 2: LngArr(2) = 3
    StrArr(0) = "ZERO": StrArr(1) = "UNO": StrArr(2) = "DUE"
    DstLngArr = CopiaArrayLng(LngArr)
    For Clc = LBound(DstLngArr) To UBound(DstLngArr)
        Debug.Print DstLngArr(Clc)
    Next
    DstStrArr = CopiaArrayStr(StrArr)
    For Clc = LBound(DstStrArr) To UBound(DstStrArr)
        Debug.Print DstStrArr(Clc)
    Next
Il risultato è che l'array di Long viene restituito correttamente e
stampato col primo ciclo for. Il secondo ciclo for dovrebbe stampare
l'array di stringhe restituito da CopiaArrayStr... ma stavolta solo il
valore del primo item ("ZERO") viene stampato.. mentre i valori "UNO" e
"DUE" si sono persi...:-(
Ho usato questo codice invece che quello postato prima per ridurre il
grado di complessità. Spero di non aver confuso le carte invece che di
chiarire....
Grazie ancora!!!! :-),
griflet

 "DUE" si sono persi...:-(
Eh, dovrei ripassarmi la struttura degli array gestiti da vb :)
Comunque, ho cercato dei miei vecchi post (una volta sě che avrei saputo 
risponderti :) ) e ho trovato tra i tanti questi:
http://groups.google.it/group/it.comp.lang.visual-basic/search?q=zanna+copymemory+array+stringhe&start=0
Prova a vedere se trovi info utili.
Ciao 

 Ciao
OK! CI SONO!!
Function StrArrMerge(ByRef strFirst() As String, ByRef strSecond() As
String) As String()
    Dim StrArr_tmp() As String
    ReDim StrArr_tmp((UBound(strFirst) - LBound(strFirst)) +
(UBound(strSecond) - LBound(strSecond) + 1))
    Call CopyMemory(ByVal VarPtr(StrArr_tmp(0)), _
                    ByVal VarPtr(strFirst(LBound(strFirst))), _
                    ByVal lngArrayItemSize(ArrayPtr(strFirst)) *
(UBound(strFirst) - LBound(strFirst) + 1))
    Call CopyMemory(ByVal VarPtr(StrArr_tmp(LBound(StrArr_tmp) +
(UBound(strFirst) - LBound(strFirst)) + 1)), _
                    ByVal VarPtr(strSecond(LBound(strSecond))), _
                    ByVal lngArrayItemSize(ArrayPtr(strSecond)) *
(UBound(strSecond) - LBound(strSecond) + 1))
    StrArrMerge = StrArr_tmp
End Function
Non è trasparente al tipo di array come mi proponevo...ma è un
compromesso accettabile!
Grazie ancora per i consigli ..e la pazienza :-)
Ciao
griflet

 OK! CI SONO!!
Proverò a capire cosa faccia :)
Un consiglio: per gli array lavora direttamente sul nome della funzione, 
senza passare da un array temporaneo, oppure restituiscili come parametri 
poichè l'assegnazione di un array comporta la copia di tutti gli elementi 
dello stesso.
(questo spece in funzioni come CopiaArray() dove lavori di CopyMemory() è 
piuttosto stupido :P )
Ciao