Problem beim Umsetzen von CopyFileEx

    • Offizieller Beitrag

    Hi,
    ich möchte gern die WIN-API Funktion CopyFileEx in AutoIt umsetzen. Im API-Guide habe ich eine VB-Version gefunden.
    Hier kurz die Beschreibung:

    Zitat

    The CopyFileEx function copies an existing file to a new file. This function preserves extended attributes, OLE structured storage, NTFS alternate data streams, and file attributes. Security attributes for the existing file are not copied to the new file.

    Declare Function CopyFileEx Lib "kernel32.dll" Alias "CopyFileExA" (ByVal lpExistingFileName As String, ByVal lpNewFileName As String, ByVal lpProgressRoutine As Long, lpData As Any, ByRef pbCancel As Long, ByVal dwCopyFlags As Long) As Long


    Besonders interessant ist der Parameter:
    · lpProgressRoutine
    Specifies the address of a callback function of type LPPROGRESS_ROUTINE that is called each time another portion of the file has been copied. This parameter can be NULL. For more information on the progress callback function, see CopyProgressRoutine.

    Die Callbackfunktion wird aufgerufen, jederzeit wenn ein Teil der Datei kopiert wurde. Somit ließe sich das gut für ein Status-Anzeige nutzen.
    Leider passiert das bei mir bisher noch nicht. Die Datei wird zwar kopiert, aber die Callbackfunktion nicht aufgerufen. Der Pointer auf die Callbackroutine wird erstellt, hab ich getestet. Momentan weiß ich erst mal nicht weiter. Der Dll-Call gibt mir auch nix zurück, AutoIt endet dort mit: AutoIT3.exe ended.rc:-1073741819
    Hier der Code:

    Spoiler anzeigen
    [autoit]


    Global Const $PROGRESS_CANCEL = 1
    Global Const $PROGRESS_CONTINUE = 0
    Global Const $PROGRESS_QUIET = 3
    Global Const $PROGRESS_STOP = 2
    Global Const $COPY_FILE_FAIL_IF_EXISTS = 0x1
    Global Const $COPY_FILE_RESTARTABLE = 0x2

    [/autoit] [autoit][/autoit] [autoit]

    $sOldFile = 'C:\sehr_grosse_Datei'
    $sNewFile = 'C:\kopie_sehr_grosse_Datei'

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Local $ProgressRoutine = DLLCallbackRegister ("CopyProgressRoutine", "long", "str;str")

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    $Ret = CopyFileEx($sOldFile, $sNewFile, DllCallbackGetPtr($ProgressRoutine), 0, 0, $COPY_FILE_RESTARTABLE)
    If $Ret Then
    MsgBox(0, 'CopyFileEx', 'Erfolgreich')
    Else
    MsgBox(0, 'CopyFileEx', 'Fehler!')
    EndIf
    DllCallbackFree($ProgressRoutine)

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func CopyFileEx($sOldFile, $sNewFile, $lpProgressRoutine, $lpData, $pbCancel, $dwCopyFlags)
    Local $ret = DllCall("kernel32.dll", "long", "CopyFileExA", _
    'str', $sOldFile, 'str', $sNewFile, 'ptr', $lpProgressRoutine, 'long', $lpData, 'long', $pbCancel, 'long', $dwCopyFlags)
    Return $ret[0]
    EndFunc

    Func CopyProgressRoutine($sOldFile, $sNewFile)
    ConsoleWrite($sNewFile & ': ' & Floor(FileGetSize($sNewFile)/FileGetSize($sOldFile)*100) & '%' & @CRLF)
    Return $PROGRESS_CONTINUE
    EndFunc

    [/autoit]


    Edit:
    Hab was überlesen :S , die Callbackfunktion muß die Struktur LPPROGRESS_ROUTINE aufweisen. Naja, dann werd ich mal versuchen das noch zu vervollständigen. Wenn es klappt melde ich mich wieder. ;)

    • Offizieller Beitrag

    Ich wollte auf Objekte verzichten, und da es die Funktion CopyFileEx nunmal gibt, versuchen diese zu nutzen.
    Aber da haperts noch etwas mit dem Umsetzen der Strukturen.
    Hier der jetzige Status, jetzt wird nicht mal mehr kopiert . :S

    Spoiler anzeigen
    [autoit]

    Global Const $PROGRESS_CANCEL = 1
    Global Const $PROGRESS_CONTINUE = 0
    Global Const $PROGRESS_QUIET = 3
    Global Const $PROGRESS_STOP = 2
    Global Const $COPY_FILE_FAIL_IF_EXISTS = 0x1
    Global Const $COPY_FILE_RESTARTABLE = 0x2

    [/autoit] [autoit][/autoit] [autoit]

    $sOldFile = 'C:\sehr_grosse_Datei'
    $sNewFile ='C:\kopie_sehr_grosse_Datei'

    [/autoit] [autoit][/autoit] [autoit]

    Global $strucData = DllStructCreate("long")
    Global $tagLPPROGRESS_ROUTINE = _
    'int TotalFileSize;int TotalBytesTransferred;int StreamSize;int StreamBytesTransferred;' & _
    'dword dwStreamNumber;dword dwCallbackReason;hwnd hSourceFile;hwnd hDestinationFile;' & DllStructGetPtr($strucData)
    Global $strucPROGRESS_ROUTINE = DllStructCreate($tagLPPROGRESS_ROUTINE)

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Local $ProgressRoutine = _
    DLLCallbackRegister ("CopyProgressRoutine", $tagLPPROGRESS_ROUTINE, _
    "int;int;int;int;dword;dword;hwnd;hwnd;ptr")

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    $Ret = CopyFileEx($sOldFile, $sNewFile, DllCallbackGetPtr($ProgressRoutine), 0, 0, $COPY_FILE_RESTARTABLE)
    If $Ret Then
    MsgBox(0, 'CopyFileEx', 'Erfolgreich')
    Else
    MsgBox(0, 'CopyFileEx', 'Fehler!')
    EndIf
    DllCallbackFree($ProgressRoutine)

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func CopyFileEx($sOldFile, $sNewFile, $lpProgressRoutine, $lpData, $pbCancel, $dwCopyFlags)
    Local $ret = DllCall("kernel32.dll", "long", "CopyFileExA", _
    'str', $sOldFile, 'str', $sNewFile, 'ptr', $lpProgressRoutine, 'long', $lpData, 'long', $pbCancel, 'long', $dwCopyFlags)
    Return $ret[0]
    EndFunc

    Func CopyProgressRoutine($TotalFileSize, $TotalBytesTransferred, $StreamSize, $StreamBytesTransferred, $dwStreamNumber, $dwCallbackReason, $hSourceFile, $hDestinationFile, $lpData)
    ConsoleWrite(Int(($TotalBytesTransferred * 10000) / ($TotalFileSize * 10000) * 100) & "% complete..." & @CRLF)
    Return $PROGRESS_CONTINUE
    EndFunc

    [/autoit]
  • Die Funktion ist hier schon eingebaut ;) _MultiFileCopy Und das sollte es in kurz sein (mit Unicode):

    Spoiler anzeigen
    [autoit]

    Global Const $PROGRESS_CANCEL = 1
    Global Const $PROGRESS_CONTINUE = 0
    Global Const $PROGRESS_QUIET = 3
    Global Const $PROGRESS_STOP = 2
    Global Const $COPY_FILE_FAIL_IF_EXISTS = 0x1
    Global Const $COPY_FILE_RESTARTABLE = 0x2

    [/autoit] [autoit][/autoit] [autoit]

    $sOldFile = 'C:\sehr_grosse_Datei'
    $sNewFile ='C:\kopie_sehr_grosse_Datei'

    [/autoit] [autoit][/autoit] [autoit]

    Local $ProgressRoutine = _
    DLLCallbackRegister ("CopyProgressRoutine", "dword", _
    'uint64;uint64;uint64;uint64;dword;dword;ptr;ptr;str')

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    $Ret = CopyFileEx($sOldFile, $sNewFile, DllCallbackGetPtr($ProgressRoutine), 0, 0, $COPY_FILE_RESTARTABLE)
    If $Ret Then
    MsgBox(0, 'CopyFileEx', 'Erfolgreich')
    Else
    MsgBox(0, 'CopyFileEx', 'Fehler!')
    EndIf
    DllCallbackFree($ProgressRoutine)

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func CopyFileEx($sOldFile, $sNewFile, $lpProgressRoutine, $lpData, $pbCancel, $dwCopyFlags)
    Local $ret = DllCall("kernel32.dll", "long", "CopyFileExW", _
    'wstr', $sOldFile, 'wstr', $sNewFile, 'ptr', $lpProgressRoutine, 'long', $lpData, 'long', $pbCancel, 'long', $dwCopyFlags)
    Return $ret[0]
    EndFunc

    Func CopyProgressRoutine($TotalFileSize, $TotalBytesTransferred, $StreamSize, $StreamBytesTransferred, $dwStreamNumber, $dwCallbackReason, $hSourceFile, $hDestinationFile, $lpData)
    ConsoleWrite(Int(($TotalBytesTransferred * 10000) / ($TotalFileSize * 10000) * 100) & "% complete..." & @CRLF)
    Return $PROGRESS_CONTINUE
    EndFunc

    [/autoit]