Open window behind another application - c#

I want to open few windows (IE window, Outlook mail windows, notepad windows) by a click of a button on my application.
Problem: When I click on the button and all these applications open one after the other. My own application (on which the user clicked) is lost in the window clutter.
I want to open all these windows behind my application. Any suggestions ? Any standard API's which I can use to achieve this kind of behavior ?
Logic: I want to do something like open window with window placement = 2 in the Z order of windows. This way, my window, which is active will always be at the top (z order = 1) when other windows are opening.
Any pointers will be helpful.
Thanks
Karephul
UPDATE:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms633545%28v=vs.85%29.aspx
I used this PInvoke to set my application window as topmost. then all the other windows will automatically open behind it. Once done, I un-set the topmost window flag using the same PInvoke. More details in the link I posted.

You can set the TopMost property of your form to True.
Make sure you allow users to change that or only do it for a short period, because it does get annoying to users.

You have two ways, call the win32 command SetForgroundWindow or toggle topmost.
To toggle topmost do the following. This will bring the window to the front but not leave it as topmost which is pretty annoying.
// Launch applications (Process.Start(...))
TopMost = true;
TopMost = false;
To call the Win32 Command
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SetForegroundWindow(IntPtr hWnd);
...
// Launch applications (Process.Start(...))
SetForegroundWindow(this.Handle);
...

It might be more intrusive than you like but I discovered by accident while doing some Office interop that after opening the office apps and files that you can issue
MessageBox.Show("All files have been opened.")
And this should bring your app (and the messagebox)frontmost.

If you are using System.Diagnostics.Process Classes Start method you can set Application variables for the process state when launched using the ProcessStartInfo class and passing it into the overridden method Start(ProcessStartInfo startInfo) as a parameter. There is a property ProcessStartInfo.WindowStyle which is of type ProcessWindowStyle which has 4 values Normal, Hidden, Minimized and Maximized, by setting the value to Minimized you can regain focus and be easily brought to the front.
Code from MSDN
// Uses the ProcessStartInfo class to start new processes,
// both in a minimized mode.
void OpenWithStartInfo()
{
ProcessStartInfo startInfo = new ProcessStartInfo("IExplore.exe");
startInfo.WindowStyle = ProcessWindowStyle.Minimized;
Process.Start(startInfo);
startInfo.Arguments = "www.northwindtraders.com";
Process.Start(startInfo);
}

Related

How can I force a redraw of a process whoʼs parent is a panel-control?

I've been tasked with creating an application launcher that hosts both Winforms and WPF applications and via a slightly different methodology Web applications. The user is presented with a list of applications they can launch and these are "captured" upon launch and are lodged inside a panel on a form by using SetParent to make the panel the parent of the processes MainWindowHandle. This bit appears to work well and the applications when launched are captured and displayed in the given panel.
What Iʼm having a particular issue with is that not all applications that are captured are happy to initially draw themselves in the panel. It seems to be isolated to those applications that are WPF based, but thatʼs not guaranteed.
Effectively what happens is that if a WPF application is launched, it is captured and moved to the panel, and the panel will remain blank until I click the panel at which point the application will happily repaint itself. From this point forward the application seems to be happy enough repainting itself as required without intervention.
Basically Iʼm now at my wits ends and have tried the following User32 native and .NET methods;
Invalidate (on the form, on the panel, on the tab control that hosts both of these)
Update
Refresh
SendMessage with a plethora of parameters, including attempting the, "you shouldnʼt do this" WM_PAINT.
RedrawWindow with the UpdateNow and Invalidate flags.
None of the above makes any visible difference and itʼs only when I physically click the panel or move the window that the contained application will behave and repaint itself.
Has anyone else produced anything similar and has a solution to the redraw/repaint issue? Iʼve scoured the entire Google/Bing/Duck Duck Go spheres trying to hunt down an answer but to no avail.
Hopefully one of you out there has an answer.
The following code represents the bulk of the feature in that it starts a process and captures the handle for the main window of the process and sets itsʼ parent to a panel control on a bog-standard WinForms window. I should probably point out that the bog-standard WinForms window is itself “hosted” inside an application using the (EasyTabs) Library. Which, I believe, is not causing any problems.
Example:
// Try to acquire a the process.
ProcessStartInfo startInfo = new ProcessStartInfo(path);
try
{
startInfo.UseShellExecute = false;
startInfo.CreateNoWindow = true;
startInfo.WindowStyle = ProcessWindowStyle.Normal;
Process.StartInfo = startInfo;
Process.EnableRaisingEvents = true;
Process.Exited += TabManagerContainerForm_ProcessExited;
Process.Start();
if (Process != null)
{
// Wait until the process has created a main window or exited.
while (Process.MainWindowHandle == IntPtr.Zero && !Process.HasExited)
{
Thread.Sleep(100);
Process.Refresh();
}
if (!Process.HasExited) // We have acquired a MainWindowHandle
{
// Capture the Process's main window and show it inside the applicationPanel panel control.
SetParent(Process.MainWindowHandle, applicationPanel.Handle);
// Change the captured Process's window to one without the standard chrome. Itʼs provided by our tabbed application.
SetWindowLong(Process.MainWindowHandle, (int)WindowLongFlags.GWL_STYLE, (int)WindowStyles.WS_VISIBLE);
}
else // Process has exited.
{
if (Process.MainWindowHandle == IntPtr.Zero) Log.Information("{0} failed to execute.", Process.ProcessName);
throw new FailedProcessException(string.Format("{0} failed to execute.", path));
}
}
else
{
throw new Exception(string.Format("Invalid path: {0}", path));
}
}
catch (Exception ex) when (!(ex is FailedProcessException)) // Catch everything but FailedProcessExceptions. FPEs are simply passed up the chain.
{
Log.Error(ex.Message);
throw;
}
Summary:
The problem seems to happen when attaching an application to a Panel in a tab that is not the currently visible tab.
Solution:
Add WS_CHILD flag to the call to SetWindowLong:
SetWindowLong(Process.MainWindowHandle, (int)WindowLongFlags.GWL_STYLE, (int)(WindowStyles.WS_VISIBLE | WindowStyles.WS_CHILD));
Details:
I tried reproducing the example in the question (without using EasyTabs). I used a simple Form with a single Panel. With a button press I call a simple WPF app and attach it to the Panel. It works OK, it renders immediately. The only problem I found was the position of the WPF window which was random. I fixed it with calling SetWindowPos (using pinvoke) like this:
SetWindowPos(Process.MainWindowHandle, IntPtr.Zero, 0, 0, 0, 0, SetWindowPosFlags.IgnoreResize);
Than, I tried using a TabControl with two tabs, each containing a Panel and two buttons, each one when pressed, launches a different WPF app to one of the Panels. I found that when a tab (TabPage) is not the visible tab, the problem occurs - the launched application is not visible until the Panel is clicked. I solved this problem by adding WS_CHILD flag to the call to SetWindowLong. I'm not sure why but it works...
My code:
// Capture the Process's main window and show it inside the applicationPanel panel control.
SetParent(Process.MainWindowHandle, applicationPanel.Handle);
// Change the captured Process's window to one without the standard chrome. Itʼs provided by our tabbed application.
SetWindowLong(Process.MainWindowHandle, (int)WindowLongFlags.GWL_STYLE, (int)(WindowStyles.WS_VISIBLE | WindowStyles.WS_CHILD));
// Change the Process's window position to the top-left corner of the panel
SetWindowPos(Process.MainWindowHandle, IntPtr.Zero, 0, 0, 0, 0, SetWindowPosFlags.IgnoreResize);

How to keep window visible at all times, but not force it to be on top

I'm creating a "desktop gadget" of sorts, I've disabled manual minimizing of the window, but now there is another problem: the system can still hide the window if the user presses Windows+D, for example.
When hidden that way, no usual minimize/resize/visibility events are fired.
I want to do something almost like TopMost, but without forcing the window order.
Maybe it's possible to install a global shortcut event using win32 API, and briefly set TopMost to true, but that sounds very hackish.
I found one solution, but it does not seem to work on Windows 10: Keeping window visible through "Show Desktop"/Win+D
The other common option, which would be writing an actual desktop gadget, is not possible on Windows 10, given their deprecation.
Are there any other methods to keep a window visible (but not on top of the screen) at all moments?
This function is working for me:
BOOL FixShowDesktop(HWND hWnd)
{
HWND hWndTmp = FindWindowEx(NULL, NULL, L"Progman", NULL);
if (hWndTmp)
{
hWndTmp = FindWindowEx(hWndTmp, NULL, L"SHELLDLL_DefView", NULL);
if (hWndTmp)
{
SetWindowLongPtr(hWnd, -8, (LONG_PTR)hWndTmp);
return TRUE;
}
}
return FALSE;
}
Note, this code is a bit better then from Keeping window visible through "Show Desktop"/Win+D because the window can be overflowed by other windows (like any other window). Using SetParent places window under all other windows.

c# remove 3rd party application from taskbar

How to remove an 3rd party application from the Windows taskbar by its handle?
I've found this:
Remove application from taskbar with C# wrapper?
But it doesnt worked for me.
It only sets another style (small x to close, no maximize/minimize button) to the Window i selected (notepad).
Any ideas about this?
EDIT: I dont want to remove MY application from the taskbar, i want to remove an external application by handle
If you have the handle to the window you can call ShowWindow() through the Win32 API. Then you can do:
// Let the window disappear (even from taskbar)
ShowWindow(this.Handle, WindowShowStyle.Hide);
// Revive the window back to the user
ShowWindow(this.Handle, WindowShowStyle.ShowNoActivate);
So from now, all your problem is to get the handle of the window you like to hide:
Process[] procs = Process.GetProcesses();
IntPtr hWnd;
foreach(Process proc in procs)
{
if ((hWnd = proc.MainWindowHandle) != IntPtr.Zero)
{
Console.WriteLine("{0} : {1}", proc.ProcessName, hWnd);
}
}
To hide it from windows task bar you just need to set ShowInTaskbar property to false :
this.ShowInTaskbar = false;
As for moving of windows you can use spy++ to check windows events and identify it.
How to remove an application from the Windows taskbar?
this.ShowInTaskbar = false;
Easy:
this.ShowInTaskbar = false;
As for the Form movement: you can use the Move event under Layout events

Set active window

I'm trying to make an app that gives a quake style drop-down HUD console. I can get it to show and hide the window, but I can't figure out how to set it as the active window after showing it. Im using Win API calls to show and hide the window. I've tried SetForegroundWindow(IntPtr hWnd) and SetFocus(IntPtr hWnd) to no avail. Anyone have any ideas?
http://pastebin.com/DgtJJGiv
public void ShowApp()
{
IntPtr h = FindWindow(null, "C:\\Windows\\system32\\cmd.exe");
ShowWindow(h, SW_SHOW);
//EnableWindow(h, true);
isHidden = false;
// set focus to console window
SetForegroundWindow(h);
System.Diagnostics.Debug.WriteLine(h);
}
I found an answer here:
How to show form in front in C#
The winAPI approaches were not working correctly for me but this did:
form.TopMost = true;
form.TopMost = false;
I originally was only setting TopMost to true but I ran into problems with dialog boxes displaying behind the form. It appears that setting TopMost to true pulls the form to the front and holds it there. Setting it to false doesn't push it back but does allow other forms to be shown in front. I was still having problems with focus so I ended up going with the following:
form.Activate();
You may use SetActiveWindow winAPI method. Hope this helps...
Try this (works for me):
public static void ShowApp()
{
IntPtr h = FindWindow(null, "C:\\Windows\\system32\\cmd.exe");
ShowWindow(h, ShowWindowCommands.Show);
SetForegroundWindow(h);
SetFocus(h);
System.Diagnostics.Debug.WriteLine(h);
}
Is there any reason why you can't implement your own console window? What I mean is a simple Form with a Textbox set to the correct style. You would probably have more control over how it works than trying to use the 'cmd' process.
Just a thought.

Should Form.ShowDialog(IWin32Window) work with any window handle?

When using System.Windows.Forms.ShowDialog(IWin32Window), should I be able to pass in an IWin32Window representing any window handle and have it be modal with respect to that window?
As part of an Internet Explorer 7 extension I'm trying to open a window modal with respect to an Internet Explorer tab. It's not the currently selected tab, but I can get the hwnd of the tab OK. However, when I pass this to ShowDialog my Form is shown, but it's not modal with respect to anything: I can still do things in Internet Explorer, including in the tab that's supposed to be the owner. My form is shown floating above the Internet Explorer windows and it stays on top, so it's not like it's just opened as a normal form, but it's not correctly modal.
Using Spy++, I can find my form and it's owner handle is correctly set.
Does this mean that something has gone wrong, or I'm doing something wrong? How do I make my form correctly modal?
FYI, I'm using this wrapper class to create an IWin32Window from a hwnd (thanks Ryan!):
/// <summary>
/// Wrapper class so that we can return an IWin32Window given a hwnd
/// </summary>
public class WindowWrapper : System.Windows.Forms.IWin32Window
{
public WindowWrapper(IntPtr handle)
{
_hwnd = handle;
}
public IntPtr Handle
{
get { return _hwnd; }
}
private IntPtr _hwnd;
}
UPDATE: Using Internet Explorer 7 & .NET 2.0
UPDATE: Playing around some more with Spy++ and the handles it exposes, I find that if I use a different hwnd then I can make my window modal to the tab:
I was using the tab's hwnd as suggested by the IWebBrowser2.HWND doc, which in Spy++ appears as class TabWindowClass. It has a child of class Shell DocObject View, which has a child of Internet_Explorer_Server. If I use the hwnd of the Internet Explorer_Server then it works correctly, for example, when I click with the mouse on other tabs, Internet Explorer reacts normally. When I click with the mouse on the tab of interest, it plays the windows d'oh sound and doesn't do anything.
I don't yet know how to programatically get the Internet_Explorer_Server hwnd, but it should be possible.
Also, for what it's worth, while playing with other window handles I was generally able to make my form modal to other applications and dialogs. So I guess the answer to my question is 'many but not all handles'... possibly it depends on the application?
UPDATE: Another side-note: The original reason I wanted to make my form modal to the tab instead of the whole window is that when opening a MessageBox from my form, passing the form as owner, the MessageBox would not always open on top of my form. If a new Internet Explorer tab had just been opened but wasn't active then the MessageBox would be hidden and that tab would start flashing. However, since Internet Explorer was disabled with my form opened modal it wasn't possible to switch to that tab, so Internet Explorer would be frozen. I thought that opening my form modal to the tab would solve this, but I've found another solution is to avoid using MessageBox: if I use a second form and ShowDialog(this) from my first form then the second form correctly opens to the front. So it seems that Form.ShowDialog() works better than MessageBox.Show() in some cases. More discussion in Problems with modal dialogs and messageboxes.
ShowDialog() does two important things. It starts pumping a message loop so it acts modally to the calling code. And it disables any other windows in the application with a EnableWindow(false) API call. The latter is what is not happening in your case. Not entirely surprising, considering that the window that needs to be disabled is not a WF window.
You may need to call EnableWindow() yourself. Be sure to re-enable it in before the dialog closes or Windows will go hunting for another app's window to give the focus to.
Your code is correct. The problem you are likely running into though is that IE has a threading model related to its tabs. I don't know the exact details but the short version is that each tab can and likely is running on a different thread than other tabs.
The Modal'ness of a dialog is specific to the thread where the dialog is running. UI on other threads will be unaffected by a model dialog on another thread. It's entirely possible you are able to access tabs which are running on a different thread for this reason.
Here's a more concise version of Ryan/Rory's WindowWrapper code:
internal class WindowWrapper : IWin32Window
{
public IntPtr Handle { get; private set; }
public WindowWrapper(IntPtr hwnd) { Handle = hwnd; }
}
I have never tried this from an IE extension, but I have a hunch that IE may not "respect" a Win32-style modal window the same way it does a modal window raised from Javascript using window.open().
Have you tested this code against something other than IE, just to confirm it works the way it should for other applications?
here is a build in solution in .NET:
public static NativeWindow FromHandle(IntPtr handle)

Categories