Supportnet / Forum / Datenbanken
Dateien animiert kopieren
Frage
Ich möchte mit Access Dateien mit dem in Windows üblichen Flying Windows Dialog kopieren. Ich habe dafür folgende Funktion:
Option Compare Database
Option Explicit
Public Type SHFILEOPSTRUCT
hwnd As Long
wFunc As Long
pFrom As String
pTo As String
fFlags As Integer
fAborted As Long
hNameMaps As Long
sProgress As String
End Type
Public Declare Function GetDesktopWindow Lib "user32" () As Long
Public Declare Function SHFileOperation Lib "shell32.dll" Alias _
"SHFileOperationA" _
(lpFileOp As SHFILEOPSTRUCT) As Long
Public Function CopyFiles(asFiles() As String, _
sTarget As String) As Boolean
// -----------------------------------------------------------------
// Methode: | Kopiert eine Anzahl Dateien;
// | Aufruf des "flying windows"-Dialogs
// | benötigt VBA6+ wegen Join-Funktion
// -----------------------------------------------------------------
// Parameter: | asFiles = Datenfeld (Array) mit gültigen Pfaden
// | sTarget = Zielordner
// -----------------------------------------------------------------
// Rückgabe: | True bei Erfolg
// -----------------------------------------------------------------
Const FO_COPY As Long = &H2
Const FOF_RENAMEONCOLLISION As Long = &H8
Dim sFiles As String
Dim uSHFileOp As SHFILEOPSTRUCT
On Error Resume Next
sFiles = VBA.Join(asFiles, vbNullChar)
sFiles = sFiles & vbNullChar
With uSHFileOp
.hwnd = GetDesktopWindow()
.wFunc = FO_COPY
.pFrom = sFiles
.pTo = sTarget
.fFlags = FOF_RENAMEONCOLLISION
End With
CopyFiles = (SHFileOperation(uSHFileOp) = 0)
End Function
Jetzt habe ich diese Funktion eingebaut und bekomme aber nur die Fehlermeldung:
Funktionsaufruf auf der linken Seite der Zuweisung muß den Typ Variant oder Object zurückgeben.
Was muß ich da korrigieren?
Ich würde mich über eine Lösung sehr freuen!!
Antwort 1 von FrankieH
Mein Tipp:
CopyFiles = (SHFileOperation(uSHFileOp) = 0)
Weiss VBA, dass es sich hier um einen Vergleich handeln soll? Bin eigentlich in der C-Schiene zuhause, wo man das deutlich unterscheiden kann (Vergleiche lauten da: ==)
Ich nehme nämlich an, dass der Interpreter versucht den Funktionszeiger auf 0 (bzw. NULL) zu setzen, und da das ein Pointer ist, kommt die Meldung bzgl Variant.
Wie gesagt - ist nur ne Vermutung.
Wäre für uns einfacher, wenn Du bekannt gibtst, welche Zeile der Kompiliervorgang anzeigt.
Frankie
CopyFiles = (SHFileOperation(uSHFileOp) = 0)
Weiss VBA, dass es sich hier um einen Vergleich handeln soll? Bin eigentlich in der C-Schiene zuhause, wo man das deutlich unterscheiden kann (Vergleiche lauten da: ==)
Ich nehme nämlich an, dass der Interpreter versucht den Funktionszeiger auf 0 (bzw. NULL) zu setzen, und da das ein Pointer ist, kommt die Meldung bzgl Variant.
Wie gesagt - ist nur ne Vermutung.
Wäre für uns einfacher, wenn Du bekannt gibtst, welche Zeile der Kompiliervorgang anzeigt.
Frankie
Antwort 2 von DixiDix
Anhand dieses Beispiels kann ich ja mal versuchen, das Problem deutlicher zu machen.
Die Meldung erscheint sobald man die Funktion StartCopy() ausführt.
Function StartCopy()
CopyFiles(Quelldateien, Zielordner) = True
End Function
Dabei hält der Debugger in der 1. Zeile an. Die Funktion wird gar nicht erst ausgeführt.
der Bereich
CopyFiles(Quelldateien, Zielordner) =
ist markiert.
Ich hoffe die Erklärung genügt!
Die Meldung erscheint sobald man die Funktion StartCopy() ausführt.
Function StartCopy()
CopyFiles(Quelldateien, Zielordner) = True
End Function
Dabei hält der Debugger in der 1. Zeile an. Die Funktion wird gar nicht erst ausgeführt.
der Bereich
CopyFiles(Quelldateien, Zielordner) =
ist markiert.
Ich hoffe die Erklärung genügt!
Antwort 3 von FrankieH
Könnte meine Vermutung bestätigen.
Versuch es mal damit:
--------------------------------------------------------------
Function StartCopy()
dim Erg as Long
Erg = CopyFiles(Quelldateien,Zielordner)
End Function
--------------------------------------------------------------
Mit Erg kannst Du ja dann beliebiges anfangen. Der Datentyp von Erg kann auch was anderes sein.
Versuch es mal damit:
--------------------------------------------------------------
Function StartCopy()
dim Erg as Long
Erg = CopyFiles(Quelldateien,Zielordner)
End Function
--------------------------------------------------------------
Mit Erg kannst Du ja dann beliebiges anfangen. Der Datentyp von Erg kann auch was anderes sein.
Antwort 4 von _gau_
Erg sollte schon Boolean sein, denn die Funktion CopyFiles() gibt ja laut Definition Boolean zurück.
[gau]
[gau]
Antwort 5 von DixiDix
Das hat auch nichts gebracht.
Hat jemand eine andere Idee, wie man zum kopieren von Dateien den animierten Windows-Dialog verwenden kann?
Danke für die bisherige Hilfe.
Hat jemand eine andere Idee, wie man zum kopieren von Dateien den animierten Windows-Dialog verwenden kann?
Danke für die bisherige Hilfe.
Antwort 6 von FrankieH
Hast Du es wirklich so wie in meinem Vorschlag eingegeben? Bei mir kommt diese Fehlermeldung nicht. Ich habe allerdings das VBA.Join auskommentiert.
Meine Idee:
Ich würde für Deinen Zweck den ganzen Vorgang in eine eigene DLL auslagern. Du brauchst dann auch nicht das VBA.Join. Nur die DLL muss im Suchpfad zu finden sein.
Meine Idee:
Ich würde für Deinen Zweck den ganzen Vorgang in eine eigene DLL auslagern. Du brauchst dann auch nicht das VBA.Join. Nur die DLL muss im Suchpfad zu finden sein.
Antwort 7 von FrankieH
Vergessen zu posten:
Bei Deinem Beispiel muss zumindest ein call vor CopyFiles vorhanden sein, weil es eine Function und kein Sub ist.
also:
call CopyFiles(Quelldateien, Zielordner)
Bei Deinem Beispiel muss zumindest ein call vor CopyFiles vorhanden sein, weil es eine Function und kein Sub ist.
also:
call CopyFiles(Quelldateien, Zielordner)
Antwort 8 von DixiDix
@FrankieH
Das haut nach wie vor nicht hin.
Was genau hast Du verändert?
Fehlt da möglicherweise ein Verweis?
Das haut nach wie vor nicht hin.
Was genau hast Du verändert?
Fehlt da möglicherweise ein Verweis?
Antwort 9 von FrankieH
Ich hab die Zeile mit VBA.join auskommentiert und ein call vor CopyFiles gesetzt. Dann lässt sich bei mir alles problemlos kompilieren.
Hab auch probiert zu kopieren - klappt. Allerdings habe ich nur eine Datei kopiert und dazu eine Zeile eingefügt: sFiles = asFiles(0) & vbNullchar
Geh doch mal Schritt-für-Schritt vor.
Erstelle ein Modul nur mit den Funktionsaufrufen (leeres Funktionsbody). Dann kompilieren und dann füllst Du diese nach und nach mit den einzelnen Code-Abschnitten.
Hier mein Modul - leider wie immer durch das posten etwas schlecht strukturiert.
-------------------------------------------------------------------
Option Compare Database
Option Explicit
Public Type SHFILEOPSTRUCT
hwnd As Long
wFunc As Long
pFrom As String
pTo As String
fFlags As Integer
fAborted As Long
hNameMaps As Long
sProgress As String
End Type
Public Declare Function GetDesktopWindow Lib "user32" () As Long
Declare Function SHFileOperation Lib "shell32.dll" Alias "SHFileOperationA" (lpFileOp As SHFILEOPSTRUCT) As Long
Public Function CopyFiles(asFiles() As String, sTarget As String) As Boolean
Const FO_COPY As Long = &H2
Const FOF_RENAMEONCOLLISION As Long = &H8
Dim sFiles As String
Dim uSHFileOp As SHFILEOPSTRUCT
On Error Resume Next
sFiles = VBA.Join(asFiles, vbNullChar)
sFiles = asFiles(0)
sFiles = sFiles & vbNullChar
With uSHFileOp
.hwnd = GetDesktopWindow()
.wFunc = FO_COPY
.pFrom = sFiles
.pTo = sTarget
.fFlags = FOF_RENAMEONCOLLISION
End With
CopyFiles = (SHFileOperation(uSHFileOp) = 0)
End Function
Function StartCopy()
Dim Quelldateien(5) As String
Dim Zielordner As String
Dim Antw As Variant
Quelldateien(0) = "c:\\tmp\\essen.dwg"
Zielordner = "c:\\tmp\\sms"
Antw = CopyFiles(Quelldateien, Zielordner)
End Function
Hab auch probiert zu kopieren - klappt. Allerdings habe ich nur eine Datei kopiert und dazu eine Zeile eingefügt: sFiles = asFiles(0) & vbNullchar
Geh doch mal Schritt-für-Schritt vor.
Erstelle ein Modul nur mit den Funktionsaufrufen (leeres Funktionsbody). Dann kompilieren und dann füllst Du diese nach und nach mit den einzelnen Code-Abschnitten.
Hier mein Modul - leider wie immer durch das posten etwas schlecht strukturiert.
-------------------------------------------------------------------
Option Compare Database
Option Explicit
Public Type SHFILEOPSTRUCT
hwnd As Long
wFunc As Long
pFrom As String
pTo As String
fFlags As Integer
fAborted As Long
hNameMaps As Long
sProgress As String
End Type
Public Declare Function GetDesktopWindow Lib "user32" () As Long
Declare Function SHFileOperation Lib "shell32.dll" Alias "SHFileOperationA" (lpFileOp As SHFILEOPSTRUCT) As Long
Public Function CopyFiles(asFiles() As String, sTarget As String) As Boolean
Const FO_COPY As Long = &H2
Const FOF_RENAMEONCOLLISION As Long = &H8
Dim sFiles As String
Dim uSHFileOp As SHFILEOPSTRUCT
On Error Resume Next
sFiles = VBA.Join(asFiles, vbNullChar)
sFiles = asFiles(0)
sFiles = sFiles & vbNullChar
With uSHFileOp
.hwnd = GetDesktopWindow()
.wFunc = FO_COPY
.pFrom = sFiles
.pTo = sTarget
.fFlags = FOF_RENAMEONCOLLISION
End With
CopyFiles = (SHFileOperation(uSHFileOp) = 0)
End Function
Function StartCopy()
Dim Quelldateien(5) As String
Dim Zielordner As String
Dim Antw As Variant
Quelldateien(0) = "c:\\tmp\\essen.dwg"
Zielordner = "c:\\tmp\\sms"
Antw = CopyFiles(Quelldateien, Zielordner)
End Function
Antwort 10 von DixiDix
Da mir geht glatt ein Licht auf.
So funktionierts tatsächlich. Zwar nur mit einer Datei, aber das müßte auch noch mit mehreren zu machen sein!
Danke erstmal!
So funktionierts tatsächlich. Zwar nur mit einer Datei, aber das müßte auch noch mit mehreren zu machen sein!
Danke erstmal!
Antwort 11 von FrankieH
Dann ist ja schon mal halb gewonnen...
Mit mehreren Dateien ist da so eine Crux. Man muß in ein SpeicherArray die Dateien jeweils durch ein Nullbyte getrennt einsetzen, hinter der letzten sind dann zwei Nullbytes. In C/C++ ist das kein Problem, aber in VB ... - Deswegen wohl dieser Join-Befehl.
Vielleicht kann ja da ein VB-Experte helfen...
Gruss
Frankie
Mit mehreren Dateien ist da so eine Crux. Man muß in ein SpeicherArray die Dateien jeweils durch ein Nullbyte getrennt einsetzen, hinter der letzten sind dann zwei Nullbytes. In C/C++ ist das kein Problem, aber in VB ... - Deswegen wohl dieser Join-Befehl.
Vielleicht kann ja da ein VB-Experte helfen...
Gruss
Frankie
Antwort 12 von PotzBlitz
Hallo Frankie,
der Join-Befehl macht genau das, was du vermutest: Die Elemente aus einem String entnehmen und zu einer Zeichenfolge zusammenzusetzen, jeweils getrennt durch das mitgelieferte Trennzeichen. Leider gibts diese Funktion nicht in Access, deswegen kommt hier die nachgebildete Join-Funktion für Access:
′-------------------------------------------------------
Private Function Join2(SourceArray As Variant, Optional Delimiter As Variant) As String
Dim lngPos As Long
Dim lngStart As Long
Dim lngEnd As Long
Dim strDelimiter As String
Dim strString As String
′Trennzeichen-Übergabe prüfen, ggfs. Leerzeichen einsetzen
If IsMissing(Delimiter) Then
strDelimiter = " "
Else
strDelimiter = Delimiter
End If
′Grenzwerte des Arrays festlegen
lngStart = LBound(SourceArray)
lngEnd = UBound(SourceArray) - 1
′String aufbauen und zurückgeben
For lngPos = lngStart To lngEnd
strString = strString & CStr(SourceArray(lngPos)) & strDelimiter
Next
Join2 = strString
End Function
′-------------------------------------------------------
Der Join2-Funktion muss dann nur noch das Array übergeben werden, sowie die Konstante vbNullChar als Null-Byte:
strErgebnis = Join2(arrFiles(), vbNullChar)
Die oben aufgeführten Codes zu SHFileOperation sind alle stark abgespeckt, da fehlen eine Menge sinnvoller Konstanten. Ich hoffe, dass die beim Kopieren ins Supportnet nur weggelassen wurden? Neben den weiteren Optionen fehlen noch Löschen, Verschieben und Umbenennen.
Gruss
PotzBlitz
der Join-Befehl macht genau das, was du vermutest: Die Elemente aus einem String entnehmen und zu einer Zeichenfolge zusammenzusetzen, jeweils getrennt durch das mitgelieferte Trennzeichen. Leider gibts diese Funktion nicht in Access, deswegen kommt hier die nachgebildete Join-Funktion für Access:
′-------------------------------------------------------
Private Function Join2(SourceArray As Variant, Optional Delimiter As Variant) As String
Dim lngPos As Long
Dim lngStart As Long
Dim lngEnd As Long
Dim strDelimiter As String
Dim strString As String
′Trennzeichen-Übergabe prüfen, ggfs. Leerzeichen einsetzen
If IsMissing(Delimiter) Then
strDelimiter = " "
Else
strDelimiter = Delimiter
End If
′Grenzwerte des Arrays festlegen
lngStart = LBound(SourceArray)
lngEnd = UBound(SourceArray) - 1
′String aufbauen und zurückgeben
For lngPos = lngStart To lngEnd
strString = strString & CStr(SourceArray(lngPos)) & strDelimiter
Next
Join2 = strString
End Function
′-------------------------------------------------------
Der Join2-Funktion muss dann nur noch das Array übergeben werden, sowie die Konstante vbNullChar als Null-Byte:
strErgebnis = Join2(arrFiles(), vbNullChar)
Die oben aufgeführten Codes zu SHFileOperation sind alle stark abgespeckt, da fehlen eine Menge sinnvoller Konstanten. Ich hoffe, dass die beim Kopieren ins Supportnet nur weggelassen wurden? Neben den weiteren Optionen fehlen noch Löschen, Verschieben und Umbenennen.
Gruss
PotzBlitz
Antwort 13 von PotzBlitz
So wie es aussieht, hat sich in den obigen Zeilen mal wieder ein Fehlerteufel eingeschlichen. Die Zeile
lngEnd = UBound(SourceArray) -1
sollte heissen
lngEnd = UBound(SourceArray)
Das war jetzt die schlechte Nachricht. Die gute ist, dass ich in der vergangenen Stunde das Thema SHFileOperation aufbereitet und eine recht einfach zu bedienende Funktion CopyFiles() auf die Beine gestellt habe. Sie erlaubt alle zulässigen Optionen inkl. Kopieren, Verschieben, Umbenennen und Löschen, ausserdem können sowohl Arrays als auch einzelne Dateien bei Quelle und Ziel angegeben werden. Das Anfügen des Null-Bytes geschieht automatisch.
Der Code ist zu lang, als dass er hier rein kopiert werden kann. Dafür kann er aber als Textdatei heruntergeladen werden. Details dazu sind in meiner Visitenkarte.
Gruss
PotzBlitz
lngEnd = UBound(SourceArray) -1
sollte heissen
lngEnd = UBound(SourceArray)
Das war jetzt die schlechte Nachricht. Die gute ist, dass ich in der vergangenen Stunde das Thema SHFileOperation aufbereitet und eine recht einfach zu bedienende Funktion CopyFiles() auf die Beine gestellt habe. Sie erlaubt alle zulässigen Optionen inkl. Kopieren, Verschieben, Umbenennen und Löschen, ausserdem können sowohl Arrays als auch einzelne Dateien bei Quelle und Ziel angegeben werden. Das Anfügen des Null-Bytes geschieht automatisch.
Der Code ist zu lang, als dass er hier rein kopiert werden kann. Dafür kann er aber als Textdatei heruntergeladen werden. Details dazu sind in meiner Visitenkarte.
Gruss
PotzBlitz
Antwort 14 von DixiDix
Ist ja mehr als ich wollte. Vielen Dank für Eure Hilfe!
DixiDix
DixiDix

