Cannot force my window to be on top - c#

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.

Related

Hide minimize, maximize, close buttons from a window and show the icon

I'm trying to hide the minimize, maximize and close buttons from the top of my window and still display my icon.
I have tried a couple different things but can't get the icon to stay. This is the code I am working with:
private const int GWL_STYLE = -16;
private const int WS_SYSMENU = 0x00080000;
[DllImport("user32.dll")]
private extern static int SetWindowLong(IntPtr hwnd, int index, int value);
[DllImport("user32.dll")]
private extern static int GetWindowLong(IntPtr hwnd, int index);
public Window()
{
SourceInitialized += MainWindow_SourceInitialized;
InitializeComponent();
Uri iconUri = new Uri("pack://application:,,,/Icon1.ico", UriKind.RelativeOrAbsolute);
this.Icon = BitmapFrame.Create(iconUri);
}
void MainWindow_SourceInitialized(object sender, EventArgs e)
{
WindowInteropHelper wih = new WindowInteropHelper(this);
int style = GetWindowLong(wih.Handle, GWL_STYLE);
SetWindowLong(wih.Handle, GWL_STYLE, style & ~WS_SYSMENU);
}
Any help will be greatly appreciated!
Thanks!
You can set the WindowStyle property of the WPF window in XAML to None.
i.e.
WindowStyle="None"
Using code you can do the same thing as follows:-
WindowName.WindowStyle = WindowStyle.None;
It must work to hide all the three buttons.
This is code I have used to enable and disable the close button in winforms. I realize that's different than what you want in 3 ways
1) It only deals with the close button (although, if Oscar is correct, it's the only one you need to worry about)
2) it doesn't hide it, it just disables/greys it out (though you may be able to change a parameter to completely hide it instead)
3) It is for winforms, not wpf
Despite these differences, perhaps looking at the code will help you figure out what you are missing. If it you do figure it out, I'd be interested in you posting your solution :)
#region Enable / Disable Close Button
[DllImport("user32.dll", CharSet=CharSet.Auto)]
private static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);
[DllImport("user32.dll", CharSet=CharSet.Auto)]
private static extern bool EnableMenuItem(IntPtr hMenu, uint uIDEnableItem, uint uEnable);
private const int SC_CLOSE = 0xF060;
private const int MF_BYCOMMAND = 0x0000;
private const int MF_ENABLED = 0x0000;
private const int MF_GRAYED = 0x0001;
protected void DisableCloseButton()
{
try
{
EnableMenuItem(GetSystemMenu(this.Handle, false), SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);
this.CloseButtonIsDisabled = true;
}
catch{}
}
protected void EnableCloseButton()
{
try
{
EnableMenuItem(GetSystemMenu(this.Handle, false), SC_CLOSE, MF_BYCOMMAND | MF_ENABLED);
this.CloseButtonIsDisabled = false;
}
catch{}
}
protected override void OnSizeChanged(EventArgs e)
{
if (this.CloseButtonIsDisabled)
this.DisableCloseButton();
base.OnSizeChanged(e);
}
#endregion
Note that some window styles can not be changed after window creation but I don't know whether this applies to these flags or not... As far as I know if your titlebar is painted by the system you either have both an icon and a close button or none of these because both of them are controlled by the WS_SYSMENU window style.
In the Form properties, for example in a WPF application, you can only hide the minimize and mazimize buttons.
There is a property called ResizeMode, and if you put to NoResize, this two button will be hidden. ;)

Why can't I embed these Applications in my Form?

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.

Attach window to window of another process

My WPF application has more than one window, I want to attach some of these windows to a window of another process. My problem is that once I attach my window it becomes invisible.
I'm trying this with the following code:
public static bool setParentWindow(IntPtr hWndChild, IntPtr hWndNewParent)
{
IntPtr previousParent = SetParent(hWndChild, hWndNewParent);
return (previousParent == null ? false : true);
}
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
setParentWindow(myWindowHwnd, newParentHwnd);
So, the above code successfully attaches the window, but unfortunately makes it invisible.
My reason for doing this is that I'm trying to extend an application by building "Widgets" for it, my widgets will hook in and show the user extra information.
Both windows have the following styles: WS_OVERLAPPEDWINDOW, WS_OVERLAPPED, WS_VISIBLE, WS_CLIPSIBLINGS, WS_CLIPCHILDREN.
I found that I could do this without even using the setParent call. I used HwndSource class as follows:
MyWindow window = new MyWindow();
window.ShowActivated = true;
HwndSourceParameters parameters = new HwndSourceParameters();
parameters.WindowStyle = 0x10000000 | 0x40000000;
parameters.SetPosition(0, 0);
parameters.SetSize((int)window.Width, (int)window.Height);
parameters.ParentWindow = newParent;
parameters.UsesPerPixelOpacity = true;
HwndSource src = new HwndSource(parameters);
src.CompositionTarget.BackgroundColor = Colors.Transparent;
src.RootVisual = (Visual)window.Content;
This is working great now without any problems.
I'm not sure what you need to do with overlapped windows, but from MSDN:
For compatibility reasons, SetParent does not modify the WS_CHILD or WS_POPUP window styles of the window whose parent is being changed. Therefore, if hWndNewParent is NULL, you should also clear the WS_CHILD bit and set the WS_POPUP style after calling SetParent. Conversely, if hWndNewParent is not NULL and the window was previously a child of the desktop, you should clear the WS_POPUP style and set the WS_CHILD style before calling SetParent.
private void TryToAttach(IntPtr ownerHandle)
{
if(ownerHandle == IntPtr.Zero)
{
return;
}
try
{
var helper = new WindowInteropHelper(window) { Owner = ownerHandle };
}
catch(Exception e)
{
Logger.Error(e, "Could not attach window.");
}
}

Docking Window inside another Window

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 to make a window always stay on top in .Net?

I have a C# winforms app that runs a macro in another program. The other program will continually pop up windows and generally make things look, for lack of a better word, crazy. I want to implement a cancel button that will stop the process from running, but I cannot seem to get the window to stay on top. How do I do this in C#?
Edit: I have tried TopMost = true; , but the other program keeps popping up its own windows over top. Is there a way to send my window to the top every n milliseconds?
Edit: The way I solved this was by adding a system tray icon that will cancel the process by double-clicking on it. The system tray icon does no get covered up. Thank you to all who responded. I read the article on why there is not a 'super-on-top' window... it logically does not work.
Form.TopMost will work unless the other program is creating topmost windows.
There is no way to create a window that is not covered by new topmost windows of another process. Raymond Chen explained why.
I was searching to make my WinForms application "Always on Top" but setting "TopMost" did not do anything for me. I knew it was possible because WinAmp does this (along with a host of other applications).
What I did was make a call to "user32.dll." I had no qualms about doing so and it works great. It's an option, anyway.
First, import the following namespace:
using System.Runtime.InteropServices;
Add a few variables to your class declaration:
private static readonly IntPtr HWND_TOPMOST = new IntPtr(-1);
private const UInt32 SWP_NOSIZE = 0x0001;
private const UInt32 SWP_NOMOVE = 0x0002;
private const UInt32 TOPMOST_FLAGS = SWP_NOMOVE | SWP_NOSIZE;
Add prototype for user32.dll function:
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
Then in your code (I added the call in Form_Load()), add the call:
SetWindowPos(this.Handle, HWND_TOPMOST, 0, 0, 0, 0, TOPMOST_FLAGS);
[Reference][1]
[1]: http://www.c-sharpcorner.com/uploadfile/kirtan007/make-form-stay-always-on-top-of-every-window/
If by "going crazy" you mean that each window keeps stealing focus from the other, TopMost will not solve the problem.
Instead, try:
CalledForm.Owner = CallerForm;
CalledForm.Show();
This will show the 'child' form without it stealing focus. The child form will also stay on top of its parent even if the parent is activated or focused. This code only works easily if you've created an instance of the child form from within the owner form. Otherwise, you might have to set the owner using the API.
Set Form.TopMost
I had a momentary 5 minute lapse and I forgot to specify the form in full like this:
myformName.ActiveForm.TopMost = true;
But what I really wanted was THIS!
this.TopMost = true;
Set the form's .TopMost property to true.
You probably don't want to leave it this way all the time: set it when your external process starts and put it back when it finishes.
The way i solved this was by making a system tray icon that had a cancel option.
Why not making your form a dialogue box:
myForm.ShowDialog();
The following code makes the window always stay on top as well as make it frameless.
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace StayOnTop
{
public partial class Form1 : Form
{
private static readonly IntPtr HWND_TOPMOST = new IntPtr(-1);
private const UInt32 SWP_NOSIZE = 0x0001;
private const UInt32 SWP_NOMOVE = 0x0002;
private const UInt32 TOPMOST_FLAGS = SWP_NOMOVE | SWP_NOSIZE;
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
public Form1()
{
InitializeComponent();
FormBorderStyle = FormBorderStyle.None;
TopMost = true;
}
private void Form1_Load(object sender, EventArgs e)
{
SetWindowPos(this.Handle, HWND_TOPMOST, 100, 100, 300, 300, TOPMOST_FLAGS);
}
protected override void WndProc(ref Message m)
{
const int RESIZE_HANDLE_SIZE = 10;
switch (m.Msg)
{
case 0x0084/*NCHITTEST*/ :
base.WndProc(ref m);
if ((int)m.Result == 0x01/*HTCLIENT*/)
{
Point screenPoint = new Point(m.LParam.ToInt32());
Point clientPoint = this.PointToClient(screenPoint);
if (clientPoint.Y <= RESIZE_HANDLE_SIZE)
{
if (clientPoint.X <= RESIZE_HANDLE_SIZE)
m.Result = (IntPtr)13/*HTTOPLEFT*/ ;
else if (clientPoint.X < (Size.Width - RESIZE_HANDLE_SIZE))
m.Result = (IntPtr)12/*HTTOP*/ ;
else
m.Result = (IntPtr)14/*HTTOPRIGHT*/ ;
}
else if (clientPoint.Y <= (Size.Height - RESIZE_HANDLE_SIZE))
{
if (clientPoint.X <= RESIZE_HANDLE_SIZE)
m.Result = (IntPtr)10/*HTLEFT*/ ;
else if (clientPoint.X < (Size.Width - RESIZE_HANDLE_SIZE))
m.Result = (IntPtr)2/*HTCAPTION*/ ;
else
m.Result = (IntPtr)11/*HTRIGHT*/ ;
}
else
{
if (clientPoint.X <= RESIZE_HANDLE_SIZE)
m.Result = (IntPtr)16/*HTBOTTOMLEFT*/ ;
else if (clientPoint.X < (Size.Width - RESIZE_HANDLE_SIZE))
m.Result = (IntPtr)15/*HTBOTTOM*/ ;
else
m.Result = (IntPtr)17/*HTBOTTOMRIGHT*/ ;
}
}
return;
}
base.WndProc(ref m);
}
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.Style |= 0x20000; // <--- use 0x20000
return cp;
}
}
}
}
What is the other application you are trying to suppress the visibility of? Have you investigated other ways of achieving your desired effect? Please do so before subjecting your users to such rogue behaviour as you are describing: what you are trying to do sound rather like what certain naughty sites do with browser windows...
At least try to adhere to the rule of Least Surprise. Users expect to be able to determine the z-order of most applications themselves. You don't know what is most important to them, so if you change anything, you should focus on pushing the other application behind everything rather than promoting your own.
This is of course trickier, since Windows doesn't have a particularly sophisticated window manager. Two approaches suggest themselves:
enumerating top-level windows
and checking which process they
belong to, dropping their
z-order if so. (I'm not sure if
there are framework methods for
these WinAPI functions.)
Fiddling with child process permissions to prevent it from accessing the desktop... but I wouldn't try this until the othe approach failed, as the child process might end up in a zombie state while requiring user interaction.
Here is the SetForegroundWindow equivalent:
form.Activate();
I have seen people doing weird things like:
this.TopMost = true;
this.Focus();
this.BringToFront();
this.TopMost = false;
http://blog.jorgearimany.com/2010/10/win32-setforegroundwindow-equivalent-in.html
I know this is old, but I did not see this response.
In the window (xaml) add:
Deactivated="Window_Deactivated"
In the code behind for Window_Deactivated:
private void Window_Deactivated(object sender, EventArgs e)
{
Window window = (Window)sender;
window.Activate();
}
This will keep your window on top.
Based on clamum's answer, and Kevin Vuilleumier's comment about the other flag responsible for the behavior, I made this toggle that switches between on-top and not on-top with a button press.
private void button1_Click(object sender, EventArgs e)
{
if (on)
{
button1.Text = "yes on top";
IntPtr HwndTopmost = new IntPtr(-1);
SetWindowPos(this.Handle, HwndTopmost, 0, 0, 0, 0, TopmostFlags);
on = false;
}
else
{
button1.Text = "not on top";
IntPtr HwndTopmost = new IntPtr(-2);
SetWindowPos(this.Handle, HwndTopmost, 0, 0, 0, 0, TopmostFlags);
on = true;
}
}
I did something i little bit differnt kinda found it much easier
so first on Form Load
private void Form1_Load(object sender, EventArgs e)
{
this.Shown += new EventHandler(Form1_Shown);//let your form show up here
}
private void Form1_Shown(Object sender, EventArgs e)
{
Form1.ActiveForm.TopMost = true //and then do your TopMost logic
}

Categories