Sammelthread "AutoIt Interne Funktionen : Erwartetes Ergebnis -> Tatsächliches Ergebnis"

  • In diesem Thread geht es um Funktionen,

    - deren Verhalten von der in der Hilfe beschriebenen Weise abweichen

    - deren Übergabeparameter/Rückgabewerte Inkonsistenzen zeigen

    - die sonstige, unerwartete Besonderheiten aufweisen

    Zusätzlich zu den internen AutoIt-Funktionen kann auch auf vergleichbare Probleme und/oder Lösungsvorschläge in UDF's eingegangen werden, die von der Community erstellt wurden. Dabei sollten wir uns aber auf UDF's beschränken, die 'qualitativ allgemein anerkannt' sind.

    Falls die Besonderheit bereits in einem eigenen Thread behandelt/gelöst wurde, dann langt als Antwort ein entsprechender Link, z.B : Merkwürdiges Verhalten bei DirMove

    Der Thread ist als Ergänzung zur AutoIt-Hilfe gedacht, soll diese aber keinesfalls ersetzen !

    Durch die Themenbreite wird das ganze zwangsläufig unübersichtlich bzw. unstrukturiert. Schwer vorherzusehen, ob ein Thread in dieser Form überhaupt funktioniert:/. Ich bitte daher, von 'Leerbeiträgen' wie "... finde ich auch ..." usw. abzusehen.

    Kommentare, Fragen und Sonstiges können im Allgemeinen Diskussionsthread gepostet werden !

    Um die Pflege der Funktionsübersicht zu erleichtern, muss folgendes an den Anfang des jeweiligen Beitrages gestellt werden :

    - Name der betreffenden Funktion (UDF)

    - ggf. eine beschreibende Kurzinformation

    Zusätzlich ist es hilfreich, wenn der Beitragsersteller folgende Angaben macht :

    - die verwendete Version des Betriebssystems (z.B. 'Win7 x64') und AutoIt (z.B. Au3: 3.3.14.5)

    - wurde das Skript für 32-Bit bzw. 64-Bit 'kompiliert (#AutoIt3Wrapper_UseX64 = N bzw Y)

    Funktionsübersicht :

    1. Auflistung der bisherigen Shoutbox-Beiträge zu : GUITreeView

    Kurzinfo : siehe Startbeitrag weiter unten

    2. WinGetHandle (Link)

    Kurzinfo : WinGetHandle('[CLASS / WinGetHandle('[REGEXPCLASS

    3. ControlSend / ControlGetText (Link)

    4. TreeView-Bug / "-1"-Bug (Win7 x64 - Au3: 3.3.14.5) (Link)

    5. TreeView DeleteChildren-Bug/Inkonsistenz (Win7 x64 - Au3: 3.3.14.5) (Link)

    6. Funktion DirMove (Link)

    Kurzinfo :

    Falls das Zielverzeichnis bereits existiert wird ein weiteres Unterverzeichnis angelegt - die Daten werden nicht in das bestehende Verzeichnis integriert

    7. Funktion DirCopy (Link)

    Kurzinfo : DirCopy mit Flag $FC_NOOVERWRITE bricht ab, auch wenn das Zielverzeichnis leer ist

    8. Funktion Opt('MustDeclareVars', 1) (Link)

    Kurzinfo: AU3Check schlägt nicht immer Alarm bei Opt('MustDeclareVars', 1)

    9. Subtrahieren von Fließkommazahlen (Link)

    Kurzinfo :

    Subtrahieren von Fließkommazahlen (floating point numbers) - auch Gleitkommazahlen genannt :

    Ändern der Reihenfolge liefert unterschiedliche Ergebnisse !

    10. Funktion Round -> Rückgabe unterschiedlicher Datentypen (Link)

    Kurzinfo :

    Dieses Verhalten tritt auf, wenn man den optionalen Parameter decimalplaces, also die Anzahl der gewünschten Nachkommastellen (selbst bei 0), verwendet oder weglässt.

    11. Funktion WinGetPos und GUISetState(@SW_MINIMIZE) (Link)

    Kurzinfo :

    WinGetPos liefert nicht wie erwartet die Position und Größe des minimierten Fensters, wenn direkt nach GUICreate('') ein GUISetState(@SW_MINIMIZE) ausgeführt wird

    Anmerkung :

    Bitnugger hat seinen Beitrag freundlicherweise erweitert, um eventuelle Missverständnisse zu vermeiden.

    12. Der Au3Stripper 'parst' einige ternäre Ausdrücke nicht korrekt (Link)

    Kurzinfo : Vom Au3Stripper erzeugter Code (*_stripped.au3) ist bei gewissen Notationen fehlerhaft.

    -> Offiziell gefixt in SciTE4AutoIt > 4.1.2 (alles nach dem 02-01-2019)

    13. Vorsicht bei den Hilfebeispielen zu einigen _WinAPI_Path... Funktionen (Link)

    Kurzinfo :

    Die Hilfebeispiele zu _WinAPI_PathRemoveArgs, _WinAPI_PathGetArgs und _WinAPI_PathParseIconLocation verwenden die Funktion _WinAPI_AssocQueryString.

    Diese Funktion ermittelt ungünstigerweise Werte aus der Registry, welche mal mit und mal ohne Anführungsstriche angegeben werden. Somit kann es zu einem Rückgabewert kommen, der in den _WinAPI_Path... Funktionen nicht verwertbar ist.

    14. Achtung bei IniRead* Funktionen und .ini-Dateien mit der Kodierung UTF-8 mit BOM (Link)

    Kurzinfo :

    Ist eine .ini-Datei als UTF-8 mit BOM gespeichert, dann wird die erste Zeile der Datei von den IniRead* Funktionen nicht erkannt.

    15. Fehlerhafte Beschreibung des Return Values bei _WinAPI_EnumWindowsTop   (Link)

    Kurzinfo :

    Statt (wie in der Hilfe beschrieben) :

    [0][0] - Number of rows in array (n)

    wird folgendes zurückgegeben :

    [0][0] - Number of top-level windows found

    [0][1] - Number of rows in array (n) ; ist immer eine durch 64 teilbare Zahl

    (leere Zeilen im Array werden vor der Rückgabe nicht eleminiert)

    16. _WinAPI_GetBkColor($hDC) -> Ausgabe der Hintergrundfarbe eines Controls (Link)

    Kurzinfo :

    Die Funktion _WinAPI_GetBkColor($hDC) gibt erst dann die Hintergrundfarbe eines Controls aus, wenn zwischen _WinAPI_GetDC($hWnd) und _WinAPI_GetBkColor($hDC) ein SendMessage aufgerufen wird, mit dem ein Brush-Objekt erzeugt wird.

    17. Int() -> unsignierte int32 verarbeiten (Link)

    Kurzinfo :

    AutoIt hat nur signierte int32- und signierte int64-Typen. Um ein vollständiges unsigned int32 zu speichern, müssen wir das int64 verwenden.

    Anmerkung : Dank an Bitnugger für die sehr ausführliche Beschreibung inkl. Beispiele. Dank auch an AspirinJunkie für die genaue Analyse, siehe (Link)


    (... hier werden neue Punkte eingefügt)

    Anmerkung : Warum starte gerade ich diesen Thread ?

    In den letzten Tagen gab es in der Shoutbox mal wieder eine interessante Diskussion (siehe Auflistung) mit sehr nützlichen Erkenntnissen. Da die Shoutbox aber nur für Mitglieder sichtbar ist, gehen Gästen diese Informationen verloren. Zudem verschwinden Shoutbox-Beiträge recht schnell im Archiv und werden dann auch von Mitgliedern nicht mehr gefunden.

    Da ich die Bitte geäußert habe daraus einen Thread zu machen, wurde mir prompt diese Ehre zuteil - meinen Dank an Bitnugger :P

    Nachfolgend die Auflistung der bisherigen Shoutbox-Beiträge zu : GUITreeView

    alpines Freitag, 25.01.2019

    Wow, darauf muss man erstmal kommen. Wenn man _ArrayDisplay verwendet, darf man nicht mit GUITreeView* neue Items erstellen und mit -1 draufzugreifen (obwohl die Parentcontrols etc. richtig übergeben werden!!!), denn es ist ja noch die ArrayDisplay GUI "aktiv" obwohl diese geschlossen wurde.

    Also entweder GUISwitch vor dem Erstellen der TreeViewItems, oder man speichert das Handle ab und übergibt es. Dann klappt es, egal auf welcher GUI man ist.

    Man hätte auch ruhig die aktuelle GUI (inkl. Tabitem falls vorhanden) auslesen können und im Nachhinein wieder mit GUISwitch setzen können.

    Anm. Bitnugger : Ja, total ätzend... oder einen zusätzlichen Parameter $hWnd, wie bei MsgBox.

    Bitnugger Samstag, 26.01.2019

    Eigentlich ist es aber ein Fehler von GUISwitch... das mit dem Handle der nicht mehr existierenden GUI von _ArrayDisplay/_DebugArrayDisplay hantiert, anstatt das zuvor gültige

    GUI zu verwenden, falls vorhanden.

    alpines Samstag, 26.01.2019

    Nein, mit GUISwitch funktioniert es ja. Das -1 greift auf die falsche GUI zu, übergebe ich allerdings das Handle von dem Item (OHNE GUISwitch) klappt es, mit -1 nicht.

    Bitnugger Sonntag, 27.01.2019

    Das -1 greift auf eine nicht mehr existierende die falsche GUI zu" ... ...AutoIt sollte das erkennen und die zuletzt gültige GUI anstelle der nicht mehr existierenden GUI verwenden.

    alpines Sonntag, 27.01.2019

    Genau, mit GUISwitch hat das ja aber nichts zu tun. Das behebt ja den Fehler, ohne klappts nur mit Handle.

    Bitnugger Sonntag, 27.01.2019

    Stimmt... ideal wäre also, wenn AutoIt beim Löschen einer GUI den Fokus automatisch auf eine zuvor erstellte und noch existierende GUI setzt, oder das Control nicht erstellt, falls keine existiert.

    Bitnugger Montag, 28.01.2019

    GUICtrlGetState($g_idIOListView) <-- hat mir heute den Tag versaut... weil --> "For ListView controls it returns the number of the clicked column."

    alpines Montag, 28.01.2019

    Ja, das hatte ich auch vor ein paar Monaten lernen müssen. Sowas wird aber leider niemals gefixt werden. Auch schön zu "erfahren", dass einige TreeView-Funktionen mit @GUI_CtrlId funktionieren, und einige auf GUICtrlGetHandle(@GUI_CtrlId) angewiesen sind.

    BugFix Dienstag, 29.01.2019

    Wenn du willst, dass es wirklich funktioniert: Eigenes Handling aller Messages durchführen.

    Dann weißt du wenigstens, dass du selbst der Depp warst, wenn es nicht klappt.

    86598-musashi-c64-png

    "Am Anfang wurde das Universum erschaffen. Das machte viele Leute sehr wütend und wurde allenthalben als Schritt in die falsche Richtung angesehen."

    33 Mal editiert, zuletzt von Musashi (5. Oktober 2021 um 13:09) aus folgendem Grund: Übersicht erweitert

  • Zu : WinGetHandle

    Bitnugger Mittwoch, 30.01.2019

    WinGetHandle('[CLASS:ad_win#2]') funktioniert nicht, mit WinGetHandle('[REGEXPCLASS:ad_win#2]') geht es aber !

    86598-musashi-c64-png

    "Am Anfang wurde das Universum erschaffen. Das machte viele Leute sehr wütend und wurde allenthalben als Schritt in die falsche Richtung angesehen."

  • Zu : ControlSend / ControlGetText

    Bitnugger Mittwoch, 30.01.2019

    Und hier noch so ein Ding für die Sammlung... ControlSend($hCtrl, '', '', 'BlaBlaBla') funktioniert... aber ControlGetText($hCtrl , '', '') funktioniert nicht... !

    alpines Mittwoch, 30.01.2019

    Das mit dem ControlSend/GetText würde ich aber nicht notwendigerweise so einstufen.

    Der 1. Parameter soll title/hWnd/class von dem Fenster sein, und controlId das was du übergibst.

    Strenggenommen sind ja Controls auch hWnds aber ich denke du verstehst was ich meine.

    In die Sammlung sollten eher Sachen die nicht so funktionieren wie sie sollten.

    86598-musashi-c64-png

    "Am Anfang wurde das Universum erschaffen. Das machte viele Leute sehr wütend und wurde allenthalben als Schritt in die falsche Richtung angesehen."

  • Tolle Aktion :thumbup:

    Damit das jeder nachvollziehen kann hier der Code zum TreeView-Bug / "-1"-Bug (Win7 x64 - Au3: 3.3.14.5)

    Es wird eine $hMainGUI erstellt die angezeigt wird. Diese dient als Haupt-GUI und öffnet die TreeView GUI und nachdem die TV-GUI angezeigt wird, @SW_DISABLEn wir die Haupt-GUI.

    Nun können wir wahllos Items anklicken und neue Unteritems spawnen lassen und es taucht eine neue GUI von _ArrayDisplay auf.

    Diese schließen wir und versuchen neue Items zu spawnen, dies ist allerdings nur auf den Items möglich die schon existierten.

    Spawnen wir ein Neues Item und versuchen mit dem Klick auf das Neue Item "Neu" wieder ein neues zu spawnen schlägt das fehl,

    denn das Event wurde nicht gesetzt. Da im GUICtrlCreateTreeViewItem kein -1 auftaucht sondern mit der Variable gearbeitet wird wird das Item zumindest erstellt.

    Der Bug ist also der, dass das Setzen von Events (oder andern Sachen die mit -1 funktionieren) auf Controls nicht funktionieren, die korrekt erstellt wurden,

    während eine andere GUI "aktiv" war. Denn das -1 bezieht sich immer auf das letzte Control und inklusive auf die letzte "aktive" GUI. (Aktiv im Sinne von SetState benutzt und nicht unbedingt Controls darauf erstellt!)

    Und nicht wie es überall in der Hilfe steht nur auf das letzte Control.

    The control identifier (controlID) as returned by a GUICtrlCreate...() function, or -1 for the last created control.

    Der Grund dafür ist, dass das -1 im GUICtrlSetOnEvent auf das falsche Control der falschen GUI zeigt (sollte eigentlich immer auf das letzte Control zeigen).

    Verwenden wir aber nun statt dem -1 die Variable mit dem ID des Controls werden auch bei den neuen Items wieder neue erstellt obwohl die GUI von ArrayDisplay auftauchte.

    Mit dem -1 klappt es nur wenn wir GUISwitch verwenden.

    Btw: Das TreeView-Begin/EndUpdate ist nicht zwangsweise notwendig, allerdings erscheinen die [+] nicht sofort (visuell) wenn man es nicht drin hat.

  • Ich hoffe es stört nicht, dass ich doppelt poste, aber so kannst du einfacher zu den Themen verlinken die du in den ersten Beiden Beiträgen angeschnitten hattest.

    TreeView DeleteChildren-Bug/Inkonsistenz (Win7 x64 - Au3: 3.3.14.5)

    Hier wurde einfach schlecht programmiert.

    Einige _GUICtrlTreeView-Funktionen akzeptieren das Standard-AutoIt-TreeViewItem (welches man mit der ID anspricht) aber DeleteChildren sträubt sich da, der Grund ist auch "schnell" gefunden.

    Einige Funktionen rufen nämlich intern noch _GUICtrlTreeView_GetItemHandle auf und arbeiten mit dem hWnd des Controls weiter, allerdings passiert das bei _GUICtrlTreeView_DeleteChildren nicht.

    Übergibt man kein hWnd (also einfach nur die ID vom Standard-TreeView-Control), so wird der Else-Zweif in der Funktion ausgeführt und als $lParam von GUICtrlSendMsg wird die AutoIt-Interne-ID eines Items weitergegeben.

    Das selbe Problem sollte auch beim Nicht-Else Zweif auftreten, allerdings muss man dann GUICtrlGetHandle um das TreeView packen und das Item normal übergeben was niemand machen würde.

    Code
    Func _GUICtrlTreeView_DeleteChildren($hWnd, $hItem)
        Local $bResult
        If IsHWnd($hWnd) Then
            $bResult = _SendMessage($hWnd, $TVM_EXPAND, BitOR($TVE_COLLAPSE, $TVE_COLLAPSERESET), $hItem, 0, "wparam", "handle")
        Else
            $bResult = GUICtrlSendMsg($hWnd, $TVM_EXPAND, BitOR($TVE_COLLAPSE, $TVE_COLLAPSERESET), $hItem)
        EndIf
        Return $bResult
    EndFunc

    Allerdings erwartet $TVM_EXPAND als $lParam ein hWnd (einen Pointer!) und keine AutoIt-Interne-ID.

    AutoIt erkennt das nicht automatisch und so wird als lParam einfach die ID gesendet welches auf einen ungültigen Speicherplatz zeigt und folglich das Control nicht gelösht werden kann.

    Fix: GUICtrlGetHandle verwenden wenn man Items an _GUICtrlTreeView_DeleteChildren versendet, dann übergibt man nämlich einen Pointer.

    Oder man setzt vollständig auf die UDF und verwendet kein einziges Standardcontrol, dann bräuchte man ehrlich gesagt aber die Tausend Abfragen nicht die in der UDF enthalten sind (die die Standardcontrols akzeptierbar machen).

    Dass hier, $TVM_EXPAND zum löschen mit $TVE_COLLAPSERESET verwendet wird, will ich mal außen vor lassen, bei mir erzeugt das einen visuellen Bug.

    Das [+] vor dem "A" verschwindet nicht, obwohl das Item keine Unteritems mehr hat und man es auch nicht mehr expandieren kann.

    • Offizieller Beitrag

    Offiziell gefixt in 3.3.10.0:

    _GUICtrlListView_SimpleSort sortiert lParam nicht (OBSOLET)

    Listview-UDF:

    _GUICtrlListView_SortItems() sortiert lParam

    _GUICtrlListView_SimpleSort() sortiert lParam nicht

    EDIT:

    Ich muss gestehen, dass ich nach Ablehnung meines Feature Requests dieses Thema nach 2 Jahren nicht weiter in den Changelogs verfolgt habe. Dadurch ist mir entgangen, dass das Problem (mit nahezu identischer Übernahme meiner Korrektur) in v3.3.10.0 gefixed wurde.

    Also Sorry für die ungewollte Falsch-Info.

    Auf das Problem wird man eher selten stoßen, aber dann fliegt es einem um die Ohren.

    lParam ist wunderbar geeignet, um zusätzliche Informationen zu einem Listview-Item zu speichern (Bei Item, die mit nativen Funktionen erstellt wurden, ist lParam die Item-ID). In meiner UDF zum Formatieren von Listviews, hatte ich dort den Verweis auf ein Array-Index für das Item abgelegt, damit ich aus dem Array alle Infos zu Font, Farbe etc. verfügbar hatte. Nachdem ich das Listview mit SimpleSort sortiert hatte, funktionierte die Zuordnung nicht mehr. Da ich in der Entwicklung der UDF war, dachte ich, ich hätte in der Arrayverwaltung einen Fehler eingebaut. Tatsächlich habe ich nochmals Schritt für Schritt alles neu entwickelt um zum selben Ergebnis zu kommen. Da ging mir dann auf, dass der Fehler in der Listview-UDF liegt.

    _GUICtrlListView_SimpleSort() sortiert nicht lParam! Das wurde bei der Erstellung der Funktion einfach vergessen. Ich hatte das als Bug gemeldet - wurde aber nicht für voll genommen. :Face:

    Darum hier meine korrigierte Variante von _GUICtrlListView_SimpleSort():

  • Funktion : DirMove (Win7 x64 - Au3: 3.3.14.2)

    Beschreibung :

    Hat man z.B. ein Verzeichnis d:\Quelle und möchte dieses Verzeichnis mittels DirMove nach d:\Ziel verschieben (Flag $FC_OVERWRITE ist gesetzt), dann :

    -> d:\Quelle wird entfernt

    -> unter d:\Ziel wird das Verzeichnis \Quelle angelegt -> der komplette Pfad lautet : d:\Ziel\Quelle

    Wiederholt man den Vorgang, d.h. d:\Quelle wird erneut befüllt und verschoben, erwartet man :

    -> d:\Quelle wird entfernt

    -> in d:\Ziel\Quelle werden die Daten aktualisiert, d.h. existierende Daten werden überschrieben und neue Daten werden hinzugefügt

    Was aber passiert ist : Es wird ein (weiteres) neues Unterverzeichnis \Quelle hinzugefügt, also

    d:\Ziel\Quelle\Quelle [ad infinitum]

    Details und 'Workaround' siehe : Merkwürdiges Verhalten bei DirMove

    86598-musashi-c64-png

    "Am Anfang wurde das Universum erschaffen. Das machte viele Leute sehr wütend und wurde allenthalben als Schritt in die falsche Richtung angesehen."

    2 Mal editiert, zuletzt von Musashi (3. Februar 2019 um 18:53)

  • Funktion : DirCopy (Win7 x64 - Au3: 3.3.14.2)

    Beschreibung :

    Selbst wenn man alle Dateien und (falls vorhanden Unterverzeichnisse) aus dem Zielverzeichnis entfernt, werden keine Dateien kopiert. Offensichtlich findet mit dem Flag $FC_NOOVERWRITE nur ein Test auf die Existenz des Zielverzeichnisses statt. Existiert es bereits, bricht DirCopy ab.

    Erst mit dem Flag $FC_OVERWRITE werden die fehlenden Dateien kopiert.

    Details siehe : Merkwürdiges Verhalten auch bei DirCopy

    86598-musashi-c64-png

    "Am Anfang wurde das Universum erschaffen. Das machte viele Leute sehr wütend und wurde allenthalben als Schritt in die falsche Richtung angesehen."

    2 Mal editiert, zuletzt von Musashi (3. Februar 2019 um 18:54)

  • Funktion: Opt('MustDeclareVars', 1)

    Wenn im Script die Pre-Deklaration von Variablen mit Opt('MustDeclareVars', 1) erzwungen wird, bevor man sie benutzen darf, denkt und erwartet man, dass AU3Check meckert, wenn dann doch eine Variable benutzt wird, die vorher nicht deklariert wurde - und wenn AU3Check nicht meckert, dass alles im grünen Bereich ist und das Script dann keinesfalls an irgendeiner Stelle abbricht, weil es auf eine nicht deklarierte Variable stößt.

    Falsch gedacht...

    Hier ein Bsp:

    In den meisten Fällen wird das Script sofort beendet und eine entsprechende Fehlermeldung ausgegeben, wenn es bei der Ausführung dann doch auf eine nicht pre-deklarierte Variable stößt, aber dies ist nicht immer der Fall! In diesen speziellen Fällen - wenn keine Fehlermeldung kommt und das Script einfach nur einfriert - wird es meist sehr schwer, den Fehler zu finden.

    Hier der relevante Teil der Funktion, die mir graue Harre beschert hat...

    Func _ListViewProc($hWnd, $iMsg, $wParam, $lParam, $iSubclassId, $hHdrFont)
  • Subtrahieren von Fließkommazahlen - Ändern der Reihenfolge liefert unterschiedliche Ergebnisse!

    Bei ganzen Zahlen spielt es keine Rolle, in welcher Reihenfolge die zu subtrahierenden Zahlen stehen, hier ein Bsp.:

    Code
    ConsoleWrite('+ 60 - 18 - 2 - 10 = ' & 60 - 18 - 2 - 10 & @CRLF) ; 30
    ConsoleWrite('+ 60 - 10 - 18 - 2 = ' & 60 - 10 - 18 - 2 & @CRLF) ; 30
    ConsoleWrite('+ 60 - 2 - 20 - 18 = ' & 60 - 2 - 20 - 18 & @CRLF) ; 30
    ConsoleWrite('+ 60 - 2 - 18 - 20 = ' & 60 - 2 - 18 - 20 & @CRLF) ; 30

    Bei Fließkomazahlen sieht es jedoch anders aus, hier ein Bsp.:

    Code
    ConsoleWrite('! 78.08 - 11.07 - 67.01   = ' & 78.08 - 11.07 - 67.01 & @CRLF)   ; -1.4210854715202e-014 <--
    ConsoleWrite('! 78.08 - 67.01 - 11.07   = ' & 78.08 - 67.01 - 11.07 & @CRLF)   ; -7.105427357601e-015  <--
    
    ; Mit Klammersetzung kann man dies verhindern.
    ConsoleWrite('- 78.08 - (11.07 + 67.01) = ' & 78.08 - (11.07 + 67.01) & @CRLF) ; -1.4210854715202e-014
    ConsoleWrite('- 78.08 - (67.01 + 11.07) = ' & 78.08 - (67.01 + 11.07) & @CRLF) ; -1.4210854715202e-014

    Zudem ist das Ergebnis in allen vier Fällen nicht 0, wie es beim Windows Calculator, meinen Taschenrechner und dem Rechner auf meinem Smartphone der Fall ist...

    Deshalb: Bei Berechnungen mit Gleitkommazahlen das Ergebnis niemals auf Gleichheit prüfen (beliebter Anfängerfehler), sondern stets eine Prüfung um ±Epsilon (einer beliebig kleinen Zahl größer als null) durchführen.

    Danke Xorianator

    Einigen Usern sind die Hintergründe sicher nicht bekannt, warum es bei der "Fließkomma-Arithmetik" zu "unerwarteten Ergebnissen" kommt, welche aber nicht als Bug (Fehler) einzustufen sind. Ausführliche Infos zu diesem Thema findet man z.B. hier:

    https://py-tutorial-de.readthedocs.io/de/latest/floatingpoint.html

    https://www.mikrocontroller.net/articles/Gleitkommazahlen

    3 Mal editiert, zuletzt von Bitnugger (14. Februar 2019 um 13:05)

  • Wird Round() in Kombination mit Funktionen verwendet, die je nach Datentyp unterschiedlich agieren (z.B. Hex(5) <> Hex(5.0)), kann es zu unerwarteten Ergebnissen führen, da Round() als Rückgabetyp immer ein Double liefert, sofern der optionale Parameter "decimalplaces" mit angegeben wird - wird dieser weggelassen, ist der Rückgabetyp immer Int32.

    Code
    ConsoleWrite('+ --------------------------------------------------------------------------------------------------------- ' & @CRLF)
    ConsoleWrite('+ Die Verwendung des optionalen Parameters "decimalplaces" führt zur Rückgabe unterschiedlicher Datentypen : ' & @CRLF)
    ConsoleWrite('! Datentyp ohne "decimalplaces" -> Round(5.5)    = ' & VarGetType(Round(5.5)) & @CRLF)
    ConsoleWrite('! Datentyp mit "decimalplaces"  -> Round(5.5, 0) = ' & VarGetType(Round(5.5, 0)) & @CRLF)
    ConsoleWrite('+ --------------------------------------------------------------------------------------------------------- ' & @CRLF)
    ConsoleWrite('+ Beispiel mit der Funktion Hex(), wo der Datentyp den Rückgabewert beeinflusst : ' & @CRLF)
    ConsoleWrite('! Hex mit Round(5.5)    = ' & Hex((Round(5.5))) & @CRLF)
    ConsoleWrite('! Hex mit Round(5.5, 0) = ' & Hex((Round(5.5, 0))) & ' (Anm.: Hex-Repräsentation einer Gleitkommazahl)'& @CRLF)
    ConsoleWrite('+ --------------------------------------------------------------------------------------------------------- ' & @CRLF)

    Edit: Rechtschreibung und Formulierung und Code :D

    M

  • WinGetPos liefert nicht wie erwartet die Position und Größe des minimierten Fensters, wenn nach GUICreate('') nur ein GUISetState(@SW_MINIMIZE) ausgeführt wird, sondern die Position und Größe, welche beim Erstellen des Fenster verwendet wurde - also entweder die angegeben Werte oder die Default-Werte.

    Edit: Inspiriert durch Musashi habe ich mich entschlossen, die Examples etwas zu erweitern, damit man der Ausgabe auch gleich entnehmen kann, wo hier der Schuh drückt.

    PS: Beim Erstellen einer GUI interpretiert GUICreate die Höhe und Breite als ClientSize, WinGetPos liefert jedoch die Position und Größe inkl. Rahmen!

    Fazit: GUISetState(@SW_MINIMIZE) funktioniert nur, wenn das Fenster vorher bereits sichtbar gemacht wurde... wohingegen WinSetState($hGUI, '', @SW_MINIMIZE) aber auch funktioniert, wenn es noch nicht sichtbar ist. Sicherheitshalber sollte aber generell besser @SW_SHOWMINIMIZED als Parameter angeben werden, wenn unklar ist, ob das Fenster bereits sichtbar ist.

    3 Mal editiert, zuletzt von Bitnugger (1. April 2019 um 10:41)

  • Offiziell gefixt in SciTE4AutoIt > 4.1.2 (alles nach dem 2-1-2019).

    Der Bug im Tracker wurde gefixt, die neue Betaversion stripped die Datei korrekt. Ich schätze ab dem nächsten Release sollte der Fehler behoben sein.

    Au3Stripper parst einige ternäre Ausdrücke nicht korrekt

    Es ist zwar keine interne Funktion, aber mehr oder weniger ein Präprozessor und sollte hier auch erwähnt werden meiner Meinung nach.

    Der Au3Stripper ist in der neuesten SciTE4AutoIt (3.3.14.5/SciTE 4.1.2) defekt (auch der neueste von der Website, 2-1-2019 gepostet, müsste sogar der selbe sein), und ich weiß nicht ob der Fehler schon in den vorherigen Versionen auftrat. Dazu hab ich bereits im bugtracker ein Ticket erstellt, mal gucken was dabei rumkommt: https://www.autoitscript.com/trac/autoit/ticket/3715

  • Zu : Der Au3Stripper 'parst' einige ternäre Ausdrücke nicht korrekt

    Offiziell gefixt in SciTE4AutoIt nach 4.1.2 (alles nach dem 02-01-2019)

    Ergänzung zum Beitrag #13 :

    (Zitat von alpines : ... und ich weiß nicht, ob der Fehler schon in vorherigen Versionen auftrat.)

    Ich habe die im Ticket beschriebenen Fälle mit dem Au3Stripper aus der SciTE4AutoIt3 Version 3.5.4 vom 07. März 2015 getestet. Fazit : identisches Fehlverhalten !

    Für Nutzer*innen älterer Versionen aber nach wie vor relevant !

    86598-musashi-c64-png

    "Am Anfang wurde das Universum erschaffen. Das machte viele Leute sehr wütend und wurde allenthalben als Schritt in die falsche Richtung angesehen."

    2 Mal editiert, zuletzt von Musashi (23. Mai 2019 um 16:08) aus folgendem Grund: an neue Sachlage angepasst

    • Offizieller Beitrag

    Falls ihr _WinAPI_Path.. Funktionen verwendet, bitte sehr misstrauisch sein. Die folgenden beiden Funktionen funktionieren definitiv nicht. ***

    Dort wird ausschließlich nach Leerzeichen im Pfad gesucht und anhand dessen in Pfad und Argumente gesplittet :Face:.

    EDIT:

    ***: Wie sich herausgestellt hat, sind die _WinAPI_Path Funktionen eigentlich unschuldig. Sie erwarten einen Leerzeichen behafteten Pfad in Gänsefüßchen eingefasst. Das Hilfebsp. verwendet ungünstigerweise die Funktion _WinAPI_AssocQueryString, die Werte aus der Registry verwendet und diese sind mal mit, mal ohne Gänsefüßchen. Somit ist der Rückgabewert in der Form des Hilfebsp. nicht für die _WinAPI_Path Funktionen verwertbar.

    Lösungsvariante:

  • Zu : IniRead* Funktionen und .ini-Dateien mit der Kodierung UTF-8 mit BOM

    Ist eine .ini-Datei als UTF-8 mit BOM gespeichert, dann wird die erste Zeile der Datei von den IniRead* Funktionen nicht erkannt.

    - falls Zeile 1 = Kommentarzeile, also ; Kommentar ...  ==> unproblematisch

    - falls Zeile 1 = [Sektion] ==> alle Key=Values der gesamten Sektion werden ignoriert

    Der Grund für das Problem ist, dass bei UTF-8 Dateien am Anfang ein “Byte Order Mark” (kurz: BOM) steht. Der BOM für UTF-8 ist drei Bytes lang : EF BB BF -> nach Windows-1252 als “” dargestellt. In Editoren werden diese Zeichen häufig nicht angezeigt.

    Hintergrund :

    AutoIt verwendet für die Verarbeitung von .ini-Dateien API-Funktionen aus der Microsoft KERNEL32.DLL. IniRead ist 'nur' ein Wrapper für die Funktion 'GetPrivateProfileString'. GetPrivateProfileString(A) geht aber immer von einer ANSI (nicht verwechseln mit ASCII) Kodierung aus.

    Hier mal die Ausgabe mittels Hex.Editor :

    Hier als ANSI :

    Beispielskript :

    Ausgabe unterschiedlich kodierter .ini-Dateien (siehe Anhang)

    >>>>> 1. Kodierung : ANSI <<<<<

    >> [Sektion1]

    Section1Key1 = Sec1/Value1

    Section1Key2 = Sec1/Value2

    >> [Sektion2]

    Section2Key1 = Sec2/Value1

    Section2Key2 = Sec2/Value2

    Section2Key3 = ÄÖÜäöüß

      

    >>>>> 2. Kodierung : UTF8 ohne BOM <<<<<

    >> [Sektion1]

    Section1Key1 = Sec1/Value1

    Section1Key2 = Sec1/Value2

    >> [Sektion2]

    Section2Key1 = Sec2/Value1

    Section2Key2 = Sec2/Value2

    Section2Key3 = ÄÖÜäöüß

      

    >>>>> 3. Kodierung : UTF8 (mit BOM) <<<<<

    >> [Sektion1]

    Section1Key1 =

    Section1Key2 =

    >> [Sektion2]

    Section2Key1 = Sec2/Value1

    Section2Key2 = Sec2/Value2

    Section2Key3 = ÄÖÜäöüß

      

    >>>>> 4. Kodierung : UTF8 (mit BOM) - erste Zeile Kommentar <<<<<

    >> [Sektion1]

    Section1Key1 = Sec1/Value1

    Section1Key2 = Sec1/Value2

    >> [Sektion2]

    Section2Key1 = Sec2/Value1

    Section2Key2 = Sec2/Value2

    Section2Key3 = ÄÖÜäöüß

    Natürlich kann man die Dateien umkonvertieren, die ersten Bytes prüfen und abschneiden usw.

    Wer dieses Verhalten der Standard IniRead* Funktionen aber nicht kennt wird sich ggf. wundern, warum der Eintrag (also die Sektion, sowie darin befindliche Werte) nicht eingelesen wird ;).

    Dateien

    86598-musashi-c64-png

    "Am Anfang wurde das Universum erschaffen. Das machte viele Leute sehr wütend und wurde allenthalben als Schritt in die falsche Richtung angesehen."

    2 Mal editiert, zuletzt von Musashi (7. Januar 2020 um 22:53) aus folgendem Grund: erweitert

  • _WinAPI_EnumWindowsTop

    C
    ; AutoIt 3.3.14.5
    
    #include <Array.au3>
    #include <WinAPI.au3>
    
    Local $aWinList = _WinAPI_EnumWindowsTop() ; Listet alle Top-Level Fenster auf
    _ArrayDisplay($aWinList, '$aWinList')

    Return Value

    Returns an array with the following format:

    [0][0] - Number of rows in array (n)

    [1][0] - Window handle

    [1][1] - Window class name

    [n][0] - Window handle

    [n][1] - Window class name

    Tatsächlich liefert die Funktion aber:

    [0][0] - Number of top-level windows found

    [0][1] - Number of rows in array (n) ; ist immer eine durch 64 teilbare Zahl

    [1][0] - Window handle

    [1][1] - Window class name

    [n][0] - Window handle

    [n][1] - Window class name

    Bsp.: Wenn [0][0] = 65, dann ist [0][1] = 128, wobei dann die Zeilen 66 - 128 leer sind.

    Korrekt wäre, wenn die Funktion die leeren Zeilen im Array vor der Rückgabe eliminiert würde.

    AutoIt
    ; AutoIt 3.3.14.5
    
    #include <Array.au3>
    #include <WinAPI.au3>
    
    Local $aWinList = _WinAPI_EnumWindowsTop()
    _ArrayDisplay($aWinList, '$aWinList - BAD')
    _ArrayDelete($aWinList, $aWinList[0][0] +1 & '-' & $aWinList[0][1] -1) ; Leere Zeilen aus Array löschen
    $aWinList[0][1] = '' ; Wird nicht benötigt, da die korrekte Anzahl der Zeilen bereits in $aWinList[0][0] steht
    _ArrayDisplay($aWinList, '$aWinList - OK')
  • _WinAPI_GetBkColor($hDC)

    Die Funktion _WinAPI_GetBkColor($hDC) gibt erst dann die Hintergrundfarbe eines Controls aus, wenn zwischen _WinAPI_GetDC($hWnd) und _WinAPI_GetBkColor($hDC) ein SendMessage aufgerufen wird, mit dem ein Brush-Objekt erzeugt wird.

    Ein Beispiel und ein Link zur Diskussion finden sich im folgenden.

    ---------------------------------------------------------

    Eine Möglichkeit, mit der man die Hintergrundfarbe von eigenen* Controls ermitteln kann, ohne GetPixel** zu verwenden, ist _WinAPI_GetBkColor($hDC). Es sollen ganz unterschiedliche Controls berücksichtig werden, wie z.B. Label, Edit, Input, Button, ComboBox, usw.

    * Eigene Controls: Wie Bitnugger treffend bemerkt hat, kann man mit diesem Code nur die Hintergrundfarbe für Controls im eigenen Script ermitteln und nicht in fremden Anwendungen.

    ** GetPixel funktioniert nicht immer wie gewünscht, jenachdem welches Pixel man bei welchem Control ausliest. Wenn man das Pixel bei "0, 0" ausliest, kann das bei einem Label funktionieren, aber bei einem Button nicht. Macht man für den Button ein Offset für das Border, und ermittelt z.B. das Pixel bei "3, 3" (siehe EN Forum) funktioniert es evtl. bei einem Edit nicht, wenn der gelesene Pixel genau das Caret erwischt, usw.

    Wie Oscar treffend bemerkt hat, gibt es nur wenig Bedarf, die Hintergrundfarben im eigenen Script zu ermitteln, da man normalerweise weiß, welche Farben man verwendet. Somit poste ich den Code nach dem Motto: Besser eine Möglichkeit haben und nicht brauchen, als brauchen und nicht haben. 8o

    Ein Demo findet man im "Skripte" Bereich. Den Diskussion-Thread findet man hier.

    Edit: Den Code für das Freigeben des Brush-Objekts habe ich entfernt, da ich auch nach langer Recherche nicht beurteilen kann, ob an dieser Stelle ein Freigeben nützt oder schadet. Der Sinn für diesen Thread bleibt erhalten.

    Wenn jemand sagt: "Das geht nicht!" Denke daran: Das sind seine Grenzen, nicht deine.

    3 Mal editiert, zuletzt von Professor Bernd (6. September 2020 um 15:55)

  • Int()

    AutoIt only has signed int32 and signed int64 types. To store a full unsigned int32 we need to use the int64.

    AutoIt hat nur signierte int32- und signierte int64-Typen. Um ein vollständiges unsigned int32 zu speichern, müssen wir das int64 verwenden.

    Was bedeutet das für uns?

    Aufgefallen ist mir dies erstmals, als ich die Funktion _WinAPI_GetDriveNumber() verwendet habe, die als Ergebnis ein Array mit folgenden Informationen liefert:

    [0] - The type of device ($FILE_DEVICE_*).

    [1] - The device number.

    [2] - The partition number, or (-1) if device cannot be partitioned.

    Hier geht es lediglich um den Wert aus [2] ...wenn der also -1 ist, kann das Device nicht partitioniert werden.

    _WinAPI_GetDriveNumber lieferte mir als Ergebnis für das Laufwerk d: (DVD-Brenner, kein Medium eingelegt) 4294967295! Mein erster Gedanke war: Was soll denn der Quatsch?

    4294967295... das kann unmöglich die Nummer der Partitionen sein (zumal ja auch kein Medium eingelegt ist), doch -1 ist es auch nicht, oder?

    Schauen wir uns die Funktion _WinAPI_GetDriveNumber also mal genauer an... da wird eine DllStruct erstellt, die nach einem DllCall die ermittelten Daten enthält, welche dann in einem Array zurückgegeben werden.

    Local $tSDN = DllStructCreate('dword;ulong;ulong')

    In $aData[2] ist also der letzte ulong-Wert enthalten... und ulong ist ja 32-bit - so steht es zumindest auch in der AutoIt-Hilfe!

    ULONG 32bit(4bytes) unsigned integer

    Ok, was sagt VarGetType denn dazu und wie sieht 4294967295 denn in hexadezimaler Schreibweise aus? Lassen wir uns das mal anzeigen:

    ConsoleWrite('> $aData[2] = 0x' & Hex($aData[2]) & ' ' & VarGetType($aData[2]) & @CRLF) ; $aData[2] = 4294967295

    > 0x00000000FFFFFFFF Int64

    Ops... Int64... obwohl ulong doch 32-bit ist?

    Fazit:

    Wird das Ergebnis eines DllCalls als ulong (32bit unsigned integer) zurückgegeben, wird es von AutoIt automatisch zu Int64 (64bit signed integer) erweitert, wenn der Wert > 0x7FFFFFFF (2147483647) ist.

    Somit kann bei ulong (bzw. allen unsigned integer-Typen) das Ergebnis nicht einfach auf -1 getestet werden...

    If $aData[2] = -1 Then ...funktioniert nicht! ; ==>> Int64: 0x00000000FFFFFFFF <> -1

    ...sondern muss es zuvor entsprechend umwandeln, in unserem Fall nach Int32.

    If Int($aData[2], 1) = -1 Then ...funktioniert! ; ==>> Int32: 0xFFFFFFFF = -1

    Hier noch mein Test-Script:

    Ausgabe:


    Einmal editiert, zuletzt von Bitnugger (5. Oktober 2021 um 02:50)

  • Das Problem hat eigentlich nichts mit AutoIt's Umwandlung in Int64 (oder auch Int32) zu tun, sondern in der merkartigen Behandlung von Datentypen in der Windows-API hier im speziellen Fall.

    Was meine ich damit?

    Die _WinAPI_GetDriveNumber() ruft die Windows-API-Funktion DeviceIoControl auf. Was diese zurückgibt wird primär über den Parameter dwIoControlCode gesteuert.
    Die AutoIT-UDF trägt hier hart die 0x002D1080 ein. Dieser Wert entspricht (etwas schwierig nachzuvollziehen) der API-Konstante IOCTL_STORAGE_GET_DEVICE_NUMBER.

    Damit ergibt sich, dass der Parameter lpOutBuffer vom Typ STORAGE_DEVICE_NUMBER sein muss.

    Diese ist in der WinIoCtl.h folgendermaßen definiert:

    Code
    typedef struct _STORAGE_DEVICE_NUMBER {
        DEVICE_TYPE DeviceType;
        DWORD       DeviceNumber;
        DWORD       PartitionNumber;
    } STORAGE_DEVICE_NUMBER, *PSTORAGE_DEVICE_NUMBER;

    Die PartitionNumber - also dein fraglicher Parameter in deiner Struktur ist dabei als DWORD-Typ definiert.

    Was ist ein DWORD? - in der WinDef.h wird dword folgendermaßen definiert: typedef unsigned long DWORD;

    Bis hierhin stimmt die UDF auch (bis auf den kleinen Aspekt, dass sie ulong statt dword genommen haben - was aber äquivalent ist).

    Die wirklich interessante Frage ist jedoch: Wie kommt Microsoft darauf einem unsigned integer einen Wert von -1 zuzuweisen?
    Dieser Wert liegt außerhalb vom Wertebereich von dword. Ist also defacto falsch.
    Im Wertebereich von 0 bis 2.147.483.647 tut dies im Grunde auch gar nicht weh, da diese Zahlen auf binärer Ebene als dword und int völlig gleich sind (nämlich in beiden Fällen 00000000 - 7FFFFFFF).
    Die Weiterbehandlung ist daher nicht wirklich problematisch.
    Ekelhaft wird es erst wenn man Zahlen außerhalb dieses Bereiches nimmt (also bei denen das 1. Bit gesetzt wird) wie eben die -1.

    Das ist (meiner Meinung nach) für dword schlicht falsch - es tut in C aber schlicht nicht wirklich dolle weh, da folgendes weiterhin funktioniert:

    Code
    (DWORD)4294967295 == -1   // ergibt true

    Man kann also munter weiter gegen -1 testen obwohl der Wertebereich von dword dafür gar nicht ausgelegt ist.

    Zusammengefasst: AutoIt analysiert die Struktur, erkennt ein dword und muss daher davon ausgehen, dass eine Zahl mit dem Binärwert 0xFFFFFFFF als unsigned long interpretiert werden muss und daher dem Gegenwert 4.294.967.295 entspricht. Es hat keine Möglichkeit von den Spielereien in C zu wissen wo auch ein unsigned long gegen negative Zahlen getestet werden kann.

    Ich kann daher kein wirkliches Fehl- oder Spezialverhalten von AutoIt in diesem Beispiel erkennen. AutoIt macht im Grunde alles richtig. (Edit: Bis auf den Umstand, dass in der Hilfe -1 als möglicher Rückgabewert angegeben wird - was defacto nicht möglich ist)
    Das kann man auch schön daran erkennen, dass auch in C 4.294.967.295 herauskommt wenn man sich ordentlich an die Doku hält:

    Edit: Hab mal >>ein Ticket<< dazu aufgemacht, so dass die Funktion auch -1 zurückgeben würde.

    Edit2: Gefixt und soll in 3.3.15.5 behoben sein

    4 Mal editiert, zuletzt von AspirinJunkie (11. Oktober 2021 um 08:30)