@@ -7,6 +7,7 @@ This Source Code Form is subject to the terms of the Mozilla Public
77*/
88using System ;
99using System . Diagnostics ;
10+ using System . Diagnostics . Contracts ;
1011using System . Linq ;
1112using System . Threading . Tasks ;
1213using System . Windows . Automation ;
@@ -30,16 +31,16 @@ internal static void WatchDialog(RuntimeContext context)
3031 {
3132 foreach ( var targetDefinition in targetDefinitions )
3233 {
33- var filteredElements = Process . GetProcessesByName ( targetDefinition . ProcessName ) ;
34+ //ブラウザのプロセスのうち、メインウィンドウがあるものに絞り込み
35+ var filteredElements = Process . GetProcessesByName ( targetDefinition . ProcessName ) . Where ( _ => _ . MainWindowHandle != IntPtr . Zero ) ;
36+
3437 foreach ( var filteredElement in filteredElements )
3538 {
3639 var targetPid = filteredElement . Id ;
37- var windowCondition = new AndCondition (
38- new PropertyCondition ( AutomationElement . ProcessIdProperty , targetPid ) ,
39- new PropertyCondition ( AutomationElement . ControlTypeProperty , ControlType . Window ) ) ;
40- var targetElement = desktop . FindFirst ( TreeScope . Children , windowCondition ) ;
40+ var targetElement = desktop . FindFirst ( TreeScope . Children , new PropertyCondition ( AutomationElement . ProcessIdProperty , targetPid ) ) ;
4141 if ( targetElement == null )
4242 {
43+ context . Logger . Log ( $ "Empty element.") ;
4344 continue ;
4445 }
4546 PrintControlIdentifiers ( context , targetElement , 0 ) ;
@@ -57,6 +58,7 @@ internal static void PrintControlIdentifiers(RuntimeContext context, AutomationE
5758 {
5859 var ind = new string ( ' ' , indent * 2 ) ;
5960 Console . WriteLine ( $ "{ ind } - { element . Current . ControlType . ProgrammaticName } : { element . Current . Name } ") ;
61+ context . Logger . Log ( $ "{ ind } - { element . Current . ControlType . ProgrammaticName } : { element . Current . Name } ") ;
6062 var children = element . FindAll ( TreeScope . Children , Condition . TrueCondition ) ;
6163 foreach ( AutomationElement child in children )
6264 {
@@ -75,41 +77,51 @@ private static void SendValue(AutomationElement element, string value)
7577 object valuePatternObj ;
7678 if ( element . TryGetCurrentPattern ( ValuePattern . Pattern , out valuePatternObj ) )
7779 {
78- element . SetFocus ( ) ;
7980 ( valuePatternObj as ValuePattern ) . SetValue ( value ) ;
8081 }
8182 else
8283 {
8384 // フォーカス後にSendKeys(WinFormsやWPF参照)などで文字列を入力
84- element . SetFocus ( ) ;
85+ try
86+ {
87+ element . SetFocus ( ) ;
88+ }
89+ catch
90+ {
91+ // ignore set focus error
92+ }
8593 System . Windows . Forms . SendKeys . SendWait ( value ) ;
8694 }
8795 }
8896
8997 internal static void LoginToProxy ( RuntimeContext context , AutomationElement targetRootElement , TargetDefinition dialogDefinition )
9098 {
91- if ( context . Config . SectionList == null || context . Config . SectionList . Count == 0 )
99+ if ( context . Config . SectionList == null || context . Config . SectionList . Count == 0 )
92100 {
101+ context . Logger . Log ( $ "Empty config.") ;
93102 return ;
94103 }
95104 try
96105 {
97106 var proxyDialogNameCondition = new PropertyCondition ( AutomationElement . NameProperty , dialogDefinition . DialogTitleName ) ;
107+ var targetControlTypeCondition = new OrCondition (
108+ new PropertyCondition ( AutomationElement . ControlTypeProperty , ControlType . Window ) ,
109+ new PropertyCondition ( AutomationElement . ControlTypeProperty , ControlType . Pane ) ) ;
98110 var proxyDialogCondition = new AndCondition (
99111 proxyDialogNameCondition ,
100- new PropertyCondition ( AutomationElement . ControlTypeProperty , ControlType . Window ) ) ;
101- var proxyDialogElement = targetRootElement . FindFirst ( TreeScope . Descendants , proxyDialogCondition ) ;
112+ targetControlTypeCondition ) ;
113+ var proxyDialogElement = targetRootElement . FindFirst ( TreeScope . Subtree , proxyDialogCondition ) ;
102114 if ( proxyDialogElement == null )
103115 {
104116 return ;
105117 }
106118 context . Logger . Log ( $ "Found proxy dialog.") ;
107- var textTypeDescendants = proxyDialogElement . FindAll ( TreeScope . Descendants , new PropertyCondition ( AutomationElement . ControlTypeProperty , ControlType . Text ) ) ;
119+ var textTypeDescendants = proxyDialogElement . FindAll ( TreeScope . Subtree , new PropertyCondition ( AutomationElement . ControlTypeProperty , ControlType . Text ) ) ;
108120
109121 bool isTargetProxy = false ;
110122 string userName = "" ;
111123 string password = "" ;
112- foreach ( AutomationElement textTypeDescendant in textTypeDescendants )
124+ foreach ( AutomationElement textTypeDescendant in textTypeDescendants )
113125 {
114126 string name = textTypeDescendant . Current . Name ;
115127 if ( ! string . IsNullOrEmpty ( name ) && name . Contains ( "プロキシ" ) )
@@ -139,54 +151,70 @@ internal static void LoginToProxy(RuntimeContext context, AutomationElement targ
139151 {
140152 return ;
141153 }
142-
154+ context . Logger . Log ( $ "Found proxy dialog matching to config." ) ;
143155 var userNameEditCondition = new AndCondition (
144156 new PropertyCondition ( AutomationElement . NameProperty , dialogDefinition . UserNameInputName ) ,
145157 new PropertyCondition ( AutomationElement . ControlTypeProperty , ControlType . Edit ) ) ;
146- var userNameEditElement = proxyDialogElement . FindFirst ( TreeScope . Descendants , userNameEditCondition ) ;
158+ var userNameEditElement = proxyDialogElement . FindFirst ( TreeScope . Subtree , userNameEditCondition ) ;
147159 if ( userNameEditElement == null )
148160 {
161+ context . Logger . Log ( $ "User name edit not found.") ;
149162 return ;
150163 }
151164 SendValue ( userNameEditElement , userName ) ;
152165
166+ context . Logger . Log ( $ "Set username.") ;
153167 var passwordEditCondition = new AndCondition (
154168 new PropertyCondition ( AutomationElement . NameProperty , dialogDefinition . PasswordInputName ) ,
155169 new PropertyCondition ( AutomationElement . ControlTypeProperty , ControlType . Edit ) ) ;
156- var passwordEditElement = proxyDialogElement . FindFirst ( TreeScope . Descendants , passwordEditCondition ) ;
170+ var passwordEditElement = proxyDialogElement . FindFirst ( TreeScope . Subtree , passwordEditCondition ) ;
157171 if ( passwordEditElement == null )
158172 {
173+ context . Logger . Log ( $ "Password edit not found.") ;
159174 return ;
160175 }
161176 SendValue ( passwordEditElement , password ) ;
162-
177+ context . Logger . Log ( $ "Set password." ) ;
163178 var loginButtonNameCondition = new PropertyCondition ( AutomationElement . NameProperty , dialogDefinition . LoginButtonName ) ;
164179 var loginButtonCondition = new AndCondition (
165180 loginButtonNameCondition ,
166181 new PropertyCondition ( AutomationElement . ControlTypeProperty , ControlType . Button ) ) ;
167- var loginButtonElement = proxyDialogElement . FindFirst ( TreeScope . Descendants , loginButtonCondition ) ;
182+ var loginButtonElement = proxyDialogElement . FindFirst ( TreeScope . Subtree , loginButtonCondition ) ;
168183 if ( loginButtonElement == null )
169184 {
185+ context . Logger . Log ( $ "Login button not found.") ;
170186 return ;
171187 }
172188 InvokePattern loginButton = loginButtonElement . GetCurrentPattern ( InvokePattern . Pattern ) as InvokePattern ;
173189 if ( loginButton == null )
174190 {
175191 return ;
176192 }
193+
177194 Task . Delay ( 50 ) . Wait ( ) ;
178195 loginButton . Invoke ( ) ;
179196 context . Logger . Log ( $ "Click login button.") ;
197+
180198 // プロキシーダイアログが消えていることを確認する。
181199 // ユーザー名、パスワードに誤りがあった場合などに、短時間で連続してダイアログの表示とOKが繰り返され、ユーザーが対処できなくなる可能性がある。
182200 // そのため、ダイアログが表示されている場合、ここで15秒間待機し、ダイアログが閉じられなかった場合にユーザーがキャンセルや正しいユーザー名
183201 // パスワードが入力できるようにする。
202+ bool isProxyDialogClosed = false ;
184203 for ( int i = 0 ; i < 30 ; i ++ )
185204 {
186205 Task . Delay ( 500 ) . Wait ( ) ;
187- proxyDialogElement = targetRootElement . FindFirst ( TreeScope . Descendants , proxyDialogCondition ) ;
188- if ( proxyDialogElement == null )
206+ // ログインボタンが消えていたらダイアログも消えていると判断する。
207+ // このあとログインボタンを押すことから、ログインボタンを再利用している。
208+ try
189209 {
210+ _ = loginButtonElement . Current . ItemType ;
211+ _ = loginButtonElement . Current . Name ;
212+ _ = loginButtonElement . Current . IsOffscreen ;
213+ }
214+ catch
215+ {
216+ context . Logger . Log ( $ "login button closed.") ;
217+ isProxyDialogClosed = true ;
190218 break ;
191219 }
192220 // ChromeでloginButton.Invoke()の実行までが早すぎて応答しないことがあるので
@@ -198,17 +226,23 @@ internal static void LoginToProxy(RuntimeContext context, AutomationElement targ
198226 loginButton . Invoke ( ) ;
199227 context . Logger . Log ( $ "Retry to click login button.") ;
200228 }
201- catch { }
229+ catch
230+ {
231+ // ログインボタンのInvokeに失敗した場合、ログインボタンが消えていると判断してループを抜ける。
232+ context . Logger . Log ( $ "Failed to invoke button") ;
233+ isProxyDialogClosed = true ;
234+ break ;
235+ }
202236 }
203237 }
204238
205- if ( proxyDialogElement != null )
239+ if ( isProxyDialogClosed )
206240 {
207- context . Logger . Log ( $ "Dialog not closed. Maybe failed to login to the proxy.") ;
241+ context . Logger . Log ( $ "Success to login to the proxy.") ;
208242 }
209243 else
210244 {
211- context . Logger . Log ( $ "Success to login to the proxy.") ;
245+ context . Logger . Log ( $ "Dialog not closed. Maybe failed to login to the proxy.") ;
212246 }
213247 }
214248 catch ( Exception ex )
0 commit comments