Using the Close() function with WPF versus not using Close() - c#

So this may be a noobish type of question but here is what I'm wondering.
Let's say I have two screens, the first screen is idk, Screen1 for example. Let's say the user hits OK on Screen1 which takes them to Screen2.
What I'm currently doing is closing the first screen ( Screen1 ) so that the screen isn't in the background because the user will no longer need that screen nor should they be able to go back to that screen.
My question are essentially is these:
Let's say that I didn't close that previous screen in the background, how will that effect the program?
Will it slow the program down, because that screen is still running or will it not effect the program at all?
I'm just thinking in terms of efficiency. Does it really matter if I don't Close(); that previous screen?

There is of course some amount of overhead in having a window open. It will receive various window messages from the operating system and process them. However, if the window is not really doing anything, then the overhead is insignificant. For example, you can open 20 copies of the Windows calculator and not see any noticeable degradation in your computer's performance because those windows are not really doing anything until you interact with them.
Basically, the difference between closing the window vs not is insignificant (unless the window is running animations or playing a video or something else causing it to change regularly).
So, you should probably be making the decision as to whether to leave the window open or not based on the desired user experience for your application. Since you stated that the user should never go back to that screen, then it probably makes sense to close it, but that is really up to the application designer (or whoever is thinking about the user experience for the application).

Related

How to detect if SetForegroundWindow changes screen resolution?

I am writing an Alt+Tab replacement in C#, and have trouble with fullscreen applications.
Is there a way to detect if a SetForegroundWindow(hWnd) call is going to change the screen resolution? Or equivalently, if hWnd is a fullscreen application? I would like to wait until the resolution change is done, or if there is no change, proceed immediately.
The screen resolution change is done asynchronously, the function call returns well before it happens, so my code runs prematurely, and draws my application onto the surface of the fullscreen application, with wrong dimensions, then after the resolution change, it looks especially ugly.
Source of my application is at https://bitbucket.org/FrigoCoder/frigotab/src if anyone is interested.
To clarify, I would be more interested in knowing beforehand if a resolution change occurs than detecting it later. I already know a half-solution where I call SetForegroundWindow() on GetDesktopWindow() or some other window and watch SystemEvents.DisplaySettingsChanging and DisplaySettingsChanged. This however only gives me a late asynchronous notification if a resolution change occurs, and does not tell me if it does not.
I managed to solve the issue. Instead of trying to detect fullscreen applications, I simply send an inactivation message to the foreground application, which triggers an early resolution change:
SendMessage(GetForegroundWindow(), WM_ACTIVATEAPP, false, GetCurrentThreadId());
This exact same message is also sent during application switches, so I essentially emulate one before it actually happens. I have not encountered any side effects yet.
Mind you however, that this does not solve DWM issues. Windows 7 automatically disables DWM composition for compatibility launches, or when it detects direct access to the primary display surface. It does not allow you to re-enable, and I do not see an easy solution to this problem. Thankfully this issue will eventually go away since DWM composition is always enabled in Windows 8 and newer.
Perhaps the Winforms Event SizeChanged can help you.
You could use this event as a continuation of sorts for the rest of your code. In the case that the event doesn't fire due to no resizing, you could have a secondary continuation that will run after a specified timeout. It's not perfect, but may meet your needs.

Performance issue when launching WPF application

I have a complex WPF application that is using a lot of resources from the shared Resource Dictionary.
The first Window initialized takes 8 seconds to initialize. The performance issue is less on SSD disk drives but still it requires 2 seconds.
I tried to use the Visual Studio Profiler and it shows big expense of time on InitializeComponent();
of the windows that needs to be displayed.
I believe it is related to the Resource dictionary used but I can't replace it because I really need it and because all windows and WPF elements are using the StaticResource references.
I tried to optimize the launch as much as it is possible.
I created many background threads but this didn't helped too much. Whenever a window needs to be displayed it must be attached on UI thread under the same Dispatcher. This makes a big performance issue and all UI and any Progress bar left on the screen is blocked.
So to summarize. From the point when the ShowDialog is called until the window is displayed it
takes 8 seconds. This is visible only on the first window. Any other window opened after that is displayed quickly.
Now I am asking firstly what happens in the background and why this delay is so big and second what can be done to increase the startup speed.
I didn't mentioned but there are no Exceptions or DataErrors present during the launch so it is
not related to Exceptions.
I believe it is something with the initialization of Buttons and other components because almost all of them have the ControlTemplate restyled.
Lots of assemblies need to be loaded and lots of code must be JIT compiled before your first window can be shown. One useful technique to reduce startup time is to structure your code in such a way that types are not loaded before they are needed. It may be preferable to get a blank window up on screen with a wait indicator before delving into code outside of the core WPF assemblies. Optimize for that scenario.
Avoid loading images/media and other resources too early if you are trying to get something up on the screen as soon as possible.
Avoid loading any data synchronously, and do as little in your view and view model constructors as possible. Defer the loading of data until your view has been shown (throw up a wait indicator if necessary).
If you think your Xaml resources are a problem, split them up, and have each view pull in only the resources it needs. Don't merge them into App.xaml. You might also look into how to share the resources more efficiently across multiple views.
Throwing up a splash screen can improve the perceived startup time. Getting anything up on the screen to let the user know your app is actually doing something goes a long way.
Lastly, don't fret too much; poor startup time is the hallmark of WPF applications, and in the end, there's only so much you can do.
You can also use the ProfileOptimization class to improve startup time over subsequent sessions of the program. May not help you, the developer, but may have an impact on your users for the better.

Detecting when a Process (GUI) is "Done" even though it doesn't Exit?

I'm writing a console app that detects USB drives, formats them, and then runs a program called UnetBootin to write an ISO to the drives. Everything works fine, but the issue is UNetbootin doesn't simply "exit" so .WaitForExit() doesn't work unless the user clicks the "Exit" button.
The only way I can imagine to solve this is either by checking for that button to appear or trying to guess if the process is idling somehow. In either case, I wouldn't know where to start.
This is going to be ugly no matter how you slice it. I 'm not aware of a better approach, so here is one that would work AFAIK:
Get the PID of your target process (you already have that if you can call WaitForExit)
Get handles to all windows of that process
Use GetWindowText to get the text of each and every window from step 2
If any window has text equal to "Reboot Now", you know you 're done
WARNING: At this point I should mention that GetWindowText should be considered extremely dangerous because it can do evil things to your thread, including hanging it, due to no fault of your own. In practice it won't happen, but it's something you should know.

C# Select default screen for separate process

Is there a way to designate the start up location of an external process? I am trying to select the screen BEFORE the application launches, NOT move it afterwards.
When start the process and then move the window from one screen to another (programatically or manually) it resizes the window but not the content of that window because they are different resolutions.
I don't have control of the resolution of the screens or selection of which one is primary.
This question is similar to, but not the same as:
Launch an application and send it to second monitor?
Launch an application and send it to second monitor
May be I understand what you mean.
You want that external programm appears immediately in the screen you want, so you will get rid of resolution mananagement bug of the program, cause this is a bug, if content of the window doesn't reflect resolution changes of host window.
There is no way to do that, that I'm aware of. In fact solutions linked by you first load program, find window and finally move where needed.
If this is not what you're actually asking for, please explain better your intentions.
So if I understand correctly, you want to decide location a windows program launches but you don't want to move it after the program starts.
Usually a program remembers its previous position when it closes in registry for next launch. I would control that. For more information, refer to http://www.mywindowsclub.com/resources/3016-Start-up-position-programs-Windows.aspx

Prevent Process 'A' from spawning Process 'B' which then shows up on top of what should be the "TopMost" Process 'C'

I have a windows form application which needs to be the TopMost. I've set my form to be the TopMost and my application works as I'd like it to except for in one case.
There is a 3rd party application (referred to as player.exe) that displays SWF movie files on a portion of the screen that popup on top of my application.
Using Process Monitor I determined that player.exe application calls
flash.exe <PositionX> <PositionY> <Width> <Height> <MovieFile>
in my case:
flash.exe 901 96 379 261 somemovie.swf
Since flash.exe is being spawned in a new process after my form has been set to the TopMost it is appearing on top of my application.
First thing I did was make my application minimize the player.exe main application window hoping that this would prevent the Flash from appearing also. But, unfortunately it doesn't... even with the window minimized whenever the flash movie starts it shows up at the pixel location (901,96). I then tried creating a timer to keep setting the form.TopMost property to true every 10ms. This sort of works but you still see a very quick blip of the swf file.
Is there some type of Windows API call which can be used to temporarily prevent player.exe from spawning child processes which are visible? I admit it sounds a little far fetched. But, curious if anyone else has had a similar problem.
Addendum:
This addendum is to provide a reply to some of the suggestions layed out in Mathew's post below.
For the emergency situation described in the comments, I would look at possible solutions along these lines:
1) How does the third party application normally get started and
stopped? Am I permitted to close it
the same way? If it is a service, the
Service Control Manager can stop it.
If it is a regular application,
sending an escape keystroke (with
SendInput() perhaps) or WM_CLOSE
message to its main window may work.
Easiest way to close the app is to CTRL-ALT-DEL, then kill process. -OR-
The proper way is to Hold ESC while clicking the left mouse button... then input your username and password, navigate some menu's to stop the player.
There is no PAUSE command... believe it or not.
I don't think using WM_CLOSE will help since minimizing the application doesn't. Would that kill the process also? If not, how do you reopen it.
2) If I can't close it nicely, am I permitted to kill it? If so,
TerminateProcess() should work.
I can't kill the process for two reasons. 1) Upon relaunch you need to supply username/password credentials... There may be a way to get around this since it doesn't prompt when the machine is rebooted but... 2) Whenever I kill the process in task manager it doesn't die gracefully and asks if you want to send an error report.
3) If I absolutely have to leave the other process running, I would try
to see if I can programmatically
invoke fast user switching to take me
to a different session (in which there
will be no competing topmost windows).
I don't know where in the API to start
with this one. (Peter Ruderman
suggests SwitchDesktop() for this
purpose in his answer.)
I got really excited by this idea... I found this article on CodeProject which provides a lot of the API Wrapper methods. I stopped implementing it because I think that in order for desktop's to work you must have explorer.exe running (which I do not).
EDIT2: On second thought... maybe explorer.exe isn't needed. I'll give it a try and report back.
Edit3: Was unable to get the code in that article working. Will have to put this on hold for a moment.
Answer Summary
As one might have expected, there is no simple answer to this problem. The best solution would be to problematically switch to a different desktop when you need to guarantee nothing will appear over it. I was unable to find a simple C# implementation of desktop switching that worked and I had a looming doubt that I would just be opening a whole new set of worms once it was implemented. Therefore, I decided not to implement the desktop switching. I did find a C++ Implementation that works well. Please post working C# virtual desktop implementations for others.
Setting the TopMost property (or adding the WS_EX_TOPMOST style to a window) does not make it unique in the system. Any number of topmost windows may be created by any number of applications; the only guarantee is that all topmost windows will be drawn 'above' all non-topmost windows. If there are two or more topmost windows, the Z-order still applies. From your description, I suspect that flash.exe is also creating a topmost window.
Aside from periodically forcing your window to the top of the Z-order, I think there is little you can do. Be warned, however, that this approach is dangerous: if two or more windows are simultaneously trying to force themselves to the top of the Z-order, the result will be a flickering mess that the user will likely have to use the task manager to escape.
I recommend that your program not attempt to meddle with other processes on the computer (unless that is its explicit purpose, e.g. a task manager clone). The computer belongs to the user, and he may not value your program more highly than all others.
Addendum:
For the emergency situation described in the comments, I would look at possible solutions along these lines:
How does the third party application normally get started and stopped? Am I permitted to close it the same way? If it is a service, the Service Control Manager can stop it. If it is a regular application, sending an escape keystroke (with SendInput() perhaps) or WM_CLOSE message to its main window may work.
If I can't close it nicely, am I permitted to kill it? If so, TerminateProcess() should work.
If I absolutely have to leave the other process running, I would try to see if I can programmatically invoke fast user switching to take me to a different session (in which there will be no competing topmost windows). I don't know where in the API to start with this one. (Peter Ruderman suggests SwitchDesktop() for this purpose in his answer.)
You can use the Process class to start flash.exe directly - and use an appropriate ProcessStartInfo settings to show the window in a hidden state - or with a WindowStyle of hidden or minimized.
You could also consider using the SetWindowsHookEx API to intercept the process start API calls, and when the process is flash.exe run some code to restore you window to top-most status.
Matthew's answer is excellent, but I suspect you may be asking the wrong question. Why does your application need to be topmost? If you're trying to create a kiosk or some such, then topmost is not the way to go.
Edit: After reading your response to Matthew's comment, I'd suggest creating a new desktop and switching to it before displaying your alert. (See CreateDesktop and SwitchDesktop in MSDN.)

Categories

Resources