Restore app from tray [duplicate] - c#

This question already has answers here:
How to create single instance WPF Application that restores the open window when an attempt is made to open another instance? [duplicate]
(2 answers)
Closed 4 years ago.
I use Hardcodet.Wpf.TaskbarNotification to create tray menu, but i have some trouble with it, how can i open my app(process) from other process if it was hide to tray
I used this methods, but had not luck
[DllImport("user32.dll")]
static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
public static extern IntPtr SetFocus(HandleRef hWnd);
[DllImport("user32.dll")]
public static extern bool ShowWindow(IntPtr hWnd, int cmd);
I have been add events Activated to MainWindow, and GotFocus, Loaded to TaskbarIcon(TaskBar WPF Element), but those methods(from user32) didn't trigger any events (it works when app is minimized, but not when is hide to tray)
Any minds what i need to do ?
Update:
It's not duplicate, there are described how to use Mutex in the original post, i already done it. I need "bring to front", Activate or Trigger any event from other instance of my app, when the first instance is in tray There are just show MessageBox when the second instance created, and the first instance minimized, that post is easy to do, i have more harder task than described in the original post

From another process? Without elevation you will probably have a hard time bringing your app to the foreground. Read the "Remarks" section here.

Related

GetWindowText vs Process.MainWindowTitle

I'm trying to obtain process information for the current active application (or window), using .Net/C#.
Currently I'm using
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
To get the current active window.
I understand there's no native way to do this other than use this API function.
From that, I use:
[DllImport("user32")]
private static extern UInt32 GetWindowThreadProcessId(IntPtr hWnd, out Int32 lpdwProcessId);
To get the process name that belongs to that window and then I get further process information.
I also use
[DllImport("user32.dll")]
private static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int count);
To get the current Window Text or caption.
Now, using the Process class, I can use
MainWindowTitle
to get the main Window title as well.
The thing is, MainWindowTitle and GetWindowText does not return the same information.
For example, let's say the main application opened is "Toad" with a connection and an editor open.
Then with GetWindowText I get:
"Toad for Oracle - myConnection - Somequery.sql".
and Process.MainWindowTitle returns
"myConnection".
So, the question is how do I get the exact same text as I get using GetWindowText, but using merely .Net classes?
Edit:
I found out that actually the reason is simply because both functions are not querying the same window handle.
The window handle returned in the GetForegroundWindow, is the number 198982.
And the MainWindowHandle property, which I suppose is the one used in the MainWindowTitle propery is the number 198954.
Using Spy++ I could find and confirm those windows handle captions are the one returned by their corresponding function.
So the "problem", if any, is that the Process class does not correctly identify the most foreground window as the Main Window.
GetForegroundWindow gives you the active window the user is working in and that might be a owned window or a modal dialog, not necessarily the applications main/root window.
MainWindow is a .NET concept, native win32 does not have such a thing and there can be 0, 1 or multiple "main windows" in an application.
Some Delphi/C++Builder applications have a HWND for the taskbar button and each form is a owned window belonging to this "invisible" window. Other UI frameworks may pull similar stunts that might confuse "main window" detection.
You can use UI Automation to inspect other applications if you don't want to use p-invoke. Start with the foreground window and walk up the tree of owned and child windows...

How to restore a window without giving it focus using WPF (or interop)

I need to restore ("un-minimize") a WPF window that has already been created but the window that's currently on top (not necessarily WPF) can't lose focus or activation. I have tried using all WIN32 functions I can find, to no avail. Getting really frustrated by now, would really appreciate any pointers and tips.
Obviously just changing to WindowState.Normal in WPF doesn't cut it as this makes the window receive focus and activation as-well. I have also tried all sorts of combinations with setting Hidden and IsEnabled while restoring.
I have tried WIN32 SetWindowPos with HWND_TOP, HWND_TOPMOST etc. but this function is not intended to restore windows and will only change position of already "displayed" windows.
Tried WIN32 ShowWindow and SetWindowPlacement but no luck there either. Tried a desperate attempt at adding a HwndHook to try and listen for WM_SETFOCUS and restoring focus to the original window but i only get zero for the last focused window handle..
Edit - Solution with window extension after tip from Joel Lucsy:
public static class RestoreWindowNoActivateExtension
{
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool ShowWindow(IntPtr hWnd, UInt32 nCmdShow);
private const int SW_SHOWNOACTIVATE = 4;
public static void RestoreNoActivate(this Window win)
{
WindowInteropHelper winHelper = new WindowInteropHelper(win);
ShowWindow(winHelper.Handle, SW_SHOWNOACTIVATE);
}
}
Call ShowWindow passing the SW_SHOWNOACTIVATE flag.

In C#, how to activate the previously focused window?

I work eg. in Firefox, and my C#.NET app brings its window to the front. That's ok, but when I use SendToBack() to hide the form, it doesn't activate Firefox's window, so altough Firefox is in the foreground, I have to click into the window to be able to scroll, etc. How can I activate the previously focused window in C#?
i have tried these:
[DllImport("User32")]
private static extern int SetForegroundWindow(IntPtr hwnd);
[DllImport("user32.dll")]
static extern bool AllowSetForegroundWindow(int dwProcessId);
[DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();
[...]
AllowSetForegroundWindow(System.Diagnostics.Process.GetCurrentProcess().Id);
SendToBack();
SetForegroundWindow(GetForegroundWindow());
I hoped that after sending my window back, the previous one will be returned by GetForegroundWindow, but it doesn't work.
Secondly, I've tried to override WndProc, and handle the WM_ACTIVATE message to get the previous window from lParam, but it doesn't work either if I use SetForegroundWindow() with this handle.
protected override void WndProc(ref Message msg) {
if (msg.Msg == 0x0006) {
prevWindow = msg.LParam;
}
base.WndProc(ref msg);
}
[...]
SetForegroundWindow(prevWindow);
did you try the SetActiveWindow function? Its separate from the SetForgroundWindow function, although it seems that you may need to use them both.
http://msdn.microsoft.com/en-us/library/windows/desktop/ms646311%28v=vs.85%29.aspx
There is also a SetFocus function which sounds like it could work.
http://msdn.microsoft.com/en-us/library/windows/desktop/ms646312%28v=vs.85%29.aspx
Update
To get the current Active Window, I would fire off the GetActiveWindow function before moving your application to the front of the stack, that way you have the handle for the window that was active before hand.
http://msdn.microsoft.com/en-us/library/windows/desktop/ms646292%28v=vs.85%29.aspx
Another Update
I did a bit more digging around on the site and came up with the following three links, which might work better. The keyboard input functions seem to be dependent on the Window you are trying to set being part of the calling threads message queue, which since we are dealing with two separate application threads, is likely to not be the case.
GetGUIThreadInfo Get the threads information, including active window
GUITHREADINFO The GUITHREADINFO structure
SwitchToThisWindow Another method of window changing
All of these are in the same method stack as the SetForegroundWindow method, which seems to make them more likely to do what you are attempting.
When you call SetFocus() to move your app forward, it returns the handle of the window that had focus before you.

How to keep window always on top

How I can keep my window staying always on top even if there is a window of another application with Topmost = true option activated and trying to stay in front of my window?
You can do a platform invoke on BringWindowToTop to achieve this:
[DllImport("user32.dll", SetLastError=true)]
static extern bool BringWindowToTop(IntPtr hWnd);
[DllImport("user32.dll", SetLastError=true)]
static extern bool BringWindowToTop(HandleRef hWnd);
And call to it when the FocusLost event fires.
It should be possible by setting the Focus on window, from OnFocusLost event handler.
Easiest way(assuming you allready have topmost promery set) would be calling
myform.BringToFront();
on FIXED but relativly small time intervals(see Timer class), through all the time form must stay on top.
If calling this was conected to event that inform you of losing privileg of beeing on top, that could possibly cause resource-fihgts between multiple applications. Price of beeing safe is that some other program might be cheating by lisstening to informations when he is overthroned by your program, but the only solution for you wolud than be to kill that other program if you want to stay on top all the time :D

c# Maximize Window from System Tray

I am having trouble trying to bring my application window to the front (i.e on top of all other windows). I want the user to be able to double click the notifyIcon in the system tray, and If the application already has a window open for it to be bought to the front. I have tried using the following two P/inovkes but neither seem to work consistently. Does anybody have any idea how to bring a window to the front/top?
[DllImport("user32.dll")]
private static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);
[DllImport("user32.dll")]
tatic extern bool SetForegroundWindow(IntPtr hWnd);
ShowWindowAsync(ADProcess.MainWindowHandle, SW_RESTORE);
SetForegroundWindow(ADProcess.MainWindowHandle);
Given the little info you have provided the best guess I can make is that you have a timing issue with the call to ShowWindowAsync which runs asynchronously followed by the call to SetForgroundWindow.
Have you tried using ShowWindow to see if that works correctly?

Categories