Windows Form Appbar Desktop Resizing - c#

Okay. Just when you think you've figured it all out, you haven't.
I have coded and tested a functional appbar class. When I use a simple Windows Form to extend and test the class, it works without issue in both XP (SP 3, 32 bit) and Windows 7 (64 bit). Other windows are accessible, and they all maximize appropriately. However, when I take my "complex" Windows Form (i.e. it is an application) and derive it from the appbar class, the desktop seems to "kick" it out. By this I mean that everything sizes appropriately initially, but then the desktop resizes itself back to its former size. Sometimes this happens rather quickly after putting the form into appbar mode, other times it happens when I click outside the form (to open a browser, for instance), and other times it happens when the form calls a MessageBox. I have put all of the Forms functions in a background worker thinking that may be the issue, but the result is the same. I've posted three images below. The first one shows the application as its initial WinForm. The second shows the appbar "functioning." The last shows the appbar not "functioning." If you're having issues seeing the problem, pay attention to the Recycle Bin. Any ideas?
Edit:
I found these calls via logging. They appear to fire off each time the desktop resizes to "normal." Now I'm trying to see if there is or is not a similar pattern in the "simple" version.
msg=0x6 (WM_ACTIVATE) hwnd=0x1e03ea wparam=0x0 lparam=0x0 result=0x0
msg=0x1c (WM_ACTIVATEAPP) hwnd=0x1e03ea wparam=0x0 lparam=0x1a90 result=0x0
msg=0x1a (WM_WININICHANGE) hwnd=0x1e03ea wparam=0x2f lparam=0x9fe048 result=0x0
msg=0x1a (WM_WININICHANGE) hwnd=0x1e03ea wparam=0x18 lparam=0x9fe038 result=0x0

So this was one wild goose chase. In the event my last comment sounded absurd, it was. While I am still not 100% certain as to this theory (someone please prove/disprove at your leisure), the two different handles came from (1) instantiation of the Form and (2) the actual handle when the Form is loaded. I presume the API follows the same concept of QUERY_POS and SET_POS, that being it initially checks for and assigns a valid handle. Then, prior to the Form being shown, it double checks the handle value.
Long story short, one line of code to verify the handle value in the Load event solved the entire problem.
EDIT:
Better yet, the HandleCreated event is irreplaceable.

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.

remote desktop application with wrongly displayed buttons

I have a winform within a remote desktop application that is built dynamically with a container panel for a toolbar with large (regular) buttons. The application is writen in C# and .NET 4.0. The application is viewed as it should only if I do not maximize the window (meaning restored view is fine).
Now, after RDP login - within most client computers - the application looks fine (even when we maximize and restoring). Within low resolution client computers (800x600), the buttons on the toolbar are not displayed in the right position (such as in the 1024x768 clients).
I used double buffering and it didn't help... the problem may or may not be depended on the screen resolution (it can be memory issue or something). It is not a problem of localization layout.
The following image shows the Fine and Bad states: http://imgur.com/gO4UJ,v7O9K
What can I do to resolve this issue?
OK, so in case anybody gets to this kind of case, this is the thing that made the issue:
In the form, there was an empty repaint override. The programmer that created the form was overriding the repaint with an empty method (don't know why, I guess I'll ask my team for the business logic).
How did I reproduce it in the development environment? Following Albin Sunnanbo's note, I ran the RDP application in minimized version during initialization, and I noticed that it occurs with large resolution clients also in this use case... So, I know repaint occurs while performing a window resize - and this made me suspicious about the method...
==> On a side note, I guess this is why inheritance is so bad, and going on to WPF is better. It took me 3 days to understand why this issue occurred.

SendInput() misinterpreted in certain applications

My c# project sends an injected key combo to the foreground window. In notepad, Firefox, IE9 everything works as it should, but Adobe Illustrator CS5 seems to misinterpret the sent combos: for example CTRL+G becomes CTRL+SHIFT+WHEEL_DOWN so instead of grouping selected objects it scrolls the page to the left. (A low level keyboard hook also confirmed that I'm sending the right combo.)
A quick test showed that there is method in this madness, so CTRL+F appears as CTRL+SHIFT+WHEEL_UP.
The system is Windows 7 64bit so at first I suspected some 32 vs 64 bit woe but things work properly in both 32 and 64 bit IE9.
I can't say for sure, but it sounds an awful lot like an issue that a user of my app pointed out (which is how I ended up here, searching for clues!).
For my app, it turned out that I needed to put some delay between the Control keydown event and the C (for copy, in this example) keydown. When sent at the same time as a single combination, results were very unpredictable.
http://www.strokesplus.com/forum/topic.asp?whichpage=1&TOPIC_ID=477#1024

Silverlight/WP7 - Navigation and events triggering on other pages

My basic issue is this, I have events firing on pages I've left based on network activity that are causing problems when I thought the old forms were being destroyed.
More detailed information: I am writing a windows phone app that communicates with a network player. I have a static instance of my communication class in my App class so all the forms can share the connection, and all my forms subscribe to it and process results within that form. From a main menu you can choose one type of source and it opens a file browsing form that refreshes a listbox as you navigate, cancels the back button and refreshes the new contents to simulate file navigation until you are the root folder. The app doesn't know if you're clicking on a file or folder, it gets a network message when media starts playing and watch for that and then navigate to a "play" form. I had been using all .Navigate's for this until now and it worked great until I added another branch off the main menu for a new source. Although the new source is completely different, the device sends a lot of the same generic commands which just mean something else in the current context. After visiting the my file browser form and going to my new source, a play command from the network, which means something else now, would cause my to jump into my old "play" form from the previous source as if I was still on the file browser form, which isn't intended.
So I've tried many things and have it kind of working now but it's message and I lose some features. Currently I changed from using all .navigates, also in the back button override, to trying to use the stack and navigate.goback's. I pass variables when needed using globals in App and unhook my net listeners from the form, goback, and then connect them in the new form's listeners in it' navigatedto. I think there is timing issue though as in some cases I needed to send a command to the media box as it's changing and it ended up triggering the wrong event handler again. I think the easiest solution, if possible, and they way I though it would work is if each time I navigated from the form it old one, it's handlers, etc were all destroyed and I didn't have to use the stack at all, handling all the back buttons myself.
I know that's a long description and thanks if you made it this far, hopefully it made some kind of sense. Does anyone have any suggestions on what I can do?
As a side note I'm a long time self-taught VB programmer who has been stuck in .net 2.0/winforms and I've just now made the move to C#, OOPs, and XAML to write my first Windows Phone app so it's likely I'm doing something stupid or overlooking something obvious...
It is likely because something has retained reference to the form. The most common cause is event handlers.
So, if your static class exposes an event, and you subscribe to that event in a form, you must unsubscribe from the event when your form closes / navigates, otherwise the form will remain in memory....
If that isn't the case, look for something else that is acquiring a reference to your form and not releasing it.
Most likely the problem is based on a bad application architecture, when it comes to handling commands send from the UI.
When you say 'sends a lot of the same generic commands which just mean something else in the current context.' you most likely reveal the source of the problem.
As a workaround, you can define an interface, that your communication class implements. Each form has it's own method it calls on a communication class instance.
If you indeed receive a command from a phone page, that is no longer in view, just don't process it.
You can store the navigation history to always know what page is the only one allowed to send commands to a communication class.

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