0

カメラシステムの起動を少し簡単にするために、作業用の AutoIT コードを作成しようとしています。現時点では、GUI を起動し、追加できるカメラ サーバーのリストを表示し、新しいサーバーを内部ディレクトリに追加するためのコードを取得できました。私が少し問題を抱えているのは、プログラムが新しく起動した Milestone ソフトウェアに切り替え、情報を入力して Enter をクリックするセクションです。この問題は、WinWaitActive($handle) が正しいハンドルを使用していないか、使用している関数が正しくない start() 関数の一部に関連していることがわかりました。

私の最終的な目標は、4 秒間待機し、ハンドルまたは PID を使用して、現在選択されているウィンドウから新しく開いたマイルストーン ウィンドウにフォーカスを切り替え、2 つのタブと IP アドレスを送信し、ENTER を送信できるようにすることです。

#include <MsgBoxConstants.au3>
#include <Array.au3>
#include <ComboConstants.au3>
#include <ButtonConstants.au3>
#include <EditConstants.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <GuiComboBox.au3>

#Region EDIT THE BELOW INFORMATION-------------------------------------------------------------------------------------------------------------------------------------------
Local Const $milestone = "C:\Program Files\Milestone\XProtect Smart Client\Client.exe"          ;Path to software
Local $Title = "Milestone Camera Selector"                                                         
#EndRegion-------------------------------------------------------------------------------------------------------------------------------------------------------------------

#Region Script---------------------------------------------------------------------------------------------------------------------------------------------------------------
Local $iFileExists = FileExists($milestone)                                                 ;Check if the file exists, returns a 1 or 0
Global $list = IniReadSection(@TempDir & "\" & $Title & "\config.ini","Server")             ;Read the ini file, this builds a 2D Array [X][0] is the key [X][1] is the value
HotKeySet("{F1}", "help")

If $iFileExists Then                                                                        ;If FileExists = 1 (exists) then
    If Not FileExists(@TempDir & "\" & $Title) Then                                         ;If config directory does not exists then
        Do
        DirCreate(@TempDir & "\" & $Title)                                                  ;Create a directory in TempDir for the config.ini file to be stored locally
        Until FileExists(@TempDir & "\" & $Title)
        IniWrite(@TempDir & "\" & $Title & "\config.ini", "Server", "", "")
    EndIf
    Local $GUI = GUICreate($Title, 267, 115)                                                ;Create the GUI
    $start = GUICtrlCreateButton("Start", 40, 72, 65, 25)                                   ;Create a button
    $create = GUICtrlCreateButton("Add Server", 160, 72, 65, 25)
    $server = GUICtrlCreateCombo("Select Server", 8, 8, 249, 25, $CBS_DROPDOWN)             ;Create the combo box
    For $i = 1 To UBound($list) - 1                                                         ;Populate combo box with first value (name) from array
        If $list[$i][0] <> "" Then GUICtrlSetData($server, $list[$i][0])                    ;Ensure array is not empty and fill combox with KEYS
    Next
    $servername = GUICtrlCreateInput("Server Name", 8, 40, 121, 21)
    GUICtrlSetState(-1, $GUI_HIDE)
    $serverip = GUICtrlCreateInput("IP Address", 136, 40, 121, 21)
    GUICtrlSetState(-1, $GUI_HIDE)

    GUISetState(@SW_SHOW)

    While 1                                                                                 ;Enter loop until user closes or presses button
        Switch GUIGetMsg()
            Case $GUI_EVENT_CLOSE                                                           ;Exit when closed
                Exit
            Case $start                                                                     ;Store selection into variable, delete the GUI, and run the start function
                $selection = GUICtrlRead($server)
                If $selection <> "Select Server" Then
                    GUIDelete()
                    start()
                EndIf
            Case $create
                If GUICtrlRead($create) = "Add Server" Then
                    GUICtrlSetState($servername, $GUI_SHOW)
                    GUICtrlSetState($serverip, $GUI_SHOW)
                    GUICtrlSetData($create, "Create")
                Else
                    If (GUICtrlRead($servername) <> "" And GUICtrlRead($servername) <> "Server Name" And GUICtrlRead($serverip) <> "" And GUICtrlRead($serverip) <> "IP Address") Then
                        IniWrite(@TempDir & "\" & $Title & "\config.ini", "Server", GUICtrlRead($servername), GUICtrlRead($serverip))
                        GUICtrlSetState($servername, $GUI_HIDE)
                        GUICtrlSetState($serverip, $GUI_HIDE)
                        GUICtrlSetData($create, "Add Server")
                    Else
                        MsgBox($MB_ICONINFORMATION, $Title, "Invalid Server Name and IP Address.")
                    EndIf
                    For $i = UBound($list) - 1 To 0 Step -1
                        _GUICtrlComboBox_DeleteString($server, $i)
                    Next
                    Local $list = IniReadSection(@TempDir & "\" & $Title & "\config.ini","Server")
                    For $i = 1 To UBound($list) - 1
                        If $list[$i][0] <> "" Then GUICtrlSetData($server, $list[$i][0])
                    Next
                EndIf
        EndSwitch
    WEnd
Else                                                                                        ;otherwise, message
    MsgBox($MB_SYSTEMMODAL, "", "Milestone XProtect wasn't found on this computer" & @CRLF)
EndIf

Func start()
    $iPID = Run($milestone,"", @SW_SHOWNOACTIVATE)                                          ;Runs the software and returns the Process ID
    Sleep(4000)                                                                             ;sleep for 4 seconds
    If @error Then MsgBox(0, $Title, "The program could not launch.")                       ;If Run returns a 0 or error, there was a problem
    $handle = _GetHandleFromPID($iPID)                                                      ;Retrieve the handle of the program ran, jump to the function below
    If $handle = 0 Then MsgBox(0, $Title, "The handle could not be found.")                 ;If the Handle returned is 0, there was no match
    Sleep(1000)
    WinWaitActive($handle)                                                                  ;Wait for the program to be activated 
    Send("{TAB}")                                                                           ;send keystrokes to active window
    Send("{TAB}")
    For $i = 0 to UBound($list) - 1                                                         ;Find the IP address that matches the selection and send it
        If $list[$i][0] = $selection Then Send($list[$i][1])
    Next
    Send("{ENTER}")
    Exit                                                                                    ;Exit for now until you can capture a succesful run
EndFunc

func _GetHandleFromPID($PID)                                                                ;Call function with the PID returned from Run function
    $WinList = WinList()                                                                    ;Assign WinList to a variable
    for $i = 1 to $WinList[0][0]                                                            ;Run through each Window in WinList, 2D array [titles][handles]
        If WinGetProcess($WinList[$i][1]) = $PID then                                       ;Look for a Window with the correct PID
            Return $WinList[$i][1]                                                          ;Assign the matching Windows handle to the variable
        EndIf
    Next
    Return 0                                                                                ;Return 0 if no matches were found
EndFunc

Func help()
    ShellExecute(@TempDir & "\" & $Title & "\config.ini")
EndFunc
#EndRegion--------------------------------------------------------------------------------------------------------------------------------------------------------------------

繰り返しになりますが、私が数か月前に始めたこのプロジェクトを完成させるために、どんな助けも大歓迎です. また、Python や AutoHotkey などの別のプログラミング言語でこれを実現する方が簡単だと思われる場合は、お知らせください。:)

4

1 に答える 1

0

MIAに行くことをお詫びします。忙しくて、ソフトウェアの詳細を調べる時間がありませんでした。

基本的に何が起こっているかというと、返された PID は CiceroUIWndFrame というプロセス (バックグラウンドで実行されている親プロセス) に関連付けられており、そのプロセスのハンドルを返しています。そのプロセスはアクティブ化されないため、スクリプトは一時停止したままになり、ポップアップするのを待ちます。残念ながら、Milestone ソフトウェアには独自の PID がないため (タスク マネージャーの [詳細] タブを見てください。Milestone ソフトウェアは単に client.exe と呼ばれていることに注意してください)、適切な方法を使用して正しいハンドルを取得することはできません。

私が知っている唯一の解決策は、アクティブなウィンドウのハンドルを取得することです。したがって、この変更されたスクリプトは、Milestone X Protect ソフトウェアを実行し、1 秒 (開始するのに十分な時間) 待ってから、アクティブなプログラムのハンドルを取得します。その後、さらに 4 秒間スリープし、クライアントが再度アクティブ化されるのを待ちます。そのため、別のウィンドウを開いて数分間待つと、クライアント ログインを再度アクティブにした瞬間にキーストロークが送信されます。

この方法の欠点は、起動後のアクティブ ウィンドウがマイルストーンであることに依存していることです (ロードに時間がかかる場合は、間違ったハンドルが取得されます。1 秒前にフォーカスから外れてクリックすると、間違ったハンドルが取得されます)。

#include <MsgBoxConstants.au3>
#include <Array.au3>
#include <ComboConstants.au3>
#include <ButtonConstants.au3>
#include <EditConstants.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <GuiComboBox.au3>
#include <AutoItConstants.au3>

#Region EDIT THE BELOW INFORMATION-------------------------------------------------------------------------------------------------------------------------------------------
Local Const $milestone = "C:\Program Files\Milestone\XProtect Smart Client\Client.exe"  ;Path to software
Local $Title = "Program Title"                                                          ;Give me a name
Local $icon = "Full\Path\To\Icon.ico"
#EndRegion-------------------------------------------------------------------------------------------------------------------------------------------------------------------

#Region Script---------------------------------------------------------------------------------------------------------------------------------------------------------------
Local $iFileExists = FileExists($milestone)                                     ;Check if the file exists, returns a 1 or 0
Global $list = IniReadSection(@TempDir & "\" & $Title & "\config.ini","Server") ;Read the ini file, this builds a 2D Array [X][0] is the key [X][1] is the value
HotKeySet("{F1}", "help")

If $iFileExists Then                                                            ;If FileExists = 1 (exists) then
    If Not FileExists(@TempDir & "\" & $Title) Then                             ;If config directory does not exists then
        Do
        DirCreate(@TempDir & "\" & $Title)                                      ;Create a directory in TempDir for the config.ini file to be stored locally
        Until FileExists(@TempDir & "\" & $Title)
        IniWrite(@TempDir & "\" & $Title & "\config.ini", "Server", "", "")
    EndIf
    Local $GUI = GUICreate($Title, 267, 115)                                    ;Create the GUI
    GUISetIcon($icon, -1)                                                       ;Create icon
    $start = GUICtrlCreateButton("Start", 40, 72, 65, 25)                       ;Create a button
    $create = GUICtrlCreateButton("Add Server", 160, 72, 65, 25)
    $server = GUICtrlCreateCombo("Select Server", 8, 8, 249, 25, $CBS_DROPDOWN) ;Create the combo box
    For $i = 1 To UBound($list) - 1                                             ;Populate combo box with first value (name) from array
        If $list[$i][0] <> "" Then GUICtrlSetData($server, $list[$i][0])        ;Ensure array is not empty and fill combox with KEYS
    Next
    $servername = GUICtrlCreateInput("Server Name", 8, 40, 121, 21)
    GUICtrlSetState(-1, $GUI_HIDE)
    $serverip = GUICtrlCreateInput("IP Address", 136, 40, 121, 21)
    GUICtrlSetState(-1, $GUI_HIDE)

    GUISetState(@SW_SHOW)

    While 1                                                                     ;Enter loop until user closes or presses button
        Switch GUIGetMsg()
            Case $GUI_EVENT_CLOSE                                               ;Exit when closed
                Exit
            Case $start                                                         ;Store selection into variable, delete the GUI, and run the start function
                $selection = GUICtrlRead($server)
                If $selection <> "Select Server" Then
                    GUIDelete()
                    start()
                EndIf
            Case $create
                If GUICtrlRead($create) = "Add Server" Then
                    GUICtrlSetState($servername, $GUI_SHOW)
                    GUICtrlSetState($serverip, $GUI_SHOW)
                    GUICtrlSetData($create, "Create")
                Else
                    If (GUICtrlRead($servername) <> "" And GUICtrlRead($servername) <> "Server Name" And GUICtrlRead($serverip) <> "" And GUICtrlRead($serverip) <> "IP Address") Then
                        IniWrite(@TempDir & "\" & $Title & "\config.ini", "Server", GUICtrlRead($servername), GUICtrlRead($serverip))
                        GUICtrlSetState($servername, $GUI_HIDE)
                        GUICtrlSetState($serverip, $GUI_HIDE)
                        GUICtrlSetData($create, "Add Server")
                    Else
                        MsgBox($MB_ICONINFORMATION, $Title, "Invalid Server Name and IP Address.")
                    EndIf
                    For $i = UBound($list) - 1 To 0 Step -1
                        _GUICtrlComboBox_DeleteString($server, $i)
                    Next
                    Local $list = IniReadSection(@TempDir & "\" & $Title & "\config.ini","Server")
                    For $i = 1 To UBound($list) - 1
                        If $list[$i][0] <> "" Then GUICtrlSetData($server, $list[$i][0])
                    Next
                EndIf
        EndSwitch
    WEnd
Else                                                                            ;otherwise, message
    MsgBox($MB_SYSTEMMODAL, "", "Milestone XProtect wasn't found on this computer" & @CRLF)
EndIf

Func start()
    $iPID = Run($milestone)                                                     ;Runs the software and returns the Process ID
    BlockInput(1)
    Sleep(1000)                                                                 ;sleep for 1 second
    BlockInput(0)
    If @error Then MsgBox(0, $Title, "The program could not launch.") Exit      ;If Run returns a 0 or error, there was a problem
    $handle = WinGetHandle("[ACTIVE]")                                          ;Get the handle of the active window, should be Milestone software as it was just ran 1 second ago.
    If $handle = 0 Then MsgBox(0, $Title, "The handle could not be found.") Exit;If the Handle returned is 0, there was no match
    Sleep(4000)
    WinWaitActive($handle)                                                      ;Wait for the program to be activated
    Send("{TAB}")                                                               ;send keystrokes to active window
    Send("{TAB}")
    For $i = 0 to UBound($list) - 1                                             ;Find the IP address that matches the selection and send it
        If $list[$i][0] = $selection Then Send($list[$i][1])
    Next
    Send("{ENTER}")
    Exit                                                                        ;Exit for now until you can capture a succesful run
EndFunc

Func help()
    ShellExecute(@TempDir & "\" & $Title & "\config.ini")
EndFunc
#EndRegion--------------------------------------------------------------------------------------------------------------------------------------------------------------------

追加/変更された行は次のとおりです。

#include <AutoItConstants.au3>
$iPID = Run($milestone) ;Removed the #shownoactivate parameter, we want it to be the active window. Very important.
BlockInput(1) ;suggestion from comment, disables all input briefly
Sleep(1000) ;wait 1 second for program to launch
BlockInput(0) ;enables all user input again
If @error Then MsgBox(0, $Title, "The program could not launch.") Exit      
$handle = WinGetHandle("[ACTIVE]") ;Get the handle of the active window, should be Milestone software as it was just ran 1 second ago.
If $handle = 0 Then MsgBox(0, $Title, "The handle could not be found.") Exit
Sleep(4000)

私はこれを私の側のソフトウェアでテストしましたが、うまくいきました。

于 2022-02-24T00:22:10.017 に答える