Close form not showing in application openforms - c#

I use the below code to pop-up a form on the screen on top of everything but it doesn't steal focus.
This works fine, but I now need to close the form, the form itself doesnt show up in Application.OpenForms
How do I go about doing this?
Setup and open the form
frmClientCall frm = new frmClientCall {StartPosition = FormStartPosition.Manual, Text = "Phone Call"};
frm.Location = new System.Drawing.Point(
Screen.PrimaryScreen.WorkingArea.Width - frm.Width,
Screen.PrimaryScreen.WorkingArea.Height - frm.Height - 202
);
frm.lblClient.Text = URI;
frm.ShowInactiveTopmost();
Code to prevent focus on the form
private const int SW_SHOWNOACTIVATE = 4;
private const int HWND_TOPMOST = -1;
private const uint SWP_NOACTIVATE = 0x0010;
[DllImport("user32.dll", EntryPoint = "SetWindowPos")]
static extern bool SetWindowPos(
int hWnd, // Window handle
int hWndInsertAfter, // Placement-order handle
int X, // Horizontal position
int Y, // Vertical position
int cx, // Width
int cy, // Height
uint uFlags); // Window positioning flags
[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
public void ShowInactiveTopmost()
{
ShowWindow(Handle, SW_SHOWNOACTIVATE);
SetWindowPos(Handle.ToInt32(), HWND_TOPMOST, Left, Top, Width, Height, SWP_NOACTIVATE);
}

Yes, this is not the only mishap. You for example can also see that the form's Load event never fires. Basic issue is that you are bypassing the normal logic, which is a pretty big deal in Winforms since it creates the native window lazily. In your case it happens when you use the Handle property. I think the underlying issue is that the Visible property was never set to true, that's the one that truly gets the ball rolling.
Well, don't do it this way, Winforms already supports showing a window without activating it. Paste this code into the form you want to display without activation:
protected override bool ShowWithoutActivation {
get { return true; }
}
The SetWindowPos() pinvoke to make it topmost is not necessary either, paste this code:
protected override CreateParams CreateParams {
get {
var cp = base.CreateParams;
cp.ExStyle |= 8; // Turn on WS_EX_TOPMOST
return cp;
}
}

Related

C# Unable to remove scroll bars on external RDP process using SetWindowLong

I am trying to remove the scroll bars from an RDP window that my C# code launches. My code launches mstsc.exe passing the appropriate path the the rdp file. But once it's open, my code needs to remove the horizontal and vertical scroll bars. My style that I am using below seems to work for removing the thick frame, removing the min and max buttons, but the WS_HSCROLL and WS_VSCROLL seems to be ignored.
Process m_proc = new Process { StartInfo = { FileName = "mstsc.exe", Arguments = rdpFullPath } };
m_proc.Start();
//Wait until process is started and main rdp window is created.
while (m_proc.MainWindowHandle == IntPtr.Zero)
{
Thread.Sleep(2000);
}
// Remove thick frame to disallow resizing of the RDP window, and remove minimize and maximize buttons.
var currentStyle = UnsafeNativeMethods.GetWindowLong(m_proc.MainWindowHandle, UnsafeNativeMethods.GWL_STYLE);
currentStyle &= ~UnsafeNativeMethods.WS_THICKFRAME;
currentStyle &= ~UnsafeNativeMethods.WS_MINIMIZEBOX;
currentStyle &= ~UnsafeNativeMethods.WS_MAXIMIZEBOX;
currentStyle &= ~UnsafeNativeMethods.WS_HSCROLL;
currentStyle &= ~UnsafeNativeMethods.WS_VSCROLL;
UnsafeNativeMethods.SetWindowLong(m_proc.MainWindowHandle, UnsafeNativeMethods.GWL_STYLE, currentStyle);
UnsafeNativeMethods.SetWindowPos(m_proc.MainWindowHandle,
UnsafeNativeMethods.HWND_TOPMOST, 0, 0, 0, 0,
UnsafeNativeMethods.SWP_NOMOVE | UnsafeNativeMethods.SWP_NOSIZE);
I have the following definitions:
public const int WS_HSCROLL = 0x00100000;
public const int WS_VSCROLL = 0x00200000;
[DllImport("user32.dll")]
public static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);

Menu out of place when application is in full screen by Windows API

I have developed an application in C# and I want to show it in full screen mode. It should also cover up the taskbar. To accomplish this I have used the Windows API. You can find the class below:
public sealed class WinAPI
{
[DllImport("user32.dll", EntryPoint = "GetSystemMetrics")]
public static extern int GetSystemMetrics(int which);
[DllImport("user32.dll")]
public static extern void
SetWindowPos(IntPtr hwnd, IntPtr hwndInsertAfter,
int X, int Y, int width, int height, uint flags);
private const int SM_CXSCREEN = 0;
private const int SM_CYSCREEN = 1;
private static IntPtr HWND_TOP = IntPtr.Zero;
private const int SWP_SHOWWINDOW = 64; // 0×0040
public static int ScreenX
{
get { return GetSystemMetrics(SM_CXSCREEN); }
}
public static int ScreenY
{
get { return GetSystemMetrics(SM_CYSCREEN); }
}
public static void SetWinFullScreen(IntPtr hwnd)
{
SetWindowPos(hwnd, HWND_TOP, 0, 0, ScreenX, ScreenY, SWP_SHOWWINDOW);
}
}
I am using this class in conjunction with the following form settings to go in full screen mode:
private void terminalModeToolStripMenuItem_Click(object sender, EventArgs e)
{
// Remove the border.
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
this.WindowState = FormWindowState.Maximized;
this.Bounds = Screen.PrimaryScreen.Bounds;
// Full screen windows API hack.
WinAPI.SetWinFullScreen(this.Handle);
}
Now comes the funny part. If I click a button in my menu bar it will show up with a gap between the button and the menu as you can see in the image below:
Does anyone knows how to fix this issue? I would like it to show up like this:
And why does this happen anyway?
As Muraad pointed you to in his comment, try moving the following block of code into your Form load event:
// Remove the border.
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
this.WindowState = FormWindowState.Maximized;
this.Bounds = Screen.PrimaryScreen.Bounds;
And see if the issue still persists.
This problem is caused by having the task bar set to the top of the screen.
It can be resolved by either moving the task bar to the bottom of the screen, or by enabling the Auto-hide task bar check box in the Properties window of the task bar.
EDIT: As stated by #slashp 's comments. The root cause of this issue comes from some inner mechanics in drawing the menu. The menu has a safety to be always drawn within the working area. Which seems to be your screen - task bar. Because the application is placed over the task bar, the calculation is placing the menu below the task bar. (you can't see it, but it's still there)

How do I put a full screen window on top in C# after screen is cloned?

I am working on a C# WPF application that uses two screens. In the application the user is able to clone or extend the screen depending on what the user want to do. This is done in windows 7 and is using the following code:
[DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Unicode)]
private static extern long SetDisplayConfig(uint numPathArrayElements, IntPtr pathArray, uint numModeArrayElements, IntPtr modeArray, uint flags);
UInt32 SDC_TOPOLOGY_INTERNAL = 0x00000001;
UInt32 SDC_TOPOLOGY_CLONE = 0x00000002;
UInt32 SDC_TOPOLOGY_EXTEND = 0x00000004;
UInt32 SDC_TOPOLOGY_EXTERNAL = 0x00000008;
UInt32 SDC_APPLY = 0x00000080;
public void CloneDisplays()
{
SetDisplayConfig(0, IntPtr.Zero, 0, IntPtr.Zero, (SDC_APPLY | SDC_TOPOLOGY_CLONE));
}
public void ExtendDisplays()
{
SetDisplayConfig(0, IntPtr.Zero, 0, IntPtr.Zero, (SDC_APPLY | SDC_TOPOLOGY_EXTEND));
}
Now to my problem. When using the above code I manage to clone/extend the screen. However, after this is done the taskbar at the bottom of the screen is in front of the full screen application which should not be the case. How do i put the application window back at the top?
Additional information:
When I start the application it starts in fullscreen with the taskbar behind the application. This is done by setting the following:
WindowState="Maximized"
WindowStyle="None"
And this is what I want after the clone/extend has been done.
Thanks
Edit:
I have noticed that after I clone/extend the screen and sleep for say 5 seconds everything works as it should. However, as soon as the 5 seconds is over and the function exits the taskbar gets on top. Therefore it seems that I can not change something right after the clone/extend because the taskbar will always get on top in the end. So somehow I have to figure out how to stop the taskbar to behave like this, instead of changing the property of the window.
Try setting the width and height of the WPF window as follows, You could set this within window constructor.
Width = System.Windows.SystemParameters.PrimaryScreenWidth;
Height = System.Windows.SystemParameters.PrimaryScreenWidth;
To hide the taskbar try setting,
Width = System.Windows.SystemParameters.FullPrimaryScreenWidth;
Height = System.Windows.SystemParameters.FullPrimaryScreenHeight;
I'm already doing full-screen mode within my winforms applications, but i think you can do it more or less the same within WPF:
(this has to be different but similar in WPF):
form.WindowState = FormWindowState.Normal;
form.FormBorderStyle = FormBorderStyle.None;
form.Bounds = Screen.GetBounds(form);
Then the next step is to hide the task-bar if your application is on the primary screen:
if (Screen.PrimaryScreen.Equals(Screen.FromRectangle(Screen.GetBounds(form))))
{
ShowWindowsToolbar(false);
}
And the method ShowWindowsToolbar() is implemented as follows:
[DllImport("user32.dll")]
private static extern int FindWindow(string lpszClassName, string lpszWindowName);
[DllImport("user32.dll")]
private static extern int ShowWindow(int hWnd, int nCmdShow);
private const int SW_HIDE = 0;
private const int SW_SHOW = 1;
public void WindowsToolbar(bool visible)
{
int hWnd = FindWindow("Shell_TrayWnd", "");
ShowWindow(hWnd, visible ? SW_SHOW : SW_HIDE);
}
That's the way, how most of the tools out there support this kind of stuff. Also note, that this mode can mostly entered/leaved by pressing F11. So it would be good, if you also support this keystroke.
Turns out all I have to do is update the dispatcher queue and force it to do the update right after the clone/extend has been done. Then I can update the window properties.
public void ExtendDisplays()
{
SetDisplayConfig(0, IntPtr.Zero, 0, IntPtr.Zero, (SDC_APPLY | SDC_TOPOLOGY_EXTEND));
this.Dispatcher.Invoke(DispatcherPriority.Background, new ThreadStart(delegate { })); //Force update
current_window.hide();
current_window.show();
}

Pinvoke MoveWindow in C#

I am try to get form2 positioned relative to form1. I've tried many things an nothing seems to work right. I wanted to try:
http://www.pinvoke.net/default.aspx/user32/MoveWindow.html
As a newbie to windows programming especially C# I'm looking at the syntax/example and I find it difficult to know what to put in for the parameters. I did get a different simpler p/invoke to work:
using System.Runtime.InteropServices;
...
public partial class Form1 : Form
{
public Form1()
{ InitializeComponent(); }
[DllImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool CreateDirectory(string lpPathName,
IntPtr lpSecurityAttributes);
private void Form1_Load(object sender, EventArgs e) { }
private void button1_Click(object sender, EventArgs e)
{ CreateDirectory(#"c:\test4", IntPtr.Zero); }
}
...
I'm taking a guess IntPtr is "saying" I'm pointing at the first node - but only a guess...
The C# signature for MoveWindow:
[DllImport("user32.dll", SetLastError = true)]
internal static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
there's comments on this as well on the site. "IntPtr hWnd" - I need to get that associated with Form2 (?) , do I repaint? I'm trying to show I've looked at it and tried to figure it out - I know we are getting it from the system's dll's...the x-y I got but getting it "with" Form2 I'm lost. Help appreciated.
In general you wouldn't need PInvoke for something as simple as this.
As long as you have a reference to form2 from form1 then you can easily do this by listening to the LocationChanged event of form1. When form1 moves then you can move form2 by doing the following:
var location = this.Location;
location.Offset(xoffset, yoffset);
form2.Location = location;
That would normally be enough to make sure form2 is placed somewhere relatively to form1 and that its position is updated when form1 is moved. You may have to set an initial position of form2 if the LocationChanged event is not called when the form is first created.
Something like this should work. Tested too. You can alter this to fit exactly what you wanted to do, which shouldn't be an issue at all.
// Win32 RECT
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
// GetWindowRect gets the win32 RECT by a window handle.
[DllImport("user32.dll", SetLastError=true)]
static extern bool GetWindowRect(IntPtr hwnd, out RECT lpRect);
// MoveWindow moves a window or changes its size based on a window handle.
[DllImport("user32.dll", SetLastError = true)]
static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
// MoveForms moves one form to another using the win api.
void MoveForms(Form fromForm, Form toForm)
{
IntPtr hWnd_from = fromForm.Handle; // fromForm window handle
IntPtr hWnd_to = toForm.Handle; // toForm window handle
RECT rect_from, rect_to; // RECT holders for fromForm and toForm
if (GetWindowRect(hWnd_from, out rect_from) &&
GetWindowRect(hWnd_to, out rect_to)) // if it gets the win32 RECT for both the fromForm and toForm do the following ...
{
int x_to = rect_to.Left; // toForm's X position
int y_to = rect_to.Top; // toForm's Y position
int width_from = rect_from.Right - rect_from.Left; // fromForm's width
int height_from = rect_from.Bottom - rect_from.Top; // fromForm's height
// Moves fromForm to toForm using the x_to, y_to for X/Y and width_from, height_from for W/H.
MoveWindow(hWnd_from, x_to, y_to, width_from, height_from, true);
}
}

Handling AeroSnap message in WndProc

In my C# .NET 4 application, I use WndProc to process some messages mostly dealing with resizing the application to and from full screen.
Right now I am just handling SC_MAXIMIZE and WM_NCLBUTTONDBLCLK to determine if the window is being resized to or from a maximized state (I know I don't need WndProc to handle SC_MAXIMIZE, but Form_Resize didn't seem to fire for a WM_NCLBUTTONDBLCLK message when I double-click on the application's title bar.
Now I noticed that if I Aero Snap the window to the top of the screen to maximize it, neither of the above messages are posted so certain logic is not applied when the window is maximized via Aero Snap. I only want to handle the message if the window is snapped to the top of the screen rather than the right or left, or if a window is unsnappped from maximized position.
I couldn't find any of the window messages related to Aero Snap. Does anyone know of any references for those messages?
I'm guessing there aren't any special messages here; Aero is likely just using the plain Win32 APIs - ShowWindow(SW_MAXIMIZE) and similar.
The thing to uderstand with the SC_ messages are that those are requests from a menu asking the window to resize/restore/etc itself, but that is not the only mechanism for changing the windows's size. What's probably happening is that when a window gets SC_MAXIMIZE, the DefWndProc implements this by calling ShowWindow(SW_MAXIMIZE).
Your best best is to listen to the WM_SIZE message, which the window receives, regardless of what triggered the size change: system menu, API, or other means. In particular, the lParam will let you know if the window was maximized (SIZE_MAXIMIZED) or restored (SIZE_RESTORED).
Here is the code for handling WM_WINDOWPOSCHANGING message for Maximise instead of WM_SIZE message. Thanks to the 20 or more questions on SO that I had to read to find all the bits to put it together and get it working. This addresses the problems that I was having with multiple monitors using different resolutions.
//register the hook
public static void WindowInitialized(Window window)
{
IntPtr handle = (new WindowInteropHelper(window)).Handle;
var hwndSource = HwndSource.FromHwnd(handle);
if (hwndSource != null)
{
hwndSource.AddHook(WindowProc);
}
}
//the important bit
private static IntPtr WindowProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
switch (msg)
{
case 0x0046: //WINDOWPOSCHANGING
var winPos = (WINDOWPOS)Marshal.PtrToStructure(lParam, typeof(WINDOWPOS));
var monitorInfo = new MONITORINFO();
IntPtr monitorContainingApplication = MonitorFromWindow(hwnd, MonitorDefaultToNearest);
GetMonitorInfo(monitorContainingApplication, monitorInfo);
RECT rcWorkArea = monitorInfo.rcWork;
//check for a framechange - but ignore initial draw. x,y is top left of current monitor so must be a maximise
if (((winPos.flags & SWP_FRAMECHANGED) == SWP_FRAMECHANGED) && (winPos.flags & SWP_NOSIZE) != SWP_NOSIZE && winPos.x == rcWorkArea.left && winPos.y == rcWorkArea.top)
{
//set max size to the size of the *current* monitor
var width = Math.Abs(rcWorkArea.right - rcWorkArea.left);
var height = Math.Abs(rcWorkArea.bottom - rcWorkArea.top);
winPos.cx = width;
winPos.cy = height;
Marshal.StructureToPtr(winPos, lParam, true);
handled = true;
}
break;
}
return (IntPtr)0;
}
//all the helpers for dealing with this COM crap
[DllImport("user32")]
internal static extern bool GetMonitorInfo(IntPtr hMonitor, MONITORINFO lpmi);
[DllImport("user32")]
internal static extern IntPtr MonitorFromWindow(IntPtr handle, int flags);
private const int MonitorDefaultToNearest = 0x00000002;
[StructLayout(LayoutKind.Sequential)]
public struct WINDOWPOS
{
public IntPtr hwnd;
public IntPtr hwndInsertAfter;
public int x;
public int y;
public int cx;
public int cy;
public int flags;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public class MONITORINFO
{
public int cbSize = Marshal.SizeOf(typeof(MONITORINFO));
public RECT rcMonitor;
public RECT rcWork;
public int dwFlags;
}
[StructLayout(LayoutKind.Sequential, Pack = 0)]
public struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
}

Categories

Resources