Intention
Using the following code, I managed to load some applications in my windows form.
Code
What this function does is...
stating a process
embedding the process into a panel of my form
maximizing the embedded process
adding a resize event handler to the panel to update the size of the embedded process on panel resize
adding a closed event handler to the form to terminate the embedded process on form close
Usings
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Forms;
Constants
const int GWL_STYLE = -16;
const long WS_VISIBLE = 0x10000000,
WS_MAXIMIZE = 0x01000000,
WS_BORDER = 0x00800000,
WS_CHILD = 0x40000000;
Function
IntPtr LoadExtern(Control Panel, string Path)
{
try
{
Process Process = Process.Start(Path);
Process.WaitForInputIdle();
IntPtr Handle = Process.MainWindowHandle;
SetParent(Handle, Panel.Handle);
SetWindowLong(Handle, GWL_STYLE, (int)(WS_VISIBLE+(WS_MAXIMIZE|WS_BORDER)));
MoveWindow(Handle, 0, 0, Panel.Width, Panel.Height, true);
Panel.Resize += new EventHandler(
delegate(object sender, EventArgs e)
{
MoveWindow(Handle, 0, 0, Panel.Width, Panel.Height, true);
}
);
this.FormClosed += new FormClosedEventHandler(
delegate(object sender, FormClosedEventArgs e) {
SendMessage(Handle, 83, 0, 0);
Thread.Sleep(1000);
Handle = IntPtr.Zero;
}
);
return Handle;
}
catch (Exception e) { MessageBox.Show(this, e.Message, "Error"); }
return new IntPtr();
}
DLL Imports
[DllImport("user32.dll")]
static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
[DllImport("user32.dll")]
static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
[DllImport("user32.dll")]
static extern bool MoveWindow(IntPtr Handle, int x, int y, int w, int h, bool repaint);
[DllImport("user32.dll")]
static extern IntPtr SendMessage(IntPtr Handle, int Msg, int wParam, int lParam);
Result
This code works nice with some applications, like the windows notepad. Notepad is started and included in the panel of my form. There is no caption and the are no borders, as it should be.
LoadExtern(panel1, "notepad.exe");
After closing the form the embedded process gets terminated like expected.
Problem
Unfortunately my code doesn't work for some other (bigger) applications like firefox or sublimetext.
LoadExtern(panel2, #"C:\Program Files (x86)\Mozilla Firefox\firefox.exe");
What happens is that my form starts and firefox starts, but in its own window. Could you help me to include sublimetext or firefox in my applications?
Part of the solution
Thanks to Sheng Jiang's answers, I got it working for some more applications. What I did is to wait for a main window handle.
Process.WaitForInputIdle();
IntPtr Handle = new IntPtr();
for (int i = 0; Handle == IntPtr.Zero && i < 300; i++)
{
Handle = Process.MainWindowHandle;
Thread.Sleep(10);
}
But I still can't embed applications like the windows explorer.
Your code worked nice by coincidence.
WaitForInputIdle wouldn't necessary wait for the UI thread. For example an input method or a hook created by some other program may create a simple thread that becomes idle while the UI thread is still busy doing initialization.
MainWindowHandle searches for the first visible top level window. It won't return the logical main window when
The main window is not the first visible window created (e.g. a login dialog is created first)
The main window is not created with the visible style (think about a program that has only an icon in the notification area on the system tray)
There is no main window created at all (e.g. some applications open new documents/urls in an existing instance, like browsers and Windows Explorer)
There isn't a main window but multiple top level windows that have equal status. Think about IE6/Outlook/Word.
Even if the main window is created visibly and in fact is the first visible window in the new process, you may still have issues.
From the documentation of SetParent:
An application can use the SetParent function to set the parent window of a pop-up, overlapped, or child window.
It does not say you can reparent a top level window. In fact the top level window offers a lot of services that the program may be relying on, such as
Act as the measuring tool to determine if a full screen request is complete (conflicts with your requirement that new program needs to appear inside your panel)
Getting notified when a new DDE conversation starts, when the active window/program changes, when new hardware arrives, when system setting changes, when the user is logging off, when Windows Explorer is started, when the user pressed the Enter key on a nested dialog, etc. The list of window messages that only sent to top level windows is too long to list here,
Act as the default owner window of modal dialogs if the program choose to (and if you display modal dialog in your program as well, watch out for crashes)
This code works for most applcations. I embedded the file explorer simply using a webbrowser control on my form and set its url to a file location. The internet explorer control magically turns into a file explorer then.
This is my final code, feel free to use this for you own projects.
IntPtr EmbedProcess(Control Panel, string Path)
{
string Name = NameFromPath(Path);
foreach (Process Task in Process.GetProcesses())
{
if (NameFromPath(Task.ProcessName).Contains(Name))
{
try { Task.Kill(); }
catch (Exception e) { }
}
}
try
{
Process Task = Process.Start(Path);
Task.WaitForInputIdle();
IntPtr Handle = new IntPtr();
for (int i = 0; Handle == IntPtr.Zero && i < 10; i++) { Handle = Task.MainWindowHandle; Thread.Sleep(100); }
SetParent(Handle, Panel.Handle);
SetWindowLong(Handle, GWL_STYLE, (int)(WS_VISIBLE + (WS_MAXIMIZE | WS_BORDER)));
MoveWindow(Handle, 0, 0, Panel.Width, Panel.Height, true);
Panel.Resize += new EventHandler(delegate(object sender, EventArgs e) { MoveWindow(Handle, 0, 0, Panel.Width, Panel.Height, true); });
this.FormClosed += new FormClosedEventHandler(delegate(object sender, FormClosedEventArgs e)
{
SendMessage(Handle, 83, 0, 0);
Thread.Sleep(100);
Handle = IntPtr.Zero;
});
return Handle;
}
catch (Exception e) { MessageBox.Show(this, e.Message, "Error"); }
return new IntPtr();
}
I somebody is interested in the hole C# classes for embedding window processes and console processes into your form, check out this github repository.
Related
I need my window to be on top of another window. That "other" window (application) is from different developer. I do not have source codes for it. I can only use Spy++ to get information about it.
I am using Windows 7.
I tryed several things but they did not work.
This is what I tryed so far:
1) Timer + BringWindowToTop
2) I changed Owner of my window
IntPtr handle = User32.FindWindow("Vega Prime", "Vega Prime");
NativeWindow win = new NativeWindow();
win.AssignHandle(handle);
ChildForm form = new ChildForm();
form.Show(win);
When I am saying that it does not work I mean this:
1) at first everything looks alright: my window is on top
2) then I click on window (Vega Prime) which is below mine
3) my window disappears
4) I click on place where my window should be and it reappears (!!!!!!)
What is that? How is it possible at all?
UPDATE:
I spent some time trying to find solution to my problem.
Here is what I found:
TopMost window going behind non-TopMost fullscreen window sometimes
https://social.msdn.microsoft.com/Forums/vstudio/en-US/92e66584-6cb8-4976-9531-eab3b9a129e3/mfc-window-with-wsextopmost-hidden-by-full-screen-window?forum=vcgeneral
I am pretty sure that my problem has something to do with "Full Screen Issue" at Windows 7 (sometimes, when not top most window becomes full screen it forces top most windows to become hidden). That explains described above weird behaviour, right?
I realized this example that seems to do the trick:
public partial class Form1 : Form
{
IntPtr hWndToStayOver = User32.FindWindow("Vega Prime", "Vega Prime");
private System.Windows.Forms.Timer timer1 = new System.Windows.Forms.Timer();
public Form1()
{
InitializeComponent();
this.Load += new EventHandler(this.Form1_Load);
this.FormClosing += new FormClosingEventHandler(Form1_FormClosing);
this.timer1.Tick += new System.EventHandler(this.timer1_Tick);
}
private void Form1_Load(object sender, EventArgs e)
{
timer1.Start(); // Routine starts now that I'm sure my Form exists
}
void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
timer1.Stop(); // Stop routine (my Form doesn't exist anymore)
}
private bool AmIAboveOtherWindow()
{
IntPtr tmpHwnd = User32.GetNextWindow(hWndToStayOver, User32.GetNextWindowCmd.GW_HWNDPREV);
while (tmpHwnd != (IntPtr)0)
{
if (tmpHwnd == this.Handle)
return true;
tmpHwnd = User32.GetNextWindow(tmpHwnd, User32.GetNextWindowCmd.GW_HWNDPREV);
}
return false;
}
private void timer1_Tick(object sender, EventArgs e)
{
timer1.Stop();
if (!AmIAboveOtherWindow()) // Check if I am behind the target window
{
User32.SetWindowPos(this.Handle, hWndToStayOver, 0, 0, 0, 0, // Move my Form behind the target
User32.SetWindowPosFlags.SWP_NOMOVE |
User32.SetWindowPosFlags.SWP_NOSIZE |
User32.SetWindowPosFlags.SWP_SHOWWINDOW |
User32.SetWindowPosFlags.SWP_NOACTIVATE |
User32.SetWindowPosFlags.SWP_ASYNCWINDOWPOS);
User32.SetWindowPos(hWndToStayOver, this.Handle, 0, 0, 0, 0, // Move target behind my Form
User32.SetWindowPosFlags.SWP_NOMOVE |
User32.SetWindowPosFlags.SWP_NOSIZE |
User32.SetWindowPosFlags.SWP_SHOWWINDOW |
User32.SetWindowPosFlags.SWP_NOACTIVATE |
User32.SetWindowPosFlags.SWP_ASYNCWINDOWPOS);
}
timer1.Start();
}
}
User32 class
public class User32
{
[Flags]
public enum SetWindowPosFlags : uint
{
SWP_ASYNCWINDOWPOS = 0x4000,
SWP_DEFERERASE = 0x2000,
SWP_DRAWFRAME = 0x0020,
SWP_FRAMECHANGED = 0x0020,
SWP_HIDEWINDOW = 0x0080,
SWP_NOACTIVATE = 0x0010,
SWP_NOCOPYBITS = 0x0100,
SWP_NOMOVE = 0x0002,
SWP_NOOWNERZORDER = 0x0200,
SWP_NOREDRAW = 0x0008,
SWP_NOREPOSITION = 0x0200,
SWP_NOSENDCHANGING = 0x0400,
SWP_NOSIZE = 0x0001,
SWP_NOZORDER = 0x0004,
SWP_SHOWWINDOW = 0x0040,
}
public enum GetNextWindowCmd : uint
{
GW_HWNDNEXT = 2,
GW_HWNDPREV = 3,
}
[DllImport("user32.dll", SetLastError = true)]
public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, SetWindowPosFlags uFlags);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", SetLastError = true, EntryPoint = "GetWindow")]
public static extern IntPtr GetNextWindow(IntPtr hWnd, GetNextWindowCmd uCmd);
}
Clearly, you have to add to this code some check on the target handle: this example works only if the target window exists when the Form is loaded and if it isn't closed until the end
Make sure you set the owner of your window to the other window.
That will make sure that your window is always on top of the owner.
Here's how to import the appr. native functions, just change the 'Get' to 'Set' everywhere.
Then you can invoke it like this:
SetWindowLong(handle_of_owned_window, -8, handle_of_owner_window);
Hint #1: it's easy to set the ownership b/w 2 Form instances via the Form.Owner property, however you don't have access to one of them Forms.
Hint #2: in order to access the handle of a window, it needs to be shown at least once first.
It turned out that "other" application (which I was trying to merge with my application) is using Full-Screen Exclusive Mode. That explains why my topmost window disappeared from view and never reappeared (unless I switch off fullscreen mode with mouse click).
Details about Full-Screen Exclusive Mode are here:
https://docs.oracle.com/javase/tutorial/extra/fullscreen/exclusivemode.html
Basic idea is that Full-Screen Exclusive Mode "allows the programmer to suspend the windowing system so that drawing can be done directly to the screen". I believe that means that during Full-Screen Exclusive Mode (some experts call it "real full screen") OS ignores different windows (to save resources).
The only solution in situation like that is to configure "other" application to disable full screen mode.
It helped in my case - I studied documentation and found a place in configuration file where to set full screen mode to false.
I am working on a wpf application where instead of exiting the app when user closes the button I am minimizing it to the tray(similar to google talk).
void MainWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
e.Cancel = true;
this.Hide();
}
What I need is if user forgets that there is an instance of the app and tries to open a new instance I have to shut down the second instance and set my application as the foreground app. If the app is in minimized state (not hidden) I am able to do this. I am using the following code
protected override void OnStartup(StartupEventArgs e)
{
Process currentProcess = Process.GetCurrentProcess();
var runningProcess = (from process in Process.GetProcesses()
where
process.Id != currentProcess.Id &&
process.ProcessName.Equals(
currentProcess.ProcessName,
StringComparison.Ordinal)
select process).FirstOrDefault();
if (runningProcess != null)
{
Application.Current.Shutdown();
ShowWindow(runningProcess.MainWindowHandle, 5);
ShowWindow(runningProcess.MainWindowHandle, 3);
}
}
[DllImport("user32.dll")]
private static extern Boolean ShowWindow(IntPtr hWnd, Int32 nCmdShow);
When the app is minimized it has some unique value for MainWindowHandle. When I hide the app, the MainWindowHandle of runningProcess is showing as 0. I think this is why my application is not opening when it is in hidden state, but don't know how to fix it.
Tell me if I need to post more code or clarify anything. Thank you in advance.
When I hide the app, the MainWindowHandle of runningProcess is showing as 0
You're right. If a process doesn't have a graphical interface associated with it (hidden/ minimized) then the MainWindowHandle value is zero.
As workaround, you could try getting the HANDLE for the hidden window by enumerating all open windows using EnumDesktopWindows function and compare its process id with the hidden/ minimized windows's process id.
Update
The WPF's WIN32 window has a bit different behavior than the standard WIN32 window. It has the class name composed of the word HwndWrapper, the name of AppDomain it was created in, and a unique random Guid (which changes on every launch), e.g., HwndWrapper[WpfApp.exe;;4d426cdc-31cf-4e4c-88c7-ede846ab6d44].
Update 2
When WPF's window is hidden by using the Hide() method, it internally calls UpdateVisibilityProperty(Visibility.Hidden), which in turns set the internal visibility flag for UIElement to false. When we call the Show() method of WPF Window, UpdateVisibilityProperty(Visibility.Visible) is called, and the internal visibility flag for UIElement is toggled.
When we show the WPF window using the ShowWindow(), the UpdateVisibilityProperty() method is not trigerred, thus the internal visibility flag does not get reversed (which causes the window to be displayed with black backround).
By looking at the WPF Window internal implementation, the only way to toggle the internal visiblity flag, without calling the Show() or Hide() method, is by sending a WM_SHOWWINDOW message.
const int GWL_EXSTYLE = (-20);
const uint WS_EX_APPWINDOW = 0x40000;
const uint WM_SHOWWINDOW = 0x0018;
const int SW_PARENTOPENING = 3;
[DllImport("user32.dll")]
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll")]
private static extern bool EnumDesktopWindows(IntPtr hDesktop, EnumWindowsProc ewp, int lParam);
[DllImport("user32.dll")]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId);
[DllImport("user32.dll")]
private static extern uint GetWindowTextLength(IntPtr hWnd);
[DllImport("user32.dll")]
private static extern uint GetWindowText(IntPtr hWnd, StringBuilder lpString, uint nMaxCount);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern bool GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
[DllImport("user32.dll")]
static extern int GetWindowLong(IntPtr hWnd, int nIndex);
delegate bool EnumWindowsProc(IntPtr hWnd, int lParam);
static bool IsApplicationWindow(IntPtr hWnd) {
return (GetWindowLong(hWnd, GWL_EXSTYLE) & WS_EX_APPWINDOW) != 0;
}
static IntPtr GetWindowHandle(int pid, string title) {
var result = IntPtr.Zero;
EnumWindowsProc enumerateHandle = delegate(IntPtr hWnd, int lParam)
{
int id;
GetWindowThreadProcessId(hWnd, out id);
if (pid == id) {
var clsName = new StringBuilder(256);
var hasClass = GetClassName(hWnd, clsName, 256);
if (hasClass) {
var maxLength = (int)GetWindowTextLength(hWnd);
var builder = new StringBuilder(maxLength + 1);
GetWindowText(hWnd, builder, (uint)builder.Capacity);
var text = builder.ToString();
var className = clsName.ToString();
// There could be multiple handle associated with our pid,
// so we return the first handle that satisfy:
// 1) the handle title/ caption matches our window title,
// 2) the window class name starts with HwndWrapper (WPF specific)
// 3) the window has WS_EX_APPWINDOW style
if (title == text && className.StartsWith("HwndWrapper") && IsApplicationWindow(hWnd))
{
result = hWnd;
return false;
}
}
}
return true;
};
EnumDesktopWindows(IntPtr.Zero, enumerateHandle, 0);
return result;
}
Usage Example
...
if (runningProcess.MainWindowHandle == IntPtr.Zero) {
var handle = GetWindowHandle(runningProcess.Id, runningProcess.MainWindowTitle);
if (handle != IntPtr.Zero) {
// show window
ShowWindow(handle, 5);
// send WM_SHOWWINDOW message to toggle the visibility flag
SendMessage(handle, WM_SHOWWINDOW, IntPtr.Zero, new IntPtr(SW_PARENTOPENING));
}
}
...
Thanks IronGeek, This is great. I'm just learning c# and struggled for a while trying to get this to work. Also I cant 'add comment' as insufficient reputation here so hence this post. I'm using WPF .Net 5.0.
I searched around to implement this, so for other newbies they will also need something like the following in their program to receive the message (sorry, not sure what page I copied this from, so many of them (individuals will need to make their own Mainwindow_Loaded event handler).
private void Mainwindow_Loaded_Event(object sender, RoutedEventArgs e)
{
hwndSource = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle);
hwndSource.AddHook(new HwndSourceHook(WndProc));
}
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
if (msg == WM_SHOWWINDOW)
{
MessageBox.Show("I recieved WM_SHOWWINDOW");
handled = true;
}
return IntPtr.Zero;
}
The 'bring to front' tip you mentioned was also needed in my case, here is what is needed:
(from Bring Word to Front )
put this in the declarations section:
[DllImport("user32.dll")]
static extern bool SetForegroundWindow(IntPtr hWnd);
and put the following just after the 'SendMessage(handle, WM_SHOWWINDOW, IntPtr.Zero, new IntPtr(SW_PARENTOPENING));' statement:
SetForegroundWindow(handle);
Without this, the activated window just remains hidden behind other windows and it has to be found by manually fishing around in the taskbar.
So now I've finally got this going for a non-hidden window but now need to look at what is needed for a hidden one as that is my real goal.
Following on from my early post, and to quote an earlier comment from IronGeek the issue is ' If a process doesn't have a graphical interface associated with it (hidden/ minimized) then the MainWindowHandle value is zero'. Therefore any attempt to pass a hidden Window's handle is doomed as it doesn't exist.
So I have found a work-around, although it requires the target process to regularly check for the presence of a new message. Therefore this is still not ideal, but it works for me in 2021 (WPF, .Net 5.0) and doesn't need to import the user32.dll. Rather it carries out a makeshift type of Inter Process Communication (IPC) using the MainWindowTitle as a container to send a message passively.
The MainWindowTitle is settable at runtime and is viewable from other processes, therefore it can be used like an inter-process variable. This is my entire solution below, note it needs to be published to a local folder to see how it runs as the point is to run multiple instances.
<Window x:Class="TitleComsTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:TitleComsTest"
mc:Ignorable="d"
Name="TitleComsTest" Title="TitleComsTest" Height="400" Width="600"
WindowStartupLocation = "CenterScreen" Closing="TitleComsTest_Closing" Visibility="Hidden">
<Grid>
<TextBox Name ="TextBox1" HorizontalAlignment="Center" VerticalAlignment="Center" Height="230" Width="460"/>
<Button Name="QuitButton" Content=" Really Quit " HorizontalAlignment="Center" Margin="0,0,0,30" VerticalAlignment="Bottom" Click="QuitButton_Click"/>
</Grid>
The code behind:
using System;
using System.Diagnostics;
using System.Windows;
using System.Windows.Threading;
namespace TitleComsTest
{
public partial class MainWindow : Window
{
//string for MainWindowTitle when first instance and visible:
const string my_Visible_exe_Name = "TitleComstest";
//string for MainWindowTitle when first instance and Hidden:
const string my_Hidden_exe_Name = "TitleComstest...";
//string for MainWindowTitle when 2nd instance :
const string my_exe_Name_Flag = "TitleComstest, Please-Wait";
bool reallyCloseThisProgram = false;
private DispatcherTimer timer1, timer2;
public MainWindow()
{
InitializeComponent();
//Get an array of processes with the chosen name
Process[] TitleComstests = Process.GetProcessesByName(my_Visible_exe_Name);
if (TitleComstests.Length > 1)
{ //Then this is not the first instance
for (int i = 0; i < TitleComstests.Length; i++)
{
if (TitleComstests[i].MainWindowTitle == my_Visible_exe_Name)
{ //The first instance is visible as the MainWindowTitle has been set to the visible name
Close(); //Quit - nothing to do but close the new instance
}
}
//The first instance is hidden, so set MainWindowTitle so the first instance can see it and react
this.Title = my_exe_Name_Flag;
this.WindowState = WindowState.Minimized; //Minimize the window to avoid having two windows shown at once
this.Visibility = Visibility.Visible; //The second instance needs to be visible (minimized is enough) to be seen
StartTimerQuit(4000); //arbitrary time, needs to be longer than 2000ms which is the checking period - see StartTimerLook(2000);
}
else
{
TextBox1.Text = "This is Multi-instance demo using the 'MainWindowTitle' to send messages\r\nto the first (hidden) instance to wake it up.";
TextBox1.Text += "\r\n\r\nThis demo requires the program be published to a local folder and \r\nnot run in the debugger.";
TextBox1.Text += "\r\n\r\nYou can type here to mark this instance: _____________ \r\n\r\nand then hide me by clicking top right close window 'X'";
TextBox1.Text += "\r\n\r\nOnce closed then start the program again to see the 1st instance pop up.";
TextBox1.Text += "\r\n\r\nFinally use the 'Really Quit' button to end this demo.";
this.Visibility = Visibility.Visible;
}
}
private void StartTimerQuit(Int32 interval) //Timer to Quit setup and start
{
timer1 = new DispatcherTimer(); timer1.Tick += timerQuit_Tick;
timer1.Interval = new TimeSpan(0, 0, 0, 0, interval); timer1.Start();
}
private void timerQuit_Tick(object sender, EventArgs e)
{
reallyCloseThisProgram = true; Close();
}
private void TitleComsTest_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
if (!reallyCloseThisProgram)
{
e.Cancel = true;
this.Title = my_Hidden_exe_Name; //Set the Title text to flag a hidden state
this.Visibility = Visibility.Hidden;
//Start checking every 2 secs at the process names - could be faster but this is a constant background process
StartTimerLook(2000);
}
}
private void StartTimerLook(Int32 interval) //Timer to look for new instances setup and start
{
timer2 = new DispatcherTimer(); timer2.Tick += timerLook_Tick;
timer2.Interval = new TimeSpan(0, 0, 0, 0, interval); timer2.Start();
}
private void timerLook_Tick(object sender, EventArgs e)
{ //Every timer interval check to see if a process is present with the Ttile name flag
Process[] myNameFlagProcesses = Process.GetProcessesByName(my_Visible_exe_Name);
for (int i = 0; i < myNameFlagProcesses.Length; i++)
{
if (myNameFlagProcesses[i].MainWindowTitle == my_exe_Name_Flag) //If name flag is seen ...
{ //... then wake up
TextBox1.Text += "\r\n Saw the other window";
this.Visibility = Visibility.Visible;
this.Title = my_Visible_exe_Name; //Set the Title text to flag a visible state
this.Show();
this.Activate();
timer2.Stop();
}
}
}
private void QuitButton_Click(object sender, RoutedEventArgs e)
{
reallyCloseThisProgram = true; Close();
}
}
}
I have been trying to send mouse clicks to a WebBrowser control inside of my form using PostMessage(), and I have run into a rather significant issue. What I am trying to achieve is to simulate mouse clicks on this WebBrowser while my form is minimized. Usually PostMessage() would work just fine doing this, but it seems that it only works while my form has focus. This leads me to believe that there is some check going on to see if the particular website I am loading into my WebBrowser control is in focus before it handles mouse events.
This is how I send the clicks with my program:
private void SendClick(Point location)
{
resetHandle = true;
StringBuilder className = new StringBuilder(100);
while (className.ToString() != "Internet Explorer_Server")
{
handle = GetWindow(handle, 5); // 5 == child
GetClassName(handle, className, className.Capacity);
//MessageBox.Show(className.ToString());
}
IntPtr lParam = (IntPtr)((location.Y << 16) | location.X);
IntPtr wParam = IntPtr.Zero;
const uint downCode = 0x201;
const uint upCode = 0x202;
const uint moveCode = 0x200;
PostMessage(handle, moveCode, wParam, lParam); //move mouse
PostMessage(handle, downCode, wParam, lParam); // mousedown
PostMessage(handle, upCode, wParam, lParam); // mouseup
}
This is what the resetHandle does:
private void timer3_Tick(object sender, EventArgs e)
{
if (resetHandle == true)
{
handle = webBrowser1.Handle;
resetHandle = false;
}
}
I'm not sure if there is a better way of sending mouse events to a background window and I am open to any ideas. What I am really asking though is if it is at all possible to make a window believe it is in focus when it is actually still minimized?
Any help at all would be much appreciated!
Rather than keep the window minimized, keep it normal (restored), but set its X or Y coordinate so that it is positioned off screen.
If you want give the user the illusion of minimizing and restoring it, use HwndSource.AddHook to watch for SC_MINIMIZE. In your HwndSourceHook handler, move the window on or off screen according to the pseudo-minimized state, and set handled to true.
I have a winform application (.NET 2.0 C#). From this application, I want to start another process (another winform application) and dock it to my window (or at least make it look like it is docked). So far, I can only find information about docking controls, not windows in separate processes. My first thought is to get the handle of the window and use unmanaged system calls to set the height/width and position of the window to my docking area. But before I got started, I wanted to check to see if any of you good people have done something similar. I have access to the source code of the application I want docked but would rather not make any changes if I can avoid it. I have complete programming control over what will be the parent application. Any advice? Thanks in advance!
The solution I have used before is to set the application window as a child of the control you want to dock it in.
using System.Diagnostics;
using System.Runtime.InteropServices;
private Process pDocked;
private IntPtr hWndOriginalParent;
private IntPtr hWndDocked;
[DllImport("user32.dll")]
public static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
[DllImport("user32.dll", SetLastError = true)]
public static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
private void dockIt()
{
if (hWndDocked != IntPtr.Zero) //don't do anything if there's already a window docked.
return;
hWndParent = IntPtr.Zero;
pDocked = Process.Start(#"notepad");
while (hWndDocked == IntPtr.Zero)
{
pDocked.WaitForInputIdle(1000); //wait for the window to be ready for input;
pDocked.Refresh(); //update process info
if (pDocked.HasExited)
{
return; //abort if the process finished before we got a handle.
}
hWndDocked = pDocked.MainWindowHandle; //cache the window handle
}
//Windows API call to change the parent of the target window.
//It returns the hWnd of the window's parent prior to this call.
hWndOriginalParent = SetParent(hWndDocked, Panel1.Handle);
//Wire up the event to keep the window sized to match the control
Panel1.SizeChanged += new EventHandler(Panel1_Resize);
//Perform an initial call to set the size.
Panel1_Resize(new Object(), new EventArgs());
}
private void undockIt()
{
//Restores the application to it's original parent.
SetParent(hWndDocked, hWndOriginalParent);
}
private void Panel1_Resize(object sender, EventArgs e)
{
//Change the docked windows size to match its parent's size.
MoveWindow(hWndDocked, 0, 0, Panel1.Width, Panel1.Height, true);
}
* Adding some solution in Answer..**
This code has helped me to dock some executable in windows form. like NotePad, Excel, word, Acrobat reader n many more...
But it wont work for some applications.
As sometimes when you start process of some application.... wait for idle time... and the try to get its mainWindowHandle.... till the time the main window handle becomes null.....
so I have done one trick to solve this
If you get main window handle as null... then search all the runnning processes on sytem and find you process ... then get the main hadle of the process and the set panel as its parent.
ProcessStartInfo info = new ProcessStartInfo();
info.FileName = "xxxxxxxxxxxx.exe";
info.Arguments = "yyyyyyyyyy";
info.UseShellExecute = true;
info.CreateNoWindow = true;
info.WindowStyle = ProcessWindowStyle.Maximized;
info.RedirectStandardInput = false;
info.RedirectStandardOutput = false;
info.RedirectStandardError = false;
System.Diagnostics.Process p = System.Diagnostics.Process.Start(info);
p.WaitForInputIdle();
Thread.Sleep(3000);
Process[] p1 ;
if(p.MainWindowHandle == null)
{
List<String> arrString = new List<String>();
foreach (Process p1 in Process.GetProcesses())
{
// Console.WriteLine(p1.MainWindowHandle);
arrString.Add(Convert.ToString(p1.ProcessName));
}
p1 = Process.GetProcessesByName("xxxxxxxxxxxx");
//p.WaitForInputIdle();
Thread.Sleep(5000);
SetParent(p1[0].MainWindowHandle, this.panel2.Handle);
}
else
{
SetParent(p.MainWindowHandle, this.panel2.Handle);
}
This is a lot clunkier than I hoped for, but working so far. I am using system calls to force the child window in the location that reflects the docking area. It is not working perfectly yet. I get a few oddities caused by the HWND_TOPMOST and I still need to add logic preventing the user from moving the child window directly.
//This is my docking window
private System.Diagnostics.Process notepad;
private void windowDockTest()
{
/*
* Docking notepad to panel2 of the splitcontainer
*/
//if panel2 moves or is resized, call the docking function
spcScript.Panel2.Move += new EventHandler(Panel2_Resize);
spcScript.Panel2.SizeChanged += new EventHandler(Panel2_Resize);
//Call the docking function if main form is moved
this.LocationChanged += new EventHandler(Panel2_Resize);
//Start the notepad process
notepad = new System.Diagnostics.Process();
notepad.StartInfo.FileName = "notepad";
notepad.Start();
//Wait a second for notpad to fully load
notepad.WaitForInputIdle(1000);
//Dock it
Panel2_Resize(new Object(), new EventArgs());
}
void Panel2_Resize(object sender, EventArgs e)
{
//Get the screen location of panel2
Rectangle r = spcScript.Panel2.RectangleToScreen(spcScript.Panel2.ClientRectangle);
//Dock it
redock(notepad.MainWindowHandle, r.X, r.Y, r.Width, r.Height);
}
[DllImport("user32.dll")]
public static extern IntPtr SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int Y, int cx, int cy, int wFlags);
public static void redock(IntPtr handle, int x, int y, int width, int height)
{
IntPtr HWND_TOPMOST = new IntPtr(-1);
const short SWP_NOACTIVATE = 0x0010;
SetWindowPos(handle,HWND_TOPMOST, x, y, width, height,SWP_NOACTIVATE);
}
How can I bring my WPF application to the front of the desktop? So far I've tried:
SwitchToThisWindow(new WindowInteropHelper(Application.Current.MainWindow).Handle, true);
SetWindowPos(new WindowInteropHelper(Application.Current.MainWindow).Handle, IntPtr.Zero, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
SetForegroundWindow(new WindowInteropHelper(Application.Current.MainWindow).Handle);
None of which are doing the job (Marshal.GetLastWin32Error() is saying these operations completed successfully, and the P/Invoke attributes for each definition do have SetLastError=true).
If I create a new blank WPF application, and call SwitchToThisWindow with a timer, it works exactly as expected, so I'm not sure why it's not working in my original case.
Edit: I'm doing this in conjunction with a global hotkey.
myWindow.Activate();
Attempts to bring the window to the foreground and activates it.
That should do the trick, unless I misunderstood and you want Always on Top behavior. In that case you want:
myWindow.TopMost = true;
I have found a solution that brings the window to the top, but it behaves as a normal window:
if (!Window.IsVisible)
{
Window.Show();
}
if (Window.WindowState == WindowState.Minimized)
{
Window.WindowState = WindowState.Normal;
}
Window.Activate();
Window.Topmost = true; // important
Window.Topmost = false; // important
Window.Focus(); // important
In case you need the window to be in front the first time it loads then you should use the following:
private void Window_ContentRendered(object sender, EventArgs e)
{
this.Topmost = false;
}
private void Window_Initialized(object sender, EventArgs e)
{
this.Topmost = true;
}
Or by overriding the methods:
protected override void OnContentRendered(EventArgs e)
{
base.OnContentRendered(e);
Topmost = false;
}
protected override void OnInitialized(EventArgs e)
{
base.OnInitialized(e);
Topmost = true;
}
I know this question is rather old, but I've just come across this precise scenario and wanted to share the solution I've implemented.
As mentioned in comments on this page, several of the solutions proposed do not work on XP, which I need to support in my scenario. While I agree with the sentiment by #Matthew Xavier that generally this is a bad UX practice, there are times where it's entirely a plausable UX.
The solution to bringing a WPF window to the top was actually provided to me by the same code I'm using to provide the global hotkey. A blog article by Joseph Cooney contains a link to his code samples that contains the original code.
I've cleaned up and modified the code a little, and implemented it as an extension method to System.Windows.Window. I've tested this on XP 32 bit and Win7 64 bit, both of which work correctly.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Interop;
using System.Runtime.InteropServices;
namespace System.Windows
{
public static class SystemWindows
{
#region Constants
const UInt32 SWP_NOSIZE = 0x0001;
const UInt32 SWP_NOMOVE = 0x0002;
const UInt32 SWP_SHOWWINDOW = 0x0040;
#endregion
/// <summary>
/// Activate a window from anywhere by attaching to the foreground window
/// </summary>
public static void GlobalActivate(this Window w)
{
//Get the process ID for this window's thread
var interopHelper = new WindowInteropHelper(w);
var thisWindowThreadId = GetWindowThreadProcessId(interopHelper.Handle, IntPtr.Zero);
//Get the process ID for the foreground window's thread
var currentForegroundWindow = GetForegroundWindow();
var currentForegroundWindowThreadId = GetWindowThreadProcessId(currentForegroundWindow, IntPtr.Zero);
//Attach this window's thread to the current window's thread
AttachThreadInput(currentForegroundWindowThreadId, thisWindowThreadId, true);
//Set the window position
SetWindowPos(interopHelper.Handle, new IntPtr(0), 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW);
//Detach this window's thread from the current window's thread
AttachThreadInput(currentForegroundWindowThreadId, thisWindowThreadId, false);
//Show and activate the window
if (w.WindowState == WindowState.Minimized) w.WindowState = WindowState.Normal;
w.Show();
w.Activate();
}
#region Imports
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
private static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr ProcessId);
[DllImport("user32.dll")]
private static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, bool fAttach);
[DllImport("user32.dll")]
public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
#endregion
}
}
I hope this code helps others who encounter this problem.
To make this a quick copy-paste one -
Use this class' DoOnProcess method to move process' main window to foreground (but not to steal focus from other windows)
public class MoveToForeground
{
[DllImportAttribute("User32.dll")]
private static extern int FindWindow(String ClassName, String WindowName);
const int SWP_NOMOVE = 0x0002;
const int SWP_NOSIZE = 0x0001;
const int SWP_SHOWWINDOW = 0x0040;
const int SWP_NOACTIVATE = 0x0010;
[DllImport("user32.dll", EntryPoint = "SetWindowPos")]
public static extern IntPtr SetWindowPos(IntPtr hWnd, int hWndInsertAfter, int x, int Y, int cx, int cy, int wFlags);
public static void DoOnProcess(string processName)
{
var allProcs = Process.GetProcessesByName(processName);
if (allProcs.Length > 0)
{
Process proc = allProcs[0];
int hWnd = FindWindow(null, proc.MainWindowTitle.ToString());
// Change behavior by settings the wFlags params. See http://msdn.microsoft.com/en-us/library/ms633545(VS.85).aspx
SetWindowPos(new IntPtr(hWnd), 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW | SWP_NOACTIVATE);
}
}
}
HTH
Why some of the answers on this page are wrong!
Any answer that uses window.Focus() is wrong.
Why? If a notification message pops up, window.Focus() will grab the focus away from whatever the user is typing at the time. This is insanely frustrating for end users, especially if the popups occur quite frequently.
Any answer that uses window.Activate() is wrong.
Why? It will make any parent windows visible as well.
Any answer that omits window.ShowActivated = false is wrong.
Why? It will grab the focus away from another window when the message pops up which is very annoying!
Any answer that does not use Visibility.Visible to hide/show the window is wrong.
Why? If we are using Citrix, if the window is not collapsed when it is closed, it will leave a weird black rectangular hold on the screen. Thus, we cannot use window.Show() and window.Hide().
Essentially:
The window should not grab the focus away from any other window when it activates;
The window should not activate its parent when it is shown;
The window should be compatible with Citrix.
MVVM Solution
This code is 100% compatible with Citrix (no blank areas of the screen). It is tested with both normal WPF and DevExpress.
This answer is intended for any use case where we want a small notification window that is always in front of other windows (if the user selects this in the preferences).
If this answer seems more complex than the others, it's because it is robust, enterprise level code. Some of the other answers on this page are simple, but do not actually work.
XAML - Attached Property
Add this attached property to any UserControl within the window. The attached property will:
Wait until the Loaded event is fired (otherwise it cannot look up the visual tree to find the parent window).
Add an event handler that ensures that the window is visible or not.
At any point, you can set the window to be in front or not, by flipping the value of the attached property.
<UserControl x:Class="..."
...
attachedProperties:EnsureWindowInForeground.EnsureWindowInForeground=
"{Binding EnsureWindowInForeground, Mode=OneWay}">
C# - Helper Method
public static class HideAndShowWindowHelper
{
/// <summary>
/// Intent: Ensure that small notification window is on top of other windows.
/// </summary>
/// <param name="window"></param>
public static void ShiftWindowIntoForeground(Window window)
{
try
{
// Prevent the window from grabbing focus away from other windows the first time is created.
window.ShowActivated = false;
// Do not use .Show() and .Hide() - not compatible with Citrix!
if (window.Visibility != Visibility.Visible)
{
window.Visibility = Visibility.Visible;
}
// We can't allow the window to be maximized, as there is no de-maximize button!
if (window.WindowState == WindowState.Maximized)
{
window.WindowState = WindowState.Normal;
}
window.Topmost = true;
}
catch (Exception)
{
// Gulp. Avoids "Cannot set visibility while window is closing".
}
}
/// <summary>
/// Intent: Ensure that small notification window can be hidden by other windows.
/// </summary>
/// <param name="window"></param>
public static void ShiftWindowIntoBackground(Window window)
{
try
{
// Prevent the window from grabbing focus away from other windows the first time is created.
window.ShowActivated = false;
// Do not use .Show() and .Hide() - not compatible with Citrix!
if (window.Visibility != Visibility.Collapsed)
{
window.Visibility = Visibility.Collapsed;
}
// We can't allow the window to be maximized, as there is no de-maximize button!
if (window.WindowState == WindowState.Maximized)
{
window.WindowState = WindowState.Normal;
}
window.Topmost = false;
}
catch (Exception)
{
// Gulp. Avoids "Cannot set visibility while window is closing".
}
}
}
Usage
In order to use this, you need to create the window in your ViewModel:
private ToastView _toastViewWindow;
private void ShowWindow()
{
if (_toastViewWindow == null)
{
_toastViewWindow = new ToastView();
_dialogService.Show<ToastView>(this, this, _toastViewWindow, true);
}
ShiftWindowOntoScreenHelper.ShiftWindowOntoScreen(_toastViewWindow);
HideAndShowWindowHelper.ShiftWindowIntoForeground(_toastViewWindow);
}
private void HideWindow()
{
if (_toastViewWindow != null)
{
HideAndShowWindowHelper.ShiftWindowIntoBackground(_toastViewWindow);
}
}
Additional links
For tips on how ensure that a notification window always shifts back onto the visible screen, see my answer: In WPF, how to shift a window onto the screen if it is off the screen?.
If the user is interacting with another application, it may not be possible to bring yours to the front. As a general rule, a process can only expect to set the foreground window if that process is already the foreground process. (Microsoft documents the restrictions in the SetForegroundWindow() MSDN entry.) This is because:
The user "owns" the foreground. For example, it would be extremely annoying if another program stole the foreground while the user is typing, at the very least interrupting her workflow, and possibly causing unintended consequences as her keystrokes meant for one application are misinterpreted by the offender until she notices the change.
Imagine that each of two programs checks to see if its window is the foreground and attempts to set it to the foreground if it is not. As soon as the second program is running, the computer is rendered useless as the foreground bounces between the two at every task switch.
I know that this is late answer, maybe helpful for researchers
if (!WindowName.IsVisible)
{
WindowName.Show();
WindowName.Activate();
}
I have had a similar problem with a WPF application that gets invoked from an Access application via the Shell object.
My solution is below - works in XP and Win7 x64 with app compiled to x86 target.
I'd much rather do this than simulate an alt-tab.
void Window_Loaded(object sender, RoutedEventArgs e)
{
// make sure the window is normal or maximised
// this was the core of the problem for me;
// even though the default was "Normal", starting it via shell minimised it
this.WindowState = WindowState.Normal;
// only required for some scenarios
this.Activate();
}
Well, since this is such a hot topic... here is what works for me. I got errors if I didn't do it this way because Activate() will error out on you if you cannot see the window.
Xaml:
<Window ....
Topmost="True"
....
ContentRendered="mainWindow_ContentRendered"> .... </Window>
Codebehind:
private void mainWindow_ContentRendered(object sender, EventArgs e)
{
this.Topmost = false;
this.Activate();
_UsernameTextBox.Focus();
}
This was the only way for me to get the window to show on top. Then activate it so you can type in the box without having to set focus with the mouse. control.Focus() wont work unless the window is Active();
Well I figured out a work around. I'm making the call from a keyboard hook used to implement a hotkey. The call works as expected if I put it into a BackgroundWorker with a pause. It's a kludge, but I have no idea why it wasn't working originally.
void hotkey_execute()
{
IntPtr handle = new WindowInteropHelper(Application.Current.MainWindow).Handle;
BackgroundWorker bg = new BackgroundWorker();
bg.DoWork += new DoWorkEventHandler(delegate
{
Thread.Sleep(10);
SwitchToThisWindow(handle, true);
});
bg.RunWorkerAsync();
}
To show ANY currently opened window import those DLL:
public partial class Form1 : Form
{
[DllImportAttribute("User32.dll")]
private static extern int FindWindow(String ClassName, String WindowName);
[DllImportAttribute("User32.dll")]
private static extern int SetForegroundWindow(int hWnd);
and in program We search for app with specified title (write title without first letter (index > 0))
foreach (Process proc in Process.GetProcesses())
{
tx = proc.MainWindowTitle.ToString();
if (tx.IndexOf("Title of Your app WITHOUT FIRST LETTER") > 0)
{
tx = proc.MainWindowTitle;
hWnd = proc.Handle.ToInt32(); break;
}
}
hWnd = FindWindow(null, tx);
if (hWnd > 0)
{
SetForegroundWindow(hWnd);
}
These codes will work fine all times.
At first set the activated event handler in XAML:
Activated="Window_Activated"
Add below line to your Main Window constructor block:
public MainWindow()
{
InitializeComponent();
this.LocationChanged += (sender, e) => this.Window_Activated(sender, e);
}
And inside the activated event handler copy this codes:
private void Window_Activated(object sender, EventArgs e)
{
if (Application.Current.Windows.Count > 1)
{
foreach (Window win in Application.Current.Windows)
try
{
if (!win.Equals(this))
{
if (!win.IsVisible)
{
win.ShowDialog();
}
if (win.WindowState == WindowState.Minimized)
{
win.WindowState = WindowState.Normal;
}
win.Activate();
win.Topmost = true;
win.Topmost = false;
win.Focus();
}
}
catch { }
}
else
this.Focus();
}
These steps will works fine and will bring to front all other windows into their parents window.
Just wanted to add another solution to this question. This implementation works for my scenario, where CaliBurn is responsible for displaying the main Window.
protected override void OnStartup(object sender, StartupEventArgs e)
{
DisplayRootViewFor<IMainWindowViewModel>();
Application.MainWindow.Topmost = true;
Application.MainWindow.Activate();
Application.MainWindow.Activated += OnMainWindowActivated;
}
private static void OnMainWindowActivated(object sender, EventArgs e)
{
var window = sender as Window;
if (window != null)
{
window.Activated -= OnMainWindowActivated;
window.Topmost = false;
window.Focus();
}
}
The problem could be that the thread calling your code from the hook hasn't been initialized by the runtime so calling runtime methods don't work.
Perhaps you could try doing an Invoke to marshal your code on to the UI thread to call your code that brings the window to the foreground.
If you are trying to hide the window, for example you minimize the window, I have found that using
this.Hide();
will hide it correctly, then simply using
this.Show();
will then show the window as the top most item once again.
Remember not to put the code that shows that window inside a PreviewMouseDoubleClick handler as the active window will switch back to the window who handled the event.
Just put it in the MouseDoubleClick event handler or stop bubbling by setting e.Handled to True.
In my case i was handling the PreviewMouseDoubleClick on a Listview and was not setting the e.Handled = true then it raised the MouseDoubleClick event witch sat focus back to the original window.
This is a combination of a few suggestions above that works well and is simple. It only comes to front when those events fire, so any window that pops up after the event will stay on top of course.
public partial class MainWindow : Window
{
protected override void OnContentRendered(EventArgs e)
{
base.OnContentRendered(e);
Topmost = true;
Topmost = false;
}
protected override void OnInitialized(EventArgs e)
{
base.OnInitialized(e);
Topmost = true;
Topmost = false;
}
....
}
I wanted to create a launcher with the keyboard hook and had the same problem.
After much trial and error, this solved the problem.
void Active()
{
MainWindow0.Show();
MainWindow0.Focus();
MainWindow0.Activate();
MainWindow0.WindowState = WindowState.Normal;
}
void Deactive()
{
MainWindow0.Hide();
MainWindow0.WindowState = WindowState.Minimized;
}
I built an extension method to make for easy reuse.
using System.Windows.Forms;
namespace YourNamespace{
public static class WindowsFormExtensions {
public static void PutOnTop(this Form form) {
form.Show();
form.Activate();
}// END PutOnTop()
}// END class
}// END namespace
Call in the Form Constructor
namespace YourNamespace{
public partial class FormName : Form {
public FormName(){
this.PutOnTop();
InitalizeComponents();
}// END Constructor
} // END Form
}// END namespace