I am using this code (on windows 2003) to remove and resize window:
Process process = Process.GetProcessById(12121);
IntPtr mwh = process.MainWindowHandle;
SetWindowLong(mwh, GWL_STYLE, WS_VISIBLE);
ShowWindowAsync(mwh, 3);
SetWindowPos(mwh, new IntPtr(0), 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED);
And declarations:
[DllImport("user32.dll")]
private static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);
[DllImport("USER32.DLL")]
public static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)]
public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, int uFlags);
static readonly int GWL_STYLE = -16;
static readonly int SWP_NOMOVE = 0x2;
static readonly int SWP_NOSIZE = 0x1;
static readonly int SWP_FRAMECHANGED = 0x20;
static readonly int WS_VISIBLE = 0x10000000;
Everything works correct, when I am resizing window associated with process started by me. But when I want to do this with other users windows, then it does nothing.
How to make it works for other users windows?
The behavior is by design in Windows Vista and later, due to the User Interface Privilege Isolation (UIPI). You could solve it if you have access to the source code of the controlled applications.
Read this answer for more: https://stackoverflow.com/a/15445510.
process.MainWindowHandle is a .NET concept, there is no such thing as a main window in native desktop apps and therefore might not always work correctly on other processes. You should check if mwh is IntPtr.Zero, if it is then you need to use EnumWindows + GetWindowThreadProcessId + IsWindowVisible to find the applications window.
Calling SetWindowLong(mwh, GWL_STYLE, WS_VISIBLE); on a window you did not create is not OK. You need to call GetWindowLong first the get the existing style, remove all the styles you don't want and add WS_POPUP. You might want to remove some of the extended styles as well.
Related
I want to be able to have my application to always be on top. so when I open a new program and that becomes on top even though I have this.TopLevel value set to true, the application will see it is not on top no more and then go back on top.
I know I can do this with a timer, but I am hoping their is a better way.
You can use a method located in user32.dll.
using System.Runtime.InteropServices;
You are going to need these variables:
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;
Import the method from the DLL...
[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, use this to set the window position to the topmost window.
SetWindowPos(this.Handle, HWND_TOPMOST, 0, 0, 0, 0, TOPMOST_FLAGS);
I hope this helps you!
I suggest you catch the event for new windows and see if you are on top after the new window opens:
https://stackoverflow.com/a/40698254/2557128
I recently implemented the solutions from this question to hide a WPF Window's icon. I found that when that solution is used in conjunction with ResizeMode=NoResize, the app's title bar context menu fails to disable Min/Max/Resize options.
The odd thing is the context menu doesn't incorrectly enable certain options, it just leaves the state of the context menu from before the icon was hidden. I found this using a simple test app that can make the necessary calls to hide the icon, and can update the Window's ResizeMode on the fly.
Icon Shown, ResizeMode=CanResize
Title bar buttons and context menu are correct.
Icon Hidden, ResizeMode=CanResize
Still correct
Icon Hidden, ResizeMode=NoResize
Title bar buttons are correctly hidden, but the context menu retains it's previous state. If I switch to CanMinimize then to NoResize, the context menu would only have "Minimize" enabled.
This becomes a problem when a resize-able WPF Window launches another Window which is set to NoResize (and you are hiding the icon).
Question
Are there additional Windows API functions that can force the Context Menu to reevaluate its state? What about the NoResize option might be causing this weird behavior? As this only affects the NoResize option, could there be a workaround at the WPF level?
EDIT - My goal is to avoid using WindowStyle=ToolWindow or the WS_EX_TOOLWINDOW extended window style. I've found a few problems with that window style in the past, one is desribed on this question. One of my goals with this whole approach was to emulate the look of ToolWindow without actually having to use it.
Using .NET 4.0 and Windows 8.1 Enterprise (I do not know if it works with other .NET versions or a different OS), you just need to use the WS_EX_TOOLWINDOW extended style instead of the WS_EX_DLGMODALFRAME one.
So the code will be:
public partial class MainWindow : Window
{
[DllImport("user32.dll")]
static extern int GetWindowLong(IntPtr hwnd, int index);
[DllImport("user32.dll")]
static extern int SetWindowLong(IntPtr hwnd, int index, int newStyle);
[DllImport("user32.dll")]
static extern bool SetWindowPos(IntPtr hwnd, IntPtr hwndInsertAfter, int x, int y, int width, int height, uint flags);
[DllImport("user32.dll")]
static extern IntPtr SendMessage(IntPtr hwnd, uint msg, IntPtr wParam, IntPtr lParam);
private const int GWL_EXSTYLE = -20;
private const int WS_EX_DLGMODALFRAME = 0x0001;
private const int SWP_NOSIZE = 0x0001;
private const int SWP_NOMOVE = 0x0002;
private const int SWP_NOZORDER = 0x0004;
private const int SWP_FRAMECHANGED = 0x0020;
private const int WM_SETICON = 0x0080;
private const int WS_EX_TOOLWINDOW = 0x00000080;
public MainWindow()
{
InitializeComponent();
ResizeMode = System.Windows.ResizeMode.NoResize;
}
protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
IntPtr hwnd = new WindowInteropHelper(this).Handle;
int extendedStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
SetWindowLong(hwnd, GWL_EXSTYLE, extendedStyle | WS_EX_TOOLWINDOW);
SendMessage(hwnd, WM_SETICON, new IntPtr(1), IntPtr.Zero);
SendMessage(hwnd, WM_SETICON, IntPtr.Zero, IntPtr.Zero);
SetWindowPos(hwnd, IntPtr.Zero, 0, 0, 0, 0, SWP_NOMOVE |
SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
}
}
Let's hope it can help you.
Believe me, I have Googled it and expected it to be a fairly easy find - turns out it isn't.
I have my window handle, but no form. How do I do it?
Thanks!
Declare these:
[DllImport("user32.dll", SetLastError = true)]
static extern int GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("user32.dll")]
static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
private const int GWL_EX_STYLE = -20;
private const int WS_EX_APPWINDOW = 0x00040000, WS_EX_TOOLWINDOW = 0x00000080;
And then use this before the form is shown:
SetWindowLong(handle, GWL_EX_STYLE, (GetWindowLong(handle, GWL_EX_STYLE) | WS_EX_TOOLWINDOW) & ~WS_EX_APPWINDOW);
(change handle to whatever your window handle is stored in)
Set Form's ShowInTaskbar property to false.
I'm trying to launch another application from C# application, is there a way to display this application inside the mainform of my application?
Thanks,
You can start other applications using Process.Start(...):
Process.Start(#"C:\Path\OtherApp.exe");
To embed the application within your form, check out this CodeProject article that demos a technique for hosting other application's windows within your form.
You can try do this via reparenting. See my post on MSDN where I describe this for WPF: Composite "shell" application.
The technique itself would be the same for WinForms. Have a host area in your app. Change the top-level window's style of the target application to WS_CHILD. Call SetParent(), changing the parent of the target window to your host area.
Note that in Win32, only a top-level window has a menu. Thus, changing to WS_CHILD removes the menu.
You can do it in that way :
[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", SetLastError = true)]
private static extern bool MoveWindow(IntPtr hwnd, int x, int y, int cx, int cy, bool repaint);
[DllImport("user32.dll", SetLastError = true)]
static extern void SwitchToThisWindow(IntPtr hWnd, bool fAltTab);
[DllImport("user32.dll")]
static extern IntPtr SetActiveWindow(IntPtr hWnd);
private const int GWL_STYLE = (-16);
private const int WS_VISIBLE = 0x10000000;
private const int WS_MAXIMIZE = 0x01000000;
private void Form1_Load(object sender, EventArgs e)
{
this.SuspendLayout();
Process notepad = new Process();
ProcessStartInfo psi = new ProcessStartInfo("notepad.exe");
psi.WindowStyle = ProcessWindowStyle.Normal;
notepad.StartInfo = psi;
notepad.Start();
this.ResumeLayout();
notepad.WaitForInputIdle(3000);
IntPtr old = SetParent(notepad.MainWindowHandle, this.Handle);
SetWindowLong(notepad.MainWindowHandle, GWL_STYLE, WS_VISIBLE + WS_MAXIMIZE);
MoveWindow(notepad.MainWindowHandle, 100, 100, 400, 400, true);
SetActiveWindow(notepad.MainWindowHandle);
SwitchToThisWindow(notepad.MainWindowHandle, true); }
In this way you have Notepad app in your form ;)
In general, it's next to impossible to display any kind of 3rd party application inside of yours.
If target app supports console interface, I would create my own interface for this app that will translate GUI commands to console commands of target app.
Is there a managed way to set the always on top flag/setting on a window that is external to my application or will I need to P/Invoke a native function?
And if P/Invoke is the only way what is the function call required and from which dll?
Since asking the question I have been researching this and came across what looks like a good example of how to achieve this via p/invoking SetWindowPos in 'user32.dll'. I will come back and accept this answer if this works.
[DllImport("user32.dll")]
static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
static readonly IntPtr HWND_TOPMOST = new IntPtr(-1);
const UInt32 SWP_NOSIZE = 0x0001;
const UInt32 SWP_NOMOVE = 0x0002;
const UInt32 TOPMOST_FLAGS = SWP_NOMOVE | SWP_NOSIZE;
public static void MakeTopMost (IntPtr hWnd)
{
SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, TOPMOST_FLAGS);
}
Simple answer:
TopMost = true;