I seem to be running into a dead end here. I have a project that does the following:
just runs and stays in notification area
when user presses middle mouse button, it shows a form
user can then chose whatever from the form, and be happy.
This is working just fine, however what is NOT working is that when the form is shown, it does NOT activate.
Now, prior to me modifying the app.manifest to requireAdmin, it was working fine. Any time the form was shown, boom it was active.
But now that i'm running the form as Administrator, given that I need to be able to control one of our other applications with it (that is ran as admin as well), the form comes up just fine, but doesn't activate.
I have tried:
- TopMost = true inside of the Form_Load method
- Calling SetForegroundWindow with the forms handle on Form_Load
- Calling ShowDialog both on Form_Load and also tried it when the form was built.
- Calling Activate on Form_Load as well as when the form was built
Here's my layout:
Program runs, requires UAC permissions due to the manifest, user agrees, and it kicks off
Only a notification icon appears, shows a nice little bubble saying it's running
Program.cs monitors the keyboard/mouse hooks
When middle mouse button, or any of the keyboard hooks are triggered, it creates a new form object
sets the location of where the form should appear
and then finally shows the form.
Again, without UAC and requireAdmin inside of the app.manifest, this works fine. But once it is running as admin, nope, wont stay in front.
I know that MS has made the SetForegroundWindow requirements much stricter with later versions of windows (Vista, 7, 8), but i really need to be able to make this form show as the top most, active window (like a context menu).
How can i do that properly?
You could split your program into two, a non-admin requiring half that sits in the tray and watches for the middle button, and the half that requires admin permission that you launch when the mouse button is pressed. The non-elevated half could then call SetForegroundWindow or AllowSetForegroundWindow as needed.
If you want to avoid a UAC prompt every time you can cache a COM elevation object via the CoCreateInstanceAsAdmin method and use it repeatedly.
Related
When I open any dialog in my Winforms application then Windows 10 behaves oddly in these ways:
ALT-TAB no longer displays the list of windows
I cannot switch to hidden applications using taskbar icons - if I select a taskbar icon of a window that is not currently visible (even if it is not hidden by the winforms app) the icon just flashes and then stays highlighted, but is not brought to the foreground. I can use other applications that are visible. As soon as I close the dialog form the other I can use the windows of other applications correctly
If I switch to the application window that is behind the winforms application by clicking on it, I cannot go back to the winforms app either by ALT-TAB or by clicking on the taskbar icon. I can get back to it by minimizing the other application
I'm opening the dialogs with
dialogFormName.ShowDialog(this);
TopMost is set false on all forms and is not set in the code.
I've read about 50 related articles and the only problems seem to be either TopMost is set or ShowDialog is not called with the parent form. I'm not a regular Winforms developer so I'm probably doing something stupid. This is driving me crazy, so I'd really appreciate any help!
Edit: The same issues occur with MessageBox.Show(this, "test"). The issue does not occur with a newly created app just with a single button calling MessageBox.Show(this, "test"). The problem application uses EntityFramework but no other packages and the problem existed before I added EF.
After trying different scenarios I eventually found the issue. In my case I was calling ShowDialog() after a user clicks an item on a ContextMenu. The blocking of ALT-TAB was caused by the following code that attached the ContextMenu to the ListView that the menu was contextually for:
lstList.ContextMenu = myContextMenu;
As soon as I removed that association, the ShowDialog no longer blocked ALT-TAB.
Form.ShowDialog() blocks the parent form until it's closed.
Use Show() to display the form separately without blocking its parent.
I have tried two installers - Setup2go, and Installmate Builder, and I have the same problem. At the last window of the install, I select the option to "Open program after installation finish", and sometimes (about 10% of the time?), my (Winforms) app's main window will open behind the Windows Explorer directory window I used to open the installation exe from.
The frustrating thing is - I am having trouble reproducing the problem reliably (the problem seems to occur around 10-20% of the time). I am using Windows 7 if that makes any difference. To clarify, if I open up the executable directly (rather than from the installation exe), the problem never occurs.
My knowledge on this kind of thing is limited - I recall a similar frustration happening with the MessageBox from this question
Any ideas?
It does not happen when you launch the app directly from installer because the shell allows it to “steal” the focus. When you launch it from the installer, the last interaction happens in the installer app. The system prevents the new window from stealing the focus from your installer. If installer window closes, then the explorer window which you used to start the installer is activated. Since the switch of the foreground window happened recently, the system does not allow to change the foreground window.
On the other hand, if your application window is shown before the installer window disappears from the screen, the the app will be placed below the installer in the Z-order; and when the installer window is finally hidden, the application window is activated.
So it's all related to timing between showing and hiding windows.
Although I am not expert in this area. You can use message tracers and WinAPI calls tracers like Spyxx which can give you more details on what happens in the system and why the new window of your application is placed below the Explorer window.
Make sure the window's title isn't changed, until the last possible moment. I moved the Text = "blahblah" line out of the Form_load event, and into the Form1_Shown event, and now the hidden taskbar icon problem has vanished. Also, the window doesn't flicker when it's loading.
Occasionally, seemingly randomly, when I close a dialog form my main form seems to move back in the window order, disappearing behind the next application back (usually Visual Studio). It retains focus, so clicking it in the taskbar minimises it, requiring another click. Whenever this happens, the control colours seem to change a little as well, but revert if I maximise and restore the window.
Any idea why this happens?
Edit: This happens when I'm debugging; it might happen at runtime too, but I usually don't have anything behind the application then, so I haven't noticed. Nobody has mentioned it.
This will happen when the dialog closes and Windows cannot find any window in your app that isn't disabled. Forced to move the focus somewhere, it will pick a window of another app to give the focus to. Your form will disappear behind it.
Exactly why your main form is disabled when this happens isn't clear. The color change certainly suggests you are changing the Enabled property of the form. Everything turns battle-ship gray when you do that. Setting Enabled back to true after the dialog closes doesn't work, it's too late. Just don't tinker with Enabled, the ShowDialog() method already disables other windows.
I have this Windows Forms application where it sits in the notification area. Clicking on the icon brings it up front, clicking it again (or clicking on the app X icon) sends it back. This is the type of app that having the window always on top is important when it's displayed by clicking the icon (it's optional though).
Right-clicking the icon brings up a context menu where one can select to enable the "always on top" option or not. When the application first starts up, the app settings are read from an XML file and I'm 99% that this is working as it should, the TopMost property is properly read (and written).
After some time (minutes, hours, days, whatever; I normally hibernate and rarely shutdown) the TopMost stops working. I don't change the option, I don't think anything is changing the option value but I click the notification area icon and app is not brought up front. It shows up but it's on the background (it displays on Alt+Tab), it's not "always on top" as it should. I bring up the context menu, disable the option (cause it's enabled) and enable it back and it starts to work after that. The app is now "always on top". However, it can lose this ability anytime after a while.
I can't understand why this happens and how this happens. Does anyone have any idea why? If not, any idea how could I try to debug such behavior?
EDIT:
I added a piece of code to show a MessageBox when the TopMost property was changed to see if I could notice any strange behavior but it was no good. It didn't help because the form was with TopMost = true but it still was in the background...
There is more than just one "Topmost" window. Topmost just says "Before all non-topmost windows".
I am pretty sure a reinitialization of the desktop (such as when hibernating) requires another SetWindowPos(hwnd, HWND_TOPMOST, ...) (which is the underlying Win32 API call).
As a workaround, you could reset and set the property again when showing the window.
Another possibility is that hiding the window also changes the Z order - either implicitely how Win32 implements that, or explicitely in the way WinForms call the hide/show window.
Like peterchen i also don't have a clue how to get the root cause. But why not make it a little bit simpler?
When you click on your Icon you'll show up your window and rely that TopMost is still active. Why not call SetWindowPos() with the current setting right before you show the window. This shouldn't make any performance problems (only happens if the user clicks the icon) nor any other side effect.
I know, it would be great to find out the root cause, but maybe it's not worth if you can solve it with such a little workaround.
I would like to be able to hide another application's window from the taskbar, without hiding the window itself. Specifically, I want to have several different Web browsers running, visible, available in the Alt+Tab list, but not taking up space on the taskbar.
(If anyone's curious why: I've written a dashboard app that uses Vista's DwmRegisterThumbnail APIs to show live previews of several windows at once -- a sort of "picture in picture", if you will. At that point, also having taskbar buttons for those windows seems redundant.)
I am aware that changing the other window's style to include WS_EX_TOOLWINDOW will hide it from the taskbar, and I tried this first. But, as expected, it had some side effects I didn't want: the title bar got shorter (not all bad, I guess) and the minimize and maximize buttons went away (not good). I also had to hide and re-show the window to get the taskbar to recognize the change, which caused repainting artifacts when I did it to IE windows.
My next thought was that, since windows with owners are hidden from the taskbar by default, maybe I could change the other windows to be owned by mine. But MSDN is pretty clear that "[a]fter creating an owned window, an application cannot transfer ownership of the window to another window."
I found this question that's worded similarly to mine, but it's specifically about windows from your own process, where you have complete control over window ownership.
Does anyone know of any other ways to hide a taskbar button, that will work for windows from another process?
Update: Tormod put me on the right track with ITaskbarList -- it works great. The pinvoke.net page had some errors (wrong GUID, methods declared alphabetically instead of in interface order), but I edited it, made corrections, and also added an example of how to instantiate the ITaskbarList via its coclass.
Update 2: If you use DeleteTab to hide a window's taskbar button, and then make that the active window (e.g. via SetForegroundWindow or Alt+Tab), its taskbar button will reappear. To keep the taskbar button hidden, I had to add a timer and keep calling DeleteTab. As long as you don't mind the taskbar button reappearing briefly whenever the window gets focused, this works well.
From MSDN:
Version 4.71 and later of Shell32.dll adds the capability to modify the contents of the taskbar. From an application, you can now add, remove, and activate taskbar buttons. Activating the item does not activate the window; it shows the item as pressed on the taskbar.
The taskbar modification capabilities are implemented in a Component Object Model (COM) object (CLSID_TaskbarList) that exposes the ITaskbarList interface (IID_ITaskbarList). You must call the ITaskbarList::HrInit method to initialize the object. You can then use the methods of the ITaskbarList interface to modify the contents of the taskbar.
It seems like COM interop is the way to go to reliably manipulate the contents of the taskbar. In particular, you would need to call the following functions:
ITaskbarList::AddTab
ITaskbarList::DeleteTab
You can find the C# signature for the ITaskbarList interface at pinvoke.net: ITaskbarList.
Have you tried removing WS_EX_APPWINDOW?