Wie wurde Programm gestartet? In cmd.exe (DOS-Box) oder Verknüpfung / Doppelklick / Explorer

  • Moin,

    vielleicht steht es schon irgendwo aber ich finde es nicht:

    Kann man irgendwie Feststellen WIE mein AutoIt Programm gestartet wurde?

    Hintergrund:
    Ich habe ein Programm geschrieben mit dem man per Command-Line Parametern ($CmdLine[x]) sich mit einem Zabbix Server verbindet und Werte abfragt etc.
    Startet man das Programm ohne Parameter so wird eine Hilfe angezeigt.

    Das Programm ist als "CUI instead of GUI EXE" kompiliert.

    Nun würde ich aber gerne einen Dialog anzeigen wenn das Programm statt in der DOS-Box per Doppelklick etc. gestartet wurde - kann ich irgendwie feststellen wie es gestartet wurde?

    Wenn es dazu als normale GUI-EXE kompiliert werden muss ... nun irgendwo hatte ich ein Beispiel wie man trotzdem in die DOS-Box schreibt ... aber mir fehlt trotzdem noch der Ansatz.

    Danke,
    BLinz

  • Moin!

    Mein Vorschlag wäre, das Programm aus der Command Line mit einem zusätzlichen Parameter zu starten.
    Da dieser bei einem Doppelklick im Explorer fehlt, kann man das entsprechend auswerten.

    Etwas in der Richtung:

    [autoit]

    If $CmdLine[0] > 0 Then
    MsgBox(0, "", "Start von der Command Line!" & @CRLF & "Parameter: " & $CmdLine[1])
    Else
    MsgBox(0, "", "Doppelklick im Explorer!")
    EndIf

    [/autoit]


    Das das nur mit dem kompilierten Programm funktioniert, sollte klar sein :rolleyes:

    Code
    C:>programm.exe 123


    Sanfte Grüße :D

  • Und was passiert wenn ich eine zufällige Datei auf die Exe ziehe? CMDLine hat dann den Wert des Pfades der draufgezogenen Datei.


    Ich kann den Parameter doch auswerten und zur Not irgendwas kryptisches nehmen, was auf keinen Fall zufällig kommen kann.
    Kann deine Bedenken echt nicht nachvollziehen.

    [autoit]

    If $CmdLine[0] > 0 Then
    If $CmdLine[1] = "123" Then
    MsgBox(0, "", "Start von der Command Line!" & @CRLF & "Parameter: " & $CmdLine[1])
    Else
    MsgBox(0, "", "Start im Explorer!" & @CRLF & "Parameter: " & $CmdLine[1])
    EndIf
    Else
    MsgBox(0, "", "Doppelklick im Explorer!")
    EndIf

    [/autoit]
  • Per WMI die Eltern-PID holen. ;)

    Spoiler anzeigen
    [autoit]


    #include <Constants.au3>

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

    Func _GetParentExecutableFile()
    ;by chesstiger (autoit.de)
    $sCommand = "wmic process where (processid=" & @AutoItPID & ") get parentprocessid"
    $hCommand = Run(@ComSpec & " /c " & $sCommand, @SystemDir, @SW_HIDE, $STDERR_CHILD + $STDOUT_CHILD)
    Local $sQueryResult
    While 1
    $sQueryResult &= StdoutRead($hCommand)
    If @error Then ExitLoop
    WEnd
    $aRegEx = StringRegExp($sQueryResult, "\d+", 3)
    $iPID = $aRegEx[0]
    $aProcesses = ProcessList()
    For $i = 0 To $aProcesses[0][0]
    If $aProcesses[$i][1] = $iPID Then Return SetExtended($iPID, $aProcesses[$i][0])
    Next
    EndFunc

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

    $sParentEXE = _GetParentExecutableFile()
    $iPID = @extended

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

    MsgBox(0, "", "Der Parent-Prozess heißt: " & $sParentEXE & "." & @CRLF & "Er hat die PID: " & $iPID & ".")

    [/autoit]

    lg chess

    Edit: Ja, per WMI-Objekt wäre effizienter. Habe aber gerade kein Code-Sample von der Benutzung des WMI-Objekts da gehabt, deswegen die CommandLine-Variante. ^^

  • Edit: Ja, per WMI-Objekt wäre effizienter. Habe aber gerade kein Code-Sample von der Benutzung des WMI-Objekts da gehabt, deswegen die CommandLine-Variante. ^^


    Sehr schicke Funktion. Die Objekt-Variante würde ich auch gerne sehen, wenns irgendwann mal möglich ist :thumbup:

    Übrigens muß bei mir (Win7 Pro) der Pfad angepasst werden, weil das Programm "WMIC.exe" nicht direkt im @SystemDir ist und auch nicht registriert ist:

    [autoit]

    $hCommand = Run(@ComSpec & " /c " & $sCommand, @SystemDir & "\wbem", @SW_HIDE, $STDERR_CHILD + $STDOUT_CHILD)

    [/autoit]
  • Prima chesstiger - da hab ich doch den vermissten Ansatz.

    Als Dank gibt es die direkte WMI Version deines Skripts ... die könnte noch 2 Schritte kleiner sein, leider weis ich nicht genau was ich zurück bekomme wenn ich direkt nach dem ParentProcess frage.

    [autoit]

    ; Fehler Abfangen bei Zugriff auf WMI Schnittstelle
    Global $oMyError = ObjEvent("AutoIt.Error","MyErrFunc"), $f_COMError = False

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

    ; ##################################################################################################################################
    ; Im Fehlerfall wird diese Routine aufgerufen
    Func MyErrFunc()
    Local $HexNumber=hex($oMyError.number,8)
    Msgbox(0,"","We intercepted a COM Error !" & @CRLF & _
    "Number is: " & $HexNumber & @CRLF & _
    "WinDescription is: " & $oMyError.windescription & @CRLF & _
    "Source is: " & $oMyError.source & @CRLF & _
    "ScriptLine is: " & $oMyError.scriptline)
    $f_COMError = True; something to check for when this function returns
    Endfunc

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

    ; ##################################################################################################################################
    Func _GetParentExecutableFileWMI()
    ;1. Version by chesstiger (autoit.de)
    ;2. Version by BLinz (autoit.de)
    ; WMI Objekt holen
    $oWMI = ObjGet("winmgmts:{impersonationLevel=impersonate,authenticationLevel=pktPrivacy, (Debug)}!\\.\root\cimv2")
    ; Wenn es geklappt hat ....
    If IsObj($oWMI) Then
    ;Infos über unseren Prozess holen
    $colProcs = $oWMI.ExecQuery("select * from win32_process where ProcessId = " & @AutoItPID)
    ;Parent Prozess holen
    For $oProc In $colProcs
    $iParentPID = $oProc.ParentProcessId
    Next
    EndIf
    ; Liste aller Prozesse in einem Array holen
    $aProcesses = ProcessList()
    ; Unseren Parent-Prozess suchen
    For $i = 0 To $aProcesses[0][0]
    If $aProcesses[$i][1] = $iParentPID Then
    Return SetExtended($iParentPID, $aProcesses[$i][0])
    EndIf
    Next
    EndFunc

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

    ; ##################################################################################################################################
    ; Hauptprogramm

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

    $sParentEXE = _GetParentExecutableFileWMI()
    $iPID = @extended

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

    MsgBox(0, "", "Der Parent-Prozess heißt: " & $sParentEXE & "." & @CRLF & "Er hat die PID: " & $iPID & ".")

    [/autoit]

    Funktioniert EINWANDFREI sowohl als GUI oder CUI kompliert !!! Genau das was ich suchte! :D

    Gruß,
    BLINZ

  • Hier eine ältere nicht WMI Version:

    Spoiler anzeigen
    [autoit]


    #include <Process.au3>

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

    $appname = "Test.exe"

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

    If $CmdLine[0] = 0 Then
    If _ProcessGetName(ProcessGetParent(@AutoItPID)) = "cmd.exe" Then
    ;Help() ;if no parameter is given from cmd.exe then call help
    Else
    WinSetState("[CLASS:ConsoleWindowClass]", "", @SW_HIDE)
    MsgBox(16, "Wrong program call", "Program was not called from CMD!" & @CRLF & @CRLF & _ ;program called not from cmd.exe
    "Please start " & $appname & " from cmd.exe!", 10)
    Exit
    EndIf
    EndIf

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

    Func ProcessGetParent($i_PID) ;get PID from parent process done by SmOke_N
    Local $TH32CS_SNAPPROCESS = 0x00000002
    Local $a_tool_help = DllCall("Kernel32.dll", "long", "CreateToolhelp32Snapshot", "int", $TH32CS_SNAPPROCESS, "int", 0)
    If IsArray($a_tool_help) = 0 Or $a_tool_help[0] = -1 Then Return SetError(1, 0, $i_PID)
    Local $tagPROCESSENTRY32 = _
    DllStructCreate( _
    "dword dwsize;" & _
    "dword cntUsage;" & _
    "dword th32ProcessID;" & _
    "uint th32DefaultHeapID;" & _
    "dword th32ModuleID;" & _
    "dword cntThreads;" & _
    "dword th32ParentProcessID;" & _
    "long pcPriClassBase;" & _
    "dword dwFlags;" & _
    "char szExeFile[260]" _
    )
    DllStructSetData($tagPROCESSENTRY32, 1, DllStructGetSize($tagPROCESSENTRY32))
    Local $p_PROCESSENTRY32 = DllStructGetPtr($tagPROCESSENTRY32)
    Local $a_pfirst = DllCall("Kernel32.dll", "int", "Process32First", "long", $a_tool_help[0], "ptr", $p_PROCESSENTRY32)
    If IsArray($a_pfirst) = 0 Then Return SetError(2, 0, $i_PID)
    Local $a_pnext, $i_return = 0
    If DllStructGetData($tagPROCESSENTRY32, "th32ProcessID") = $i_PID Then
    $i_return = DllStructGetData($tagPROCESSENTRY32, "th32ParentProcessID")
    DllCall("Kernel32.dll", "int", "CloseHandle", "long", $a_tool_help[0])
    If $i_return Then Return $i_return
    Return $i_PID
    EndIf
    While @error = 0
    $a_pnext = DllCall("Kernel32.dll", "int", "Process32Next", "long", $a_tool_help[0], "ptr", $p_PROCESSENTRY32)
    If DllStructGetData($tagPROCESSENTRY32, "th32ProcessID") = $i_PID Then
    $i_return = DllStructGetData($tagPROCESSENTRY32, "th32ParentProcessID")
    If $i_return Then ExitLoop
    $i_return = $i_PID
    ExitLoop
    EndIf
    WEnd
    DllCall("Kernel32.dll", "int", "CloseHandle", "long", $a_tool_help[0])
    Return $i_return
    EndFunc ;==>ProcessGetParent

    [/autoit]

    Kann sein, dass man sich auch von WinAPIEx.au3 bzw. in der letzten Beta bezgl. ProcessGetParent bedienen kann.


    Gruß,
    UEZ

    Auch am Arsch geht ein Weg vorbei...

    ¯\_(ツ)_/¯