Beiträge von AspirinJunkie
-
-
kommen nicht alle Programme mit Netzlaufwerksverknüpfungen auf lokale Ordner klar.
Nur eine Vermutung: Wenn du ein Netzlaufwerk eingerichtet hast, dann gilt das erst einmal nur für den User.
Wenn du dann ein Programm mit Administratorrechten startest, sieht dieses das Laufwerk nicht, da es nicht für den Admin gemountet ist.
Vielleicht könnte es so eine Situation bei dir sein?
-
aber bei den Tests dazu bisher keinen Unterschied gemerkt ob ich StdoutRead durchschleife oder nicht 🤔 .
Wenn keine Sonderzeichen vorkommen dann brauchst du es nicht.
Mach mal ein dir in einem Ordner, welcher Dateien mit Umlauten im Namen enthält - StdOutRead versaut hierbei die Kodierung.In eine wiederverwendbare Funktion gehört sowas rein.
-
Ich dachte schon ich übertreibe bisschen mit meinem Anspruch das etwas fundierter zu berechnen aber ich hatte wie so oft nicht mit dir gerechnet...
In deiner stochastischen Analyse gehst du von einer Gleichverteilung der Buchstaben aus. Das ist quasi "genau in die andere Richtung" und sollte ein wenig zu kleine Ergebnisse liefern.
Ja das stimmt tatsächlich und ging mir auch durch den Kopf.
Das habe ich allerdings überhaupt nicht in Angriff genommen, da ich schon mit der einfacheren Stochastik hier zu kämpfen hatte.
Das Problem ist nämlich kniffliger als man erst annimmt. Das Problem ist, dass die Anzahl der Versuche nicht fest ist, sondern nur bei Fehlversuchen gezählt werden.
Am Ende habe ich einen Ansatz gefunden, welcher halbwegs stimmen sollte aber der Einfachheit halber, habe ich auch hier einen bestimmten Aspekt unterschlagen so dass die Wahrscheinlichkeiten nicht die 100% korrekten darstellen.
Um deine Erweiterung mit den Buchstabenhäufigkeiten noch zu verkomplizieren mal noch ein anderer Gedanke hierzu:
Prinzipiell müsste man erst einmal ermitteln mit welcher Wahrscheinlichkeit Nutzer Buchstaben zufällig auswählen.
Dies unterscheidet sich ja noch von der tatsächlichen Buchstabenhäufigkeit für die es bereits hinreichende empirische Daten gibt. -
bekomme ich einen Fehler
Und Fehler sollten eigentlich von jedem Kommandozeilenprogramm nicht auf stdout ausgeben sondern auf stderr.
git macht das auch brav und deshalb bekommst du das nicht mit, da du bei deinem Run-Aufruf lediglich $STDOUT_CHILD gesetzt hast.
Also entweder $STDERR_CHILD setzen und den Stream noch mit StdErrRead() auslesen oder alternativ statt $STDOUT_CHILD $STDERR_MERGED setzen, dann sollte sich das auch über StdOutRead mit auslesen lassen.
Ansonsten noch 3 Hinweise:- git ist kein Befehl der cmd.exe sondern ein eigenständiges Programm. Es ist daher unsinnig es erst indirekt über den Umweg @comspec & "/c " aufzurufen.
- Ich empfehle um Probleme mit der Zeichenkodierung zu umgehen prinizpiell alles was von stdoutread kommt noch durch _WinAPI_OemToChar() zu schleifen.
- Du musst StdOutRead() nicht unbedingt in einer Schleife ausführen. Es würde auch reichen den Prozess rödeln zu lassen und mit ProcessWaitClose() auf dessen Ende zu warten. Danach nur einmal StdOutRead() auf die Prozess-ID. Also so etwa:
AutoIt
Alles anzeigen#include <AutoItConstants.au3> #include <WinAPIConv.au3> $Status = _GitStatus('C:\Users') MsgBox(0,"<< Status >>", $Status) Func _GitStatus($sPath) Return _CMDLineRead('git status', False, $sPath, $STDERR_MERGED) EndFunc ; run cmdline-commands and return their output Func _CMDLineRead($sCmd, $bComspec = False, $sWorkDir = '', $oFlags = $STDOUT_CHILD) Local $iPID = Run(($bComspec ? '"' & @ComSpec & '" /c ' : "") & $sCmd, $sWorkDir, @SW_Hide, $oFlags) ProcessWaitClose($iPID) Return _WinAPI_OemToChar(StdoutRead($iPID)) EndFunc
-
Allerdings darf ich auch bekannt geben, dass sich keines der Programme/Skripte bisher so verhält wie ich es "versucht habe" in den Vorgaben zu beschreiben/vorzugeben
Das war an 2 Stellen bei mir auch bewusst so gemacht.
- Die vorgebene Wortliste - gefiel mir einfach nicht, weswegen ich die Online-API genommen habe (damit ist aber auch die Kategorieangabe raus)
- Die Anzahl der Versuche richtet sich nach dem zufällig ausgewähltem Wort:
Die Methodik der Verdopplung war für mich hierbei fachlich nicht nachvollziehbar.
Denn: Wenn ein Wort 9 verschiedene Buchstaben hat, dann ist die Anzahl der maximalen Fehlversuche 18.
Das bedeutet, dass man schlicht gar nicht mehr verlieren kann, da es mehr Fehlversuche gibt als mögliche Fehlbuchstaben.
Daher schlage ich einen Ansatz vor, welcher versucht die Wahrscheinlichkeit, dass man in der vorgegebenen Anzahl an Ziehungen das Lösungswort zufällig richtig zieht, über alle Buchstabenanzahlen hinweg halbwegs konstant zu halten.
Mein Vorschlag (mit nicht ganz trivialer Stochastik) zur Berechnung der Anzahl der Fehlversuche wäre daher hierzu folgender:
Spoiler anzeigen
AutoIt
Alles anzeigen$sWord = "blablablub" $nDistinctChars = StringLen(StringRegExpReplace($sWord, '(?i)(.)(?!.*\1)', '')) $nVersuche = _getSteps($nDistinctChars, 0.005) $nVersuche = $nVersuche > (26 - $nDistinctChars) ? 26 - $nDistinctChars - 1 : $nVersuche ConsoleWrite($nVersuche & @CRLF) ; berechnet die Anzahl an Fehlversuchen um eine Mindestwahrscheinlichkeit $nPMind zu erreichen ; diese gibt an wie wahrscheinlich es ist das Wort mit $n verschiedenen Buchstaben zufällig zu erraten Func _getSteps($n, $nPMind = 0.005) Local $nP For $k = $n To 25 ; Wahrscheinlichkeit, dass man in $k zufällige Züge die $n richtigen Buchstaben erwischt: $nP = _calcProb($k, $n) If $nP > $nPMind Then Return $k Next EndFunc ; berechnet die Wahrscheinlichkeit alle $k korrekten Elemente in $n Ziehungen zufällig zu ziehen ; Ansatz: Die Wahrscheinlichkeiten der Scheitervarianten aufaddieren ; $n = Anz. Ziehungen, $k = Anz. korrekte Elemente Func _calcProb($n, $k, $nG = 26) Local $M = $nG - $k ; Anzahl Trefferelemente (hier Fehlversuche) Local $nP = 0 For $i = $n - $k + 1 To ($n > $M ? $M : $n) $nP += _hypergeom($nG, $M, $n, $i) Next ; Erfolgswahrscheinlichkeit zurückgeben Return 1 - ($nP > 1 ? 1 : $nP) EndFunc ; berechnet die hypergeometrische Verteilung Func _hypergeom($N, $M, $nC, $k) Return _binomialcoefficient($M, $k) * _binomialcoefficient($N - $M, $nC - $k) / _binomialcoefficient($N, $nC) EndFunc ; berechnet den Binomialkoeffizienten Func _binomialcoefficient($n, $k) Local $iR = 1 If $k > ($n - $k) Then $k = $n - $k For $i = 0 To $k - 1 $iR *= $n - $i $iR /= $i + 1 Next Return $iR EndFunc
- Die vorgebene Wortliste - gefiel mir einfach nicht, weswegen ich die Online-API genommen habe (damit ist aber auch die Kategorieangabe raus)
-
Ups - stimmt.
Bin nicht so der GUI-Experte -
Meine Lösung für Teil 1 (46 min.):
Spoiler anzeigen
AutoIt
Alles anzeigen#include <String.au3> #include <GUIConstantsEx.au3> ; zufälliges (deutsches) Suchwort Global $sWord = StringRegExp(BinaryToString(InetRead('https://random-word-api.herokuapp.com/word?lang=de')), "[[:alpha:]]+", 1)[0] ; Umlaute konvertieren $sWord = StringReplace($sWord, 'ä', 'ae', 0, 2) $sWord = StringReplace($sWord, 'ö', 'oe', 0, 2) $sWord = StringReplace($sWord, 'ü', 'ue', 0, 2) $sWord = StringReplace($sWord, 'ß', 'ss', 0, 2) ; Parameter des Suchwortes Global Const $nWordLen = StringLen($sWord) Global Const $aWord = StringSplit($sWord, '', 2) Global Const $nVersuche = 8 #Region GUI Opt("GUIOnEventMode", 1) GUICreate("Galgenraten", 227, 119) GUICtrlCreateLabel("Gib einen Buchstaben oder ein Wort ein.", 8, 16, 196, 17) Global $idInput = GUICtrlCreateInput("", 8, 48, 201, 21) Global $idStart = GUICtrlCreateButton("OK", 24, 72, 81, 33) Global $idAbbrechen = GUICtrlCreateButton("Abbrechen", 120, 72, 73, 33) GUISetOnEvent($GUI_EVENT_CLOSE, _raus) GUICtrlSetOnEvent($idAbbrechen, _raus) GUICtrlSetOnEvent($idStart, _nextChar) ; Tastenbelegung Local $aAccelKeys[2][2] = [["{ESC}", $idAbbrechen], ["{Enter}", $idStart]] GUISetAccelerators($aAccelKeys) GUISetState(@SW_SHOW) ; Begrüßungstext ConsoleWrite(StringFormat('+---------------+\n|--GALGENRATEN--|\n+---------------+\n\nErrate ein Wort mit %d Buchstaben %s.\nDu hast %d Versuche, jeder falsche Buchstabe reduziert deine Versuche.\n\n', $nWordLen, _StringRepeat("_ ", $nWordLen), $nVersuche)) Do Sleep(100) Until 0 Func _raus() Exit EndFunc #EndRegion GUI ; Funktion welche bei einer Usereingabe ausgeführt wird Func _nextChar() Local Static $mUsed[] ; bereits verwendete Buchstaben Local Static $nTries = 0, $nChars = 0 Local Static $aLoesung[$nWordLen] ; process input For $cChar In StringSplit(GUICtrlRead($idInput), '', 2) Local $bFound = False If MapExists($mUsed, $cChar) Then ConsoleWrite("Buchstabe " & $cChar & " bereits versucht du Trottel!" & @CRLF) ContinueLoop ElseIf Not StringRegExp($cChar, '^[a-zA-z]$') Then ConsoleWrite('Dein eingegebenes Zeichen "' & $cChar & '" ist kein Buchstabe' & @CRLF) ContinueLoop Else $mUsed[$cChar] = 1 EndIf ; die Eingabebuchstaben durchgehen: For $i = 0 To UBound($aWord) - 1 ; Buchstabe für Buchstabe mit Lösungswort vergleichen: If $aWord[$i] = $cChar Then $aLoesung[$i] = StringUpper($cChar) $nChars += 1 $bFound = True EndIf Next ; Versuchezähler hochzählen $nTries += $bFound ? 0 : 1 ; Lösung gefunden: If $nChars >= $nWordLen Then ConsoleWrite(StringFormat('\n:-) Gewonnen!\n%d Versuche übrig, gut gemacht!\nDas gesuchte Wort war "%s".\n\n' & @CRLF, $nVersuche - $nTries, $sWord)) Exit ; verloren ElseIf $nTries >= $nVersuche Then ConsoleWrite(StringFormat('\n;-( Verloren! Das gesuchte Wort war "%s".\n\n,', $sWord)) Exit EndIf Next ; Inputfeld löschen GUICtrlSetData($idInput, '') ; Zwischenstand ausgeben: ConsoleWrite(StringFormat("Wort: %s (%d Versuche übrig)\n", _printLoesung($aLoesung), $nVersuche - $nTries)) EndFunc Func _printLoesung($aWord) Local $sRet = "" For $i = 0 To UBound($aWord) - 1 $sRet &= $aWord[$i] = "" ? "_ " : $aWord[$i] & " " Next Return StringTrimRight($sRet, 1) EndFunc
Und doch noch die Erweiterung auf Teil 2 (+ 20 Minuten) um optional auf der Konsole zu spielen:
Teil 2
AutoIt
Alles anzeigen#pragma compile(Console, true) #include <String.au3> #include <GUIConstantsEx.au3> #include <WinAPIProc.au3> ; cmdline-Version oder GUI-Version? Global Const $bCMD = StringInStr(_WinAPI_GetProcessName(_WinAPI_GetParentProcess(@AutoItPID)), 'cmd.exe') = 0 ? False : True ; zufälliges (deutsches) Suchwort Global $sWord = StringRegExp(BinaryToString(InetRead('https://random-word-api.herokuapp.com/word?lang=de')), "[[:alpha:]]+", 1)[0] ; Umlaute konvertieren $sWord = StringReplace($sWord, 'ä', 'ae', 0, 2) $sWord = StringReplace($sWord, 'ö', 'oe', 0, 2) $sWord = StringReplace($sWord, 'ü', 'ue', 0, 2) $sWord = StringReplace($sWord, 'ß', 'ss', 0, 2) ; Parameter des Suchwortes Global Const $nWordLen = StringLen($sWord) Global Const $aWord = StringSplit($sWord, '', 2) Global Const $nVersuche = 8 ; Begrüßungstext ConsoleWrite(StringFormat('+---------------+\n|--GALGENRATEN--|\n+---------------+\n\nErrate ein Wort mit %d Buchstaben %s.\nDu hast %d Versuche, jeder falsche Buchstabe reduziert deine Versuche.\n\n', $nWordLen, _StringRepeat("_ ", $nWordLen), $nVersuche)) If $bCMD = False Then ; gui-version #Region GUI Opt("GUIOnEventMode", 1) GUICreate("Galgenraten", 227, 119) GUICtrlCreateLabel("Gib einen Buchstaben oder ein Wort ein.", 8, 16, 196, 17) Global $idInput = GUICtrlCreateInput("", 8, 48, 201, 21) Global $idStart = GUICtrlCreateButton("OK", 24, 72, 81, 33) Global $idAbbrechen = GUICtrlCreateButton("Abbrechen", 120, 72, 73, 33) GUISetOnEvent($GUI_EVENT_CLOSE, _raus) GUICtrlSetOnEvent($idAbbrechen, _raus) GUICtrlSetOnEvent($idStart, _guiInput) ; Tastenbelegung Local $aAccelKeys[2][2] = [["{ESC}", $idAbbrechen], ["{Enter}", $idStart]] GUISetAccelerators($aAccelKeys) GUISetState(@SW_SHOW) ; Endlosschleife um das GUI am Leben zu erhalten Do Sleep(100) Until 0 #EndRegion GUI Else ; cmdline-Version Global $sInput ConsoleWrite("Eingabe: ") While sleep(100) $sInput = ConsoleRead() If @error Then ConsoleWrite("Fehler bei ConsoleRead()" & @CRLF) Exit ElseIf @extended > 0 Then $sInput = StringRegExpReplace($sInput, '\R', '') If StringLen($sInput) = 0 Then ContinueLoop _nextChar($sInput) ConsoleWrite(@CRLF & "Eingabe: ") EndIf WEnd EndIf Func _raus() Exit EndFunc ; wrapper if gui is used Func _guiInput() _nextChar(GUICtrlRead($idInput)) ; Inputfeld leeren GUICtrlSetData($idInput, '') EndFunc ; Funktion welche bei einer Usereingabe ausgeführt wird Func _nextChar($sInput) Local Static $mUsed[] ; bereits verwendete Buchstaben Local Static $nTries = 0, $nChars = 0 Local Static $aLoesung[$nWordLen] ; Console aufräumen RunWait(@ComSpec & " /C CLS", "", @SW_HIDE) ; process input For $cChar In StringSplit($sInput, '', 2) Local $bFound = False If MapExists($mUsed, $cChar) Then ConsoleWrite("Buchstabe " & $cChar & " bereits versucht du Trottel!" & @CRLF) ContinueLoop ElseIf Not StringRegExp($cChar, '^[a-zA-z]$') Then ConsoleWrite('Dein eingegebenes Zeichen "' & $cChar & '" ist kein Buchstabe' & @CRLF) ContinueLoop Else $mUsed[$cChar] = 1 EndIf ; die Eingabebuchstaben durchgehen: For $i = 0 To UBound($aWord) - 1 ; Buchstabe für Buchstabe mit Lösungswort vergleichen: If $aWord[$i] = $cChar Then $aLoesung[$i] = StringUpper($cChar) $nChars += 1 $bFound = True EndIf Next ; Versuchezähler hochzählen $nTries += $bFound ? 0 : 1 ; Lösung gefunden: If $nChars >= $nWordLen Then ConsoleWrite(StringFormat('\n:-) Gewonnen!\n%d Versuche übrig, gut gemacht!\nDas gesuchte Wort war "%s".\n\n' & @CRLF, $nVersuche - $nTries, $sWord)) Exit ; verloren ElseIf $nTries >= $nVersuche Then ConsoleWrite(StringFormat('\n;-( Verloren! Das gesuchte Wort war "%s".\n\n', $sWord)) Exit EndIf Next ; Zwischenstand ausgeben: ConsoleWrite(StringFormat("Wort: %s (%d Versuche übrig)\n", _printLoesung($aLoesung), $nVersuche - $nTries)) EndFunc Func _printLoesung($aWord) Local $sRet = "" For $i = 0 To UBound($aWord) - 1 $sRet &= $aWord[$i] = "" ? "_ " : $aWord[$i] & " " Next Return StringTrimRight($sRet, 1) EndFunc
-
Mal noch ein anderes Pattern, welches vor allem bei großen Ini-Dateien besser performen sollte:
AutoIt$pathINI = @ScriptDir & "\Test.ini" $sPersNr = '0xC39C07ECD016536F9C49E1' $aRegEx = StringRegExp(FileRead($pathINI), '(?m)^\[([^\]]+)\][^\[]+' & $sPersNr, 1) ConsoleWriteError((@error ? "Person nicht gefunden" : $aRegEx[0]) & @CRLF)
Ansonsten halte ich hier die Variante mit den Ini-Funktionen für die beste. (es gäbe nämlich noch einen Sonderfall für mein Pattern wo dieses Probleme bekommen würde)
-
brauchen wir nicht eine Art Zustimmung für Pakete?
Ich hatte im Kopf, dass man bei den Paketen direkt auf die Setups bei den Herstellerseiten verlinkt und von dort bezieht.
Könnt ihr natürlich machen wie ihr das wollt.was für Pakete hast du den im sinn? Software o.o oder ?
Allgemein wie bei den Linux-Distros auch - Anwendungssoftware, Bibliotheken etc.
Ansonsten hatte ich nicht viel im Sinn - ich hab nur gesehen, dass ihr momentan was Vorschläge angeht noch bisschen in der Luft hängt und hab daher das nur spontan eingeworfen. -
Projektvorschlag: Ein Paketmanager für Windows.
Man hat dort mit Dateisystemoperationen zu tun, mit einem Frontend, Netzwerkkommunikation, Datenbanken usw.
Und von der Performance gibt es keine Ansprüche, welche AutoIt nicht bedienen können sollte.
Klingt abwechslungsreich.
Erstmal vielleicht auf self-hosted-Basis so dass jeder sein eigenes Repository pflegt und wenn die Nummer funktioniert kann man ja ein öffentliches draus machen. -
-
-
Ich möchte einfach nur ein paar Tasmota Steckdosen schalten
Dann brauchst du eigentlich keine externen Geschichten wie powershell oder curl.
Ein InetRead("http://192.168.8.66/cm?cmnd=Power%20On") sollte den gleichen Effekt haben.Je nachdem was du genau machen möchtest, wäre evtl. MQTT die effektivere Wahl.
Tasmota unterstützt das glaube ich auch.
Aber den genauen Anwendungsfall kennen wir ja nicht. -
mit "Run" in einem Script ausführen. Durch die Anführungszeichen bekomme ich aber immer Fehlermeldungen.
Um in AutoIt einen String zu definieren muss man ihn entweder in doppelte Anführungszeichen setzen oder in einfache.
Beide Varianten existieren unter anderem, damit man im String die jeweils anderen Anführungszeichen verwenden kann.
Würde man z.B. einen String in doppelte Anführungszeichen anfangen und im String selbst sollen wiederrum selbst doppelte vorkommen, dann hat der Interpreter keine Chance zu unterscheiden ob die Anführungszeichen nun das Ende des Strings definieren sollen oder zum Inhalt der Zeichenkette gehören sollen.
Nun hast du allerdings einen Fall, bei dem im String selbst sowohl doppelte als auch einfache Anführungszeichen vorkommen.
Hier gibt es noch eine weitere Methode um diese dann für den Interpreter zu maskieren: doppeln
Sprich: Wenn man einen String in doppelten Anführungszeichen einschließt und darin auch doppelte Anführungszeichen verwenden möchte, dann schreibt man diese 2x: $sString = "Ein ""Test"" für Anführungszeichen"
Analog würde man dies mit den einfachen auch machen.
Sprich: Du musst festlegen ob du deinen String in doppelten oder einfachen Anführungszeichen definieren willst und dann dieses Zeichen im String selbst doppeln.
Dann wird alles als gemeinsamer String erkannt. -
Eine kleine Funktion, welche schon längere Zeit bei mir liegt und mir beim Umgang mit Dll-Strukturen schon öfters mal geholfen hat.
Ich denke die Funktion könnte auch für den ein oder andere nützlich sein:AutoIt
Alles anzeigen#include-once #include <Array.au3> ; die Strukturdefinition Local $sStructStr = "Align 16;Short Albi;byte;hwnd;char;align 8;byte;short[2];dword;byte;short;byte;int64;char[9];int64;byte;" & _ "byte;ptr;char;double;short;wchar[3];byte;float;byte;uint_ptr;byte;char buffer[128];int;byte[13];word 2bytes;handle isptr;hwnd isalsoptr;" & _ "boolean isbyte[2];bool isint;dword_ptr;long_ptr;ulong_ptr;lparam;wparam;lresult;byte;" ; Struktur anhand der Definition erzeugen Local $stStruct = DllStructCreate($sStructStr) DllStructSetData($stStruct, 12, "Test") ; Konvertierung der Struktur in ein Array Global $aArray = _DllStruct2Array($sStructStr, $stStruct) ; Ausgabe des Arrays _ArrayDisplay($aArray, "DllStruct", "" , 64, Default, "Index|Name|Typ|Arraygröße|Wert|Größe|Offset|Pointer") ; #FUNCTION# ====================================================================================== ; Name ..........: _DllStruct2Array() ; Description ...: converts a DllStruct variable to a 2D array based on its structure string ; Syntax ........: _DllStruct2Array($tagStruct, ByRef $tStruct) ; Parameters ....: $tagStruct - A string representing the structure to create (like "Struct" in DllStructCreate) ; ByRef $tStruct - a structure variable with the structure described in $tagStruct ; Return values .: Success: 2D-Array with the following structure: ; |[[index N, name N, type N, arraysize N, value N, size N, offset N, isPointer N], [...], ...] ; Failure: Null and set @error to: ; |@error = 1: $tStruct is not a dll struct variable ; Author ........: aspirinjunkie ; Modified ......: 2022-07-13 ; Remarks .......: for LRESULT/[LW]PARAM/PTR/HWND/HANDLE value is pointer address, ; for xxx_PTR value is taken from the address where the pointer points, ; for [W]CHAR value is a string if element is an [W]CHAR-array, otherwise the numerical value ; Link ..........: x ; Example .......: Yes ; #include <Array.au3> ; $tagSTRUCT1 = "struct;int var1;byte var2;uint var3;char var4[128];endstruct" ; Local $tSTRUCT1 = DllStructCreate($tagSTRUCT1) ; $aStructInfo = _DllStruct2Array($tagSTRUCT1, $tSTRUCT1) ; _ArrayDisplay($aStructInfo, "DllStruct", "" , 64, Default, "Index|Name|Typ|Arraygröße|Wert|Größe|Offset|Pointer") ; ================================================================================================= Func _DllStruct2Array($tagStruct, ByRef $tStruct) Local Enum $eIndex, $eName, $eType, $eArraySize, $eValue, $eSize, $eOffset, $eIsPointer Local $aRegEx, $sTmp Local $aElements = StringSplit($tagStruct, ";", 3) If Not IsDllStruct($tStruct) Then Return SetError(1, 0, Null) Local $aArray[UBound($aElements)][8], $iC = 0, $tTmp, $iBaseAddress = DllStructGetPtr($tStruct) For $tagElement In $aElements $aArray[$iC][$eArraySize] = "" $aArray[$iC][$eIsPointer] = "" ; a data element $aRegEx = StringRegExp($tagElement, "(?i)^\h*(BOOL(?>EAN)?|BYTE|(?>U|W)?CHAR|DOUBLE|D?WORD(?>_PTR)?|FLOAT|HANDLE|HWND|U?INT(?>64|_PTR)?|(?>L|W)PARAM|LRESULT|PTR|U?SHORT|U?LONG(?>_PTR)?)", 3) If @error Then ContinueLoop ; no "align", "struct", "endstruct" etc. handling - only elements ; element data type $aArray[$iC][$eType] = $aRegEx[0] ; element index $aArray[$iC][$eIndex] = $iC + 1 ; element offset $aArray[$iC][$eOffset] = Int(DllStructGetPtr($tStruct, $aArray[$iC][$eIndex]) - $iBaseAddress) ; pointer type? $sTmp = StringStripWS(StringTrimLeft($tagElement, StringLen($aArray[$iC][$eType])), 2) If StringInStr($sTmp, "*", 1) Then $aArray[$iC][$eIsPointer] = True ; Array defined? $aRegEx = StringRegExp($sTmp, "\[\h*(\d+)\h*\]", 3) If Not @error Then $aArray[$iC][$eArraySize] = Int($aRegEx[0]) ; element name $aRegEx = StringRegExp($sTmp, "(\w+)\h*(?>$|\[)", 3) If Not @error Then $aArray[$iC][$eName] = $aRegEx[0] ; element size $aArray[$iC][$eSize] = -1 If StringRegExp($aArray[$iC][$eType], "(?i)^(BOOLEAN?|BYTE|U?CHAR)$") Then $aArray[$iC][$eSize] = 1 If StringRegExp($aArray[$iC][$eType], "(?i)^(WCHAR|U?SHORT|WORD)$") Then $aArray[$iC][$eSize] = 2 If StringRegExp($aArray[$iC][$eType], "(?i)^(U?INT|U?LONG|BOOL|DWORD|FLOAT)$") Then $aArray[$iC][$eSize] = 4 If StringRegExp($aArray[$iC][$eType], "(?i)^(U?INT64|DOUBLE)") Then $aArray[$iC][$eSize] = 8 If StringRegExp($aArray[$iC][$eType], "(?i)^(.+\_PTR|LRESULT|[LW]PARAM|PTR|HWND|HANDLE)") Then ; pointer type $aArray[$iC][$eIsPointer] = True $aArray[$iC][$eSize] = @AutoItX64 ? 8 : 4 EndIf If $aArray[$iC][$eArraySize] > 1 Then $aArray[$iC][$eSize] *= $aArray[$iC][$eArraySize] ; element value If $aArray[$iC][$eIsPointer] Then ; pointer type If StringRegExp($aArray[$iC][$eType], "(?i)\_PTR$") Then ; pointer to integer values $tTmp = DllStructCreate(StringTrimRight($aArray[$iC][$eType], 4), DllStructGetPtr($tStruct, $aArray[$iC][$eIndex])) $aArray[$iC][$eValue] = DllStructGetData($tTmp, 1) $tTmp = Null Else ; normal unspecific pointer $aArray[$iC][$eValue] = DllStructGetData($tStruct, $aArray[$iC][$eIndex]) EndIf ElseIf $aArray[$iC][$eArraySize] > 0 Then ; array elements If StringRegExp($aArray[$iC][$eType], "(?i)W?CHAR") Then ; char array (a string) $aArray[$iC][$eValue] = DllStructGetData($tStruct, $aArray[$iC][$eIndex]) Else ; normal element array Local $aTmp[$aArray[$iC][$eArraySize]] For $i = 0 To $aArray[$iC][$eArraySize] - 1 $aTmp[$i] = DllStructGetData($tStruct, $aArray[$iC][$eIndex], $i + 1) Next $aArray[$iC][$eValue] = $aTmp EndIf Else $aArray[$iC][$eValue] = DllStructGetData($tStruct, $aArray[$iC][$eIndex]) EndIf $iC += 1 Next ReDim $aArray[$iC][UBound($aArray, 2)] Return SetExtended(DllStructGetSize($tStruct), $aArray) EndFunc ;==>_DllStruct2Array
-
ob wenn man ein Skript mit AutoIt3ExecuteScript() aufruft, dessen Funktionen nach dem Aufruf im "Hauptprogramm" zur Verfügung stehen?
Nein
-
Nun nur mit Einschränkungen.
Du kannst Code aus Strings oder Dateien ausführen lassen aber da gibt es ein paar Einschränkungen.
Methode 1 - Execute():hierbei kann kurzer Code in Strings ausgeführt werden und deren Rückgabewert im Hauptskript weiterverwendet werden.
Mehrzeilige Konstrukte wie Schleifen oder Funktionsdefinitionen gehen damit nicht.
Auch Variablenzuweisungen klappen nicht.
Variablen aus dem Hauptskript können zwar in diesen Ausdrücken verwendet, aber nicht überschrieben werden - nur der Return-Wert von Execute() könnte hierfür dienen.Methode 2 - /AutoIt3ExecuteLine bzw. /AutoIt3ExecuteScript:
Man kann den AutoIt-Interpreter aufrufen und entweder eine Codezeile oder ein ganzes Skript angeben, welches ausgeführt werden soll.
Das geht auch mit der kompilierten Exe-Datei des Hauptskriptes, wenn es mit der richtigen Compileroption kompiliert wurde.
Damit kann man auch umfangreichere Skripte ausführen, aber diese haben keine Verknüpfung zum Hauptskript - teilen sich also keine Variablen usw.
Es wird einfach nur aufgerufen:AutoIt
Alles anzeigen#pragma compile(AutoItExecuteAllowed, True) ; je nachdem ob Skript kompiliert vorliegt oder direkt über den Interpreter aufgerufen wird $sAutoItExe = @Compiled ? @ScriptFullPath : @AutoItExe ; einzelne Zeile Code ausführen: $sVar = "msgbox(0,'','Test')" ; AutoIt-Code, welcher irgendwie in eine Variable gelangt ist RunWait(StringFormat('"%s" /AutoIt3ExecuteLine "%s"', $sAutoItExe, $sVar)) ; ein anderes AutoIt-Skript aufrufen, welches noch nicht kompiliert vorliegt RunWait(StringFormat('"%s" /AutoIt3ExecuteScript "%s"', $sAutoItExe, @ScriptDir & "\other.au3"))
-
Ich finde die 50s aber schon ziemlich heftig.
Die sind meiner Meinung nach auch viel zu lange.
Ob das am Zugriff über Wine liegt - keine Ahnung.
Aber eine Antwort auf meine Frage ob du die aktuelle Version von AutoIt verwendest steht noch aus. -
Dein Skript scheint ja nur ein Ausschnitt zu sein.
Wenn ich das richtig verstehe (und da kann ich natürlich meilenweit falsch liegen), dann hast du diesen Code mindestens 6x vorliegen - oder?
Also das scheint ja nur der Code für $Input6 zu sein.
Die anderen Zeiten fehlen ja noch in dem Gezeigten.
Es ist sicherlich nicht gut was ich jetzt mache aber mich hat es irgendwie gerade gejuckt zu versuchen, dass was ich vermute was dein Ziel ist mal etwas dynamischer zu implementieren.
Wenn ich das richtig verstehe, hast du mehrere Edit-Felder wo die Zeiten eingetragen werden und am Ende kommt eine Summe heraus.
Quasi eine Art Zeitenaddierer?
Falls ja, dann würde ich dir gerne zeigen, dass man die Felder für die Zeiten und das ganze drumherum dynamisch schreiben kann, so dass man deutlich weniger Code hierfür benötigt und gleichzeitig flexibler ist.
Es besteht natürlich die Gefahr, dass ich an deinem Thema vorbei schramme aber dann hab ich mir eben halt damit kurz die Zeit vertrieben:AutoIt
Alles anzeigen#include <GUIConstantsEx.au3> #Region GUI erstellen ; Eventmode statt Message-Loop-Modus (gefällt mir persönlich besser) Opt("GUIOnEventMode", 1) ; Über die Größe des Arrays, kann man die Anzahl der Einträge und die GUI-Größe steuern Global $aIdInputs[6] ; hält die Control-IDs für die Zeitinputs ; GUI erstellen GUICreate("Zeitaddierer", 120, UBound($aIdInputs) * 25 + 70) GUISetOnEvent($GUI_EVENT_CLOSE, "raus") ; die Inputs für die Zeitangaben erstellen For $i = 0 To UBound($aIdInputs) - 1 $aIdInputs[$i] = GUICtrlCreateInput("", 10, 5 + $i * 25, 100, 20) GUICtrlSetOnEvent(-1, "_gui_eingetragen") Next ; Edit-Control für die Ausgabe der Summe: Local $idSumme = GUICtrlCreateInput("", 10, UBound($aIdInputs) * 25 + 35, 100, 20) ; GUI sichtbar schalten GUISetState(@SW_SHOW) ; Endlosschleife für das GUI Do Sleep(10) Until 0 #EndRegion ; Funktion um über das Kreuz zu beenden Func raus() Exit EndFunc ; Funktion, welche aufgerufen wird, wenn eine Zeit eingetragen wurde Func _gui_eingetragen() Local $sInputRaw = GUICtrlRead(@GUI_CtrlId) ; wenn eingetragene Form nicht stimmt - aufhören If Not StringRegExp($sInputRaw, '^(\d{3,4}|\d{1,2}:\d{2})$', 0) Then Return ; Doppelpunkt hinzufügen, falls nicht vorhanden: If Not StringInStr($sInputRaw, ':') Then $sInputRaw = StringTrimRight($sInputRaw, 2) & ":" & StringRight($sInputRaw, 2) ; führende 0 hinzufügen: $sInputRaw = StringRight("0" & $sInputRaw, 5) ; aufgehübschte Zeit eintragen: GUICtrlSetData(@GUI_CtrlId, $sInputRaw) ; Summe berechnen und ausgeben: _calcTimeSum($sInputRaw, @GUI_CtrlId) EndFunc ; berechnet die Summe aller Zeiten Func _calcTimeSum($sWert, $sCtrlID) Local Static $mZeiten[] ; map, welche die eingetragenen Zeiten hält ; Zeit in h und m zerlegen Local $aZeit = StringSplit($sWert, ":", 3) If @error Then Return ; aus String Integer machen: $aZeit[0] = Int($aZeit[0]) $aZeit[1] = Int($aZeit[1]) ; Bereichscheck: If $aZeit[1] < 0 Or $aZeit[1] > 59 Then Return ; den Zeiten hinzufügen: $mZeiten[$sCtrlID] = $aZeit ; Alle Zeiten zusammenrechnen und Summe ausgeben: Local $nMinuten = 0, $aZeitTmp For $iID In MapKeys($mZeiten) $aZeitTmp = $mZeiten[$iID] $nMinuten += $aZeitTmp[0] * 60 + $aZeitTmp[1] Next Local $nStunden = Floor($nMinuten / 60) $nMinuten = Mod($nMinuten, 60) ; ausgeben GUICtrlSetData($idSumme, StringFormat("%02d:%02d", $nStunden, $nMinuten)) EndFunc