VB /Excel VBA: Array vergrößern

Hallo Rainer,

Warum Reinhard Bereiche des Arrays kopieren möchte habe ich
noch nicht verstanden, das ist halt Excel, da komme ich nicht
mit.

nein, das hat mit Excel nix zu tun. Ich habe ein gefülltes Array a(5) das so im Speicher abgelegt ist (die Zahlen sind die Werte in dem Array):

1
2
3
4
5
6

Nun möchte ich es „vergrößern“ um einen Eintrag, damit es nachher so aussieht im Speicher:

1
2
3
Neuer Eintrag
4
5
6

Dazu kann ich mir ein neues leeres array b(6) anlegen, dann gehe ich das Array a einzeln durch und schaufle die ersten 3 Einträge in die drei ersten Einträge von b, dann schreibe ich den 4ten Eintrag in b hinein,dann schaufle ich die letzten 3 Einträge von a in die 3 letzten Einträge von b.

Das geht, kriegen wir alle hin.

Nun möchte ich aber auf einen Rutsch die ersten 3 Einträge in die 3 ersten Einträge von b kopieren und auch die 3 letzten Einträge von a in die 3 letzten Einträge von b kopieren. Darum geht es mir.

Trotz der Hilfe von Alex und Euch kriege ich das aber nichtmal mit einem eindimensionalen Array hin.

Die Codes von Alex habe ich stundenlang getestet in VB5.0 , ich glaube ich habe alle Varianten durchgespielt wo man strptr(), Byval, byref sowohl in den Aufrufen als auch in der API-Deklaration benutzen kann.

Ich glaube eine Lösung kann ich mir abschminken:frowning:
Denn erschwerdend kommt dazu, daß Originalarray um das es geht, wird beim Einlesen einer Textdatei erstellt, und ergibt dann ein Array von ca. a(45000,2) und alle Einträge sind Strings von unterschiedlicher Länge.

Soweit ich weiß wird das dann so im Speicher abgelegt, daß erst die 45000 Einträge mit dem Zweitindex 0 abgelegt werden, dann die nächsten 45000 Einträge mit dem zweitindex 1, dann die letzten 45000 Einträge mit dem Zweitindex 2.

Um da jetzt was in dieses Array „einzufügen“ müßte ich ja an drei Stellen etwas einfügen und die SpeicherAdressen dieser drei Stellen kenne ich ja nicht da die Einträge unterschiedliche Bytelängen haben.

Würde ich diese Speicheradressen kennen könnte ich ja mit rtlmovememory die nachfolgenden Einträge verschieben um da was einzutragen.

Theoretisch bin ich mir sehr sicher die Lösung zu kennen wie man das lösen kann.
Angenommen ich habe das Array a(45000,2) und ich möchte dort wo in a(x,1) das Wort „Huhu“ steht, etwas einfügen.
Dann muß ich nur ab der Startspeicheradresse vom Array a nach dem Wort „Huhu“ suchen.
Wenn ich jetzt die Speicheradresse des Wortes „Huhu“ kenne, nützt mir das erstmal nix.
Aber, soweit ich weiß hat jeder Eintrag in einer Arrayliste die im Speicher steht hinten eine 0 o.ä.
Wenn ich nun ermitteln könnte wieviele „Nullen“ es zzwischen der Startadresse des Array und dem Eintrag „Huhu“ gibt, so kann ich daraus berechnen, daß das Wort „Huhu“ in a(32378,1) stehen muß.
Auch durch Zählung der „Nullen“ kriege ich dann raus wo im Speicher a(32378,0) und a(32378,2) abgelegt wurde.
Dann könnte ich durch dreimaliges „Move“ das Problem lösen.

Soweit die Theorie :smile:

Ich hoffe ich konnte mich einigermaßen verständlich machen :smile:

Das Array bleibt erst mal im Speicher, Reinhard möchte es ja
an ein Listen-Steuerelement übergeben. Ob das dann so
fesichert wird, oder ob das nur eine Anzeige ist, weiß ich
nicht.

Letzlich soll die reine Ausgabe dann doch in Excel erfolgen. Aber ich wollte es ja umbauen sodaß man das Ergebnis in einer VB-Listbox sieht.
Leider weigert sich meine Listbox in VB5.0 beharrlich mehrere Spalten anzuzeigen. Hinweise auf ListView brachten mir nix, weil ich die bei VB5.0 nicht finde :frowning:

Danke an alle die sich einen Kopf machen um mir da zu helfen mit dem Problem der Arrayumverschiebung.
Gruß
Reinhard

Hallo Reinhard,

nein, das hat mit Excel nix zu tun. Ich habe ein gefülltes
Array a(5) das so im Speicher abgelegt ist (die Zahlen sind
die Werte in dem Array):

OK.

1
2
3
4
5
6

Nun möchte ich es „vergrößern“ um einen Eintrag, damit es
nachher so aussieht im Speicher:

1
2
3
Neuer Eintrag
4
5
6

Auch OK. Mit Zahlen kein Problem.

Private Declare Sub CopyMemory Lib "kernel32" \_
 Alias "RtlMoveMemory" (pDst As Any, pSrc As Any, \_
 ByVal ByteLen As Long)

Dim Arr() As Byte

Private Sub Command1\_Click()
 Dim Pos As Long, i As Integer
 Pos = 3 '




> Dazu kann ich mir ein neues leeres array b(6) anlegen, dann  
> gehe ich das Array a einzeln durch und schaufle die ersten 3  
> Einträge in die drei ersten Einträge von b, dann schreibe ich  
> den 4ten Eintrag in b hinein,dann schaufle ich die letzten 3  
> Einträge von a in die 3 letzten Einträge von b.  
>   
> Das geht, kriegen wir alle hin.


Ja, auch ohne neues Array. :smile:



> Nun möchte ich aber auf einen Rutsch die ersten 3 Einträge in  
> die 3 ersten Einträge von b kopieren und auch die 3 letzten  
> Einträge von a in die 3 letzten Einträge von b kopieren. Darum  
> geht es mir.


Wenn Du unbedingt zwei Arrays willst, das geht genau so.



    
    
    Private Declare Sub CopyMemory Lib "kernel32" \_
     Alias "RtlMoveMemory" (pDst As Any, pSrc As Any, \_
     ByVal ByteLen As Long)
    
    Dim a() As Byte
    Dim b() As Byte
    
    Private Sub Command1\_Click()
     Dim Pos As Long, i As Integer
     Pos = 3 '
    
    
    
    > Trotz der Hilfe von Alex und Euch kriege ich das aber nichtmal  
    > mit einem eindimensionalen Array hin.
    
    
    Das muss aber jetzt auch bei Dir laufen, ist getestet.
    
    
    
    > Die Codes von Alex habe ich stundenlang getestet in  
    > **<u>VB5.0</u>** , ich glaube ich  
    > habe alle Varianten durchgespielt wo man strptr(), Byval,  
    > byref
    
    
    Brauchst Du bei Arrays nicht. Einfach weg lassen und nur das Feld des Arrays schreiben. Das wird Dein Problem gewesen sein.
    
    
    
    > sowohl in den Aufrufen als auch in der API-Deklaration  
    > benutzen kann.  
    >   
    > Ich glaube eine Lösung kann ich mir abschminken:frowning:  
    > Denn erschwerdend kommt dazu, daß Originalarray um das es  
    > geht, wird beim Einlesen einer Textdatei erstellt, und ergibt  
    > dann ein Array von ca. a(45000,2) und alle Einträge sind  
    > Strings von unterschiedlicher Länge.
    
    
    
    Das ist der Punkt. Sobald das Array als String deklariert ist, funktioniert das so nicht mehr. Ob und wie das dann geht, habe ich keine Ahnung. Dafür habe ich noch keine Lösung gesehen.
    
    
    
    > Soweit ich weiß wird das dann so im Speicher abgelegt, daß  
    > erst die 45000 Einträge mit dem Zweitindex 0 abgelegt werden,  
    > dann die nächsten 45000 Einträge mit dem zweitindex 1, dann  
    > die letzten 45000 Einträge mit dem Zweitindex 2.
    
    
    Das zweidimensionale Array ist eher nicht das Problem. Das Problem sind die Strings!
    
    
    
    > Um da jetzt was in dieses Array "einzufügen" müßte ich ja an  
    > drei Stellen etwas einfügen und die SpeicherAdressen dieser  
    > drei Stellen kenne ich ja nicht da die Einträge  
    > unterschiedliche Bytelängen haben.
    
    
    Zumal Du da nichts verändern kannst. So einfach ist es nicht.
    
    
    
    > Würde ich diese Speicheradressen kennen könnte ich ja mit  
    > rtlmovememory die nachfolgenden Einträge verschieben um da was  
    > einzutragen.
    
    
    Nein. Nur die Zeiger stehen in einem Zusammenhängenden Speicherbereich. Die einzelnen Strings werden an zufällig freie Speicheradressen geschrieben, stehen nicht direkt hintereinender. 
    
    
    
    > Theoretisch bin ich mir sehr sicher die Lösung zu kennen wie  
    > man das lösen kann.
    
    
    Du warst Dir sicher, weil Du fälschlicher Weise angenommen hast, daß das Array in der richtigen Reihenfolge in einem zusammenhängenden Speicherbereich steht. Das war ein Irrtum.
    
    
    
    > Angenommen ich habe das Array a(45000,2) und ich möchte dort  
    > wo in a(x,1) das Wort "Huhu" steht, etwas einfügen.  
    > Dann muß ich nur ab der Startspeicheradresse vom Array a nach  
    > dem Wort "Huhu" suchen.  
    > Wenn ich jetzt die Speicheradresse des Wortes "Huhu" kenne,  
    > nützt mir das erstmal nix.  
    > Aber, soweit ich weiß hat jeder Eintrag in einer Arrayliste  
    > die im Speicher steht hinten eine 0 o.ä.
    
    
    Nein. Diese 'Arrayliste' gibt es so nicht. Es gibt ein eigenes Array, in dem die Zeiger auf die Strings stehen. Das habe ich erfolglos versucht zu manipulieren. :frowning:
    
    
    
    > Wenn ich nun ermitteln könnte wieviele "Nullen" es zzwischen  
    > der Startadresse des Array und dem Eintrag "Huhu" gibt, so  
    > kann ich daraus berechnen, daß das Wort "Huhu" in a(32378,1)  
    > stehen muß.  
    > Auch durch Zählung der "Nullen" kriege ich dann raus wo im  
    > Speicher a(32378,0) und a(32378,2) abgelegt wurde.  
    > Dann könnte ich durch dreimaliges "Move" das Problem lösen.  
    >   
    > Soweit die Theorie :smile:
    
    
    Leider falsch. 
    
    
    
    > Ich hoffe ich konnte mich einigermaßen verständlich machen :smile:
    
    
    Ja, das schon, aber Du hast eine falsche Vorstellung. So wie du dachtest, wird das Array nicht verwaltet.
    
    
    
    > > Das Array bleibt erst mal im Speicher, Reinhard möchte es ja  
    > > an ein Listen-Steuerelement übergeben. Ob das dann so  
    > > fesichert wird, oder ob das nur eine Anzeige ist, weiß ich  
    > > nicht.
    > 
    >   
    > Letzlich soll die reine Ausgabe dann doch in Excel erfolgen.  
    > Aber ich wollte es ja umbauen sodaß man das Ergebnis in einer  
    > VB-Listbox sieht.  
    > Leider weigert sich meine Listbox in VB5.0 beharrlich mehrere  
    > Spalten anzuzeigen.
    
    
    Das geht schon, aber sehr schlecht zu handhaben und sieht auch nicht gut aus. Stell mal bei List2 Die Eigenschaft 'Columns' auf 3 und dann:
    
    
    
        
        
        Private Sub Command2\_Click()
         Dim c As Integer, r As Integer
         For i = 1 To 4
         List2.AddItem " "
         Next
         For r = 0 To 4
         List2.List(r) = CStr(r) + Chr(9) + "a" + Chr(9) + "b"
         Next
        End Sub
        
    
    
    
    
    Übel, finde ich. :frowning:
    
    
    
    > Hinweise auf ListView brachten mir nix,  
    > weil ich die bei VB5.0 nicht finde :frowning:
    
    
    Und das MsFlexgrid? Sag bloß, das hast Du auch nicht. Auch nicht unter Projekte/Komponenten? 
    
    Gruß Rainer

Hallo Jungs,

ich antworte nun mal nicht jeden einzeln.
Ihr macht euch das alles viel zu schwer oder denkt zu kompliziert :s

Schauen wir doch einmal uns das alles genauer an!

Bei der API CopyMemory wird einmal nach der Destination gefragt, dann noch nach der Source Quelle und dann noch einmal nach der Grösse.

Die Destination, sowie die Source sind kein Thema! Der Hund ist bei der Grösse begraben.

Wenn wir nun einmal ueberlegen, wie man das am besten löst fallen einem doch spontan 2 wege ein! Entweder man vergibt im Vorfeld schon eine Fixe Grösse. Diese kann man dann angeben. Also Grösse *2 ist ja klar :wink:( VB speichert intern String im Unicode Format ab, deswegen 2 Byte anstatt nur 1!)
Aber da stellt sich die Frage. Was für ein Daten Volumen kommen an Daten an. VB Strings koennen glaub bis zu max. 2 GB an Daten aufnehmen. Also verwerfen wir die Idee mal wieder ganz fix!

Für alle die es dennoch interessiert.

Public Function CopyString(ByVal Pointer As Long, ByVal Size As Long)As String
 Dim nString As String
 Dim nPos As Long
 nString = String$(Size, 0)
 CopyMemory ByVal StrPtr(nString), ByVal Pointer, Size \* 2
 nPos = InStr(nString, Chr(0))
 If nPos Then
 PtrStr = Mid$(nString, 1, nPos - 1)
 Else
 PtrStr = nString
 End If
End Function

Wenn wir nun einmal weiter überlegen. Hmm, welche Datentypen unter VB koennen Strings speichern. Da haetten wir einmal den String, der aber flexibel ist und wir die Grösse nicht wissen!
Dann haetten wir noch den Datentyp Variant! Und genau dem machen wir uns zu nutzen. Der Datentyp Variant kann alles mögliche beinhalten, also auch Strings. dabei interessiert die Länge nicht! der Datentyp Variant brauch 16 Byte!
Also schreiben wir den ganzen Kram halt auf Variant. Benötigt man später dann die Daten so kann man sie jederzeit wieder in einen String umwandeln :wink:

Speziell für Reinhard, wo ich mal hoffe das ich nun richtig liege.

'Demo mit 1000 Daten!
'eine Form erstellen.
'Darauf 2 listboxen ( List1 und List2)
'Ein Command Button ( Command1)
'List1 zeigt die Daten im Array A an und List2 die Daten im Array B

Option Explicit


Private Declare Sub Copy Lib "kernel32" Alias "RtlMoveMemory" (pDst As Any, pSrc As Any, ByVal ByteLen As Long)


Dim a() As Variant
Dim b() As Variant
Dim Loading As Boolean

Private Sub Command1\_Click()
On Error Resume Next
Dim Count As Variant
Dim vData As String
Count = InputBox("Ab welcher Position einfügen?")
If IsNumeric(Count) Then
 If Count \> UBound(a) Or Count "" Then
 List2.AddItem b(i)
 End If
Next
Screen.MousePointer = 0
End Sub

Private Sub Form\_Activate()
Dim i As Long
Dim j As Byte
Dim k As Integer
If Loading Then
 Screen.MousePointer = 11
 Me.Caption = "Lade Daten"
 Loading = Not Loading
 ReDim a(1000)
 ReDim b(UBound(a) + 1)
 For i = 0 To 1000
 k = Int(Rnd \* 30) + 1
 For j = 1 To k
 a(i) = a(i) + Chr(Int((26 \* Rnd) + 1) + 65)
 Next j
 List1.AddItem a(i)
 Me.Caption = "Lade Daten [" & i & "/1000]"
 If i Mod 1000 = 0 Then DoEvents
 Next i
End If
Me.Caption = "Bereit"
Screen.MousePointer = 0
End Sub

Private Sub Form\_Load()
 Loading = True
End Sub

MfG Alex

1 Like

Hallo Jungs,

Hallo Alex!

ich antworte nun mal nicht jeden einzeln.
Ihr macht euch das alles viel zu schwer oder denkt zu
kompliziert :s

hmmm, die Lösung habe ich noch nie gesehen, SUPER !!! Schon gesichert! :smile:

Ja, das ist exakt das, was Reinhard gesucht hat und was ich nicht gefunden habe.

Gruß Rainer

Hallo Rainer,

hmmm, die Lösung habe ich noch nie gesehen, SUPER !!! Schon
gesichert! :smile:

Marke Eigenbau mit ca. 10 Minuten Arbeit *zwinker*

Ja, das ist exakt das, was Reinhard gesucht hat und was ich
nicht gefunden habe.

Da waerst du auch selbst darauf gekommen, wenn du nicht zu kompliziert gedacht haettest. Waerst du auf die Idee gekommen die Daten in ein Variant Feld abzulegen haettest du das auch binnen paar Minuten hinbekommen :smile: Ansonsten haettet man es halt mit einem String einer Fixen Grössen lösen koennen :smile: Dazu habe ich dir ja auch den Weg gezeigt.
Aber warum verwendet Reinhard bei solch einem Datenvolumen nicht eine Klasse und daraus eine Collection? Da ist er flexibler :wink:

Aber schön das wir es nun geschafft haben, Reinhard zu helfen. Da wird er sich sicher freuen und sein Vorhaben nicht aufgeben :wink:

Er muss nur darauf achten das er sich so den Speicher sinnlos zu müllt und das frueher oder später zu abstuerzen führen kann!

MfG Alex

Ein Zeiger lässt sich ja kopieren und ich hätte erwartet, daß
die Zeiger hintereinander stehen. Unklar ist allerdings, wie
viele Bytes so ein Zeiger hat. Ich habe auch schon mal ein
paar Bytes mehr kopiert, keie Veränderung, noch nicht mal ein
Absturz.

Ein Zeiger ist nichts weiter als eine Variable vom Typ Long. Ein Zeiger wird im Stack abgelegt, beinhaltet die Adresse der Daten im Heap und zeigt auf diese. Also ist die Grösse eines Zeigers immer 4 Byte!

MfG Alex

Hi Alex,

Ein Zeiger ist nichts weiter als eine Variable vom Typ Long.
Ein Zeiger wird im Stack abgelegt, beinhaltet die Adresse der
Daten im Heap und zeigt auf diese. Also ist die Grösse eines
Zeigers immer 4 Byte!

danke. Inzwischen hatte ich ein wenig ‚Grundlagenforschung‘ :smile: betrieben und habe gesehen, daß das vier Bytes sind. Mein erster Versuch, die zu verbiegen ist allerdings gescheitert. Ich habe inzwischen eine vage Vermutung, warum und wie man das eventuell umgehen kann. Ich werde jetzt aber aufhören, mir das Hirn zu zermartern wo da die Probleme liegen und wie man das eventuell doch noch packen könnte, Deine Lösung mit Hilfe von ‚Variant‘ funktioniert ja perfekt. Warum muss ich ja nicht unbedingt verstehen.

Gruß Rainer

Hi Alex,

ich habe das Programm noch ein paar mal gestartet, alles verstehe ich noch nicht, aber es gibt ein Problem. Beim Beenden des Programms stürzt die IDE ab. Ich bastel mal weiter …

Gruß Rainer

Hi Alex,

ich habe es doch noch mal mit Strings versucht, klappt und stürzt auch nicht ab.

Option Explicit

Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" \_
 (pDst As Any, pSrc As Any, ByVal ByteLen As Long)

Dim Arr() As String
Dim Ze() As Long

Private Sub Command1\_Click()
 Dim i As Integer, m As Long, Po As Long, Txt As String
 Txt = "AAAAAAAAAAAAAAAAAAAAA"
 Po = 4
 ReDim Preserve Arr(UBound(Arr) + 1)
 ReDim Preserve Ze(UBound(Arr))
 Arr(UBound(Arr)) = Txt
 CopyMemory Ze(0), ByVal VarPtr(Arr(0)), (UBound(Arr) + 1) \* 4
 m = Ze(UBound(Ze))
 CopyMemory Ze(Po + 1), Ze(Po), (UBound(Ze) - Po) \* 4
 Ze(Po) = m
 CopyMemory ByVal VarPtr(Arr(0)), Ze(0), (UBound(Arr) + 1) \* 4
 List2.Clear
 For i = 0 To UBound(Arr)
 List2.AddItem Arr(i)
 Next
End Sub

Private Sub Form\_Load()
 Dim r As Integer, p As Integer, n As Integer, i As Integer, zl As String
 ReDim Arr(10)
 ReDim Ze(10)
 For i = 0 To 10
 zl = ""
 n = Int(Rnd(1) \* 10) + 1
 For p = 1 To n
 r = Int(Rnd(1) \* 26) + 65
 zl = zl + Chr(r)
 Next
 Arr(i) = zl
 List1.AddItem zl
 Next
End Sub

Der Umweg über das zweite Array ist nötig. Wenn ich das richtig verstehe weigert sich VB mit zweí verschiedenen Zeigern auf die selbe Stelle im Speicher zu zeigen. Schritt für Schritt an den Zeigern zu arbeiten geht also nicht, aber das ganze Array auf einmal überschreiben geht.

Gruß Rainer

Speziell für Reinhard, wo ich mal hoffe das ich nun richtig
liege.

Hallo Alex,

danke für deine Ausführlichkeit.
Ja, jetzt klappt es so wie ich mir das gewünscht habe:smile:

Ich habe jetzt mehrmals den Code unverändert ausprobiert, leider ist, wenn ich auf das Schließkreuz der Form klicke, danach die IDE wech :frowning:

@Rainer, ich kam noch nicht dazu deine Codes zu testen. Ich habe jetzt so viele Codes erhalten und auch selbst eigene entwickelt und einige im Internet gefunden, ich muß da erst mal wieder den Überblick kriegen,also diesen Artikelbaum ausdrucken usw.

Wie ich schon schrieb wird das Ganze mehr mehrdimensionalen Arrays noch komplizierter.

Und eine Umsetzung nach VBA steht je nach Code noch in den Sternen, da z.B. VBA kein „strptr“ kennt. „varptr“ ist bekannt, wird aber nicht in der Hilfe beschrieben.
Das macht aber nix, dann ist halt das Excelprojekt gestorben, es war sowieso nur der Versuch einer Lösung für eine Anfrage im Excelbrett, die sich gar nicht um Arrays handelt.

Jmd. wollte aufgrund der Vornamen einer bestehenden Kundendatenliste wissen ob man für einen Serienbrief aufgrund des Vornamens die Anrede „Herr“ oder „Frau“ automatisch festlegen könnte.
Dazu braucht man ja Listen mit weiblichen und männlichen Vornamen, ich stieß dabei auf eine entsprechende Liste im Txtformat,
hier der Anfang dieser Liste: http://www.hostarea.de/server-10/Oktober-3285ab8e90.txt
Die insgesamt ca. 45000 Zeilen mit den Vornamen habe ich dann in ein Array a(45000,2) gesplittet. Im Index 1 stehen die Vornmaen, im Index 0 M oder F, und im Index 2 Infos in welchen Ländern das so ist.

Die Liste ist komprimiert/kodiert, das heißt im Index 1 steht nicht z.B.

Ralf
Rainer
Reiner
Rheiner
Richard

untereinander, sondern verkürzt zu

Ralf
Rner
Richard

und im Kopf der Originaldatei ist halt aufgelistet, daß „“ durch „ai“, „ei“ und „hei“ zu ersetzen ist um die komplette Liste zu erhalten. Neben „“ gibt es noch andere „Ersetzungen“

So kam ich halt auf die ganze Arraygeschichte…

Gruß
Reinhard

Hallo Reinhard,

Ich habe jetzt mehrmals den Code unverändert ausprobiert,
leider ist, wenn ich auf das Schließkreuz der Form klicke,
danach die IDE wech :frowning:

ja, bei mir auch. Da muss es Probleme mit dem Speicher geben, die ich aber noch nicht verstehe.

Deshalb habe ich noch weiter gebastelt und eine stablie Lösung gefunden.

/t/vb-excel-vba-array-vergroessern/4820024/22

Nach meiner Meinung muss das auch in Excel-VBA in einer Userform laufen.

Gruß Rainer

Der Umweg über das zweite Array ist nötig. Wenn ich das
richtig verstehe weigert sich VB mit zweí verschiedenen
Zeigern auf die selbe Stelle im Speicher zu zeigen. Schritt
für Schritt an den Zeigern zu arbeiten geht also nicht, aber
das ganze Array auf einmal überschreiben geht.

Hallo Rainer,

bei meinen Recherchen stiess ich auf rtlMOVEmemory und rtlCOPYmemory, beim letzteren ist die Einschränkung daß sich Quell- und Zielbereich nicht überlappen dürfen.

Bei rtlMOVEmemory gibt es diese Einschränkung nicht, insofern verstehe ich auch nicht warum man nicht paar Zeiger auf die gleiche Stelle lassen dürfte.

Irritieren tut mich auch die allgemeine Verwendung von „copymemory“ für rtlMOVEmemory.

Für mich unterscheiden sich Copy und Move schon eklatant. D.h. den Aliasnamen „Movememory“ für rtlMOVEmemory würde ich verstehen, den Aliasnamen „Copymemory“ halt nihct.
Aber alle benutzen „Copymemory“ für rtlMOVEmemory *grübel*

Gruß
Reinhard

Hallo Reinhard,

bei meinen Recherchen stiess ich auf rtlMOVEmemory und
rtlCOPYmemory, beim letzteren ist die Einschränkung daß sich
Quell- und Zielbereich nicht überlappen dürfen.

Bei rtlMOVEmemory gibt es diese Einschränkung nicht, insofern
verstehe ich auch nicht warum man nicht paar Zeiger auf die
gleiche Stelle lassen dürfte.

Wenn die Zeiger von ‚a‘ und ‚b‘ gleich sind und ich ändere ‚a‘ müsste sich ‚b‘ mit ändern. Daß VB das nicht mag, kann ich verstehen. :smile:

Irritieren tut mich auch die allgemeine Verwendung von
„copymemory“ für rtlMOVEmemory.

Für mich unterscheiden sich Copy und Move schon eklatant. D.h.
den Aliasnamen „Movememory“ für rtlMOVEmemory würde ich
verstehen, den Aliasnamen „Copymemory“ halt nihct.
Aber alle benutzen „Copymemory“ für rtlMOVEmemory *grübel*

Das ist einfach, kein Mensch tippt die Deklaration. :smile:
Das steht so in der API-Guide und ich kopiere das dort. Das ist bequem und vermeidet Tippfehler oder Irrtümer. Wenn ‚alle‘ das so verwenden, werden die die Deklaration auch nicht tippen, sondern nur kopieren.

Gruß Rainer

Hallo Rainer,

danke. Inzwischen hatte ich ein wenig ‚Grundlagenforschung‘

-) betrieben und habe gesehen, daß das vier Bytes sind. Mein

erster Versuch, die zu verbiegen ist allerdings gescheitert.
Ich habe inzwischen eine vage Vermutung, warum und wie man das
eventuell umgehen kann. Ich werde jetzt aber aufhören, mir das
Hirn zu zermartern wo da die Probleme liegen und wie man das
eventuell doch noch packen könnte, Deine Lösung mit Hilfe von
‚Variant‘ funktioniert ja perfekt. Warum muss ich ja nicht
unbedingt verstehen.

Nichts zu danken :smile:
Aber was verstehst du denn nicht an dem Source ( Mit dem Variant?)
Und welchen Zeiger willst du denn wie verbiegen? Und wobei hast du denn da Schwierigkeiten? Vielleicht kenne ich ja die Lösung und dann weisst du sie dann auch danach :wink:

MfG Alex

Hallo Alex,

Aber was verstehst du denn nicht an dem Source ( Mit dem
Variant?)

Nein. :smile:

Und welchen Zeiger willst du denn wie verbiegen? Und wobei
hast du denn da Schwierigkeiten? Vielleicht kenne ich ja die
Lösung und dann weisst du sie dann auch danach :wink:

In jedes Feld des Arrays passen ja X Zeichen, mit CopyMemory werden nur 16 Bytes kopiert. Da können also unmöglich die Zeichen stehen, sondern nur Zeiger auf den Speicherplatz, an dem die Zeichen stehen.

Nach dem Kopieren habe ich die Zeichen aber tatsächlich in beiden Arrays, denn ich kann sie voneinander unabhängig verändern. Der String selbst muss also auch irgendwann irgendwie kopiert werden, der Code tut es nicht. Das ist der Teil, den ich nicht verstehe.

Zu schade, daß die IDE von dem Code abstürzt. :frowning:

Für Reinhards Problem habe ich ja jetzt eine Lösung, die ich verstehe, und an der die IDE nicht abstürzt. Ich tausche einfach die Stringpointer aus, wo die stehen, steht in den Varpointern.

Daß das erst nicht funktioniert hat, muss wohl daran gelegen haben, daß nicht zwei Stringpointer auf die selbe Speicheradresse zeigen dürfen. Bereite ich das vor und verbiege alle Pointer auf einmal, geht es. Dazu brauche ich eben das Long-Array, in das ich die Pointer kopieren kann, dort verschieben, ohne daß das auf die Speicherverwaltung Einfluss hat und dann zurück kopieren.

Ob meine Vorstellung vom Vorgang ganz korrekt ist, weiß ich nicht, aber es funktioniert stabil.

Gruß Rainer

Hallo Rainer,

In jedes Feld des Arrays passen ja X Zeichen, mit CopyMemory
werden nur 16 Bytes kopiert. Da können also unmöglich die
Zeichen stehen, sondern nur Zeiger auf den Speicherplatz, an
dem die Zeichen stehen.

Jups genau. Aber was interessieren uns die Zeiger in dem Falle?
Schau ein Variant kann alles mögliche speichern!
Da kommt es öfters vor das man mehr wie 16 Bytes benötigt. Man denke mal nur an ein Object.
Wo VB nun die Daten ablegt ist unrelevant, wir wissen das wir 16 Bytes brauchen und das wars. Wir koennen ja damit dann auf alles zugreifen. Wo er nun letztendlich da welchen zeiger wohin tüttelt weiss keiner! Das darin Zeiger stehen kann ich mir nicht vorstellen, da er ja ueber die Variable auf den Stack zugreift und dort dann in den Heap!!!

Nach dem Kopieren habe ich die Zeichen aber tatsächlich in
beiden Arrays, denn ich kann sie voneinander unabhängig
verändern. Der String selbst muss also auch irgendwann
irgendwie kopiert werden, der Code tut es nicht. Das ist der
Teil, den ich nicht verstehe.

Er kopiert dir doch die Zeichen, wobei es unrelevant ist, wie lang der String ist! Dann hast du im Stack 2 Daten liegen die auf den Heap verweisen, mit 2 unterschiedlichen Adressen! Du greifst danach also indirekt auf dem heap zu und hast dort 2 verschiedene Daten stehen! Sie sind zwar gleich aber nicht die selben!

Zu schade, daß die IDE von dem Code abstürzt. :frowning:

Hast du es mal mit weniger Daten probiert? Ich vermute mal das es an der Datenmenge liegen wird. Ein bereinigen des Speichers vor dem Beenden der Form sollte das Problem lösen :wink: VB ist nicht .NET wo man sich darum nicht kuemmern muss *gg*
Aber wie ich das mitbekommen habe, hat Reinhard ja aufgegeben :frowning:
Ok für sein Vorhaben waere das mit den Arrays nicht gerade sinnvoll gewesen. NE Collection waere da besser gewesen :wink:

Für Reinhards Problem habe ich ja jetzt eine Lösung, die ich
verstehe, und an der die IDE nicht abstürzt. Ich tausche
einfach die Stringpointer aus, wo die stehen, steht in den
Varpointern.

Wie meinst du das?

Daß das erst nicht funktioniert hat, muss wohl daran gelegen
haben, daß nicht zwei Stringpointer auf die selbe
Speicheradresse zeigen dürfen. Bereite ich das vor und
verbiege alle Pointer auf einmal, geht es. Dazu brauche ich
eben das Long-Array, in das ich die Pointer kopieren kann,
dort verschieben, ohne daß das auf die Speicherverwaltung
Einfluss hat und dann zurück kopieren.

Ich kenne die voherige Lösung nicht Rainer. Aber lag es vielleicht daran das ein String pro Zeichen VB Intern 2 Bytes belegt?

Ob meine Vorstellung vom Vorgang ganz korrekt ist, weiß ich
nicht, aber es funktioniert stabil.

Das ist die Hauptsache. Und das schoene ist, das wir wieder etwas gelernt haben :wink:

MfG Alex

PS: Übrigens in .NET gibt es den schönen Befehl

Array.Copy und viele andere tolle Sachen, die einem das Leben leicht machen *gg*

Hi Alex,

In jedes Feld des Arrays passen ja X Zeichen, mit CopyMemory
werden nur 16 Bytes kopiert. Da können also unmöglich die
Zeichen stehen, sondern nur Zeiger auf den Speicherplatz, an
dem die Zeichen stehen.

Jups genau. Aber was interessieren uns die Zeiger in dem
Falle?
Schau ein Variant kann alles mögliche speichern!
Da kommt es öfters vor das man mehr wie 16 Bytes benötigt. Man
denke mal nur an ein Object.

Die 16 ist von Dir! :smile: Du kopierst pro Feld 16 Bytes.
Wir müssen uns schon darum kümmern was wir tun, wenn wir Windows ins Handwerk pfuschen. CopyMemory ist keine VB-Methode, wir schreiben in den Arbeitsspeicher, wie zu Zeiten vom C64 mit Peek und Poke.

Wo VB nun die Daten ablegt ist unrelevant, wir wissen das wir
16 Bytes brauchen und das wars.

Eben leider nicht. Wenn es denn ohne Fehler funktionieren würde, dann würde ich ja auch sagen ich muss nicht immer alles genau wissen, aber ganz offensichtlich bleibt die Manipulation nicht unentdeckt, es kommt zu einem schwerwiegenden Fehler, den Windows gern nach Redmond melden würde.

Wir koennen ja damit dann auf
alles zugreifen. Wo er nun letztendlich da welchen zeiger
wohin tüttelt weiss keiner!

Muss man aber wissen, um den Fehler vermeiden zu können. So kann man den Code nicht verwenden.

Das darin Zeiger stehen kann ich
mir nicht vorstellen, da er ja ueber die Variable auf den
Stack zugreift und dort dann in den Heap!!!

Nein, wir schreiben mit CopyMemory direkt in den Arbeitsspeicher, holen uns nur vorher die Adressen, die uns zugewiesen wurden.

So lange wir nichts tun, das Windows interessiert, ist das egal. Sobald wir Zeiger verbiegen, müssen wir das so tun, daß Windows das nicht bemerkt.

Zu schade, daß die IDE von dem Code abstürzt. :frowning:

Hast du es mal mit weniger Daten probiert?

Ja.

Für Reinhards Problem habe ich ja jetzt eine Lösung, die ich
verstehe, und an der die IDE nicht abstürzt. Ich tausche
einfach die Stringpointer aus, wo die stehen, steht in den
Varpointern.

Wie meinst du das?

Private Sub Command2\_Click()
 Dim i As intrger
 For i = LBound(Arr) To UBound(Arr)
 List1.AddItem Hex(VarPtr(Arr(i))) + " " + Hex(StrPtr(Arr(i))) + " " + Arr(i)
 Next
End Sub

Sieh Dir das mal an.
Wo die einzelnen Strings liegen, verwaltet Windows.
Die Adressen der Strings werden als StringPointer in einem Long-Array abgelegt, dessen Adresse als VariablenPointer bekannt ist. Die kann man manipulieren, wenn man das so tut, daß Windows es nicht merkt.

Daß das erst nicht funktioniert hat, muss wohl daran gelegen
haben, daß nicht zwei Stringpointer auf die selbe
Speicheradresse zeigen dürfen. Bereite ich das vor und
verbiege alle Pointer auf einmal, geht es. Dazu brauche ich
eben das Long-Array, in das ich die Pointer kopieren kann,
dort verschieben, ohne daß das auf die Speicherverwaltung
Einfluss hat und dann zurück kopieren.

Ich kenne die voherige Lösung nicht Rainer. Aber lag es
vielleicht daran das ein String pro Zeichen VB Intern 2 Bytes
belegt?

*gg* Nein. :smile:

OK, ich habe zur Verdeutlichung ein kurzes Beispiel ohne Array geschrieben, einzelne Strings verhalten sich auch so.

Option Explicit

Dim a As String, b As String

Private Sub Command1\_Click()
 Dim m As Long
 m = VarPtr(a)
 VarPtr(a) = VarPtr(b)
 VarPtr(b) = m
 anz
End Sub

Private Sub Form\_Load()
 a = "a"
 b = "b"
 anz
End Sub

Private Sub anz()
 List1.AddItem "a: " + Hex(VarPtr(a)) + " " + Hex(StrPtr(a)) + " " + a
 List1.AddItem "b: " + Hex(VarPtr(b)) + " " + Hex(StrPtr(b)) + " " + b
End Sub

Das funktioniert natürlich nicht. Das funktioniert auch nicht, wenn wir es Schritt für Schritt mit CopyMemory versuchen. Das darf nicht funktionieren, weil es einen Zeitpunkt gibt, an dem zwei Zeiger gleichzeitig auf die selbe Speicheradresse zeigen.

Mache ich das aber in einem Schritt … (Einfügen in den Code oben)

Private Declare Sub SwapMemoryBytewise Lib "ISWAP.dll" \_
 (ByVal pDst As Long, ByVal pSrc As Long, ByVal ByteLen As Long)

Private Sub Command2\_Click()
 SwapMemoryBytewise VarPtr(a), VarPtr(b), 4&
 anz
End Sub

… merken VB und Windows nichts davon und es funktioniert.
Was Swap tut ist ja sicher klar. Die DLL hat mir CMБ mal geschrieben.
Wenn Du das testen möchtest, müsste ich Dir die mailen.

Ob meine Vorstellung vom Vorgang ganz korrekt ist, weiß ich
nicht, aber es funktioniert stabil.

Das ist die Hauptsache. Und das schoene ist, das wir wieder
etwas gelernt haben :wink:

Ja, ich weiß jetzt, wie die Strings verwaltet werden. :smile:
Was in Deinem Code exakt passiert weiß ich noch nicht, aber Windows meckert darüber, da fehlt noch etwas Grundlagenforschung. Wir schreiben da in den Arbeitsspeicher, verbiegen Zeiger ohne genau zu wissen was wir tun und es sieht so aus, als würden wir etwas tun, mit dem Windows nicht klar kommt.

PS: Übrigens in .NET gibt es den schönen Befehl

Array.Copy und viele andere tolle Sachen, die einem das Leben
leicht machen *gg*

Habe ich übrigens schon erzählt, daß ich mit .NET angefangen habe? VB und C#. :smile:

Gruß Rainer

Hallo Rainer,

Die 16 ist von Dir! :smile: Du kopierst pro Feld 16 Bytes.

Eine Variable vom Datentyp Variant belegt 16 Byte oder irre ich mich?

Wir müssen uns schon darum kümmern was wir tun, wenn wir
Windows ins Handwerk pfuschen. CopyMemory ist keine
VB-Methode, wir schreiben in den Arbeitsspeicher, wie zu
Zeiten vom C64 mit Peek und Poke.

Das weiss ich :smile: Wir arbeiten ja nicht mit Variablen

Eben leider nicht. Wenn es denn ohne Fehler funktionieren
würde, dann würde ich ja auch sagen ich muss nicht immer alles
genau wissen, aber ganz offensichtlich bleibt die Manipulation
nicht unentdeckt, es kommt zu einem schwerwiegenden Fehler,
den Windows gern nach Redmond melden würde.

Also vom .net springt bei mir der Debugger an und sagt mir das ein unbehandelter Win32 Fehler vorliegt in VB6.exe.
Einige kurze Recherchen ergaben das zu 98% eine Memorylek vorliegt.
Das koennte man aber beraeumen und somit den Absturz umgehen.

Muss man aber wissen, um den Fehler vermeiden zu können. So
kann man den Code nicht verwenden.

In dem Falle nicht. Es reicht wenn wir den Memory „reinigen“.

Nein, wir schreiben mit CopyMemory direkt in den
Arbeitsspeicher, holen uns nur vorher die Adressen, die uns
zugewiesen wurden.

Ok das war mein Fehler. Wo war ich da nur mit meinen Gedanken?

Zu schade, daß die IDE von dem Code abstürzt. :frowning:

Hast du es mal compiliert als EXE versucht?

Wo die einzelnen Strings liegen, verwaltet Windows.
Die Adressen der Strings werden als StringPointer in einem
Long-Array abgelegt, dessen Adresse als VariablenPointer
bekannt ist. Die kann man manipulieren, wenn man das so tut,
daß Windows es nicht merkt.

jetzt macht es klickt. Du setzt einen Zeiger auf einen anderen Zeiger.
Ok das ist auch eine Variante!

*gg* Nein. :smile:

Ok :wink:

… merken VB und Windows nichts davon und es funktioniert.
Was Swap tut ist ja sicher klar. Die DLL hat mir CMБ
mal geschrieben.
Wenn Du das testen möchtest, müsste ich Dir die mailen.

Och naja du weisst doch das ich rueber zu .NET bin und da brauch ich die nicht mehr. Das kann man da mit einfacheren Bordmitteln lösen. Aber das weisst du ja :wink:

Ja, ich weiß jetzt, wie die Strings verwaltet werden. :smile:
Was in Deinem Code exakt passiert weiß ich noch nicht, aber
Windows meckert darüber, da fehlt noch etwas
Grundlagenforschung. Wir schreiben da in den Arbeitsspeicher,
verbiegen Zeiger ohne genau zu wissen was wir tun und es sieht
so aus, als würden wir etwas tun, mit dem Windows nicht klar
kommt.

Schau dir das mal an

http://www.vbarchiv.net/workshop/workshop_86.html

dort ist auch einiges erklärt mit einem schoenen Demo.
Aber eigentlich ist das alles ja nun unrelavant, da reinhard aufgegeben hat und wir uns ja einer anderen Sprache widmen wo das unrelevant ist :smile:

Habe ich übrigens schon erzählt, daß ich mit .NET angefangen
habe? VB und C#. :smile:

Nein das nicht. Ich hatte mal gelesen das du dich in C probierst aber dann glaub aufgegeben hast. Wo schreibst du denn nun in .NET ?

Kommst du gut voran und machst Fortschritte.

Ich bin uebrigens gerade dabei meine erste Datenbank zu schreiben. Aber alleine die DB an das DatagridView dort zu binden ist ja wahnsinn :s

Du kennst dich damit nicht aus oder ?

MfG Alex

Hi Alex,

OK, Thema CopyMmory und Array erledigt. :smile:

Habe ich übrigens schon erzählt, daß ich mit .NET angefangen
habe? VB und C#. :smile:

Nein das nicht. Ich hatte mal gelesen das du dich in C
probierst aber dann glaub aufgegeben hast.

Ja, C/C++ habe ich bis auf weiteres aufgegeben. Eventuell sehe ich da noch mal rein, wenn ich mich mit C# wohl fühle. :smile:

Wo schreibst du denn nun in .NET ?

Privat und in der Firma. Nächstes Jahr kommt SAP ins Haus … :smile:

Kommst du gut voran und machst Fortschritte.

Na ja, geht so. Als erstes habe ich mal ein ‚Breakout‘ in C# geschrieben, das hat recht gut geklappt.

Ich bin uebrigens gerade dabei meine erste Datenbank zu
schreiben. Aber alleine die DB an das DatagridView dort zu
binden ist ja wahnsinn :s

Du kennst dich damit nicht aus oder ?

Noch nicht. Den Inhalt einer Datenbank im Datagridview anzeigen ist kein Problem, das geht ja noch ohne selbst Code zu schreiben. Wie das aber mit den Steuerelementen ist, das funktioniert nur bei bekanntem Pfad. Ich wollte dann mal den Code lesen, den der Assistent geschrieben hat um das nach Application.Path umzuschreiben … Da steht ja ein ganzes Buch! Jetzt warte ich erst mal auf die Bücher, die der Chef bestellt hat.

Mein Vorteil dabei: Der Chef bezahlt die Bücher und ich kann während der Arbeitszeit herumspielen wie ich mag … So lange sonst alles läuft. :smile:

Nächstes Jahr um diese Zeit sind dann .NET und Datenbanken mein Job … Bis dahin kann ich das richtig.

Gruß Rainer

Hi Alex,

Ich bin uebrigens gerade dabei meine erste Datenbank zu
schreiben. Aber alleine die DB an das DatagridView dort zu
binden ist ja wahnsinn :s

Du kennst dich damit nicht aus oder ?

hmmm, Ich habe mir gerade mal das Tutorial für VB.NET auf AVB angesehen, etwas daran herumgefummelt …

Imports System
Imports System.Data.OleDb

Public Class Form1
 Dim myCon As New OleDbConnection

 Private Sub Form1\_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

 Try
 myCon.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\Betr\_Ber.mdb;"
 myCon.Open()
 Dim myCom As New OleDbCommand("SELECT \* FROM Personaldaten;", myCon)
 Dim myAdapter As New OleDbDataAdapter(myCom)
 Dim myStruktur As New DataTable("Struktur")
 Dim myData As New DataTable("Data")

 myAdapter.FillSchema(myStruktur, SchemaType.Mapped)
 myAdapter.Fill(myData)
 DataGridView1.DataSource = myData
 myCon.Close()

 Catch ex As Exception
 MessageBox.Show("Fehler beim Verbinden!")
 End Try

 End Sub

End Class

Die Tabelle wird mir angezeigt.

Über Probleme stoplpere ich erst später. :smile:
Aber damit sind wir jetzt im falschen Brett.

Gruß Rainer