DLLCall mit DragQueryFile

  • Habe mich leider noch nicht in das Thema DLL (call, struct, etc) eingearbeitet.
    Möchte gerade eine kleine GUI für Drag and Drop Operationen erstellen und habe im Forum für das Handling von mehreren Dateien hier und hier etwas gefunden:

    Zweierlei verstehe ich (gar) nicht:
    erstens was ist der Unterschied zwischen folgenden beiden DLLCall-Varianten, bitte den letzten Parameter beachten (0 vs 255):

    Spoiler anzeigen
    [autoit]

    ; ### Variante 1 ###
    Local $nAmt = DllCall('shell32.dll', 'int', 'DragQueryFileW', _
    'hwnd', $wParam, _
    'int', 0xFFFFFFFF, _
    'ptr', 0, _
    'int', 255)
    ; ### Variante 1 ###
    Local $nAmt = DllCall('shell32.dll', 'int', 'DragQueryFileW', _
    'hwnd', $wParam, _
    'int', 0xFFFFFFFF, _
    'ptr', 0, _
    'int', 0)

    [/autoit]


    und woher kommen die Werte für int = 0xFFFFFFFF (ist das ein Begrenzer?!), ptr = 0 und int = 0 bzw. 255?

    Zusätzlich: Wie kann man diese Dinge herausfinden respektive wo nachschlagen?

    Einmal editiert, zuletzt von Hakeem (15. April 2012 um 22:24) aus folgendem Grund: gelöst

  • Danke für deine Antwort.
    Jetzt sehe ich auch, dass ich vorhin viel zu kurz nur auf die Zeile geschaut habe die als erstes unklar war.

    Also wenn ich das richtig interpretiere (siehe Kommentare):

    [autoit]


    GUIRegisterMsg($WM_DROPFILES, 'WM_DROPFILES_FUNC')
    ; (...)
    Func WM_DROPFILES_FUNC($hWnd, $msgID, $wParam, $lParam) #cs $WM_DROPFILES übergibt als 'ersten Nachrichtenpparameter' _
    an die Funktion die Namen der Dateien, die gedroppt wurden und zwar in einer "structure" _
    die "structue" wird als Hexadezimalwert referenziert und nach $wParam übergeben. #ce
    ;(...)
    Local $nAmt = DllCall('shell32.dll', 'int', 'DragQueryFileW', _
    'hwnd', $wParam, _ #cs 'hDrop' "Identifier of the structure that contains the file names of the dropped files." _
    ALSO: eigentlich der einzige übergebene Parameter und HIER zusammen mit dem nächsten der einzige wichtige #ce
    'int', 0xFFFFFFFF, _ #cs 'iFile' "Index of the file to query. If the value of this parameter is 0xFFFFFFFF, _
    DragQueryFile returns a count of the files dropped. If the value of this parameter is between zero _
    and the total number of files dropped, DragQueryFile copies the file name with the corresponding value _
    to the buffer pointed to by the lpszFile parameter." (Nullbasiert!) Also wird hier erstmal nur abgefragt, _
    wieviele Dateien übergeben wurden #ce
    'ptr', 0, _ #cs 'lpszFile' "The address of a buffer that receives the file name of a dropped file _
    when the function returns. This file name is a null-terminated string. _
    if this parameter is NULL, DragQueryFile returns the required size, in characters, of this buffer." _
    ALSO: im Prinzip an dieser Stelle erstmal unwichtig #ce
    'int', 255) #cs 'cch' "The size, in characters, of the 'lpszFile' buffer." ALSO: hier unwichtig, daher egal ob 0 oder 255 _
    Vermutlich ist 0 erstmal besser, da es etwas Speicher schont... wahrscheinlich wird es HIER aber gar nicht ausgewertet #ce
    ; Richtig spannend wird es wohl erst ab hier:
    For $i = 0 To $nAmt[0] - 1 ; $nAmt[0] ist der Rückgabewert der Funktion DragQueryFileW, hier also die Anzahl gedropper Dateien
    $nSize = DllCall('shell32.dll', 'int', 'DragQueryFileW', 'hwnd', $wParam, 'int', $i, 'ptr', 0, 'int', 0)
    #cs Abfrage der Buffersize 'cch' von 'lpszFile'
    ### When the function copies a file name to the buffer, the return value is a count of the characters copied, not including _
    the terminating null character. ### #ce
    $nSize = $nSize[0] + 1 ; von 0- auf 1-basiert für DllStructCreate, damit eigentlich 1 zu groß für DllCall _
    ; aber egal, soviel Speicher können wir opfern
    $pFileName = DllStructCreate('wchar[' & $nSize & ']') #cs wäre schön würde ich DllStruct schon verstehen... _
    hier wird wohl irgendwie ein Buffer 'lpszFile' angelegt in dem der Dateiname gespeichert wird. #ce
    DllCall('shell32.dll', 'int', 'DragQueryFileW', 'hwnd', $wParam, 'int', $i, 'ptr', DllStructGetPtr($pFileName), 'int', $nSize) ; Buffer füllen
    ReDim $gaDropFiles[$i + 1] ; Array wird vergrößert
    $gaDropFiles[$i] = DllStructGetData($pFileName, 1) ; ... und bekommt den im Buffer gespeicherten Dateinamen
    $pFileName = 0 ; Speicher wieder frei geben
    Next
    ; Am Ende stehen alle Datei-Pfade in $gaDropFiles

    [/autoit]

    Kann mir bitte noch jemand Feedback geben, ob es so richtig verstanden wurde

  • Du hast fast alles richtig verstanden.

    [autoit]

    $nSize = $nSize[0] + 1 ; von 0- auf 1-basiert für DllStructCreate, damit eigentlich 1 zu groß für DllCall _
    ; aber egal, soviel Speicher können wir opfern

    [/autoit]


    Das ist nicht korrekt. Du bekommst die Länge des Strings, da ist nichts mit 0 und 1-basiert. Es ist jedoch so, dass das Stringende in C mit einem Chr(0) markiert wird und der wurde nicht mitgezählt. Daher Buffer = Länge + 1.

  • Moin,

    hier noch einmal die einfache Version:

    Spoiler anzeigen
    [autoit]

    #include <WindowsConstants.au3>
    #include <GUIConstantsEx.au3>
    #include <Constants.au3>

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

    Global $g_DropFiles [1]
    ; ...
    GUIRegisterMsg($WM_DROPFILES, 'OnDropFiles')
    ; (...)
    Func OnDropFiles ($hWnd, $msgID, $wParam, $lParam)

    Local $cnFiles

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

    $cnFiles = DragQueryFile ($wParam, 0xFFFFFFFF, 0, 0)

    ReDim $g_DropFiles[$cnFiles] ; $g_DropFiles ist globales Array

    For $i = 0 To $cnFiles - 1

    DragQueryFile ($wParam, $i, $gaDropFiles[$i], 261) ; 261 = MAX_PATH + 1
    Next

    Return 0

    EndFunc

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

    Func DragQueryFile ($hDrop, $iFile, ByRef $lpszFile, $cch)

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

    Local $aRes = DllCall ("shell32.dll", "UINT", "DragQueryFileW", _
    "HANDLE", $hDrop, _
    "UINT", $iFile, _
    "WSTR", $lpszFile, _
    "UINT", $cch)
    $lpszFile = $aRes[3]
    Return $aRes[0]

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

    EndFunc

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

    Oder Deine ursprüngliche Version:

    Spoiler anzeigen
    [autoit]

    #include <WindowsConstants.au3>
    #include <GUIConstantsEx.au3>
    #include <Constants.au3>

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

    Global $g_DropFiles [1]
    ; ...
    GUIRegisterMsg($WM_DROPFILES, 'OnDropFiles')
    ; (...)
    Func OnDropFiles ($hWnd, $msgID, $wParam, $lParam)

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

    Local $cnFiles
    Local $cchBuffer
    Local $szBuffer

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

    $szBuffer = DllStructCreate ("WCHAR [261]") ; 261 = MAX_PATH + 1

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

    $cnFiles = DragQueryFile ($wParam, 0xFFFFFFFF, 0, 0)

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

    ReDim $g_DropFiles[$cnFiles] ; $g_DropFiles ist globales Array

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

    For $i = 0 To $cnFiles - 1

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

    $cchBuffer = DragQueryFile ($wParam, $i, 0, 0)

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

    If ($cchBuffer < 261) Then
    ; Dateiname in Puffer kopieren
    DragQueryFile ($wParam, $i, DllStructGetPtr ($szBuffer), 260)
    $g_DropFiles[$i] = DllStructGetData ($szBuffer)
    Else
    ; Eher unwahrscheinlich ...
    MsgBox (BitOR($MB_OK, $MB_ICONHAND), "Fehler", "Puffer ist zu klein!")
    EndIf
    Next

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

    Return 0

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

    EndFunc

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

    Func DragQueryFile ($hDrop, $iFile, $lpszFile, $cch)

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

    Local $aRes = DllCall ("shell32.dll", "UINT", "DragQueryFileW", _
    "HANDLE", $hDrop, _
    "UINT", $iFile, _
    "ptr", $lpszFile, _
    "UINT", $cch)

    Return $aRes[0]

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

    EndFunc

    [/autoit]

    Edith sagte ich hatte noch etwas vergessen ...

    Gruß
    Greenhorn


    2 Mal editiert, zuletzt von Greenhorn (15. April 2012 um 23:59)