CMD, StringSplit und die Sache mit dem sauber programmieren

  • Hallo liebe Community :thumbup:

    Ich bin dabei, einen W-LAN Hotspot Programm (So was wie Connectify) zu programmieren und bin gut dran.
    Nur mal eine kleine Frage wegen Sauberkeit und weil ich unerfahren mit Arrays bin:
    Sieht so ein Script "gut" aus oder kann man es auch weiter kürzen oder schöner schreiben?

    Spoiler anzeigen
    [autoit]


    ; _ArrayDisplay() ist hier als Debugging gedacht, sie werden später entfernt.

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

    #include <Constants.au3>
    #include <Array.au3>
    #include <StringConstants.au3>

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

    _GetHostedNetworkSetting()

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

    Func _GetHostedNetworkSetting()
    ;Wir wollen hier Modus, SSID-Name, Maximale Clientanzahl, Authentifizierung, Verschlüsselung.
    Local $aFinalArray[11]
    Local $iFACounter = 1

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

    $sOutput = _CMDRead("netsh wlan show hostednetwork") ;Ausführen des Consolenbefehls
    $aFullResult = StringSplit($sOutput, @CR) ;Aufteilen des Resultats
    _ArrayDisplay($aFullResult) ;Ausgabe wie es in CMD ist

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

    For $iArrayCounter = 4 To 8 Step 1 ;Auslesen der einzelnen Einstellungen

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

    $aLineResult = StringSplit($aFullResult[$iArrayCounter], ":") ;Aufteilung zwischen Einstellungen und Zustand
    _ArrayDisplay($aLineResult) ;Ausgabe pro Einstellung

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

    ;Löschen der unnötigen Leerzeichen
    $sResultL = StringStripWS($aLineResult[1], $STR_STRIPLEADING + $STR_STRIPTRAILING + $STR_STRIPSPACES)
    $sResultR = StringStripWS($aLineResult[2], $STR_STRIPLEADING + $STR_STRIPTRAILING + $STR_STRIPSPACES)

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

    ;Resultate in einen Array schreiben
    $aFinalArray[$iFACounter] = $sResultL
    $iFACounter += 1
    $aFinalArray[$iFACounter] = $sResultR
    $iFACounter += 1
    Next
    _ArrayDisplay($aFinalArray) ;Fertiger Array
    Return $aFinalArray
    EndFunc

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

    Func _CMDRead($command)
    Local $line

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

    $CMD = Run(@ComSpec & " /c " & $command, @SystemDir, @SW_HIDE, $STDERR_CHILD + $STDOUT_CHILD)

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

    While 1
    $line &= StdoutRead($CMD)
    If @error Then ExitLoop
    Wend
    Return $line
    EndFunc

    [/autoit]

    Einmal editiert, zuletzt von bbm1995 (5. August 2014 um 19:03)

    • Offizieller Beitrag

    Siht doch okay aus. Hier noch ne Variante:

    Spoiler anzeigen
    [autoit]

    #include <Constants.au3>
    #include <Array.au3>
    #include <StringConstants.au3>
    _GetHostedNetworkSetting()

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

    Func _GetHostedNetworkSetting()
    ;Wir wollen hier Modus, SSID-Name, Maximale Clientanzahl, Authentifizierung, Verschlüsselung.
    Local $sOutput = _CMDRead("netsh wlan show hostednetwork") ;Ausführen des Consolenbefehls
    Local $re = StringRegExp($sOutput, '\:\s+(.*)', 3)
    _ArrayDisplay($re) ;Fertiger Array
    Return $re
    EndFunc

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

    Func _CMDRead($command)
    Local $line

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

    $CMD = Run(@ComSpec & " /c " & $command, @SystemDir, @SW_HIDE, $STDERR_CHILD + $STDOUT_CHILD)

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

    While 1
    $line &= StdoutRead($CMD)
    If @error Then ExitLoop
    Wend
    Return $line
    EndFunc

    [/autoit]
    • Offizieller Beitrag

    Hallo bbm,

    Ich finde das sieht schon ganz gut und sauber aus! Bei _CMDRead hast du die Variablen nicht ganz "richtig" benannt.
    Ein weiteres Problem ist: In jedem Code gehören Fehlerabfragen! Was passiert wenn der User kein WLAN hat? Was wenn er mehrere hat? Ich zum Beispiel hab an meinem festen PC kein WLAN und wurde gleich mit einer schönen Fehlermeldung von Autoit rausgeschmissen

    Code
    "001.au3" (21) : ==> Array variable has incorrect number of subscripts or subscript dimension range exceeded.:


    ist auch logisch, weil der StringSplit in Zeile 16 nicht genügend CR's findet.

    Allgemein würde ich auch stark davon abraten, Kommandozeilenparameter zu parsen, da sie abhängig von Windows Version und Spracheinstellungen unterschiedliche Ergebnisse ausgeben können.
    Da solltest du eine elegantere Lösung, entweder über die WinApi oder über WMI (schaue da mal nach Scriptomatic). Google sollte dir hier weiterhelfen können.

    Spoiler anzeigen
    [autoit]

    ; _ArrayDisplay() ist hier als Debugging gedacht, sie werden später entfernt.

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

    #include <Constants.au3>
    #include <Array.au3>
    #include <StringConstants.au3>

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

    _GetHostedNetworkSetting()
    If @error Then MsgBox(16, "", "Fehler: " & @error)

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

    Func _GetHostedNetworkSetting()
    ;Wir wollen hier Modus, SSID-Name, Maximale Clientanzahl, Authentifizierung, Verschlüsselung.
    Local $aFinalArray[11]
    Local $iFACounter = 1

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

    $sOutput = _CMDRead("netsh wlan show hostednetwork") ;Ausführen des Consolenbefehls
    $aFullResult = StringSplit($sOutput, @CR) ;Aufteilen des Resultats
    _ArrayDisplay($aFullResult) ;Ausgabe wie es in CMD ist

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

    ;Fehlerabfrage 1:
    If $aFullResult[0] < 8 Then Return SetError(1, 0, False)

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

    For $iArrayCounter = 4 To 8 Step 1 ;Auslesen der einzelnen Einstellungen

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

    $aLineResult = StringSplit($aFullResult[$iArrayCounter], ":") ;Aufteilung zwischen Einstellungen und Zustand
    _ArrayDisplay($aLineResult) ;Ausgabe pro Einstellung

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

    ;Fehlerabfrage 2:
    If $aLineResult[0] < 2 Then Return SetError(2, 0, 0)

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

    ;Löschen der unnötigen Leerzeichen
    $sResultL = StringStripWS($aLineResult[1], $STR_STRIPLEADING + $STR_STRIPTRAILING + $STR_STRIPSPACES)
    $sResultR = StringStripWS($aLineResult[2], $STR_STRIPLEADING + $STR_STRIPTRAILING + $STR_STRIPSPACES)

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

    ;Resultate in einen Array schreiben
    $aFinalArray[$iFACounter] = $sResultL
    $iFACounter += 1
    $aFinalArray[$iFACounter] = $sResultR
    $iFACounter += 1
    Next
    _ArrayDisplay($aFinalArray) ;Fertiger Array
    Return $aFinalArray
    EndFunc ;==>_GetHostedNetworkSetting

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

    Func _CMDRead($sCommand)
    Local $sLine, $hPID

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

    $hPID = Run(@ComSpec & " /c " & $sCommand, @SystemDir, @SW_HIDE, $STDERR_CHILD + $STDOUT_CHILD)
    ProcessWaitClose($hPID)
    $sLine = StdoutRead($hPID)

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

    Return $sLine
    EndFunc ;==>_CMDRead

    [/autoit]

    Gruß,
    Spider

    Edit: Achja, in der CMD Funktion hast du eine While Schleife die untunterbrochen den StdOut abfragt, das führt zu hoher Prozessorlast. Außerdem hast du in der Funktion nicht alle Variablen deklariert. Schau dir einfach mal mein Beispiel an ;)

  • Funktionsinterne Variablen wie z.B. $Cmd hast du teilweise nicht als lokal deklariert. Dadurch bekommen sie implizit Dim als Scope.
    Das heißt wiederrum: Existiert global eine Variable $Cmd (was bei dieser Bezeichnung nicht unwahrscheinlich ist), wird diese überschrieben.

    Man kann sich selbst zu einer ordentlichen Deklaration zwingen wenn man am Anfang des Skriptes folgende Option setzt:

    [autoit]

    Opt("MustDeclareVars", 1)

    [/autoit]


    Dann schmeißt AutoIt bei jeder nicht explizit deklarierten Variable einen Fehler.

    Ansonsten: Prinzipiell doch ganz vernünftig aufgebaut.
    Es kommt, vor allem bei Skriptsprachen wie AutoIt, auf den Anwendungsfall an.
    Wenn du dir mal schnell ein Skriptchen für irgendeine Automation hinwürfelst dann brauchst du nicht auf perfekte Codestrukturierung zu achten.
    Wichtig wird es aber dann wenn du das ganze verteilen willst so dass andere es in Ihre Programme einbauen können oder Ähnliches.
    Dann sollte man sich schon mehr auf wirklich sauberen Code achten da dort die Umgebungen eben nicht von vornherein klar sind.

    Einmal editiert, zuletzt von AspirinJunkie (5. August 2014 um 12:47)

  • Super, danke euch allen :thumbup:

    Xenobiologist , nicht schlecht, mit einem einzigen RegExp kann man vieles kürzen. Ist mir aber noch zu kompliziert, zu verstehen was da passiert, aber gut gibt es hier Tutorials dafür ^^

    GtaSpider , genau so ein Beispiel habe ich gesucht, wie man @error und SetError() benutzen kann, danke nochmals :thumbup:
    Das mit der CMD ist leider ein Copy-Paste, aber danke für eine Alternative :)
    Leider stürzt bei mir Scriptomatic ab, braucht viel zu lange, bis da was kommt oder die Scripte funktionieren teilweise nicht :/

    AspirinJunkie , das mit der $Cmd habe ich jetzt auch verstanden, nachdem ich den Code von GtaSpider verglichen habe, auch dir danke ich dafür :)
    Der Grund wieso ich es sauber halten möchte ist, falls ich das Script nach einer vielleicht langen Zeit anschaue, dass gleich sehe, was dieser und jener Teil des Scripts genau tut.