18

I have the following two methods that I call in sequence (with appropriate class level field in sequence)

public const string ProcessName = "This is"
public const string WindowTitle = "somewhat proprietary."

public Application App { get; set; }

public void Launch()
{
    var theProcess = Process.GetProcesses().First(p => p.ProcessName.Contains(ProcessName))
     App = Application.Attach(theProcess);
}

public void Select()
{ 
    var window = App.GetWindow(WindowTitle);

    var textBox = window.Get<TextBox>();
    //etc, do more stuff in the window
}

When I run it, the call to App.GetWindow() takes a REALLY long time. Like more than a minute. The application and window are both open and running.

I've tried experimenting with the overloads of GetWindow() and also tried calls to Application.GetWindows() and Application.Find(), but with the same result.

Does anyone have any thoughts as to how I could cut down on this time, or at least pinpoint what is taking so long? I'm not married to the implementation I have by any stretch - whatever gets me that window object is fine with me.

Update:

To address the comments so far, I modified the code to try to eliminate as many other concerns as possible.

public void Select()
{
    var processes = Process.GetProcesses().ToList();
    var process = processes.First(p => p.ProcessName.ToLower().Contains("notepad"));
    App = Application.Attach(process);
    var window = App.GetWindow("Untitled - Notepad");
}

I threw in the enumerable evaluation to eliminate any deferred execution as well. And, I tried it with both my app and notepad. The above code, for both my app and notepad, executes the first 3 lines immediately in the debugger, and then takes excessive time on the last one in both cases.

(It seems possible that White might internally defer executing Application.Attach, but I don't know very much about this tool, so that's very opaque to me.)

Second Update:

Here's the breakdown of the time spent in the GetWindow() method. The app spent around 10% of the time in GetWindow(), so more than half of that time is spent in WaitTillFound() and almost all of that in a Retry() method. Any thoughts on how to reduce that time (or to reduce the time spent in Window constructor after it is found)? Diagnostics

Erik Dietrich
  • 6,080
  • 6
  • 26
  • 37
  • 1
    What calls Launch? Are you sure the app isn't delaying the call to Launch until you call GetWindow - the code you provide doesn't show how, but the only part that should run slow is your LINQ query of all running processes to find the one that contains the specified text, which will require querying info for every running process on your machine. I can't tell from the code, maybe you are using await/async somewhere and it doesn't call Launch until the value for App is resolved? – Matt Jordan Mar 17 '16 at 15:49
  • 2
    Have you tried it with another application? When I run your code with `ProcessName = "notepad"` and `WindowTitle = "Untitled - Notepad"` it returns the window almost instantaneously. – Yusuf Tarık Günaydın Mar 17 '16 at 16:28
  • I figured it'd be easier to update the post with my responses here. It does seem weird to me that it's taking a long time to attach to Notepad. Also, if I use Application.Launch(), GetWindow() is very quick. Unfortunately, I that isn't an option with my application. – Erik Dietrich Mar 17 '16 at 17:24
  • One more data point... when I take the updated code and run it in an empty Console project from Main, I get the same behavior as @qqww2 GetWindow() returns almost immediately. But when I do the same with my app, it takes a long time. – Erik Dietrich Mar 17 '16 at 19:42
  • 1
    If you are using Visual Studio 2015 you might try "Start Diagnostic Tools Without Debugging" with "CPU Usage" option to determine in which method your application spends most of the time. Or you might pause the program with debugger and check the call stack. – Yusuf Tarık Günaydın Mar 17 '16 at 20:38
  • `App = Application.Attach(processes);` - are you attaching to all running processes here? – 500 - Internal Server Error Mar 17 '16 at 21:20
  • Oops, no. That was a typo that I made when transposing from VS and realizing I had reversed the variable names, "processes" and "process." I'm doing the thing that makes sense in the actual code (and edited the question to reflect that) :) – Erik Dietrich Mar 17 '16 at 21:26
  • Thanks, @qqww2 -- I'll give that a try when I'm back at my developmentm machine. – Erik Dietrich Mar 17 '16 at 21:26
  • 2
    The profile info isn't very useful, it will inevitably point to [External code] since the real heavy lifting is done by unmanaged code. Nothing ever takes a *minute*, finding a window back certainly doesn't, except two things. A network timeout, we can eliminate that if the posted code snippet is accurate. And a virus scan by wonky anti-malware. Which certainly has a reason to mistrust code that is poking around in another process. So disable it and try again. If it is the dreaded Avast, particularly viral in the past couple of months, then get rid of it immediately. – Hans Passant Mar 22 '16 at 06:02
  • Have you tried using sysinternals Process Explorer or Process Monitor? Process Explorer can provide interesting details while waiting for the operation to complete. – yonisha Mar 25 '16 at 21:30
  • Can you re-write code so it would be standalone. For example Application.Attach - not clear - is it winforms / xaml / something else. Cannot diagnose problem if code is incomplete. – TarmoPikaro Mar 28 '16 at 19:09
  • What is your anti-malware system? I'm using Avira and I tested your code, it runs smooth... – Lost_In_Library Mar 28 '16 at 23:34
  • Did you manage to resolve the issue? We are experiencing up to 5 min. searches with Application.GetWindows(). Probably because this contains a recursive search. Not sure if a similar findwindow timeout should prevent the recursive call to go too deep. – ISAF Jan 26 '17 at 14:09

1 Answers1

1

It's not clear if target window is actually found after that waiting. If yes - that's very strange behaviour indeed. Anyhow, when you call GetWindow, White will try to find that window for a certain period, by default 30 seconds (with intervals of 200ms). So most likely that is what you experience - white for some reason cannot find window you target. You can configure this timeout via:

TestStack.White.Configuration.CoreAppXmlConfiguration.Instance.FindWindowTimeout = 0;

Where with 0 it will fail immediatly if window cannot be found. You can also use some other value lower than 30 seconds.

Evk
  • 98,527
  • 8
  • 141
  • 191
  • That timeout bit is a help, and will definitely play with that when I'm back at my development machine. FWIW, it DOES eventually find the window. I'll be interested to see, however, if ratcheting the timeout way down causes it not to. – Erik Dietrich Mar 29 '16 at 13:59