If the user tries to start another instance of my application, I want to activate the window of the process which is already running.
To find the process, I call Process.GetProcessesByName(), which gives me the System.Diagnostics.Process instance of the running instance of my application. However, I have hidden my process from the taskbar using
Form.ShowInTaskbar = false
This causes the Process.MainWindowHandle to be zero, so I can not access the current window of the running process.
Is there another way I can activate the window of the already running process?
Yes, the ShowInTaskBar property is special. There are several other properties of the Form class that are in the same category. These properties are implemented by style flags specified in the native CreateWindowEx() winapi call. The WS_EX_APPWINDOW flag for ShowInTaskBar.
Which is a problem when you change these properties, the window has to be recreated. Winforms does this automatically for you but it has several side-effects. One of which is that the Handle property value changes. Making it impossible for the Process class to find the MainWindowHandle back.
You'll have to find the window back another way. Making EnumWindows work is definitely not easy for Winforms forms, you can't get a guessable window class name. Not changing the ShowInTaskBar property is certainly the better approach. Also consider using the WindowsFormsApplicationBase class, it makes this trivial with the OnStartupNextInstance method.
Related
I was using this single instance implementation:
http://sanity-free.org/143/csharp_dotnet_single_instance_application.html
However, It stopped working when I added a NotifyIcon and I set ShowInTaskbar = false when the window is minimized. In this state the windows doesn't get the broadcast event.
So I changed the code to find the window using EnumWindows and matching the window title, which is a flimsy solution. I tried SetProp, GetProp, but the window handled is recreated when the value in ShowInTaskbar changes. I'm in .net core so I can't use the visual basic class WindowsFormsApplicationBase.
Is there a better good simple solution for activating the first window? Hopefully without sockets, pipes and stuff like that?
In my WPF application, I have multiple classes each of which implements a message loop. All of these message loops then run in parallel when I create objects of these classes. These objects may show a dialog box at times. The main application thread must keep an eye on these objects and make sure none of them is stuck with the dialog (and press Cancel (Escape key) if it determines such cases). What is the correct way to determine the active foreground window of a thread? I know there is a GetForegroundWindow() API, but it appears as if it works at system level and not thread level.
There's no such thing as the per-thread active foreground window. So what you are explicitly asking for does not have an answer.
Probably the right way to go here, using Win32 at least, is to enumerate top-level windows with EnumWindows. Then use GetWindowThreadProcessId to identify that the window is associated with one of your threads. Finally use GetClassName to identify that the window is a file dialog. Then feel free to do whatever dastardly thing it is you want to do to the window!
On the other hand, this sounds like a perfect candidate for UIAutomation. You are automating testing of UI. UIAutomation will be able to find these file dialog windows and press buttons on them.
What would be the best method to retrieve a reference of each window located in the background in reference to another window?
I want to apply a blur animation to every window except one that has IsTopMost set to true. My goal is to focus attention on a tool window that displays updates on a long running process. I currently have a static class that holds a reference to each open window to prevent multiple instances from running. I could use that; however, I want to make this code reusable in other apps.
You don't need your own list, there is Application.Current.Windows.
I am developing a (in-process) plug-in to application and as part of my plug-in I want to replace the application's tool-tips with my own. However, there is no API available for me to do so, so I've decided to go low-level.
I know the window class of the tool tip, but the question is, how do I detect it being created and how do I close it afterward?
Here's what I thought to do so far:
Create a system-wide hook on WM_CREATE
When caught, check the class and the process of the WM_CREATE target
Verify it is indeed the window I care about:
If the process is the one my plug-in is sitting in
And if the class is of the correct type
And if the correct application is in focus (in case of multiple applications)
Send a WM_DESTROY to the created window and create my own window at its position instead
How does it sound? Assuming there is indeed no API to handle the tooltips, is there a simpler way for what I need?
Thanks!
P.S Tagged as C++/C# as I intend to write it in these 2 languages (C++ for system-wide hook, C# for everything else)
If you know the type of the window you want to block, you can simply subclass it and handle the destruction in your own WndProc. Use GetClassLongPtr() with GCL_WNDPROC on the tooltip class, use SetClassLongPtr() with GCL_WNDPROC to set your own WndProc and have it call DestroyWindow() on WM_CREATE and call the old WndProc for the rest..
This won't work. Consider the view of the application that you're replacing the tooltips of and assuming that you could tell it to destroy windows. What will happen when the app decides that it needs to close the tooltip? It doesn't have the handle of your new window, it has the handle of the old window, which you've destroyed. Time for things to go wrong.
Your plugin system needs to explicitly support replacing the tooltips if you want this to work smoothly. Perhaps an optional part of the plugin framework could be a RequestTooltip function. If it doesn't exist, or returns null, or whatever then the default tooltips are used, otherwise your plugin provided ones are used.
The application retrieve window handles, using Enum* routines.
It happens that in the while the application manage the handle (get class name, window statistics...) of an enumerated/created window, the handle is no more valid. The code managing window handles are protected using a try/catch block, but the window handle is stored and the successively used for managing the represented window.
How to handle the window handle lifetime? It is possible to detect the handle invalidity?
I'd like to avoid try/catch blocks every time the application uses the window handles.
Window handles are only safe if used from the thread that created the window. From any other thread, all you can know about a window handle is, it was valid sometime in the past. right now, it may or may not be, and if it is, it could refer to a different window than intended entirely.
I already have the actual solution... but I didn't know about this until now!
Thank you all for having clarified about the window handle lifetime, but there is actually a method for being detected about window handle lifetime: CbtProc.
In the case the hook is installed system wide, it's possible to notify specific applications (it depends all on real implementation of the CBT hook) about a window destroy, which indicates that the a specific handle won't be valid after the notification.
From the documentation:
HCBT_DESTROYWND Specifies the handle to the window about to be destroyed.
Of course the access of the handles using WINAPI routines must be synchronized with the notification system, which doesn't seem to give good feasibility (CBT hook actually blocks window destroy because it is synchronized with the application logic).
You can pass it to IsWindow() to validate it.
There are a couple of caveats, however both will apply to pretty much any approach to this:
A thread should not use IsWindow for a
window that it did not create because
the window could be destroyed after
this function was called. Further,
because window handles are recycled
the handle could even point to a
different window.
If your doing this to a window in one of your own external apps, you could add a 2nd tier of validation by Set/GetProp()'ing a unique identifier of some kind.
You can use the GetWindowInfo function. It returns 0 if the handle is not valid.