1. Dashboard
  2. Mitglieder
    1. Letzte Aktivitäten
    2. Benutzer online
    3. Team
    4. Mitgliedersuche
  3. Forenregeln
  4. Forum
    1. Unerledigte Themen
  • Anmelden
  • Registrieren
  • Suche
Alles
  • Alles
  • Artikel
  • Seiten
  • Forum
  • Erweiterte Suche
  1. AutoIt.de - Das deutschsprachige Forum.
  2. Mitglieder
  3. Kanashius

Beiträge von Kanashius

  • GUI mit benutzerdefinierter Titelleiste

    • Kanashius
    • 23. Februar 2023 um 19:43

    Hi,

    das schaut doch schon recht gut aus :)

    Ich hab das gleiche vor kurzem in JavaFX gemacht um bei nem Fenster Darktheme zu unterstützen.

    Deshalb hab ich ein paar Verbesserungsvorschläge für dich :)

    Erstmal ein Fehler (vmtl. vom posten des Codes):

    1. Bei mir haben der Schließen (Í) und Maximieren-button (£) ein falsches Symbol (auch hier auf der Webseite; keine Ahnung, wo es falsch konvertiert wurde). Ich würde empfehlen mit ChrW die UTF-codes direkt zu nutzen, dann kann sowas nicht passieren. Für mein Tool hab ich z.B. minimize: ChrW(0x2015), maximize: ChrW(0x2610) und close: ChrW(0x2715)

    Verbesserung:

    1. Doppelkick auf die Titleleiste maximiert/entmaximiert ein Fenster, sollte recht leicht zu implementieren sein.

    2. Eigenes resize implementieren; relativ einfach, aber aufwändiger.

    3. AeroSnap: Wenn man ein Fenster an den Bildschirmrand zieht, füllt es je nach Rand einen Bereich. Linker Rand: linke hälfte, Ecke links oben/unten jeweiles die obere/untere linke Hälfte und das gleiche auch Rechts. Der obere Rand maximiert.

    Dafür muss man aber die Maus fangen und verhindern, dass sie auf andere Bildschirme an dem Rand übergeht, wenn man die Maus nicht zu schnell über die Kante bewegt. Außerdem zeigt Windows mittlerweile die Option, die andere freie Hälfte mit nem anderen Tool zu füllen,...

    Leider gibt es keine API dafür, sodass es nicht möglich ist das ganze exakt umzusetzen, aber zumindest die eigene Fenstergröße kann man anpassen. Auch wenn es nicht ganz so einfach ist.

    ?4. Vor kurzem hab ich mitbekommen, dass es mittlerweile in Windows auch FancyPages gibt; So ähnlich wie AeroSnap, nur mit mehr möglichkeiten, ABER auch wieder ohne API... X(

    Das standard Verhalten von GUIs nachzubauen ist also leider ziemlich schwer... (insbesondere, wenn man wie ich mit JavaFX auch Linux/Mac unterstützen will).

    Es ist leider ziemlich nervig, dass sobald man die Standard Titlebar wegnimmt (Window style undecorated), fast alle Funktionalität für ein normales Fenster mit verschwindet... Vor allem, weil auch die Standard Testenkombinationen mit wegfallen. Win+Left funktioniert z.B. nicht mehr um ein Fenster auf die linke Bildschirmhälfte zu packen (AeroSnap),... Das alles nachzubauen ist echt nervig. :/

  • CMD Aurfuf haut nicht hin

    • Kanashius
    • 4. Februar 2023 um 15:29

    Ich hab den Code mal genommen und ihn umgeschrieben.

    Das wichtigste, was dir fehlt, ist Errorhandling. Wenn ein Fehler auftritt, sollte dieser als Fehler in der jeweiligen Funktion behandelt werden und Funktionsaufrufe sollten auf Fehler geprüft werden.

    Außerdem sollte man Globale Variablen so gut wie möglich vermeiden. Das bedeutet mehr als nur alle Global to Local zu wechseln. Es betrifft die Struktur, wie der Code aufgebaut ist. Ich hoffe, der Code von mir zeigt dir, wie das am besten geht.

    Ich hab die Fenstergröße,... wie immer als Variablen definiert. Das sorgt dafür, dass du die Größe nur an einer Stelle geändert werden muss, und alles andere wird automatisch angepasst.

    Variablen sollte mit dem Typ beginnen, der in ihnen gespeichert wird (wenn möglich). Stichwort "ungarische Notation": unter Names of Variables

    Dadurch, dass alles in einer Funktion ist, kann ich den Funktionsaufruf auch einfach in einer While-Schleife wrappen, sodass es mehrmals probiert wird.

    AutoIt
    Opt('MustDeclareVars', 1)
    #AutoIt3Wrapper_Au3Check_Parameters=-q -d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 -w 7
    
    #include <GuiConstants.au3>
    #include <FileConstants.au3>
    #include <ProcessConstants.au3>
    #include <WinAPIHObj.au3>
    #include <WinAPIProc.au3>
    #include <WinAPISys.au3>
    
    Global $iWidth=530, $iHeight=120, $iBorder=10
    
    Global $hMainGui = GUICreate('Drag and Drop', $iWidth, $iHeight, @DesktopWidth/2-$iWidth/2, @DesktopHeight/2-$iHeight/2, _
                                 Default, BitOR($WS_EX_ACCEPTFILES,$WS_EX_TOPMOST))
    Global $iInfoLabel = GUICtrlCreateLabel('Bitte ziehen Sie mit der Maus die erhaltene PFX-Datei in diese Fenster ' & _
                                            'und lassen es hier fallen, danach geben Sie Ihr Passwort ein, welches ' & _
                                            'Sie per Mail erhalten haben, den Rest erledige ich für Sie.', _
                                            $iBorder, $iBorder, $iWidth-2*$iBorder, $iHeight-2*$iBorder)
    GUICtrlSetFont($iInfoLabel, 16, 0, "Arial")
    GUICtrlSetBkColor($iInfoLabel, $GUI_BKCOLOR_TRANSPARENT)
    GUICtrlSetState($iInfoLabel, $GUI_DROPACCEPTED)
    GUISetState(@SW_SHOW, $hMainGui)
    
    _mainLoop()
    
    Func _mainLoop()
        While Sleep(10)
            Local $iMsg = GUIGetMsg()
            Switch $iMsg
                case $GUI_EVENT_CLOSE
                    GUIDelete($hMainGui)
                    Exit
                case $GUI_EVENT_DROPPED
                    If @GUI_DropId = $iInfoLabel Then
                        Local $sFile = @GUI_DragFile
                        Local $iTry = 0, $iMaxTries = 3
                        While $iTry<$iMaxTries
                            If Not _handleFile($sFile) Then
                                Switch @error
                                    case 1
                                        MsgBox(16, "Fehler", "Sie haben keine Datei gedropped, oder die Datei existiert nicht." & _
                                                             @CRLF & "Fehler Info: " & @extended, Default, $hMainGui)
                                    case 2
                                        MsgBox(16, "Fehler", "Das Passwort konnte nicht erfolgreich abgefragt werden." & _
                                                             @CRLF & "Fehler Info: " & @extended, Default, $hMainGui)
                                    case 3
                                        MsgBox(16, "Fehler", "Das Certifikat konnte nicht erfolgreich erstellt werden." & _
                                                             @CRLF & "Fehler Info: " & @extended, Default, $hMainGui)
                                EndSwitch
                            Else
                                ExitLoop
                            EndIf
                            $iTry+=1
                        WEnd
                        If $iTry=$iMaxTries Then MsgBox(16, "Fehler", "Leider hat das nicht geklappt.", Default, $hMainGui)
                    EndIf
            EndSwitch
        WEnd
    EndFunc
    
    Func _handleFile($sFile)
        If Not FileExists($sFile) Then return SetError(1, 0, False)
        Local $sPassword = _getPassword()
        If @error Then return SetError(2, @extended, False)
        _makeCert($sFile, $sPassword)
        If @error Then return SetError(3, @error, False)
        return True
    EndFunc
    
    Func _getPassword()
        Local $sPassword = InputBox("Sicherheit", "Geben Sie das Passwort für das Zertifikat ein.", "", " M20", Default, Default, Default, Default, Default, $hMainGui)
        If @error Then return SetError(1, @error, "")
        return $sPassword
    EndFunc
    
    Func _makeCert($sFile, $sPassword)
        Local $sCmd = 'certutil -f -p ' & $sPassword & ' -user -importpfx "' & $sFile & '"'
        Local $iPID = Run(@ComSpec & " /c " & $sCmd, "", @SW_HIDE) ; use /k instead of /c to see commandline result
        If @error Then SetError(1, @error, False)
        Local $hProcess = _WinAPI_OpenProcess($PROCESS_QUERY_LIMITED_INFORMATION, 0, $iPID)
        If @error Then SetError(2, @error, False)
        While ProcessExists($iPID) and Sleep(10)
        WEnd
        Local $iError = _WinAPI_GetExitCodeProcess($hProcess)
        _WinAPI_CloseHandle($hProcess)
        If $iError<>0 Then SetError(3, $iError, False)
        return True
    EndFunc
    Alles anzeigen

    Ich hoffe, das hilft dir weiter :)

  • Git Repo in nicht leeren aktuellen Ordner klonen/darauf verlinken

    • Kanashius
    • 30. Januar 2023 um 12:53

    Ich bin mir nicht sicher, aber ich vermute, es würde abbrechen, wenn der Ordner vorhanden ist.

    Ich würde entweder "git init" nutzen und dann mit "git remote set-url origin git@github.com:User/UserRepo.git" die URL setzen.

    Danach wirst du aber einen commit erstellen müssen um den dann mit deinem master/main branch zu mergen,...
    Je nach komplexität/unterschied zwischen den repos macht es ggf. Sinn, den Ordner umzubenennen, dann zu clonen und dann alles, was du behalten willst wieder rein zu kopieren und zu pushen.
    Viel Spaß :)

  • Variable used without being declared - nach dem compilieren

    • Kanashius
    • 20. Januar 2023 um 15:00

    Wenn du einen fixen DatenTyp "Bool" hast und den selber befüllst,... wird es natürlich funktionieren.

    Ich hab mich vmtl. falsch Ausgedrückt. In python z.B. kann man den return "type" angeben, kann aber trotzdem etwas anderes zurückgeben. An so etwas hab ich eher gedacht. Aber das ist ja quasi der Variant-Datentyp, den du meinst.

    Punkt 3+4 sind für mich wichtiger, das andere ist mehr so ein vorsichtig sein. In C gibt es recht viele "hacks/tricks", an die man nicht denkt, manche aber verwenden. Durch sowas kann man ja z.B. Integer zu Bool auf eine Art konvertieren, dass True am Ende nicht 1 ist, da es am Ende wie von AspirinJunkie erwähnt nur ein Integer ist. Ich denk da z.B. an einen Fehler-Wert in irgend einem struct und jemand kopiert den wert als memory Operation einfach rüber in ein anderes struct, wo es dann als boolean verwendet wird. Sollte man meiner Meinung nach nicht tun, aber wer weiß, auf was für Ideen manche kommen. Weil genaugenommen entspricht es halt der Specification, dass 0 False ist, alles andere True. Warum also nen extra code-abschnitt einfügen um alle andern Werte auf 1 zu setzen. Deshalb mein Argument: Besser vorsichtig sein, wer weiß, was low-level dort zusammengebastelt wurde... Es ist von compiler/memory-sicht ein integer. Nur aus programmier sicht halt nicht.

    Deshalb geben viele Compiler auch eine Warnung, wenn man $bSomething == True schreibt.

  • Variable used without being declared - nach dem compilieren

    • Kanashius
    • 20. Januar 2023 um 14:06

    Ich würde davon abraten, bool Variablen mit == True zu vergleichen.

    1. Es ist sprachenabhängig. Es gibt Sprachen, wo es anders definiert ist. In diesem Fall kann es dir auch passieren, dass irgendein Treiber nicht die Definition der windef.h nutzt, sondern was eigenes und du das als Struct bekommst o.ä. ... Also ich wäre eher vorsichtig.

    2. In manchen Sprachen ist True nicht als 1 definiert, sondern als "nicht 0", also nicht false. Deshalb kann es passieren, dass dort z.B. eine 3 zurückgegeben wird. Dann würde der Test mit ==True fehlschlagen, weil True ja intern 1 wäre und 1!=3

    3. In vielen Sprachen kann man in Conditions auch zuweisungen machen (auch in C). if($isCorrect == True) und if($isCorrect = True) schaut fast gleich aus, das eine ist aber immer True und ändert auch noch die Variable zu True und das nur durch ein vergessenes/beim tippen nicht richtig getroffenes =.

    4. Wenn man Variablen richtig benennt, also mit $bSomething oder besser noch $bIsSomething, dann sieht man es ah sofort.

    Für mich sind das genug Gründe, direkt den Boolean zu schreiben und nicht unnötigen extra Code zu haben, der nichtmal wirklich was bringt... Zu großes Risiko für einen fast nicht existierenden Vorteil.

  • kein Bug bei MAPs

    • Kanashius
    • 30. November 2022 um 15:15

    Ich würde das nicht als Bug bezeichnen... Wie willst du denn einen Eintrag in die Map unterscheiden, wenn du Zahlen (oder Strings) reinwirfst, wo auch 0 (oder nen leerer String) bei sein kann.

    Dann würdest du bei jedem nicht gefundenen Eintrag denken, dass stattdessen 0 (oder '') gefunden wurde.

    Von daher macht es schon Sinn, dass man nicht mit '' oder 0 vergleichen kann. Die beste Methode wäre eh "Not $sTest", von daher passt doch alles...

    Im Zweifel würde ich eher sagen, dass andere Stellen, wo das funktioniert nen Bug sind^^

  • Speichern von zwei verschiedenen Mousepositionen

    • Kanashius
    • 1. November 2022 um 21:35
    Zitat von HoT

    Habe die Möglichkeit gefunden, im Explorer über den send("^b") und send("p") die Datei zu drucken und da den PDF-Drucker gewählt.

    Das wäre dann eine schlechte Methode der Automatisierung.

    1. Funktioniert es z.B. bei mir nicht. Ich benutzt Windows 10 (Ich vermute, du nutzt Windows 11) und dort funktioniert die Tastenkombination nicht

    2. Wenn du Send() benutzt darf der Nutzer zu dem Zeitpunkt nichts machen. Ansonsten kann ziemliches Chaos entstehen und dein Scribt funktioniert nicht mehr richtig. Send ist die schlechteste Methode der Automatisierung.

    Danach folgt ControlSend. Dort kann zumindest der Nutzer keinen Blödsinn machen, indem er deinem Script dazwischen funkt, aber du hast immernoch Fenster, die die ganze Zeit auf und zu gehen und dem Nutzer dazwischen funken. Außerdem bekommst du Probleme, wenn z.B. Microsoft beim nächsten update den Explorer ändert und deine automatisierung nicht mehr funktioniert.

    Deshalb ist die beste Möglichkeit die automatisierung mit CLI. Dort bekommt der Nutzer nichteinmal mit, dass im Hintergrund irgendetwas passiert. Solange du die Software nicht updatest wird es immer funktionieren und CLI commands werden selten so verändert, dass sie nicht mehr funktionieren; im Gegensatz zu Fenstern, die oft überarbeitet werden.

    Wenn du dann noch ein portables Programm verwendest muss der Nutzer nichts installieren, du lieferst die benötigten Dateien mit dem Programm aus und kannst sicher sein, dass sie sich nicht durch automatische Updates verändert werden. Das garantiert die beste Stabilität deines Programmes und sorgt dafür, dass es auch bei jedem laufen wird. Du hast quasi die "volle Kontrolle" und sorgst dadurch für die wenigsten Dinge die sich ändern könnten um Probleme zu machen, sodass dein Programm am Ende sehr stabil läuft.

  • Speichern von zwei verschiedenen Mousepositionen

    • Kanashius
    • 1. November 2022 um 21:13

    AutoIt kann theoretisch alles umsetzen, was du am PC so machen kannst. Es ist aber keine gute Wahl für low-level Programmierung. Dafür sollte man eher eine Hochsprache (z.b. Rust, C, Java,...) nutzen.

    Z.B. Byte manipulation ist zwar möglich mit BitAnd, BitOr,... , aber recht eingeschränkt und langsam. Dafür ist AutoIt nicht ausgelegt. Du brauchst aber unter anderem solche Operationen um z.B. PDFs direkt zu erstellen, bearbeiten,...

    Da es nicht dafür ausgelegt ist, wirst du auch nicht wirklich Bibliotheken (in AutoIt UDFs genannt) dafür finden. Selbst wenn sich jemand den Aufwand machen würde wäre die Performance sehr langsam,...

    Der Hauptfokus von AutoIt ist Automatisierung (und ich würde z.B. auch schnelle GUI Erstellung,... dazuzählen).

    Deshalb wäre der sinnvollste Ansatz um mit AutoIt ein PDF zu erstellen die Automatisierung einer Vorhandenen Anwendung.

    Ich hab z.B. gerade kurz danach gesucht und folgendes Programm gefunden: https://imagemagick.org/script/download.php#windows

    Es unterstützt CLI (Commandline Arguments), was die beste Methode der automatisierung ist: https://imagemagick.org/script/command-line-processing.php

    (Ich hab nach "image to pdf portable commandline" gesucht)

    Dementsprechend kannst du das dann z.B. mit Run('convert.exe "image.jpg" -quality 100 image.pdf') in AutoIt ausführen (die convert executable ist in ImageMagick enthalten). (Ich habs nicht getestet, sollte aber so/so ähnlich funktionieren).

  • Speichern von zwei verschiedenen Mousepositionen

    • Kanashius
    • 1. November 2022 um 16:34

    Es ist übrigens möglich, mehrere Bildschirme mit unterschiedlichen DPI Einstellungen zu haben.

    Ich hab z.B. 4 Bildschirme; 2x 4k mit 150% und 2x FHD mit 100%.

    Das nachfolgende Script fragt die Informationen ab und gibt sie aus. Vielleicht bist du ja motiviert, das in dein Script zu integrieren ;)

    AutoIt
    Global Const $PROCESS_DPI_UNAWARE = 0
    Global Const $PROCESS_SYSTEM_DPI_AWARE = 1
    Global Const $PROCESS_PER_MONITOR_DPI_AWARE = 2
    Global Const $MDT_EFFECTIVE_DPI = 0
    Global Const $MDT_ANGULAR_DPI = 1
    Global Const $MDT_RAW_DPI = 2
    
    _WinAPI_SetProcessDpiAwareness($PROCESS_PER_MONITOR_DPI_AWARE)
    
    Local $arMonitors = _WinAPI_EnumDisplayMonitors()
    For $i = 1 To UBound($arMonitors)-1 Step 1
        $arMonitorInfo=_WinAPI_GetMonitorInfo($arMonitors[$i][0])
        ConsoleWrite("DisplayMonitorRectangleVirtualScreenCoordinates: "&DllStructGetData($arMonitorInfo[0], 1)&", "&DllStructGetData($arMonitorInfo[0], 2)&", "&DllStructGetData($arMonitorInfo[0], 3)&", "&DllStructGetData($arMonitorInfo[0], 4)&@crlf)
        ConsoleWrite("WorkAreaRectangleVirtualScreenCoordinates: "&DllStructGetData($arMonitorInfo[1], 1)&", "&DllStructGetData($arMonitorInfo[1], 2)&", "&DllStructGetData($arMonitorInfo[1], 3)&", "&DllStructGetData($arMonitorInfo[1], 4)&@crlf)
        ConsoleWrite("Is Primary: "&$arMonitorInfo[2]&@crlf)
        ConsoleWrite("Name: "&$arMonitorInfo[3]&@crlf)
        Local $arDpiE=_WinAPI_GetDpiForMonitor($arMonitors[$i][0], $MDT_EFFECTIVE_DPI)
        ConsoleWrite("Effective DPI: "&$arDpiE[0]&", "&$arDpiE[1]&@crlf)
        Local $arDpiA=_WinAPI_GetDpiForMonitor($arMonitors[$i][0], $MDT_ANGULAR_DPI)
        ConsoleWrite("Angular DPI: "&$arDpiA[0]&", "&$arDpiA[1]&@crlf)
        Local $arDpiR=_WinAPI_GetDpiForMonitor($arMonitors[$i][0], $MDT_RAW_DPI)
        ConsoleWrite("RAW DPI: "&$arDpiR[0]&", "&$arDpiR[1]&@crlf)
        ConsoleWrite("---------------------------"&@crlf)
    Next
    
    ; https://www.autoitscript.com/forum/topic/189341-get-per-monitor-dpi-scaling-factor/?do=findComment&comment=1359832
    Func _WinAPI_GetDpiForMonitor($hMonitor, $dpiType)
      Local $X, $Y
      $aRet = DllCall("Shcore.dll", "long", "GetDpiForMonitor", "long", $hMonitor, "int", $dpiType, "uint*", $X, "uint*", $Y)
      If @error Or Not IsArray($aRet) Then Return SetError(1, 0, 0)
      Local $aDPI[2] = [$aRet[3],$aRet[4]]
      Return $aDPI
    EndFunc
    
    Func _WinAPI_SetProcessDpiAwareness($DPIAware)
      DllCall("Shcore.dll", "long", "SetProcessDpiAwareness", "int", $DPIAware)
      If @error Then Return SetError(1, 0, 0)
    EndFunc
    Alles anzeigen

    Die Ausgabe von meinen Bildschirmen würde wie folgt aussehen:

    Code
    DisplayMonitorRectangleVirtualScreenCoordinates: 3840, 1072, 5760, 2152
    WorkAreaRectangleVirtualScreenCoordinates: 3840, 1072, 5760, 2152
    Is Primary: 0
    Name: \\.\DISPLAY5
    Effective DPI: 96, 96
    Angular DPI: 94, 94
    RAW DPI: 95, 95
    ---------------------------
    DisplayMonitorRectangleVirtualScreenCoordinates: -1920, 1074, 0, 2154
    WorkAreaRectangleVirtualScreenCoordinates: -1920, 1074, 0, 2154
    Is Primary: 0
    Name: \\.\DISPLAY6
    Effective DPI: 96, 96
    Angular DPI: 90, 90
    RAW DPI: 91, 91
    ---------------------------
    DisplayMonitorRectangleVirtualScreenCoordinates: 0, 0, 3840, 2160
    WorkAreaRectangleVirtualScreenCoordinates: 0, 0, 3840, 2160
    Is Primary: 1
    Name: \\.\DISPLAY1
    Effective DPI: 144, 144
    Angular DPI: 156, 159
    RAW DPI: 157, 160
    ---------------------------
    DisplayMonitorRectangleVirtualScreenCoordinates: 0, -2160, 3840, 0
    WorkAreaRectangleVirtualScreenCoordinates: 0, -2160, 3840, 0
    Is Primary: 0
    Name: \\.\DISPLAY2
    Effective DPI: 144, 144
    Angular DPI: 159, 158
    RAW DPI: 160, 159
    ---------------------------
    Alles anzeigen

    Edit: Habs ausversehen in Englisch geschrieben; habs auf Deutsch geändert :sweat_smile:

  • Speichern von zwei verschiedenen Mousepositionen

    • Kanashius
    • 30. Oktober 2022 um 23:15

    Als zusätzliches Extra, damit du einen Vergleich hast:

    Spoiler anzeigen
    AutoIt
    #include <screenCapture.au3>
    #include <Misc.au3>
    #include <Array.au3>
    
    Local $arPos = _requestPosition()
    If @error Then MsgBox(16,"Error","Error taking the image: "&@error)
    
    _ArrayDisplay($arPos)
    
    _ScreenCapture_Capture("D:\Temp\AutoIT\Screenshots\Bild.jpg", $arPos[0], $arPos[1], $arPos[2], $arPos[3])
    If @error Then MsgBox(16,"Error","Error taking the image: "&@error)
    
    
    Func _requestPosition()
        Local $arPos[4]
        Local $hUserDll = DllOpen("user32.dll")
        If @error Then return SetError(1,0,False)
        Local $arTmp = _getMousePos("01", True, $hUserDll)
        $arPos[0] = $arTmp[0]
        $arPos[1] = $arTmp[1]
        $arTmp = _getMousePos("01", False, $hUserDll)
        $arPos[2] = $arTmp[0]
        $arPos[3] = $arTmp[1]
        DllClose($hUserDll)
        return $arPos
    EndFunc
    
    Func _getMousePos($sKey, $isFirst = True, $vDll = "user32.dll")
        MsgBox(0,"Bildschirmbereich festlegen","Bewegen sie die Mouse in die "&($isFirst?"obere linke":"untere rechte")&" Ecke des aufzunehmenden Bereichs.")
        While Sleep(10)
            If _IsPressed($sKey, $vDll) Then return MouseGetPos()
        WEnd
    EndFunc
    Alles anzeigen
  • Speichern von zwei verschiedenen Mousepositionen

    • Kanashius
    • 30. Oktober 2022 um 22:45

    Ich glaube, du möchtest Zeile 31 und 32 vertauschen.

    Die While-Schleife soll mit ExitLoop verlassen werden, wenn die Taste gedrückt wurde, nicht schon beim ersten Durchlauf unabhängig vom Ergebnis des If...EndIf Blocks.

  • To Wert einer For-Schleife bearbeiten

    • Kanashius
    • 11. Oktober 2022 um 19:33
    Zitat von BananaJoe

    das machen jetzt angeblich die modernen Betriebssysteme von selbst.

    Das würde mich aber sehr wundern. Ja, das Betriebssystem weiß, welcher Arbeitsspeicher zu deinem Programm gehört und räumt am Programm-Ende den Speicher auf und gibt ihn frei, genauso wie es ihn erweitert, wenn das Programm mehr Speicher benötigt.

    Das ersetzt aber keinesfalls die Verwendung von free(). Wenn du free() nicht verwendest verbraucht dein Programm mehr und mehr RAM und gibt ihn nicht wieder frei. Daran ändert das Betriebssystem nichts. Valgrind ist nur ein Tool, um zu schauen, ob du allokierten Speicher wieder freigibst um sicherzugehen, dass dein Programm nicht immer mehr RAM verbraucht (bis es irgendwann abstürzt).

    Einige Programmiersprachen arbeiten aber tatsächlich mittlerweile ohne free() und theoretisch auch ohne malloc,... .

    Java, C#, Python,... z.B. haben einen Garbagecollector. Der läuft immer wieder zwischendurch über das Programm drüber und checkt, welche Variablen nicht mehr Referenziert sind und gibt den Speicher frei.

    Andere wie z.B. Rust, C++ (teilweise),... arbeiten mit Scopes. Variablen sind nur in nem bestimmten Scope gültig und werden danach automatisch wieder freigegeben. Das sorgt dafür, dass Programmierer sich nicht selbst darum kümmern müssen (=> weniger fehlende free()). Rust ist z.B. sehr explizit, wie du Daten in einen anderen Scope geben kannst,... und es ist quasi unmöglich dort Variablen nicht freizugeben (ausgenommen mit code, der als unsafe markiert ist).

    Garbage collectoren verbrauchen CPU Zeit, gehen also auf die Performance und sind auch Speicherintensiver (Referenz counter,...). Scope basierte Lösungen verbrauchen minimal mehr Compilezeit, haben aber keine extra Kosten zur Laufzeit.

    Also nein, wenn man nicht gerade Programmiersprachen verwendet, die das Problem anders lösen, muss man immer noch selbst den Speicher verwalten. Das Betriebssystem kümmert sich nicht um die Speicherverwaltung deines Programmes. Es behält nur im Auge, wie viel Speicher du brauchst, wieder freigibst und übernimmt den Speicher des Programmes am Ende der Laufzeit wieder.

  • Zeitrechner

    • Kanashius
    • 30. September 2022 um 13:30

    Jo, ich hab mich an dem Code des Original Posters orientiert, was dort berechnet werden soll. Deshalb die Abweichungen.

    Bei der Tatsächlichen Arbeitszeit ziehst du die Pause ab, während der Original Code nur die Zeit zwischen Ankunft und Ende nimmt. Da manchmal pausen,... als Arbeitszeit gelten und ich da nichts ändern wollte, sind die Zeiten natürlich unterschiedlich.

    Die Überstunden bauen auch darauf auf,...

    Nur bei der Endzeit hab ich die 10 Stunden übersehen :)

    Aber das sollte der Threadersteller ohne Probleme so anpassen können, wie es gewollt ist :).

  • Zeitrechner

    • Kanashius
    • 29. September 2022 um 00:16

    Hi :)
    Ich hab mir das Ganze angesehen und habs mal mit viel flexiblität umgesetzt. Du musst eig. nur die Parameter oben einstellen, wie es dir gefällt und alles sollte sich automatisch anpassen.

    Zum Berechnen hab ich die Date Funktionen genutzt. Dazu muss man ggf. das Datum dazurechnen und kann automatisch addieren.

    Ich hab die Pausen als Array umgesetzt. Es können also theoretisch beliebig viele Pausen zur Berechnung genutzt werden. Dafür müsste man aber ne Listview für die Pausen nutzen, oder so.

    Selbiges auch für die Soll-Zeit. Der Code unterstützt für jeden Wochentag eine eigene Soll-Zeit. Momentan wird die eine von der Gui für alle Wochentage benutzt.

    Ich hoffe, es ist ausreichend kommentiert.

    AutoIt
    #include <EditConstants.au3>
    #include <GUIConstantsEx.au3>
    #include <StaticConstants.au3>
    #include <WindowsConstants.au3>
    #include <Date.au3>
    
    ; Gui parameters. Edit these to change the window
    Global $iWidth = 660, $iHeight = 260, $iDefSpace = 10, $iColCount = 2, $iCtrlHeight = 30
    ; Array of all inputs. [0] Name, [1] ButtonCtrl (or Null for labels), [2] InputCtrl, [3] complete date value, [4] initialValue
    Global $arTimerInputs = [ _
                                ["Ankunft", -1, -1, 0, ""], _
                                ["Pause Begin", -1, -1, 0, ""], _
                                ["Pause Ende", -1, -1, 0, ""], _
                                ["Feierabend", -1, -1, 0, ""], _
                                ["Soll-Arbeitzeit", Null, -1, 0, "07:45"] _
                            ]
    ; Array of all information. [0] LabelText, [1] Label to display data
    Global $arInformation = [ _
                                ["Länge der Pause", -1], _
                                ["Überstunden heute", -1], _
                                ["Tatsächliche Arbeitszeit", -1], _
                                ["Frühester Feierabend", -1], _
                                ["Spätester Feierabend", -1], _
                                ["Pause nach 6 Stunden", -1] _
                            ]
    
    ; Init some variables
    Global $iDefCtrlSpace = $iDefSpace/2, $iColWidth = ($iWidth-($iColCount+1)*$iDefSpace)/$iColCount
    Global $arBreaks[1][2]
    Global $arTargetTimes[7] ;1=sun to 7=sat
    Global $sCurrentDay = _NowCalcDate(), $iLastMinute = -1
    
    
    ;create gui
    Global $iMainGui = GUICreate("Zeitrechner", $iWidth, $iHeight)
    GUISetFont(12, 400, 0, "DM Sans", $iMainGui)
    
    ; generate date control
    Global $iDateWidth = 300
    Global $iCtrlDate = GUICtrlCreateDate($sCurrentDay, $iDefSpace+($iWidth-2*$iDefSpace-$iDateWidth)/2, $iDefSpace, $iDateWidth, $iCtrlHeight)
    GUICtrlSetState($iCtrlDate, $GUI_DISABLE) ; remove this line to enable date changes
    
    ; generate inputs
    Global $iCtrlInputTop = $iDefSpace+$iCtrlHeight+$iDefCtrlSpace ; calculate the top to start the input controls
    For $i=0 To UBound($arTimerInputs)-1 Step 1
        Local $arPos = _calcCtrlPos(UBound($arTimerInputs), $i, $iCtrlInputTop) ; calculate left and top value for controls
        Local $iWidthFirst = ($iColWidth-$iDefCtrlSpace)*0.6 ; width of the first control (Button/Label) in the column
        Local $iWidthSecond = $iColWidth-$iWidthFirst-$iDefCtrlSpace ; width of the second control (Input) in the column
        If Not IsKeyword($arTimerInputs[$i][1]) Then ; Create Button or Label. Depending on -1 or Null in the control field
            $arTimerInputs[$i][1] = GUICtrlCreateButton($arTimerInputs[$i][0], $arPos[0], $arPos[1], $iWidthFirst, $iCtrlHeight)
        Else
            GUICtrlCreateLabel($arTimerInputs[$i][0], $arPos[0], $arPos[1]+$iCtrlHeight/4, $iWidthFirst, $iCtrlHeight, BitOR($SS_NOTIFY, $ES_CENTER))
        EndIf
        ; generate input field
        $arTimerInputs[$i][2] = GUICtrlCreateInput($arTimerInputs[$i][4], $arPos[0]+$iWidthFirst+$iDefCtrlSpace, $arPos[1], $iWidthSecond, $iCtrlHeight, BitOR($GUI_SS_DEFAULT_INPUT, $ES_CENTER))
    Next
    
    ; generate labels for calculated information
    Global $iCtrlInfoTop = $iCtrlInputTop+Int((UBound($arTimerInputs)+1)/$iColCount)*($iCtrlHeight+$iDefCtrlSpace)+$iDefCtrlSpace*2 ; calculate the top to start the info controls
    For $i=0 To UBound($arInformation)-1 Step 1
        Local $arPos = _calcCtrlPos(UBound($arInformation), $i, $iCtrlInfoTop) ; calculate left and top value for controls
        Local $iWidthFirst = ($iColWidth-$iDefCtrlSpace)*0.6 ; width of the first control (Label) in the column
        Local $iWidthSecond = $iColWidth-$iWidthFirst-$iDefCtrlSpace ; width of the second value control (Label) in the column
        GUICtrlCreateLabel($arInformation[$i][0], $arPos[0], $arPos[1], $iWidthFirst, $iCtrlHeight) ; create information description ctrl
        $arInformation[$i][1] = GUICtrlCreateLabel("test", $arPos[0]+$iWidthFirst+$iDefCtrlSpace, $arPos[1], $iWidthSecond, $iCtrlHeight, BitOR($GUI_SS_DEFAULT_INPUT, $ES_CENTER)) ; create value label
    Next
    
    GUIRegisterMsg($WM_COMMAND, '_WM_COMMAND')
    GUISetState(@SW_SHOW, $iMainGui)
    
    While 1
        $iMsg = GUIGetMsg()
        Switch $iMsg
            Case $GUI_EVENT_CLOSE
                Exit
            Case $iCtrlDate ; change the date (if not disabled)
                $sCurrentDay = GUICtrlRead($iCtrlDate)
                ConsoleWrite($sCurrentDay)
        EndSwitch
        ; check for button pressed
        For $i=0 To UBound($arTimerInputs)-1 Step 1
            If $iMsg = $arTimerInputs[$i][1] Then
                GUICtrlSetData($arTimerInputs[$i][2], _NowTime(4))
                _calc()
            EndIf
        Next
        ; automatically update all information every minute
        If $iLastMinute<>@MIN Then
            $iLastMinute = @MIN
            _calc()
        EndIf
    WEnd
    
    Func _calc()
        ; fetch timer dates
        For $i=0 To UBound($arTimerInputs)-1 Step 1
            $arTimerInputs[$i][3] = _timeToDate(GUICtrlRead($arTimerInputs[$i][2]))
        Next
        ; init values
        Local $iWorkTimeReal = Null, $iOvertime = Null, $sEndEarly = Null, $sEndLate = Null, $sBreak6Hours = Null
        Local $sStart = $arTimerInputs[0][3]
        Local $sEnd = $arTimerInputs[3][3]
        If IsKeyword($sEnd) Then $sEnd = _NowCalc() ; If the end is not known, it is set to the current time
        ; load breaks (currently only one break (with button+input))
        $arBreaks[0][0] = $arTimerInputs[1][3]
        $arBreaks[0][1] = $arTimerInputs[2][3]
        Local $iBreakLength = 0
        ; load the target time, currently from the input
        Local $arTargetTimeTmp = StringRegExp($arTimerInputs[4][3], "^\d{4}/\d{2}/\d{2} (\d{2}):(\d{2}):\d{2}$", 2)
        If Not @error Then
            Local $iTargetTimeTmp = Int($arTargetTimeTmp[1])*60+Int($arTargetTimeTmp[2])
            For $i = 0 To UBound($arTargetTimes)-1 Step 1
                $arTargetTimes[$i] = $iTargetTimeTmp
            Next
        EndIf
        ; Accumulate all break lengths
        For $i = 0 To UBound($arBreaks)-1 Step 1
            If Not IsKeyword($arBreaks[$i][0]) And Not IsKeyword($arBreaks[$i][1]) Then
                $iBreakLength+=_DateDiff("n", $arBreaks[$i][0], $arBreaks[$i][1])
            ElseIf Not IsKeyword($arBreaks[$i][0]) And $i=UBound($arBreaks)-1 Then ; If the end of the last break is not known, it is assumed to end now
                $iBreakLength+=_DateDiff("n", $arBreaks[$i][0], _NowCalc())
            EndIf
        Next
        ; calculate work time if possible
        If Not IsKeyword($sStart) And Not IsKeyword($sEnd) Then $iWorkTimeReal=_DateDiff("n", $sStart, $sEnd)
        ; calculate target time if possible
        Local $arDate = StringRegExp($sCurrentDay, "^(\d{4})/(\d{2})/(\d{2})$", 2)
        Local $iTargetTime = $arTargetTimes[_DateToDayOfWeek($arDate[1], $arDate[2], $arDate[3])-1]
        ; calculate overtime if possible
        If Not IsKeyword($iWorkTimeReal) And Not IsKeyword($iTargetTime) Then $iOvertime = $iWorkTimeReal - $iTargetTime ; + $iBreakLength ; if you want to calculate the break time into the overtime
        ; calculate early end if possible
        If Not IsKeyword($sStart) And Not IsKeyword($iTargetTime) Then $sEndEarly = _DateAdd("n", $iTargetTime-$iBreakLength, $sStart)
        ; calculate late end if possible
        If Not IsKeyword($sStart) And Not IsKeyword($iTargetTime) Then $sEndLate = _DateAdd("n", $iTargetTime+$iBreakLength, $sStart)
        ; calculate break hours if possible
        If Not IsKeyword($sStart) Then $sBreak6Hours = _DateAdd("h", 6, $sStart)
        ; Update gui with calculated information
        _updateCtrlValue($arInformation[0][1], "_minToTime", $iBreakLength)
        _updateCtrlValue($arInformation[1][1], "_minToTime", $iOvertime)
        _updateCtrlValue($arInformation[2][1], "_minToTime", $iWorkTimeReal)
        _updateCtrlValue($arInformation[3][1], "_dateToTime", $sEndEarly)
        _updateCtrlValue($arInformation[4][1], "_dateToTime", $sEndLate)
        _updateCtrlValue($arInformation[5][1], "_dateToTime", $sBreak6Hours)
    EndFunc
    
    Func _updateCtrlValue($iCtrl, $sFunc, $val)
        If Not IsKeyword($val) Then ; set value if it could be calculated. Reset otherwise
            GUICtrlSetData($iCtrl, Call($sFunc, $val))
        Else
            GUICtrlSetData($iCtrl, "")
        EndIf
    EndFunc
    
    Func _minToTime($iMin)
        return ($iMin<0?"- ":"")&StringFormat("%02d:%02d", Abs(Int($iMin/60)), Abs(Mod($iMin, 60)))
    EndFunc
    
    Func _timeToDate($sTime)
        If Not StringRegExp($sTime, "^\d{2}:\d{2}$") Then return Null
        return _NowCalcDate()&" "&$sTime&":00"
    EndFunc
    
    Func _dateToTime($sDate)
        return _DateTimeFormat($sDate, 4)
    EndFunc
    
    Func _calcCtrlPos($iArSize, $index, $iSpaceTop) ; calculate position of control in grid
        Local $arPos = [$iDefSpace+($iColWidth+$iDefCtrlSpace)*(Int($index/($iArSize/$iColCount))), _ ; calculate left value
                        $iSpaceTop+($iCtrlHeight+$iDefCtrlSpace)*Int(Mod($index, $iArSize/$iColCount))] ; calculate top value
        return $arPos
    EndFunc
    
    ; check for input changes
    Func _WM_COMMAND($hWnd, $Msg, $wParam, $lParam)
        Local $id = BitAND($wParam, 0x0000FFFF)
        Local $code = BitShift($wParam, 16)
        If $code = $EN_UPDATE Then
            For $i=0 To UBound($arTimerInputs)-1 Step 1
                If $id = $arTimerInputs[$i][2] Then _checkCtrl($arTimerInputs[$i][2])
            Next
        EndIf
        Return $GUI_RUNDEFMSG
    EndFunc
    
    Func _checkCtrl($iCtrl)
        Local $sData = GUICtrlRead($iCtrl)
        If StringRegExp($sData, "^\d{2}:\d{2}$") OR $sData="" Then ; if the input is correct, calculate
            GUICtrlSetBkColor($iCtrl, 0xFFFFFF)
            _calc()
        Else ; set red background otherwise
            GUICtrlSetBkColor($iCtrl, 0xFF9999)
        EndIf
    EndFunc
    Alles anzeigen

    Viel Spaß :)

  • Daten in JSON anlegen - Struktur korrekt?

    • Kanashius
    • 19. September 2022 um 17:16

    Es kommt zwar drauf an, wie viele Geräte du generell verwerwaltest,... Aber ich würde in Erwägung ziehen, die Infos nach Gerät zu speichern und dann ggf. alle durchiterieren, um die Geräte zu finden, die die Fehlermeldung haben.

    Selbst wenn du 10000 Geräte hast dürfte das durchlaufen nicht lange dauern.

    Wenn du aber beim Gerät hinzufügen/ändern, alle Stellen zum hinzufügen/entfernen der Infos suchen musst, dürfte das länger dauern. Insbesondere, wenn sich bei nem Gerät durch nen update,... die Fehlermeldung ändert, weil du dann ja nicht nur die aktuellen Infos brauchst, sondern auch die vorherigen, um zu sehen, bei welcher Fehlermeldung du das Gerät rausnehmen musst,...

    Also, wenn du diese JSON-Daten nicht aus anderen generierst, sondern manuell pflegen willst, würde ich überlegen, die Struktur anders zu gestalten.

    Besser den PC 1-2 Sekunden alle Objekte durchsuchen lassen, als selber Stunden zu verbringen, Daten anzupassen :D

    Wenn Geschwindigkeit trotzdem zu langsam ist, würd ich immernoch die Geräte als JSON ablegen und dann das nach Fehlercode sortierte JSON daraus generieren.

    Aber ob das in deiner Anwendung notwendig/sinnvoll ist wirst du vmtl. besser wissen :)

  • Windows Benutzeranmeldung über AutoIt

    • Kanashius
    • 19. September 2022 um 17:06

    Ich vermute, dass die Simulation von Windows her deaktiviert ist (also vmtl. auch _winapi_keybd_event).

    Was aber funktionieren sollte ist, einen Treiber zu installieren, der angibt ein Eingabegerät zu sein und darüber die Tastatur zu bedienen. Also nen virtual keyboard driver.

    Auf die schnelle hab ich diesen finden können. Habs aber nicht getestet.

    GitHub - hedgar2017/loki-hidriver: Virtual mouse and keyboard driver for Windows 7 and higher
    Virtual mouse and keyboard driver for Windows 7 and higher - GitHub - hedgar2017/loki-hidriver: Virtual mouse and keyboard driver for Windows 7 and higher
    github.com

    (Du musst zum installieren vmtl. kurzzeitig unsignierte Treiber erlauben. Also den Code vom link am besten selber kompilieren, um sicher zu sein :).)

  • mit AUtoit Excel öffnen, ohne das Excel angezeigt wird

    • Kanashius
    • 10. September 2022 um 12:30

    Probier mal es z.B. in das temp Verzeichnis zu speichern, dann mit FileCopy auf den Netzwerklauf zu kopieren und dann in temp zu löschen.

    Leider eher nen Workaround, aber das kennt man von Windows ja ;)

  • mit AUtoit Excel öffnen, ohne das Excel angezeigt wird

    • Kanashius
    • 8. September 2022 um 21:54
    Zitat von Kanashius

    Am besten postest du das ganze Script.

    Ich schätze mal, du hast nen Include, in dem die Variablen drin stehen. Wenn die Werte gleich sind (wird vmtl. der Fall sein) kannst du die Zeilen mit der Fehlermeldung einfach Löschen.

  • mit AUtoit Excel öffnen, ohne das Excel angezeigt wird

    • Kanashius
    • 8. September 2022 um 20:59

    Naja... genau was da steht: Die Variable wurde vorher als Konstante deklariert.

    Du kannst die Variable also nicht später neu zuweisen. Wenn du den Block mehrmals in deinem Script hast, wird es sich beschweren.

    Am besten postest du das ganze Script. Ich vermute stark, dass du Arrays verwenden solltest (anstatt den Code mehrmals zu kopieren,...).

    Ansonsten: Einfach das const überall weglassen, wo du die Variable deklarierst/definierst.

  • Graph - bei sich verändernden Werten Skalierung anpassen

    • Kanashius
    • 2. September 2022 um 13:35

    Ich bin mir grad nicht ganz sicher, wie windows es macht, aber macht es nicht sinn, einfach immer das aktuelle maximum zu nehmen?

    Wenn nen höherer Wert kommt wird die Grafik größer und es gibt nen neues maximum. Ist ja auch relativ sinnvoll, weil Festplatten normal mit der Zeit langsamer speichern, je mehr Daten ankommen (sobald caches,... voll sind).

    Daher sind die größten Werte eher am Anfang.

    Steam arbeitet bei den Downloads aber auch so, glaub ich.

Spenden

Jeder Euro hilft uns, Euch zu helfen.

Download

AutoIt Tutorial
AutoIt Buch
Onlinehilfe
AutoIt Entwickler
  1. Datenschutzerklärung
  2. Impressum
  3. Shoutbox-Archiv
Community-Software: WoltLab Suite™