Qt Dll in AutoIt

  • (Da es auch mit AutoIt zu tun hat hab ich es mal in Hilfe&Unterstützung gepackt, auch wenn es mehr um Qt geht.)
    Ich wollte eine Funktion zum auflisten aller Dateien als Dll nutzen, da das ja viel schneller laden würde...
    Jetzt weiß ich aber nicht, wie ich die Dll für AutoIt anpassen muss, bzw. wie ich sie in AutoIt nutzen kann.
    Mein Ansatz:
    Qt:
    GlobalHeader:

    Spoiler anzeigen


    Header:

    Spoiler anzeigen


    Cpp:

    Spoiler anzeigen


    ProjektDatei:

    Spoiler anzeigen

    AutoIt:

    Spoiler anzeigen
    [autoit]

    $ret=DllCall("FileSearch.dll","PTR","_getFileList","LPCSTR","D:\Bibliotheken\Musik","INT",0,"BOOL",true)
    if @error then
    msgbox(48,"",@error)
    endif

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

    for $i in $ret
    msgbox(48,"",$i)
    next

    [/autoit]

    Ich vermute auch schon, dass AutoIt nicht einfach mit QString umgehen kann und ich dort die C++ Strings benutzen muss.

    Ich hoffe ihr habt euch schonmal damit beschäftigt und/oder konnt mir dabei weiterhelfen.
    Achja: Als error kommt bei AutoIt direkt 1 ("unable to use the DLL file").

    MfG Kanashius.

  • QString ist ein Objekt und kein primitiver Datentyp.
    Ebenso C++-Strings.
    Wenn du diese in AutoIt nutzen willst musst du C-kompatible Schnittstellen implementieren.
    Ein Beispiel wie man sowas machen kann findest du >>hier<<.

    Ich wollte eine Funktion zum auflisten aller Dateien als Dll nutzen, da das ja viel schneller laden würde...

    Unwahrscheinlich, dass es bedeutend schneller wird, nur weil es sich um eine kompilierte Sprache handelt.
    Die Dateisystemfunktionen auf die zugegriffen wird sind die selben. Das Management drumherum (Ergebnisse zwischenspeichern etc.) macht dabei nicht mehr den großen Unterschied.
    Vielleicht erreicht man sogar das Gegenteilt, durch das umständliche Wrappen der Qt-Typen in C-und AutoIt-kompatible Datenstrukturen.

    Ebenfalls zu hinterfragen wäre, wieso man seinem kleinen AutoIt-Script die Abhängigkeit zum kompletten Qt-Framework aufbürdet nur in der theoretischen Hoffnung, dass eine Dateiauflistung etwas schneller vonstatten geht. Für welches Projekt macht soetwas Sinn?
    Wenn dann wäre es schon sinnvoller die Auflistung in reinem C[++] zu implementieren, so dass man nur die Abhängigkeit zu einer Dll anstatt zu einem ganzem Framework hat.

    Wenn du das dennoch so durchziehst, bitte ich dich das Ergebnis mal hochzuladen. Ich wette in reinem AutoIt wird man an die Performance heranreichen können.

    2 Mal editiert, zuletzt von AspirinJunkie (1. März 2015 um 11:09)

  • In AutoIt dauert es bei einem aktuellen Programm ca. 4-10 sekunden um die DateiInfos (ExtProperty) von 93 Dateien auszulesen.

    Zeig mal das Skript, vielleicht schlummert da ja noch Potential.

    Vermutlich hast du aber recht, dass es in reinem C++ schneller wäre.

    Schneller habe ich nicht gemeint. Schlanker aber, da das Qt-Framework nicht mehr mitgeliefert werden muss (Sei es als extra Dlls oder in Form einer deutlich größeren Dll wenn man es statisch linkt).

  • Hier die Funktionen:

    Spoiler anzeigen
    [autoit]


    #cs
    ;Aufruf:
    _GUICtrlListView_BeginUpdate($hGUIList)
    ;AdlibRegister("_setToolTip",1000)
    ;AdlibRegister("_aktToolTip",10)
    _addFile(_TLE_getActPath($oExplorer),true)
    ;AdlibUnRegister("_setToolTip")
    ;AdlibUnRegister("_aktToolTip")
    _GUICtrlListView_EndUpdate($hGUIList)
    #ce

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

    Func _addFile($file, $all=false);ORdner/Datei übergeben,true rekursiv mit unterordnern
    If StringInStr($file, ".mp3") or StringInStr($file, ".wav") or StringInStr($file, ".wma") or StringInStr($file, ".m4a") or StringInStr($file, ".aac") or StringInStr($file, ".ogg") Then
    $ar=StringSplit($file,"\")
    $string=""
    for $i=1 to UBound($ar)-2 step 1
    $string&=$ar[$i]
    if $i<> UBound($ar)-2 then
    $string&="\"
    endif
    next
    $text=_GetExtProperty($file,-1)
    $sText = $string&"|"&$ar[$ar[0]] &"|"& $text[21] &"|"& $text[20] &"|"& $text[14] &"|"& $text[27]
    GUICtrlCreateListViewItem($sText, $hGUIList)
    GUICtrlSetBkColor(-1,$Colors[6])
    GUICtrlSetColor(-1,$Colors[7])
    else
    if StringInStr(FileGetAttrib($file),"D") then
    $search=FileFindFirstFile($file&"\"&"*.*")
    while 1
    $datei=FileFindNextFile($search)
    if @error then
    ExitLoop
    EndIf
    if Not @extended then
    _addFile($file&"\"&$datei)
    endif
    if @extended and $all then
    _addFile($file&"\"&$datei,true)
    endif
    WEnd
    EndIf
    EndIf
    EndFunc

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

    Func _GetExtProperty($sPath, $iProp);DateiInfos abrufen (nicht von mir)
    Local $iExist, $sFile, $sDir, $oShellApp, $oDir, $oFile, $aProperty, $sProperty
    $iExist = FileExists($sPath)
    If $iExist = 0 Then
    SetError(1)
    Return 0
    Else
    $sFile = StringTrimLeft($sPath, StringInStr($sPath, "\", 0, -1))
    $sDir = StringTrimRight($sPath, (StringLen($sPath) - StringInStr($sPath, "\", 0, -1)))
    $oShellApp = ObjCreate ("shell.application")
    $oDir = $oShellApp.NameSpace ($sDir)
    $oFile = $oDir.Parsename ($sFile)
    If $iProp = -1 Then
    Local $aProperty[35]
    For $i = 0 To 34
    $aProperty[$i] = $oDir.GetDetailsOf ($oFile, $i)
    Next
    Return $aProperty
    Else
    $sProperty = $oDir.GetDetailsOf ($oFile, $iProp)
    If $sProperty = "" Then
    Return 0
    Else
    Return $sProperty
    EndIf
    EndIf
    EndIf
    EndFunc ;==>_GetExtProperty

    [/autoit]

    Ich meinte auch die Größe (Dlls)... hatte mich verschrieben/denkt :D

  • Für jede einzelne Datei wird die Funktion _GetExtProperty einzeln aufgerufen.
    Das heißt für jede einzelne Datei wird ein Shell.application-Objekt erzeugt, zur Datei navigiert und dann insgesamt 35 Eigenschaften der Datei einzeln ausgelesen, obwohl du nur 4 davon benötigst.

    Da schlummert schon einiges an Optimierungspotential.
    Als erstes wäre ein Shell.application-Objekt für alle Aufrufe schon mal ein großer Schritt nach vorn.
    Da bei dir aber das Shell-Objekt nur zum Auslesen der Dateiinformationen verwendet wird, wäre die nächste Überlegung: Warum nicht gleich für alles nehmen und auch die Dateien damit auflisten?
    So umstrukturiert könnte es ungefähr so aussehen und sollte etwas schneller als vorher laufen:

    Spoiler anzeigen
    [autoit]

    Global Const $s_Path = "F:\Musik" ; Pfad anpassen
    GetMusicData($s_Path)

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

    Func GetMusicData($Path, Const $s_FileTypes = "mp3|wma|m4a|aac|ogg", $b_First = True)
    Local Static $o_Shell
    Local Static $s_Pattern
    Local $sText, $s_Name
    If $b_First Then
    $o_Shell = ObjCreate("Shell.Application")
    $s_Pattern = "\.(?:" & $s_FileTypes & ")$"
    $Path = $o_Shell.NameSpace($Path)
    If @error Or $Path = "" Then Return SetError(1, @error, 0)
    EndIf

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

    For $i In $Path.Items
    $s_Name = $i.Name
    If StringRegExp($s_Name, $s_Pattern) Then
    $sText = $s_Name & "|" & $Path.GetDetailsOf($i, 21) & "|" & $Path.GetDetailsOf($i, 20) & "|" & $Path.GetDetailsOf($i, 14) & "|" & $Path.GetDetailsOf($i, 27)
    ConsoleWrite($sText & @CRLF)
    ElseIf $i.IsFolder Then
    GetMusicData($i.GetFolder(), "", False)
    EndIf
    Next
    If $b_First Then $o_Shell = 0 ; Shell Objekt wieder killen
    EndFunc ;==>GetMusicData

    [/autoit]

    Noch ein kleiner Hinweis zu deinem Skript: Zu jedem FileFindFirstFile gehört auch ein FileClose.

    2 Mal editiert, zuletzt von AspirinJunkie (2. März 2015 um 09:51)

  • Danke, AspirinJunkie. Die Funktion ist super. Ich hab das noch angepasst. $i.getFolder() hat immer nen leerString zurückgegeben-> hab das geändert. Und die Rekurion hab ich noch eingefügt, Ebenso wie das einfügen von einzelnen Files über die alte Funktion.

    Spoiler anzeigen
    [autoit]

    Func GetMusicData($Path, $rek = False, Const $s_FileTypes = "mp3|wma|m4a|aac|ogg", $b_First = True,$ShellObj=-1)
    if Not StringInStr(FileGetAttrib($Path),"D") then
    _addFile($Path)
    endif
    Local Static $o_Shell
    Local Static $s_Pattern
    Local $sText, $s_Name
    local $s_Path=$Path
    If $b_First Then
    $o_Shell = ObjCreate("Shell.Application")
    $s_Pattern = "\.(?:" & $s_FileTypes & ")$"
    $Path = $o_Shell.NameSpace($Path)
    If @error Or $Path = "" Then Return SetError(1, @error, 0)
    else
    $o_Shell=$ShellObj
    $s_Pattern=$s_FileTypes
    $Path = $o_Shell.NameSpace($Path)
    If @error Or $Path = "" Then Return SetError(1, @error, 0)
    EndIf
    For $i In $Path.Items
    $s_Name = $i.Name
    $s_Name2 = $i.Name
    If StringRegExp($s_Name, $s_Pattern) Then
    $sText = $s_Path&"\"&$s_Name2 & "|" & $s_Name & "|" & $Path.GetDetailsOf($i, 21) & "|" & $Path.GetDetailsOf($i, 20) & "|" & $Path.GetDetailsOf($i, 14) & "|" & $Path.GetDetailsOf($i, 27)
    GUICtrlCreateListViewItem($sText, $hGUIList);ConsoleWrite($sText & @CRLF)
    ElseIf $i.IsFolder And $rek Then
    GetMusicData($s_Path&"\"&$s_Name, true,$s_Pattern,false,$o_Shell)
    EndIf
    Next
    If $b_First Then $o_Shell = 0 ; Shell Objekt wieder killen
    EndFunc ;==>GetMusicData

    [/autoit]
    • Was soll $ShellObj? $o_Shell ist static und damit in allen Rekursionen ebenfalls vorhanden.
    • Warum der Else-Zweig für $b_First? Hier gilt auch wieder: $s_Pattern ist static und muss daher nur einmal beschrieben werden.
    • Was soll $s_Name2? Die selbe Information wie in $s_Name - warum also nochmal auslesen? Wenn du den gesamten Pfad haben möchtest schreibe statt $s_Path & "\" & $s_Name2 einfach $i.Path
    • Zitat

      $i.getFolder() hat immer nen leerString zurückgegeben-> hab das geändert.

      $i.getFolder war auch kein Pfadstring sondern ein Folderobjekt. Der Sinn dahinter war zu vermeiden in jeder Iteration erst aus der Pfadangabe per NameSpace das Folderobjekt zu ermitteln. Stattdessen kann direkt damit weiter gearbeitet werden. Hatte schon seinen Sinn das ich das so gemacht habe...


    • Zitat

      Und die Rekurion hab ich noch eingefügt

      Die Funktion war bereits rekursiv.

  • Das Skript, so wie ich es gepostet habe funktioniert korrekt.
    Was war konkret falsch und wie hast du es korrigiert?

    Dein Problem war wahrscheinlich, dass du keine Möglichkeit gefunden hast die komplette Pfadangaben (Siehe $i.Path()) zu ermitteln.
    Die Lösung hierfür kennst du ja mittlerweile.

  • Könntest du da noch die finale Version posten um zu schauen in wie weit sie noch weiter optimiert werden kann?

    Und nochmal: Was war falsch und wie hast du es konkret behoben?
    Ich würde gerne wissen wo der Fehler lag, da ich ihn selbst nicht erkennen kann.

  • So sieht meine Lösung aus (Die langsame _addFile ist für Dateien ausreichen, da es nur bei vielen Dateien zu Problemen kam, es werden aber nur einzelne Dateien mit der Maus auf diese Weise hinzugefügt)

    Spoiler anzeigen
    [autoit]

    Func GetMusicData($Path, $rek = False, Const $s_FileTypes = "mp3|wma|m4a|aac|ogg", $b_First = True)
    if Not StringInStr(FileGetAttrib($Path),"D") then
    _addFile($Path)
    endif
    Local Static $o_Shell
    Local Static $s_Pattern
    Local $sText, $s_Name
    local $s_Path=$Path
    If $b_First Then
    $o_Shell = ObjCreate("Shell.Application")
    $s_Pattern = "\.(?:" & $s_FileTypes & ")$"
    $Path = $o_Shell.NameSpace($Path)
    If @error Or $Path = "" Then Return SetError(1, @error, 0)
    else
    $Path = $o_Shell.NameSpace($Path)
    If @error Or $Path = "" Then Return SetError(1, @error, 0)
    EndIf
    For $i In $Path.Items
    $s_Name = $i.Name
    If StringRegExp($s_Name, $s_Pattern) Then
    $sText = $s_Path & "|" & $s_Name & "|" & $Path.GetDetailsOf($i, 21) & "|" & $Path.GetDetailsOf($i, 20) & "|" & $Path.GetDetailsOf($i, 14) & "|" & $Path.GetDetailsOf($i, 27)
    GUICtrlCreateListViewItem($sText, $hGUIList);ConsoleWrite($sText & @CRLF)
    ElseIf $i.IsFolder And $rek Then
    GetMusicData($s_Path&"\"&$s_Name, true,$s_Pattern,false)
    EndIf
    Next
    If $b_First Then $o_Shell = 0 ; Shell Objekt wieder killen
    EndFunc ;==>GetMusicData

    [/autoit]
  • Ignorierst du meine Frage absichtlich?

    Hier noch so abgewandelt, dass das Folder-Objekt den Iterationen direkt übergeben wird:

    Spoiler anzeigen
    [autoit]

    #include <GUIConstantsEx.au3>

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

    GUICreate("Musik", 1000, 800)
    Global $hGUIList = GUICtrlCreateListView("Pfad|Dateiname|Artist|Title|Album|Duration", 10, 10, 980, 780)
    GUISetState(@SW_SHOW)

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

    GetMusicData("H:\Musik", True)

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

    Do
    Until GUIGetMsg() = -3

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

    Func GetMusicData($Path, $rek = False, Const $s_FileTypes = "mp3|wma|m4a|aac|ogg", $b_First = True)
    If Not StringInStr(FileGetAttrib($Path), "D") Then _addFile($Path)
    Local Static $o_Shell
    Local Static $s_Pattern
    Local $s_Name

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

    If $b_First Then
    $o_Shell = ObjCreate("Shell.Application")
    $s_Pattern = "\.(?:" & $s_FileTypes & ")$"
    $Path = $o_Shell.NameSpace($Path)
    If @error Or $Path = "" Then Return SetError(1, @error, 0)
    EndIf

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

    For $i In $Path.Items
    $s_Name = $i.Name
    If $i.IsFolder And $rek Then
    GetMusicData($i.GetFolder(), "", True, False)
    ElseIf StringRegExp($s_Name, $s_Pattern) Then
    GUICtrlCreateListViewItem(StringTrimRight($i.Path, StringLen($s_Name) + 1) & "|" & $s_Name & "|" & $Path.GetDetailsOf($i, 21) & "|" & $Path.GetDetailsOf($i, 20) & "|" & $Path.GetDetailsOf($i, 14) & "|" & $Path.GetDetailsOf($i, 27), $hGUIList)
    EndIf
    Next
    If $b_First Then $o_Shell = 0 ; Shell Objekt wieder killen
    EndFunc ;==>GetMusicData

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

    Func _addFile($x)
    EndFunc ;==>_addFile

    [/autoit]
  • Es wäre nur gut zu wissen was den Fehler verursacht hatte.
    Ich würde es auch jetzt nicht anders schreiben - daher wäre der Grund für den Fehler schon wichtig zu wissen um ihn in Zukunft zu vermeiden.
    Da du den Fehler, den ich nicht reproduzieren kann, laut eigener Aussage beheben konntest hatte ich auf Hinweise für dessen Ursache gehofft.

    Kann irgendjemand den Fehler reproduzieren?