Nana der Hinweis auf RegEx-Suche in Fenstertiteln kam hier ja nicht von mir.
Den hat Hipfzwirgel ja schon selbts mitgebracht.
Ich hab hier ja nur das Pattern angepasst.
Beiträge von AspirinJunkie
-
-
Du verwendest doch RegEx für das Title-Matching.
RegEx bietet die Suche nach verschiedenen Alternativen.
Genau deinen Anwendungsfall - suche nach mehreren verschiedenen Möglichkeiten - ist bereits in der Hilfe dazu beschrieben.Vom Grundaufbau so:
-
Das ist ein leidiges uraltes Thema. AutoIt selbst kann da wenig tun.
Das Problem ist, dass AutoIt in exe Dateien den Interpreter an den Anfang der Datei schreibt und das auszuführende Skript dahinter. Wenn nun irgendjemand eine bösartige Software mit AutoIt schreibt, dann entspricht die Signatur die bei den Virenscannerherstellern landet, der des AutoIt-Interpreters. Also sind ab diesem Zeitpunkt alle AutoIt-exe Dateien betroffen.
Die Möglichkeiten hierbei sind u.a. hier aufgeführt:
Are my AutoIt exes really infected?If you have been using AutoIt for any length of time you will know that it is a great, and powerful scripting language. As with all powerful languages there…www.autoitscript.com -
das Problem ist nur wo und an welcher Stelle sollte ich dies einabuen, die Listview kann ich ja anscheinend nicht damit auslesen.
Da es sich ja um eine ListView handelt sieht das ganze wieder bisschen anders aus, als bei der Sortierung eines Arrays.
Die ListView bringt eine eigene Sortierlogik mit.
Die _ArraySortFlexible(), welche diese für Arrays beinhaltet brauchst du daher nicht.
Das was man aber bei der ListView-Sortierung machen kann ist, eine eigene Vergleichsfunktion mitzugeben (per GUICtrlRegisterListViewSort()).
Es reicht daher dort den Vergleich mit der in der ArrayPlus enthaltenen Vergleichsfunktion __ap_cb_comp_Natural() durchzuführen und dann werden auch die IPs richtig sortiert.
Bisschen nervig ist jedoch der Aufwand den man betreiben muss um die ListviewElemente auszulesen, sowie die Sortierreihenfolge ordentlich übergeben zu bekommen.
Dann klappt es aber wie gewünscht:AutoIt
Alles anzeigen#include <GUIConstants.au3> #include <ListViewConstants.au3> #include <ArrayPlus.au3> ; Ausgangsarray: Local $aListViewData[10][4] = [ _ ["PC-001", "00:1A:2B:3C:4D:5E", "192.168.23.145", "Büro 101"], _ ["PC-002", "00:2B:3C:4D:5E:6F", "10.0.15.87", "Empfang"], _ ["PC-003", "00:3C:4D:5E:6F:7G", "172.16.78.209", "Besprechungsraum"], _ ["PC-004", "00:4D:5E:6F:7G:8H", "192.168.1.3", "Buchhaltung"], _ ["PC-005", "00:5E:6F:7G:8H:9I", "10.10.55.201", "Marketing"], _ ["PC-006", "00:6F:7G:8H:9I:0J", "172.20.100.50", "Entwicklung 1"], _ ["PC-007", "00:7G:8H:9I:0J:1K", "192.168.0.11", "Entwicklung 2"], _ ["PC-008", "00:8H:9I:0J:1K:2L", "10.1.1.254", "Personalabteilung"], _ ["PC-009", "00:9I:0J:1K:2L:3M", "172.31.255.1", "Kantine"], _ ["PC-010", "00:0J:1K:2L:3M:4N", "192.168.100.100", "Serverraum"] _ ] ; Variablen mit deren Hilfe man die Sortierreihenfolge handeln kann (Siehe Hilfe zu GUICtrlRegisterListViewSort()) Global $g_iCurCol = -1, _ $g_iSortDir = 1, _ $g_bSet = False, _ $g_iCol = -1 ; GUI Global $hGUI = GUICreate("LARCH-Network Browser", 600, 400) Global $idListView = GUICtrlCreateListView("PC Name|MAC Address|IP Address|Bezeichnung", 10, 10, 580, 300, $LVS_REPORT) ; Hinzufügen der neuen Spalte ; GUI Events (hier OnEvent-Modus im Gegensatz zum 2. GUI) Opt("GUIOnEventMode", 1) GUISetOnEvent($GUI_EVENT_CLOSE, "raus") ; GUI-Ctrl Events (was passiert wenn man mit den Controls interagiert) GUICtrlSetOnEvent($idListView, _cb_lv_clicked) ; andere Sortierfunktion für die Listview verknüpfen GUICtrlRegisterListViewSort(-1, _myCompare) ; ListView füllen (fürs Beispiel) For $i = 0 To UBound($aListViewData) -1 GUICtrlCreateListViewItem($aListViewData[$i][0] & "|" & $aListViewData[$i][1] & "|" & $aListViewData[$i][2] & "|" & $aListViewData[$i][3], $idListView) Next ; Display the GUI. GUISetState(@SW_SHOW, $hGUI) ; Endlosschleife um GUI am Leben zu halten While Sleep(100) WEnd Func raus() Exit EndFunc ; wird ausgeführt wenn man mit dem ListView interagiert Func _cb_lv_clicked() $g_bSet = False $g_iCurCol = $g_iCol GUICtrlSendMsg($idListView, $LVM_SETSELECTEDCOLUMN, GUICtrlGetState($idListView), 0) EndFunc ; eigene Vergleichsfunktion für die ListView-Sortierung Func _myCompare($iControlID, $iA, $iB, $iColumn) ; Switch the sorting direction If $iColumn = $g_iCurCol Then If Not $g_bSet Then $g_iSortDir *= -1 $g_bSet = True EndIf Else $g_iSortDir = 1 EndIf $g_iCol = $iColumn ; Werte der aktuellen Listviewelemente holen Local $sA = GetSubItemText($iControlID, $iA, $iColumn) Local $sB = GetSubItemText($iControlID, $iB, $iColumn) ; Größenvergleich zweier Elemente per Natural Compare Return __ap_cb_comp_Natural($sA, $sB) * $g_iSortDir EndFunc ; Retrieve the text of a listview item in a specified column Func GetSubItemText($idCtrl, $idItem, $iColumn) Local $tLvfi = DllStructCreate("uint;ptr;int;int[2];int") DllStructSetData($tLvfi, 1, $LVFI_PARAM) DllStructSetData($tLvfi, 3, $idItem) Local $tBuffer = DllStructCreate("char[260]") Local $iIndex = GUICtrlSendMsg($idCtrl, $LVM_FINDITEM, -1, DllStructGetPtr($tLvfi)); Local $tLvi = DllStructCreate("uint;int;int;uint;uint;ptr;int;int;int;int") DllStructSetData($tLvi, 1, $LVIF_TEXT) DllStructSetData($tLvi, 2, $iIndex) DllStructSetData($tLvi, 3, $iColumn) DllStructSetData($tLvi, 6, DllStructGetPtr($tBuffer)) DllStructSetData($tLvi, 7, 260) GUICtrlSendMsg($idCtrl, $LVM_GETITEMA, 0, DllStructGetPtr($tLvi)); Local $sItemText = DllStructGetData($tBuffer, 1) Return $sItemText EndFunc ;==>GetSubItemText
-
Als ich letztens mit SSH rumgespielt habe, hatte ich mir fix folgende Funktionen zusammengestellt:
AutoIt
Alles anzeigen#pragma compile(Console, true) #include-once #include <WinAPIConv.au3> Global CONST $_SCP_EXISTS = _scp_where("PSCP.exe") = "" ? False : True Global CONST $_SSH_EXISTS = _scp_where("PLINK.exe") = "" ? False : True #include <File.au3> #region main function If @ScriptName = "SCP.au3" Then EndIf #endregion Func _ssh_run(Const $sServer, Const $sUser, Const $sPassword, Const $sCommand, Const $WorkDir = @WorkingDir) If Not $_SSH_EXISTS Then Return SetError(1,0,Null) Local $hPID = Run(StringFormat("PLINK.exe -batch -pw %s %s@%s %s", _scp_quoteIf($sPassword), $sUser, $sServer, _scp_quoteIf($sCommand)) _ , $WorkDir, @SW_HIDE, 0x2 + 0x4) If $hPID = 0 Then Return SetError(1,@error,"") ; warten bis Prozess beendet ist ProcessWaitClose($hPID) Return StdoutRead($hPID) EndFunc Func _scp_get(Const $sServer, Const $sUser, Const $sPassword, Const $sFilePath, Const $sTargetPath, Const $WorkDir = @WorkingDir) If Not $_SCP_EXISTS Then Return SetError(1,0,Null) Local $hPID = Run(StringFormat("PSCP.exe -C -scp -batch -pw %s %s@%s:%s %s", _scp_quoteIf($sPassword), $sUser, $sServer, _scp_quoteIf($sFilePath), _scp_quoteIf($sTargetPath)) _ , $WorkDir, @SW_HIDE, 0x2 + 0x4) If $hPID = 0 Then Return SetError(1,@error,"") Local $s_Ret, $s_Line, $s_Err Do Sleep(10) $s_Line = StdoutRead($hPID) If @extended > 0 Then $s_Ret &= $s_Line Until @error Do Sleep(10) $s_Line = StderrRead($hPID) If @extended > 0 Then $s_Err &= $s_Line Until @error $s_Ret = _WinAPI_OemToChar($s_Ret) If $s_Err <> "" Then If $s_Ret <> "" Then Return SetError(3, 0, "------- StdOut -----------" & @CRLF & $s_Ret & @CRLF & @CRLF & "------- StdErr -----------" & @CRLF & $s_Err) Return SetError(2, 0, $s_Err) EndIf Return $s_Ret EndFunc Func _scp_read(Const $sServer, Const $sUser, Const $sPassword, Const $sFilePath, Const $WorkDir = @WorkingDir) If Not $_SCP_EXISTS Then Return SetError(1,0,Null) Local $sTempFilePath = _TempFile() _scp_get($sServer, $sUser, $sPassword, $sFilePath, $sTempFilePath, $WorkDir) If @error Then Return SetError(2,@error, False) Local $sFile =FileRead($sTempFilePath) FileDelete($sTempFilePath) Return $sFile EndFunc Func _scp_put(Const $sServer, Const $sUser, Const $sPassword, Const $sFilePath, Const $sTargetPath, Const $WorkDir = @WorkingDir) If Not $_SCP_EXISTS Then Return SetError(1,0,Null) RunWait(StringFormat("PSCP.exe -C -scp -batch -pw %s %s %s@%s:%s", _scp_quoteIf($sPassword), _scp_quoteIf($sFilePath), $sUser, $sServer, _scp_quoteIf($sTargetPath)) _ , $WorkDir, @SW_HIDE) If @error Then Return SetError(2, @error, "") EndFunc ; #FUNCTION# ====================================================================================== ; Name ..........: _scp_runCmd() ; Description ...: runs commandline programs or cmd-command and return their output ; Syntax ........: _scp_runCmd($s_Cmd, [$sParameter = '', [$b_CmdSpec = False, [$WorkDir = @WorkingDir]]]) ; Parameters ....: $s_Cmd - the command which should be executed (can be full command or without parameters) ; $sParameter - additional parameters for the command ; $b_CmdSpec - If true the command is interpreted as a command for cmd.exe ; $WorkDir - the working directory ; Return values .: Success: returns a string with the output ; Failure: set @error and returns a debug-string ; Author ........: AspirinJunkie ; ================================================================================================= Func _scp_runCmd($s_Cmd, $sParameter = '', $b_CmdSpec = False, $WorkDir = @WorkingDir) Local Static $h_User32DLL = DllOpen('user32.dll') If @error Then Return SetError(1, @error, "") If $b_CmdSpec Then $s_Cmd = @ComSpec & " /c " & $s_Cmd Local $s_Ret, $s_Line, $s_Err If $sParameter <> '' Then $sParameter = ' ' & $sParameter Local $iPID = Run($s_Cmd & $sParameter, $WorkDir, @SW_HIDE, 0x2 + 0x4) If @error Then Return SetError(2, @error, "") Do Sleep(10) $s_Line = StdoutRead($iPID) If @extended > 0 Then $s_Ret &= $s_Line Until @error Do Sleep(10) $s_Line = StderrRead($iPID) If @extended > 0 Then $s_Err &= $s_Line Until @error $s_Ret = _WinAPI_OemToChar($s_Ret) If $s_Err <> "" Then If $s_Ret <> "" Then Return SetError(3, 0, "------- StdOut -----------" & @CRLF & $s_Ret & @CRLF & @CRLF & "------- StdErr -----------" & @CRLF & $s_Err) Return SetError(3, 0, $s_Err) EndIf Return $s_Ret EndFunc ;==>_scp_runCmd ; gibt den Pfad einer Datei nur anhand ihres Dateinamens zur�ck (durchsucht Path-Variable) Func _scp_where(Const $s_Name) Local $s_Return = _scp_runCmd("where", _scp_quoteIf($s_Name), True) If Not StringRegExp($s_Return, '^[A-Za-z]:\\') Then Return SetError(1, 0, "") Return $s_Return EndFunc ;==>_scp_where ; adds quotes around string if white spaces are inside Func _scp_quoteIf(ByRef Const $s_String, Const $s_Quote = '"') If StringLeft($s_String, StringLen($s_Quote)) == $s_Quote And StringRight($s_String, StringLen($s_Quote)) == $s_Quote Then Return $s_String Return StringInStr($s_String, ' ', 1) ? $s_Quote & $s_String & $s_Quote : $s_String EndFunc
Wie gesagt mit einer gewissen Warnung versehen, da diese wirklich nur schnell dahingeschustert sind und alles andere als optimiert.
Aber eventuell bringt es dich doch ein Stück weiter.
Ansonsten ist mir folgender Fallstrick begegnet: Wenn sich der Server-Key ändert oder noch nicht vorhanden ist, dann kommt man hiermit nicht weit.
In diesem Fall manuell die Verbindung per z.B. Putty herstellen (die Keys werden für alle diese Tools in HKCU\Software\SimonTatham\PuTTY\SshHostKeys gespeichert) damit plink ein bereits bekanntes Gegenüber hat. -
Ich interpretiere das mal so, dass meine 2. Variante keine Rolle mehr spielt - nun gut.
Dann halt auch mal mein Vorschlag für Variante 1:
Als sortierbaren Wert nehme ich die IP-Adresse aber alle Teile sind immer 3 Stellen lang (mit 0 aufgefüllt):AutoIt
Alles anzeigen#include <Array.au3> ; Ausgangsarray: Local $aListViewData[10][4] = [ _ ["PC-001", "00:1A:2B:3C:4D:5E", "192.168.23.145", "Büro 101"], _ ["PC-002", "00:2B:3C:4D:5E:6F", "10.0.15.87", "Empfang"], _ ["PC-003", "00:3C:4D:5E:6F:7G", "172.16.78.209", "Besprechungsraum"], _ ["PC-004", "00:4D:5E:6F:7G:8H", "192.168.1.3", "Buchhaltung"], _ ["PC-005", "00:5E:6F:7G:8H:9I", "10.10.55.201", "Marketing"], _ ["PC-006", "00:6F:7G:8H:9I:0J", "172.20.100.50", "Entwicklung 1"], _ ["PC-007", "00:7G:8H:9I:0J:1K", "192.168.0.11", "Entwicklung 2"], _ ["PC-008", "00:8H:9I:0J:1K:2L", "10.1.1.254", "Personalabteilung"], _ ["PC-009", "00:9I:0J:1K:2L:3M", "172.31.255.1", "Kantine"], _ ["PC-010", "00:0J:1K:2L:3M:4N", "192.168.100.100", "Serverraum"] _ ] ; Spalte hinzufügen Local $iRows = UBound($aListViewData), $iCols = UBound($aListViewData, 2) Redim $aListViewData[$iRows][$iCols + 1] ; Spalte mit einem sortierbaren Wert (hier mit Nullen aufgefüllte IP-Adresse) füllen: For $i = 0 To $iRows - 1 $aListViewData[$i][$iCols] = Execute(StringRegExpReplace($aListViewData[$i][2], '^(\d+)\.(\d+)\.(\d+)\.(\d+)$', 'StringFormat("%03d.%03d.%03d.%03d",$1,$2,$3,$4)')) Next ; nach dieser Spalte sortieren _ArraySort($aListViewData, 0, 0, 0, $iCols) ; letzte Spalte wieder löschen: Redim $aListViewData[$iRows][$iCols] ; Ergebnis ausgeben _ArrayDisplay($aListViewData)
-
IPs sind in AutoIt einfach nur Strings.
Strings werden in AutoIt, wenn sie mit den eingebauten Funktionalitäten (">", "<", "=", "==", StringCompare) verglichen werden, zeichenweise verglichen.
Die Sortierfunktion _ArraySort() verwendet lediglich die eingebauten Vergleichsfunktionen während der Sortierung.Bei IP-Adressen führt ein Zeichenweiser Vergleich jedoch nicht zum gewünschten Ergebnis.
Es gibt da mehrere Ansätze:
Ansatz 1: weitere Spalte mit Datenkonvertierung:- Dem Array eine weitere Spalte hinzufügen (per ReDim)
- Nun zeilenweise durchgehen
- Dabei die gewünschte Eigenschaft (hier Spalte 3) so konvertieren, dass AutoIt-Bordvergleiche diese wie gewünscht behandeln.
- Im Falle von IP-Adressen könnte man z.B. den 32 Bit-Integer-Wert, welchen sie repräsentieren, ableiten (eigene Funktion hierfür schreiben).
- Nun das Array mit _ArraySort() nach dieser letzten Spalte sortieren.
- Die letzte Spalte wieder löschen (ReDim)
- Fertig
Ansatz 2: Sortierfunktion mit nutzerdefinierter Vergleichsfunktion nutzen:
Es gibt Funktionen, welche es zulassen, dass die Vergleichsfunktion für die Sortierung vom Nutzer definiert werden kann.
Eine dieser findest du in der >>ArrayPlus-UDF<<. Und deine Aufgabe lässt sich damit dann folgdendermaßen lösen:AutoIt
Alles anzeigen#include "ArrayPlus.au3" ; Ausgangsarray: Local $aListViewData[10][4] = [ _ ["PC-001", "00:1A:2B:3C:4D:5E", "192.168.23.145", "Büro 101"], _ ["PC-002", "00:2B:3C:4D:5E:6F", "10.0.15.87", "Empfang"], _ ["PC-003", "00:3C:4D:5E:6F:7G", "172.16.78.209", "Besprechungsraum"], _ ["PC-004", "00:4D:5E:6F:7G:8H", "192.168.1.3", "Buchhaltung"], _ ["PC-005", "00:5E:6F:7G:8H:9I", "10.10.55.201", "Marketing"], _ ["PC-006", "00:6F:7G:8H:9I:0J", "172.20.100.50", "Entwicklung 1"], _ ["PC-007", "00:7G:8H:9I:0J:1K", "192.168.0.11", "Entwicklung 2"], _ ["PC-008", "00:8H:9I:0J:1K:2L", "10.1.1.254", "Personalabteilung"], _ ["PC-009", "00:9I:0J:1K:2L:3M", "172.31.255.1", "Kantine"], _ ["PC-010", "00:0J:1K:2L:3M:4N", "192.168.100.100", "Serverraum"] _ ] ; sortiere Array mit eigener Vergleichsfunktion _ArraySortFlexible($aListViewData, _sortIPColumn3) ; alternativ kann auch direkt die Funktionalität als String eingetragen werden (dann braucht es keine extra Funktionsdefinition): ;~ _ArraySortFlexible($aListViewData, "__ap_cb_comp_Natural($A[2], $B[2])") ; sortiertes Array ausgeben lassen _ArrayDisplay($aListViewData, "Sortiert") ; eigene Vergleichsfunktion, welcher die jeweils 3. Spalten zweier Elemente per NaturalCompare vergleicht Func _sortIPColumn3($A, $B) Return __ap_cb_comp_Natural($A[2], $B[2]) EndFunc
-
welcher ein neues fenster öffnet indem ich nun die Größe des virtuellen Images eingeben kann und mittels klick auf "erstellen" sollte nun in einen auswählbaren ordner ein Image erstellt werden.
Nun der schnelle und einfache Weg wäre, anstatt eines extra dafür neu zu erstellenden GUI, für ersters die Funktion InputBox() und für letzteres FileSelectFolder() zu verwenden.
Für alles andere müsstest du ein neues GUI erzeugen und auswerten. Am besten gekapselt in einer eigenen Funktion.
Hatten erst letztens mal wieder so einen Fall wo du dir das Grundkonzept evtl abschauen könntest.Edit: Ach was solls - ich hab dir einfach mal ein Beispiel gebastelt, welches das Zusammenspiel zwischen mehreren Fenstern zeigen soll:
AutoIt
Alles anzeigen#include <GUIConstants.au3> ; Äußeres GUI (Haupt-GUI) Global $hGUI = GUICreate("Example", 300, 120) Global $idLabel = GUICtrlCreateLabel("", 20, 20, 180, 35) Global $idButton = GUICtrlCreateButton("2. GUI starten", 90, 70, 120, 35) ; GUI Events (hier OnEvent-Modus im Gegensatz zum 2. GUI) Opt("GUIOnEventMode", 1) GUISetOnEvent($GUI_EVENT_CLOSE, "raus") GUICtrlSetOnEvent($idButton, _klickButton) ; Tastenverknüpfungen erzeugen Global $aAccelKeys[][2] = [["{Enter}", $idButton]] GUISetAccelerators($aAccelKeys) ; Display the GUI. GUISetState(@SW_SHOW, $hGUI) ; Endlosschleife um GUI am Leben zu halten While Sleep(100) WEnd ; Funktionen welche bei GUI-Ereignissen ausgeführt werden Func _klickButton() Local $sEingabe = _AbfrageFenster() GUICtrlSetData($idLabel, $sEingabe) EndFunc Func raus() Exit EndFunc ; Funktion welche ein neues Fenster mit einer Eingabemöglichkeit erstellt und bei Beenden den Wert zurückgibt Func _AbfrageFenster($sTitle = "Abfrage", $sText = "Trag mal was ein") ; alten Wert von OnEvent merken Local $iOldOnEvent = Opt("GUIOnEventMode") ; auf Message-Loop-Modus umschalten (falls bisher OnEvent an war) Opt("GUIOnEventMode", 0) ; neues zusätzliches GUI erzeugen Local $hGUI = GUICreate($sTitle, 180, 110) Local $hOldGUI = GUISwitch($hGUI) ; Elemente dem GUI hinzufügen GUICtrlCreateLabel($sText & ":", 15, 15, 150, 20) Local $idInput = GUICtrlCreateInput("", 15, 35, 150, 20) ; create first item Local $idButton = GUICtrlCreateButton("Login", 50, 70, 73, 25) ; Tastenverknüpfungen erzeugen Local $aAccelKeys[2][2] = [["{Enter}", $idButton], ["{ESC}", $idButton]] GUISetAccelerators($aAccelKeys) ; GUI sichtbar schalten GUISetState(@SW_SHOW) ; Message-Loop-Endlosschleife Do Switch GUIGetMsg() Case $GUI_EVENT_CLOSE, $idButton ; Falls noch nichts eingegeben wurde - GUI nicht beenden lassen If StringStripWS(GUICtrlRead($idInput), 3) = "" Then MsgBox(48, "Fehler", "Eingabe vergessen!") ContinueLoop EndIf ExitLoop ; NICHT Exit! EndSwitch Until 0 Local $sReturn = GUICtrlRead($idInput) ; das temporäre GUI löschen GUIDelete($hGUI) ; wieder zum vorherigen GUI-Modus wechseln (hier ist es OnEvent) Opt("GUIOnEventMode", $iOldOnEvent) ; wieder zum äußeren GUI wechseln (nicht unbedingt nötig bei OnEvent) GUISwitch($hOldGUI) Return $sReturn EndFunc
-
Oben Return $params & ' ""' & $splayer & '"" -Idummy ' und unten ' $psexecArgs = "-u " + $username + " -p " + $password + " \\" + $computer + "' & $parameter & '""" + $batchFilePath + ''"''' & @CRLF & _
-
die resultierende PS Zeile sieht ja eigentlich gut aus
$psexecArgs = "-u $username -p $password \\" + $computer + " -i "c:\Program Files\VideoLAN\VLC\vlc.exe" -Idummy " + $batchFilePath
Wo sieht die denn gut aus?
Die doppelten Anführungszeichen sind ja gar nicht escaped im String und geöffnete Anführungszeichen ohne korrespondierendes schließendes Anführungszeichen glaube ich kaum, dass dies in PS so korrekt ist.
Wenn schon dann sollte es am Ende eher so aussehen: -
also das generierte Script was im Normalfall funktioniert
Die beiden gezeigten Skripte haben ja auch nicht das von mir beschriebene Problem.
-
Alternativ die betroffene Zeile (mit dem richtigen Inhalt/Formel) anklicken und dann doppelt auf das + unten rechts klicken.
Danke - den Kniff kannte ich noch nicht.
Aber da alle ihre Tricks auspacken hier mal meine Variante, welche ohne Maus auskommt:- Zur 1. Formelzelle navigieren
- STRG-SHIFT-ENDE um von dort bis zur letzten Zeile, welche noch Inhalt hat zu markieren
- STRG-U um die Formel in diesen Zellen zu übernehmen.
-
Ich denke das Problem liegt eher in dem resultierenden Powershell-Skript.
Das Skript welches du erzeugst sieht für mich - obwohl ich keine Ahnung von PS habe - nicht richtig aus:1. wird der Inhalt vom Dateipfad nach den doppelten Anführungszeichen mit einem Leerzeichen dazwischen gesetzt. Das könnte je nach Pfadparser Probleme bereiten.
2. Es gibt keine abschließenden doppelten Anführungszeichen.Es scheint also weniger ein Problem auf AutoIt-Seite zu sein.
Ich würde daher empfehlen dir das PS-Skript mal ausgeben zu lassen und mal händisch auszuführen.
Dann sollte dir der ps-Interpreter schon sagen was da noch im argen liegt.Eine AutoIt-Sache dennoch:
Ich verstehe den Sinn von @ComSpec hier noch nicht ganz.
Du willst ja etwas mit Powershell ausführen lassen und eben nicht mit der cmd.exe.
Warum schleifst du dann aber den Powershell-Aufruf erst noch durch den Kommandozeileninterpreter cmd.exe anstatt powershell direkt aufzurufen? -
In J5 =MITTELWERT($H$5:H5) schreiben und runter ziehen geht nicht?
Und vielleicht nochmal als Hinweis: Deine Problembeschreibung ist eigentlich nicht ausreichend.
Kein Mensch weiß anhand deiner Beschreibung, was thematisch in Zeile J5 stehen soll.
Ob das irgendwas aufsummiertes ist oder der Mittelwert bisher oder oder oder.
Einfach nur paar Zahlen hinklatschen und hoffen, dass die anderen das schon blicken was gemeint ist, ist in der Regel nicht ausreichend. -
Naja eine simple lineare 1D-Regression ist fix dahingerotzt:
AutoIt
Alles anzeigen; Datenpunkte Local $data[][2] = [[2.5,22],[3,17.5],[3.5,27],[4,23],[4.5,25],[5,22.5],[5.5,33],[6,26],[6.5,35]] ; Parameter der Regressionsgeraden berechnen: Local $aReg = _calc_LinRegression_1D($data) ; Ausgabe der Ergebnisse ConsoleWrite("y = " & $aReg[0] & " + " & $aReg[1] & "·x" & @CRLF) ; calculate a simple 1D linear overdetermined regression Func _calc_LinRegression_1D($aData) ; number of x-y-pairs in the data Local $iN = UBound($aData, 1) ; check the input data If $iN < 2 Or UBound($aData, 2) <> 2 Then Return SetError(1, UBound($aData, $iN), Null) ; calculate the sums Local $fSumX = 0, $fSumY = 0, $fSumXY = 0, $fSumX2 = 0, $fX, $fY For $i = 0 To $iN - 1 $fX = $aData[$i][0] $fY = $aData[$i][1] $fSumX += $fX $fSumY += $fY $fSumXY += $fX * $fY $fSumX2 += $fX * $fX Next ; calculate the coefficients Local $b = ($iN * $fSumXY - $fSumX * $fSumY) / ($iN * $fSumX2 - $fSumX * $fSumX) Local $a = ($fSumY - $b * $fSumX) / $iN ; return the coefficients Local $aRet[] = [$a, $b] Return $aRet EndFunc
Die Frage ist was du genau unter Regressionsanalyse verstehst.
Wenn es auch Angaben zur Signifikanz wie R² oder dem F-Test beinhalten soll dann kann man das durchaus auch noch mit implementieren.Wirklich eklig wird es dann aber, wenn es auch um allgemeine mehrdimensionale und nichtlineare Regression gehen soll.
Dann bedarf es hierzu der Ausgleichungsrechnung und das ist eine Sache die ich dir zwar mathematisch durchaus darstellen kann.
In AutoIt möchte ich das aber nur sehr ungern umsetzen.
Die Matrizenoperationen in reinem AutoIt sind nicht so schick und da wir ja auch die Inverse einer Matrix benötigen und das am besten auch noch numerisch stabil, dann wären das Cholesky-Verfahren, die QR-Zerlegung und die Singulärwertzerlegung angesagt.
Und das setze ich definitiv nicht in AutoIt um.
Sprich: Hier bedarf es externer Bibliotheken (am besten LAPACK), deren Wrapping aber auch nicht unbedingt trivial ist.
Bereits umgesetzt gibt es die Eigen4AutoIt-Geschichte aber die gefällt mir persönlich nicht, da ich das für völlig überladen halte.
Also nochmal kurz: Simple lineare Regression: ok - alles darüber: lieber nicht.Btw: Ist das nicht die falsche Kategorie? Talk ist eher für allgemeines, nicht AutoIt-spezifisches.
-
Ihr habt beide komplett Recht.
Da ist noch ein ziemlicher Schnitzer in der Projektion.
Ich will aber auf Teufel komm raus kein klassisches UV-Mapping umsetzen sondern versuche immer noch eine möglichst performantere Variante zu finden.
Mal sehen ob und wie weit ich komme.
Bis dahin ist obiges Skript natürlich zu ignorieren. -
mir kommt es vor, dass die Projektion des Bildes auf die Kugel nicht richtig aussieht
Evtl. kommt dies dadurch zustande, dass derzeit nur die Rotation um die X und Y-Achse implementiert wurde.
Das sieht erstmal komisch aus, wenn die Geraden in der Textur immer gleich ausgerichtet bleiben.
Aber für die reine Kugelbewegung ohne Spin gibt es tatsächlich ja auch keine Drehung um die Z-Achse.
Das werde ich später sicherlich auch noch mit einbauen aber für die Thematik einer rollenden Kugel hier war das noch nicht nötig.Der Flaschenhals waren Trigonometrie aufrufe in der MapImage2Sphere() Funktion.
Und jetzt stell dir vor wie deine Funktion rennen würde, wenn du die trigonometrischen Funktionen auf ein Minimum reduzieren könntest.
Genau das habe ich ja versucht in meiner Funktion umzusetzen.
Wenn man eine Kugel mit einem Radius von 25 Pixeln zeichnen lässt, dann sind die einzigen Aufrufe trigonometrischer Funktionen bei mir 25x ein ArcSin - das wars.
Und wie man schön an Mars Beispiel sieht, ist die Texture-Map starr. Das heißt man kann diese für jede Kugel nur einmal erstellen und braucht dann lediglich die Offsets aufgrund der Rotationen hinzuzufügen. Dann kommt jeder neue Kugelframe komplett ohne trigonometrische Funktionsaufrufe aus.
Mir ist schon bewusst, dass man sich das Leben viel leichter machen könnte, wenn man mit UV-Mapping da herangeht.
Aber dann haben wir halt diese exzessive Nutzung von trigonometrischen Funktionen und ich denke unser Anspruch liegt höherDer Texturabdruck dieser Formel ist auch nicht ganz richtig für eine "korrekte" perspektivische Projektion einer Ebene auf eine Kugeloberfläche (Das Abbild ist eine um 45° gedrehte Raute).
Also perspektivisch stimmt das aus meiner Sicht schon erst einmal - Korrekturen sind aber natürlich erwünscht wenn ich daneben liegen sollte.
Ein wirklicher Fehler steckt aber tatsächlich im Texturemapping - und zwar beim Mapping der Y-Koordinate.
Wenn dort ein Bereichsüberlauf stattfindet, dann springt er auf die andere Seite (Modulo lässt grüßen).
Bei der X-Koordinate ist das ja auch so richtig.
Stattdessen wäre es aber ja für die Y-Koordinate korrekt den Überlauf an der jeweiligen Kante zu spiegeln.
Oder um es plastisch zu machen: Wenn man die Erde mappt und bei der Arktis über den Nordpol hinaus mappt, dann hat man auf einmal die Antarktis als nächsten Pixel...
Das passe ich natürlich unbedingt noch an - ist mir bei dieser symmetrischen Textur hier nicht aufgefallen. -
Werden Anführungszeichen in Lua nicht mit vorangesteltem Backslash escaped?
-
Dieses Thema soll als Diskussionsort für ein Problem dienen, welches wir kurz in der Shoutbox mit UEZ erörtert haben.
Auch wenn du ( UEZ) paar Tage nichts von mir gehört hast, war ich nicht untätig.
Ich habe mir brav FreeBasic angesehen.
Da aber sowohl die Sprache, als auch die Thematik, für mich Neuland waren, musste ich ein eigenes Programm von Grundauf erstellen um die Sache zu verstehen, anstatt am vorhandenen Skript rumzudoktorn.
Kurzum: Irgendwann habe ich aber entnervt aufgegeben - FB und ich werden wohl keine Freunde mehr.
Anstatt mich nun noch mit einer anderen Sprache rumzuschlagen habe ich mir für das Thema good old AutoIt wieder hochgeholt und versucht damit nun zu zeigen wie ich mir das algorithmisch vorstelle, was ich in der Shoutbox beschrieben habe.
Das ganze hat dann aber auch länger gebraucht, da ich absolut Null Plan von GDI+ hatte.
Am Ende habe ich aber nun etwas vorzeigbares erstellt was evtl. als Grundlage für weitere Diskussionen und Verbesserungen dienen kann.
Im Idealfall sind hieran die Mathematik dahinter schon erkennbar, so dass du bestimmte Dinge in dein FB-Programm übernehmen kannst:AutoIt
Alles anzeigen#include <GDIPlus.au3> #include <GUIConstantsEx.au3> OnAutoItExitRegister(_exit) Opt("GUIOnEventMode", 1) Global Const $PI = ACos(-1), $PI_2 = ASin(1), $PI_4 = ATan(1), $_2PI = $PI + $PI main() Func main() Local $mC = _b3d_createCanvas(1000, 750) ; start moving textured ball Local $mTexture = _b3d_importTexture(@ScriptDir & "\13h_310x156.bmp") _b3d_ballMoving($mC, 50, 50, 50, 5, 3, $mTexture) ; GUI endless loop While Sleep(100) WEnd EndFunc ; demo function for drawing a moving ball Func _b3d_ballMoving(ByRef $mCanvas, Const $iRadius, Const $iXStart, Const $iYStart, Const $fVx, Const $fVy, $mTexture, Const $fRotX0 = 0, Const $fRotY0 = 0) Local $iXPos = $iXStart, $iYPos = $iYStart Local $fRotX = $fRotX0, $fRotY = $fRotY0 Local $fU = 2 * $PI * $iRadius Do ; clear old image _GDIPlus_GraphicsClear($mCanvas.Context, 0xFF303030) ; draw textured sphere _b3d_drawTexturedSphere($mCanvas, $iXPos, $iYPos, $iRadius, $mTexture, $fRotX, $fRotY) _b3d_canvasShow($mCanvas) $iXPos += $fVx $iYPos += $fVy $fRotX += __b3d_modPos($fVy, $fU) / $fU * $_2PI $fRotY -= __b3d_modPos($fVx, $fU) / $fU * $_2PI Until $iXPos > 900 EndFunc ; draws a sphere and map a texture on it Func _b3d_drawTexturedSphere(ByRef $mCanvas, $iMx, $iMy, $iR, $mTexture, $iRotX = 0, $iRotY = 0) Local $iTexWidth = $mTexture.width Local $iTexHeight = $mTexture.height Local $iX, $iY, $iHalfChord, $iSegmentHeight Local $fXTex, $fYTex Local $iColor Local $aBitmap = $mTexture.Pixels ; faster than _GDIPlus_BitmapGetPixel Local $hBitmap = $mCanvas.Bitmap ; Koordinaten-Transformation als LUT um Doppelberechnung zu vermeiden ; Zum jeweiligen aktuellen Kreissegment (Radius - aktuelle Position im Kreis) wird die dazugehörige Koordinate im Texturraum berechnet Local $aTexCoordsY[$iR + 1][2] Local $aTexCoordsX[$iR + $iR + 1] Local $fRad, $fRadX, $fRadY, $fRadYBottom For $iH = 0 To $iR ; der Kreisbogenabstand vom Zenitpunkt (=Kugelwinkel in rad) $fRad = ASin(($iR-$iH) / $iR) ; upper half $fRadY = $fRad + $iRotX $aTexCoordsY[$iH][0] = Round(__b3d_modPos($PI_2 - $fRadY, $Pi) / $Pi * ($iTexHeight - 1)) ; lower half $fRadYBottom = $fRadY - $fRad - $fRad $aTexCoordsY[$iH][1] = Round(__b3d_modPos($PI_2 - $fRadYBottom, $Pi) / $Pi * ($iTexHeight - 1)) ; left half $fRadX = $PI - $fRad + $iRotY ; "+ $PI": um 0-Punkt auf Texturmitte zu platzieren $aTexCoordsX[$iH] = Round(__b3d_modPos($fRadX , $_2PI) / $_2PI * ($iTexWidth - 1)) ; right half $fRadXRight = $fRad + $PI + $iRotY ; "+ $PI": um 0-Punkt auf Texturmitte zu platzieren $aTexCoordsX[$iR + $iR - $iH] = Round(__b3d_modPos($fRadXRight, $_2PI) / $_2PI * ($iTexWidth - 1)) Next ; middle line (extra to avoid double processing): $iYTexMid = $aTexCoordsY[$iR][0] For $iX = $iMx - $iR To $iMx + $iR $fXTex = $aTexCoordsX[$iX - $iMx + $iR] $iColor = $aBitmap[$fXTex][$iYTexMid] DllCall($__g_hGDIPDll, "int", "GdipBitmapSetPixel", "handle", $hBitmap, "int", $iX, "int", $iMy, "uint", $iColor) ; faster than extra _GDIPlus_BitmapSetPixel() Next ; rest of circle area For $iSegmentHeight = 0 To $iR - 1 ; halbe Sehnenlänge $iHalfChord = Int(Round(Sqrt(2*$iR*$iSegmentHeight - ($iSegmentHeight*$iSegmentHeight)))) ; Koordinaten des Quellpixels aus dem Texturbitmap $fYTex = $aTexCoordsY[$iSegmentHeight][0] $fYTexBottom = $aTexCoordsY[$iSegmentHeight][1] For $iX = $iMx - $iHalfChord To $iMx + $iHalfChord $fXTex = $aTexCoordsX[$iX - $iMx + $iR] ; draw top case $iColor = $aBitmap[$fXTex][$fYTex] $iY = $iMy + $iSegmentHeight - $iR DllCall($__g_hGDIPDll, "int", "GdipBitmapSetPixel", "handle", $hBitmap, "int", $iX, "int", $iY, "uint", $iColor) ; draw bottom case $iColor = $aBitmap[$fXTex][$fYTexBottom] $iY = $iMy - $iSegmentHeight + $iR DllCall($__g_hGDIPDll, "int", "GdipBitmapSetPixel", "handle", $hBitmap, "int", $iX, "int", $iY, "uint", $iColor) Next Next EndFunc Func _b3d_importTexture($sPath) Local $mTexture[] Local $hBitmap = _GDIPlus_BitmapCreateFromFile($sPath) $mTexture.Bitmap = $hBitmap If @error Then Return SetError(@error, @extended, Null) $mTexture.width = _GDIPlus_ImageGetWidth($hBitmap) $mTexture.height = _GDIPlus_ImageGetHeight($hBitmap) ; convert to AutoIt-Array for faster pixel access Local $aBitmap[$mTexture.width][$mTexture.height], $x, $y For $x = 0 To $mTexture.width - 1 For $y = 0 To $mTexture.height - 1 $aBitmap[$x][$y] = _GDIPlus_BitmapGetPixel($hBitmap, $x, $y) Next Next $mTexture.Pixels = $aBitmap Return $mTexture EndFunc ; function to draw a filled circle on a bitmap Func _b3d_drawCircleFilled(ByRef $mCanvas, $iMx, $iMy, $iR, $sColor = "0xFFFFFFFF") Local $iX, $iY, $iHalfChord, $iSegmentHeight ; middle line (extra to avoid double processing): For $iX = $iMx - $iR To $iMx + $iR _GDIPlus_BitmapSetPixel($mCanvas.Bitmap, $iX, $iMy, $sColor) Next ; rest of circle area For $iSegmentHeight = 0 To $iR - 1 $iHalfChord = Round(Sqrt(2*$iR*$iSegmentHeight - ($iSegmentHeight*$iSegmentHeight))) For $iX = $iMx - $iHalfChord To $iMx + $iHalfChord $iY = $iMy + $iSegmentHeight - $iR _GDIPlus_BitmapSetPixel($mCanvas.Bitmap, $iX, $iY, $sColor) $iY = $iMy - $iSegmentHeight + $iR _GDIPlus_BitmapSetPixel($mCanvas.Bitmap, $iX, $iY, $sColor) Next Next EndFunc ; zeigt den aktuellen Zustand der Canvas (des Zeichnungsbitmaps an) Func _b3d_canvasShow(ByRef $mCanvas) _GDIPlus_GraphicsDrawImage($mCanvas.Graphic, $mCanvas.Bitmap, 0, 0) EndFunc Func _b3d_createCanvas($iWidth, $iHeight) ; map which holds all the necessary parameters Local $mCanvas[] $mCanvas.width = $iWidth $mCanvas.height = $iHeight ; Initialize GDI+ library _GDIPlus_Startup() ; create GUI $mCanvas.GUI = GUICreate("Ball 3D", $iWidth, $iHeight) GUISetBkColor(0x303030, $mCanvas.GUI) ;set GUI background color GUISetOnEvent($GUI_EVENT_CLOSE, _exit) GUISetState(@SW_SHOW, $mCanvas.GUI) ; create Canvas $mCanvas.Graphic = _GDIPlus_GraphicsCreateFromHWND($mCanvas.GUI) $mCanvas.Bitmap = _GDIPlus_BitmapCreateFromGraphics($iWidth, $iHeight, $mCanvas.Graphic) $mCanvas.Context = _GDIPlus_ImageGetGraphicsContext($mCanvas.Bitmap) Return $mCanvas EndFunc ; positive modulo Func __b3d_modPos($divident, $divisor) Local $m = Mod($divident, $divisor) Return $m < 0 ? $m + $divisor : $m EndFunc Func _exit() _GDIPlus_Shutdown() Exit EndFunc
Die Texturdatei liegt im Anhang.
-
Wenn man WMI verwendet, kann man die Abfrage auch bis zu einem Einzeiler hin schrumpfen:
AutoItGlobal $sLabel = "Backup" $bFound = ObjGet("winmgmts:\\localhost\root\CIMV2").ExecQuery('SELECT * FROM Win32_Volume WHERE Label="' & $sLabel & '"', "WQL").Count > 0 MsgBox(0, "Gefunden?", $bFound)
Man kann damit auch relativ leicht auf andere Eigenschaften wie DeviceID, Seriennummern etc. abfragen.