I am trying to find out if the windows 10 virtual touch keyboard is visible or not to know whether to open it or not from my application. THe following code has worked fine up until the latest Windows 10 update 15063 or possible the one right before it. Seems like Microsoft changed something with the window styles possibly but I can't figure it out.
public static bool IsKeyboardVisible()
{
IntPtr keyboardHandle = GetKeyboardWindowHandle();
// Specifies we wish to retrieve window styles.
int GWL_STYLE = -16;
//The window is disabled. See http://msdn.microsoft.com/en-gb/library/windows/desktop/ms632600(v=vs.85).aspx.
UInt32 WS_VISIBLE = 0x10000000;
UInt32 WS_DISABLED = 0x08000000;
UInt32 WS_POPUP = 0x80000000;
bool visible = false;
bool disabled = false;
if (keyboardHandle != IntPtr.Zero)
{
UInt32 style = GetWindowLong(keyboardHandle, GWL_STYLE);
visible = ((style & WS_VISIBLE) == WS_VISIBLE);
disabled = ((style & WS_DISABLED) == WS_DISABLED); // ref https://stackoverflow.com/questions/11065026/get-window-state-of-another-process
log.InfoFormat("style:{0:X4} visible:{1} disabled:{2}", style, visible, disabled);
}
return visible && !disabled ;
}
This is related to: Show touch keyboard (TabTip.exe) in Windows 10 Anniversary edition
I've done some research with Spy++ . Looks like the new keyboard in Fall Creators Update (ver. 1709) is hosted by another window. This window has Windows.UI.Core.CoreWindow class and Microsoft Text Input Application as its title.
The following code works for all Windows 10 versions including the new 1803 and older Windows versions as well (starting with Windows 8, I believe).
static class TouchKeyboard
{
public static bool GetIsOpen()
{
return GetIsOpen1709() ?? GetIsOpenLegacy();
}
private static bool? GetIsOpen1709()
{
var parent = IntPtr.Zero;
for (;;)
{
parent = FindWindowEx(IntPtr.Zero, parent, WindowParentClass1709);
if (parent == IntPtr.Zero)
return null; // no more windows, keyboard state is unknown
// if it's a child of a WindowParentClass1709 window - the keyboard is open
var wnd = FindWindowEx(parent, IntPtr.Zero, WindowClass1709, WindowCaption1709);
if (wnd != IntPtr.Zero)
return true;
}
}
private static bool GetIsOpenLegacy()
{
var wnd = FindWindowEx(IntPtr.Zero, IntPtr.Zero, WindowClass);
if (wnd == IntPtr.Zero)
return false;
var style = GetWindowStyle(wnd);
return style.HasFlag(WindowStyle.Visible)
&& !style.HasFlag(WindowStyle.Disabled);
}
private const string WindowClass = "IPTip_Main_Window";
private const string WindowParentClass1709 = "ApplicationFrameWindow";
private const string WindowClass1709 = "Windows.UI.Core.CoreWindow";
private const string WindowCaption1709 = "Microsoft Text Input Application";
private enum WindowStyle : uint
{
Disabled = 0x08000000,
Visible = 0x10000000,
}
private static WindowStyle GetWindowStyle(IntPtr wnd)
{
return (WindowStyle)GetWindowLong(wnd, -16);
}
[DllImport("user32.dll", SetLastError = false)]
private static extern IntPtr FindWindowEx(IntPtr parent, IntPtr after, string className, string title = null);
[DllImport("user32.dll", SetLastError = false)]
private static extern uint GetWindowLong(IntPtr wnd, int index);
}
Update: I updated the answer and the code to be compatible with Redstone 4 (v1803) as well.
I'm using this solution, and it is working on Windows 1607, 1709 and 1803 (check the Main method below on the code):
using System;
using System.Drawing;
using System.Runtime.InteropServices;
namespace ConsoleApp1
{
class Program
{
[ComImport, Guid("D5120AA3-46BA-44C5-822D-CA8092C1FC72")]
public class FrameworkInputPane
{
}
[ComImport, System.Security.SuppressUnmanagedCodeSecurity,
InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
Guid("5752238B-24F0-495A-82F1-2FD593056796")]
public interface IFrameworkInputPane
{
[PreserveSig]
int Advise(
[MarshalAs(UnmanagedType.IUnknown)] object pWindow,
[MarshalAs(UnmanagedType.IUnknown)] object pHandler,
out int pdwCookie
);
[PreserveSig]
int AdviseWithHWND(
IntPtr hwnd,
[MarshalAs(UnmanagedType.IUnknown)] object pHandler,
out int pdwCookie
);
[PreserveSig]
int Unadvise(
int pdwCookie
);
[PreserveSig]
int Location(
out Rectangle prcInputPaneScreenLocation
);
}
static void Main(string[] args)
{
var inputPane = (IFrameworkInputPane)new FrameworkInputPane();
inputPane.Location(out var rect);
Console.WriteLine((rect.Width == 0 && rect.Height == 0) ? "Keyboard not visible" : "Keyboard visible");
}
}
}
It uses the IFrameworkInputPane interface (https://learn.microsoft.com/en-us/windows/desktop/api/shobjidl_core/nn-shobjidl_core-iframeworkinputpane)
I discovered yet another undocumented COM API that returns the position of the touch keyboard. It returns the bounds of the keyboard window or zeroes if the keyboard is hidden. I tested it in Windows 8.1, Windows 10 and Windows 10 Fall Creators Update and it works fine.
Now some bad news: in all versions prior to Fall Creators Update it only reports accurate results if the active window and the touch keyboard are located on the same monitor. If this is not the case - the API just returns the previous cached value. I'm guessing it has something to do with the fact that this API was meant to be used to calculate occlusion of the touch keyboard and your app's window. (It's called inside Windows::UI::ViewManagement::InputPane.get_OccludedRect() UWP API).
So if you don't care about supporting older versions or multi-monitor scenarios - use it. Otherwise I would suggest checking the Windows version and falling back to the previous method (GetIsOpenLegacy() from my other answer).
The API:
[ComImport, Guid("228826af-02e1-4226-a9e0-99a855e455a6")]
class ImmersiveShellBroker
{
}
[ComImport, Guid("9767060c-9476-42e2-8f7b-2f10fd13765c")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IImmersiveShellBroker
{
void Dummy();
IInputHostManagerBroker GetInputHostManagerBroker();
}
[ComImport, Guid("2166ee67-71df-4476-8394-0ced2ed05274")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IInputHostManagerBroker
{
void GetIhmLocation(out Rect rect, out DisplayMode mode);
}
[StructLayout(LayoutKind.Sequential)]
struct Rect
{
public int Left, Top, Right, Bottom;
}
enum DisplayMode
{
NotSupported = 0,
Floating = 2,
Docked = 3,
}
Usage example:
// do this once:
var brokerClass = new ImmersiveShellBroker();
var broker = (IImmersiveShellBroker)brokerClass;
var ihm = broker.GetInputHostManagerBroker();
Marshal.ReleaseComObject(broker);
// now ihm reference can be cached and used later:
Rect rect;
DisplayMode mode;
ihm.GetIhmLocation(out rect, out mode);
Note: looks like GetIhmLocation() always returns DisplayMode.NotSupported instead of the actual mode prior to Windows 10.
Related
How can I show/hide the desktop icons programmatically, using C#?
I'm trying to create an alternative desktop, which uses widgets, and I need to hide the old icons.
You can do this using the Windows API. Here is sample code in C# that will toggle desktop icons.
[DllImport("user32.dll", SetLastError = true)] static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", SetLastError = true)] static extern IntPtr GetWindow(IntPtr hWnd, GetWindow_Cmd uCmd);
enum GetWindow_Cmd : uint
{
GW_HWNDFIRST = 0,
GW_HWNDLAST = 1,
GW_HWNDNEXT = 2,
GW_HWNDPREV = 3,
GW_OWNER = 4,
GW_CHILD = 5,
GW_ENABLEDPOPUP = 6
}
[DllImport("user32.dll", CharSet = CharSet.Auto)] static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
private const int WM_COMMAND = 0x111;
static void ToggleDesktopIcons()
{
var toggleDesktopCommand = new IntPtr(0x7402);
IntPtr hWnd = GetWindow(FindWindow("Progman", "Program Manager"), GetWindow_Cmd.GW_CHILD);
SendMessage(hWnd, WM_COMMAND, toggleDesktopCommand, IntPtr.Zero);
}
This sends a message to the SHELLDLL_DefView child window of Progman, which tells it to toggle visibility (by adding or removing the WS_VISIBLE style) of it's only child, "FolderView". "FolderView" is the actual window that contains the icons.
To test to see if icons are visible or not, you can query for the WS_VISIBLE style by using the GetWindowInfo function, shown below:
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("user32.dll", SetLastError = true)]
private static extern bool GetWindowInfo(IntPtr hwnd, ref WINDOWINFO pwi);
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
private int _Left;
private int _Top;
private int _Right;
private int _Bottom;
}
[StructLayout(LayoutKind.Sequential)]
struct WINDOWINFO
{
public uint cbSize;
public RECT rcWindow;
public RECT rcClient;
public uint dwStyle;
public uint dwExStyle;
public uint dwWindowStatus;
public uint cxWindowBorders;
public uint cyWindowBorders;
public ushort atomWindowType;
public ushort wCreatorVersion;
public WINDOWINFO(Boolean? filler)
: this() // Allows automatic initialization of "cbSize" with "new WINDOWINFO(null/true/false)".
{
cbSize = (UInt32)(Marshal.SizeOf(typeof(WINDOWINFO)));
}
}
Here is a function that calls the above code and returns true if the window is visible, false if not.
static bool IsVisible()
{
IntPtr hWnd = GetWindow(GetWindow(FindWindow("Progman", "Program Manager"), GetWindow_Cmd.GW_CHILD), GetWindow_Cmd.GW_CHILD);
WINDOWINFO info = new WINDOWINFO();
info.cbSize = (uint)Marshal.SizeOf(info);
GetWindowInfo(hWnd, ref info);
return (info.dwStyle & 0x10000000) == 0x10000000;
}
The windows API code along with more information about the window styles can be found here: http://www.pinvoke.net/default.aspx/user32/GetWindowInfo.html
Even though this is quite old when I tried Ondrej Balas's answer, one problem I found with this solution is that it does not work if the ToggleDesktop command is used to show the desktop ( also if wallpaper rotation is enabled ).
In both of these cases the SHELLDLL_DefView window, which is the recipient of the toggleDesktopCommand in the ToggleDesktopIcons function, is not a child of the "Program manager" window but of a 'WorkerW" window. (see WinApi - How to obtain SHELLDLL_DefView and Windows Desktop ListView Handle.
Based on those and building upon Ondrej Balas's earlier answer change the ToggleDesktopIcons function to be :
static void ToggleDesktopIcons()
{
var toggleDesktopCommand = new IntPtr(0x7402);
SendMessage(GetDesktopSHELLDLL_DefView(), WM_COMMAND, toggleDesktopCommand, IntPtr.Zero);
}
And add a GetDesktopSHELLDLL_DefView function:
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, string windowTitle);
[DllImport("user32.dll", SetLastError = false)]
static extern IntPtr GetDesktopWindow();
static IntPtr GetDesktopSHELLDLL_DefView()
{
var hShellViewWin = IntPtr.Zero;
var hWorkerW = IntPtr.Zero;
var hProgman = FindWindow("Progman", "Program Manager");
var hDesktopWnd = GetDesktopWindow();
// If the main Program Manager window is found
if (hProgman != IntPtr.Zero)
{
// Get and load the main List view window containing the icons.
hShellViewWin = FindWindowEx(hProgman, IntPtr.Zero, "SHELLDLL_DefView", null);
if (hShellViewWin == IntPtr.Zero)
{
// When this fails (picture rotation is turned ON, toggledesktop shell cmd used ), then look for the WorkerW windows list to get the
// correct desktop list handle.
// As there can be multiple WorkerW windows, iterate through all to get the correct one
do
{
hWorkerW = FindWindowEx(hDesktopWnd, hWorkerW, "WorkerW", null);
hShellViewWin = FindWindowEx(hWorkerW, IntPtr.Zero, "SHELLDLL_DefView", null);
} while (hShellViewWin == IntPtr.Zero && hWorkerW != IntPtr.Zero);
}
}
return hShellViewWin;
}
Now regardless of the desktop toggle or wallpaper rotation the ToggleDesktopIcons should always work.
For reference this is my toggle desktop function which caused the issue with the original ToggleDesktopIcons function
static public void ToggleDesktop(object sender, EventArgs e)
{
var shellObject = new Shell32.Shell();
shellObject.ToggleDesktop();
}
In response to James M, this function returns the current state:
bool IconsVisible()
{
var hWnd = GetDesktopListView();
var info = new User32.WINDOWINFO(null);
User32.GetWindowInfo(hWnd, ref info);
return (info.dwStyle & User32.WindowStyle.WS_VISIBLE) == User32.WindowStyle.WS_VISIBLE;
}
A different approach is to create a separate desktop and show it instead. It will not have icons.
Application running itself on a separate desktop
You can do this in RegEdit
HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced
change HideIcons to 1
static void HideIcons()
{
RegistryKey myKey = Registry.CurrentUser.OpenSubKey(#"SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced", true);
if (myKey != null)
{
myKey.SetValue("HideIcons", 1);
myKey.Close();
}
}
Use the Registry class as described here.
http://msdn.microsoft.com/en-us/library/microsoft.win32.registry.aspx
You can create a full screen view application and make it the top most window.
Then make your application to be start up with windows.
You are going about this the wrong way. What you are really trying to do is to replace the shell. Windows provides for this so you should just take advantage of it. Write your own shell to replace explorer.
Nice topic. Without actually creating a different desktop it would be visually pleasant to have the running applications minimized in the same swoop.
With this code:
internal static List<DetectedWindow> EnumerateWindows()
{
var shellWindow = GetShellWindow();
var windows = new List<DetectedWindow>();
EnumWindows(delegate (IntPtr handle, int lParam)
{
if (handle == shellWindow)
return true;
if (!IsWindowVisible(handle))
return true;
if (IsIconic(handle))
return true;
var length = GetWindowTextLength(handle);
if (length == 0)
return true;
var builder = new StringBuilder(length);
GetWindowText(handle, builder, length + 1);
GetWindowRect(handle, out Rect rect);
windows.Add(new DetectedWindow(handle, rect.ToRect(), builder.ToString()));
return true;
}, IntPtr.Zero);
return windows;
}
Auxiliar class:
public class DetectedWindow
{
public IntPtr Handle { get; private set; }
public Rect Bounds { get; private set; }
public string Name { get; private set; }
public DetectedWindow(IntPtr handle, Rect bounds, string name)
{
Handle = handle;
Bounds = bounds;
Name = name;
}
}
I'm getting this list of applications (Window text - Rect bounds):
Microsoft Visual Studio - -8;-8;1936;1056
Microsoft Edge - 0;77;1920;963
EnumWindows - Stack Overflow and 7 more pages - Microsoft Edge - -8;-8;1936;1056
Microsoft Edge - 0;77;1920;963
Microsoft Edge - 0;77;1920;963
Microsoft Edge - 0;0;1920;1080
Microsoft Edge - 0;0;1920;1080
Microsoft Edge - 0;8;1920;1040
Microsoft Edge - 0;85;1920;963
Microsoft Edge - 150;79;1532;42
Microsoft Edge - 0;85;1920;963
Microsoft Edge - 0;77;1920;963
Microsoft Edge - 0;85;1920;963
Microsoft Edge - 0;213;1920;964
Microsoft Edge - 0;0;1920;1080
Microsoft Edge - 484;208;952;174
Microsoft Edge - 0;84;1920;964
Microsoft Edge - 0;84;1920;964
Microsoft Edge - 0;84;1920;964
Microsoft Edge - 0;0;1920;1080
Mail - 0;32;1356;693
Mail - 278;252;1372;733
OneNote - 0;8;1920;1040
My notes - OneNote - -8;-8;1936;1056
Photos - 0;32;1920;1008
Photos - -8;-8;1936;1056
Skype - 0;40;1920;1008
Skype - -8;-8;1936;1056
Store - 0;40;1920;1008
Store - -8;-8;1936;1056
Movies & TV - 0;0;1920;1080
Movies & TV - -8;-8;1936;1056
Groove Music - 0;32;1466;712
Groove Music - -7;3;1372;733
Settings - 0;40;1920;1008
Settings - -8;-8;1936;1056
Windows Shell Experience Host - 0;0;1920;1080
My current not minimized windows are Visual Studio and two Edge windows (with several tabs each). I can understand the fact that only one Edge item was listing the title of the current page. Because I recently recovered from a crash and only that page was loaded.
My questions are:
Why are my closed Windows Store apps being listed? (and even twice)
Why are my Edge tabs being listed?
How can I filter the Edge tabs and the closed Windows Store apps?
EDIT:
By "Filter": Only retrieve the apps with visible window. With my use case, only 3 windows are visible.
I tried to get the WsStyle and WsEXStyle of each window to compare, but I couldn't find any difference.
The method IsWindowVisible() fails filter out the Windows Store apps that are not visible.
Why are my closed Windows Store apps being listed?
Because they are not actually closed. Easy to see with Task Manager, Processes tab. You'll see that the process that owns these windows is suspended. Part of the WinRT (aka UWP, aka Store, aka Modern UI, aka Metro) programming framework approach, modern machines have enough RAM to make it feasible to keep processes running even if the user doesn't interact with them. Brings them back quickly again and saves battery life. If RAM is needed elsewhere then the OS will salvage it by killing such a process.
Why are my Edge tabs being listed?
Because Edge is a WinRT app as well.
How can I filter the Edge tabs and the closed Windows Store apps?
It is not entirely clear by which property you want to filter, given that the window is in fact not closed. GetWindowThreadProcessId() and IsImmersiveProcess() can tell you that you are dealing with such a process. Consider IsWindowVisible(). Maybe this post can help, also tells you why you see multiple windows.
Edit (Nicke Manarin):
By checking the Cloacked attribute, it is possible to ignore the hidden/background Store apps:
DwmGetWindowAttribute(handle, (int)DwmWindowAttribute.Cloaked, out bool isCloacked, Marshal.SizeOf(typeof(bool)));
if (isCloacked)
return true;
Edit 2 (Nicke Manarin):
Each Edge tab behaves like a window (I believe it has something to do with the fact that you can drag the tab to create a new window).
I can't reproduce the behavior in my W10 Desktop. After using your code, also filtering out the WsEXStyle WS_EX_TOOLWINDOW, shows the same apps than alt+tab does. I opened and closed Edge and Photos and they didn't appear when closed anymore. Maybe it was tinkering with P/Invoke that triggered that behavior. Does it continue with the code below after a restart?.
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
namespace ConsoleApp1
{
public class EnumerateWindowsTest
{
[StructLayout(LayoutKind.Sequential)]
public struct Rect
{
public int Left; // x position of upper-left corner
public int Top; // y position of upper-left corner
public int Right; // x position of lower-right corner
public int Bottom; // y position of lower-right corner
}
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool GetWindowRect(IntPtr hWnd, out Rect lpRect);
[DllImport("user32.dll")]
static extern IntPtr GetShellWindow();
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern int GetWindowTextLength(IntPtr hWnd);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
public delegate bool EnumWindowsProc(IntPtr hwnd, IntPtr lParam);
[DllImport("user32.dll")]
static extern int EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool IsWindowVisible(IntPtr hWnd);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool IsIconic(IntPtr hWnd);
[DllImport("user32.dll", SetLastError = true)]
static extern System.UInt32 GetWindowLong(IntPtr hWnd, int nIndex);
internal static List<DetectedWindow> EnumerateWindows()
{
var shellWindow = GetShellWindow();
var windows = new List<DetectedWindow>();
EnumWindows(delegate (IntPtr handle, IntPtr lParam)
{
if (handle == shellWindow)
return true;
if (!IsWindowVisible(handle))
return true;
if (IsIconic(handle))
return true;
if (HasSomeExtendedWindowsStyles(handle))
return true;
var length = GetWindowTextLength(handle);
if (length == 0)
return true;
var builder = new StringBuilder(length);
GetWindowText(handle, builder, length + 1);
GetWindowRect(handle, out Rect rect);
windows.Add(new DetectedWindow(handle, rect, builder.ToString()));
return true;
}, IntPtr.Zero);
return windows;
}
static bool HasSomeExtendedWindowsStyles(IntPtr hwnd)
{
const int GWL_EXSTYLE = -20;
const uint WS_EX_TOOLWINDOW = 0x00000080U;
uint i = GetWindowLong(hwnd, GWL_EXSTYLE);
if ((i & (WS_EX_TOOLWINDOW)) != 0)
{
return true;
}
return false;
}
}
public class DetectedWindow
{
public IntPtr Handle { get; private set; }
public EnumerateWindowsTest.Rect Bounds { get; private set; }
public string Name { get; private set; }
public DetectedWindow(IntPtr handle, EnumerateWindowsTest.Rect bounds, string name)
{
Handle = handle;
Bounds = bounds;
Name = name;
}
}
class Program
{
static void DetectWindows()
{
foreach (DetectedWindow w in EnumerateWindowsTest.EnumerateWindows())
{
Console.WriteLine("{0} - {1};{2};{3};{4}",w.Name,w.Bounds.Left,w.Bounds.Top,w.Bounds.Right,w.Bounds.Bottom);
}
}
static void Main(string[] args)
{
DetectWindows();
Console.ReadLine();
}
}
}
I have made simple window filter method that include Microsoft store apps that are cloaked. They are also identified by the class names ApplicationFrameWindow and Windows.UI.Core.CoreWindow
public static class WindowFilter
{
public static bool NormalWindow(IWindow window)
{
if (IsHiddenWindowStoreApp(window, window.ClassName)) return false;
return !window.Styles.IsToolWindow && window.IsVisible;
}
private static bool IsHiddenWindowStoreApp(IWindow window, string className)
=> (className == "ApplicationFrameWindow" || className == "Windows.UI.Core.CoreWindow") && window.IsCloaked;
}
The above example is part of a project of github, were you can see the rest of the code.
https://github.com/mortenbrudvik/WindowExplorer
As the title says, I want to position it to the bottom left corner of the screen. Here's the code I have so far:
Console.WindowWidth = 50
Console.WindowHeight = 3
Console.BufferWidth = 50
Console.BufferHeight = 3
Console.BackgroundColor = ConsoleColor.Black
Console.ForegroundColor = ConsoleColor.DarkMagenta
Console.Title = "My Title"
Console.WriteLine("")
Console.Write(" Press any key to close this window ...")
Console.ReadKey()
Note: Despite their names, setting Console.WindowLeft and Console.WindowTop of the System.Console class does not change the window's position on screen.
Instead, they position the visible part of the window relative to the (potentially larger) window buffer - you cannot use type System.Console to change the position of console windows on the screen - you need to use the Windows API for that.
The following is code for a complete console application that positions its own window in the lower left corner of the screen, respecting the location of the taskbar.
Note:
It should work with multi-monitor setups - positioning the window on the specific monitor (display, screen) it is (mostly) being displayed on - but I haven't personally verified it.
Only Windows API functions are used via P/Invoke declarations, avoiding the need for referencing the WinForms assembly (System.Windows.Forms), which is not normally needed in console applications.
You'll see that a good portion of the code is devoted to P/Invoke signatures (declaration) for interfacing with the native Windows APIs; these were gratefully adapted from pinvoke.net
The actual code in the Main() method is short by comparison.
If you compile the code below from a console-application project in Visual Studio and run the resulting executable from a cmd.exe console window (Command Prompt), that console window should shift to the lower left corner of the (containing screen).
To verify the functionality while running from Visual Studio, place a breakpoint at the closing } and, when execution pauses, Alt-Tab to the console window to verify its position.
using System;
using System.Runtime.InteropServices; // To enable P/Invoke signatures.
public static class PositionConsoleWindowDemo
{
// P/Invoke declarations.
[DllImport("kernel32.dll")]
static extern IntPtr GetConsoleWindow();
[DllImport("user32.dll")]
static extern IntPtr MonitorFromWindow(IntPtr hwnd, uint dwFlags);
const int MONITOR_DEFAULTTOPRIMARY = 1;
[DllImport("user32.dll")]
static extern bool GetMonitorInfo(IntPtr hMonitor, ref MONITORINFO lpmi);
[StructLayout(LayoutKind.Sequential)]
struct MONITORINFO
{
public uint cbSize;
public RECT rcMonitor;
public RECT rcWork;
public uint dwFlags;
public static MONITORINFO Default
{
get { var inst= new MONITORINFO(); inst.cbSize = (uint)Marshal.SizeOf(inst); return inst; }
}
}
[StructLayout(LayoutKind.Sequential)]
struct RECT
{
public int Left, Top, Right, Bottom;
}
[StructLayout(LayoutKind.Sequential)]
struct POINT
{
public int x, y;
}
[DllImport("user32.dll", SetLastError = true)]
static extern bool GetWindowPlacement(IntPtr hWnd, ref WINDOWPLACEMENT lpwndpl);
[DllImport("user32.dll", SetLastError = true)]
static extern bool SetWindowPlacement(IntPtr hWnd, [In] ref WINDOWPLACEMENT lpwndpl);
const uint SW_RESTORE= 9;
[StructLayout(LayoutKind.Sequential)]
struct WINDOWPLACEMENT
{
public uint Length;
public uint Flags;
public uint ShowCmd;
public POINT MinPosition;
public POINT MaxPosition;
public RECT NormalPosition;
public static WINDOWPLACEMENT Default
{
get
{
var instance = new WINDOWPLACEMENT();
instance.Length = (uint) Marshal.SizeOf(instance);
return instance;
}
}
}
public static void Main()
{
// Get this console window's hWnd (window handle).
IntPtr hWnd = GetConsoleWindow();
// Get information about the monitor (display) that the window is (mostly) displayed on.
// The .rcWork field contains the monitor's work area, i.e., the usable space excluding
// the taskbar (and "application desktop toolbars" - see https://msdn.microsoft.com/en-us/library/windows/desktop/ms724947(v=vs.85).aspx)
var mi = MONITORINFO.Default;
GetMonitorInfo(MonitorFromWindow(hWnd, MONITOR_DEFAULTTOPRIMARY), ref mi);
// Get information about this window's current placement.
var wp = WINDOWPLACEMENT.Default;
GetWindowPlacement(hWnd, ref wp);
// Calculate the window's new position: lower left corner.
// !! Inexplicably, on W10, work-area coordinates (0,0) appear to be (7,7) pixels
// !! away from the true edge of the screen / taskbar.
int fudgeOffset = 7;
wp.NormalPosition = new RECT() {
Left = -fudgeOffset,
Top = mi.rcWork.Bottom - (wp.NormalPosition.Bottom - wp.NormalPosition.Top),
Right = (wp.NormalPosition.Right - wp.NormalPosition.Left),
Bottom = fudgeOffset + mi.rcWork.Bottom
};
// Place the window at the new position.
SetWindowPlacement(hWnd, ref wp);
}
}
You can use Console.WindowTop and Console.WindowWidth of the System.Console class to set the location of the console window.
Here is an example on MSDN
The BufferHeight and BufferWidth property gets/sets the number of rows and columns to be displayed.
WindowHeight and WindowWidth properties must always be less than BufferHeight and BufferWidth respectively.
WindowLeft must be less than BufferWidth - WindowWidth and WindowTop must be less than BufferHeight - WindowHeight.
WindowLeft and WindowTop are relative to the buffer.
To move the actual console window, this article has a good example.
I have used some of your code and code from the CodeProject sample. You can set window location and size both in a single function. No need to set Console.WindowHeight and Console.WindowWidth again. This is how my class looks:
class Program
{
const int SWP_NOZORDER = 0x4;
const int SWP_NOACTIVATE = 0x10;
[DllImport("kernel32")]
static extern IntPtr GetConsoleWindow();
[DllImport("user32")]
static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter,
int x, int y, int cx, int cy, int flags);
static void Main(string[] args)
{
Console.WindowWidth = 50;
Console.WindowHeight = 3;
Console.BufferWidth = 50;
Console.BufferHeight = 3;
Console.BackgroundColor = ConsoleColor.Black;
Console.ForegroundColor = ConsoleColor.DarkMagenta;
var screen = System.Windows.Forms.Screen.PrimaryScreen.Bounds;
var width = screen.Width;
var height = screen.Height;
SetWindowPosition(100, height - 300, 500, 100);
Console.Title = "My Title";
Console.WriteLine("");
Console.Write(" Press any key to close this window ...");
Console.ReadKey();
}
/// <summary>
/// Sets the console window location and size in pixels
/// </summary>
public static void SetWindowPosition(int x, int y, int width, int height)
{
SetWindowPos(Handle, IntPtr.Zero, x, y, width, height, SWP_NOZORDER | SWP_NOACTIVATE);
}
public static IntPtr Handle
{
get
{
//Initialize();
return GetConsoleWindow();
}
}
}
Run any console application
Click RMB on headline.
Choose properties option.
choose Position tab.
Uncheck box "Automatic choice"
Set console position as you want.
I have a C# WPF application intended specifically for Win8.1 (a desktop app, NOT metro).
I want users to be able to use touch injections but I'm trying to disable the visualization feedback that windows creates for a Tap gesture Press Hold and Drag (like selecting multiple files on desktop) and other gestures (zooming scrolling etc).
After Searching the web for a long time I've found this post:
How do I disable Windows 8 touch contact visualizations for my application?
So I tried to do the same...
I tried this (Will put my Win32 class at the end)
public void DisableGestureVisualization()
{
const int SPI_SETCONTACTVISUALIZATION = 0x2019;
const int SPI_SETGESTUREVISUALIZATION = 0x201B;
ulong gv = 0;
Logger.Debug(!Win32.SystemParametersInfo(SPI_SETGESTUREVISUALIZATION, 0, ref gv, 0)
? #"Failed SystemParametersInfo SPI_SETGESTUREVISUALIZATION"
: #"Successfuly returned from SystemParametersInfo SPI_SETGESTUREVISUALIZATION");
Logger.Debug(!Win32.SystemParametersInfo(SPI_SETCONTACTVISUALIZATION, 0, ref gv, 0)
? #"Failed SystemParametersInfo SPI_SETCONTACTVISUALIZATION"
: #"Successfuly returned from SystemParametersInfo SPI_SETCONTACTVISUALIZATION");
}
And also this:
public void TryDisableWindowsVisualFeedback(IntPtr hWnd)
{
bool enable = false;
foreach (Win32.FEEDBACK_TYPE type in Enum.GetValues(typeof(Win32.FEEDBACK_TYPE)))
{
if (type == Win32.FEEDBACK_TYPE.FEEDBACK_MAX)
{
continue;
}
Logger.Debug(!Win32.SetWindowFeedbackSetting(hWnd, type, 0, 4, ref enable)
? #"Failed to SetWindowFeedbackSetting for " + type
: #"Successfuly returned from SetWindowFeedbackSetting for " + type);
}
}
And I call this from my WPF app like this:
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
Window window = Window.GetWindow(this);
var wih = new WindowInteropHelper(window);
IntPtr hWnd = wih.Handle;
TryDisableWindowsVisualFeedback(hWnd);
}
This is my auxiliary Win32 class:
internal class Win32
{
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SystemParametersInfo(
uint uiAction,
uint uiParam,
ref ulong pvParam,
uint fWinIni
);
public enum FEEDBACK_TYPE : uint
{
FEEDBACK_TOUCH_CONTACTVISUALIZATION = 1,
FEEDBACK_PEN_BARRELVISUALIZATION = 2,
FEEDBACK_PEN_TAP = 3,
FEEDBACK_PEN_DOUBLETAP = 4,
FEEDBACK_PEN_PRESSANDHOLD = 5,
FEEDBACK_PEN_RIGHTTAP = 6,
FEEDBACK_TOUCH_TAP = 7,
FEEDBACK_TOUCH_DOUBLETAP = 8,
FEEDBACK_TOUCH_PRESSANDHOLD = 9,
FEEDBACK_TOUCH_RIGHTTAP = 10,
FEEDBACK_GESTURE_PRESSANDTAP = 11,
FEEDBACK_MAX = 0xFFFFFFFF
}
[DllImport("user32.dll")]
public static extern bool SetWindowFeedbackSetting(
IntPtr hwnd,
FEEDBACK_TYPE feedback,
uint dwFlags,
uint size,
[In] ref bool configuration
);
}
Non of the above disabled the round gray tap visual feedback nor did it disable the small white circle that appears when holding and dragging.
I even tried using the C# example in the blog:
Windows.UI.Input.PointerVisualizationSettings.
GetForCurrentView().
IsContactFeedbackEnabled = false;
This code works for a metro app, so I tried This SO post and got the Windows namespace but when running the code I get
"An unhandled exception of type 'System.Exception' occurred in MyProg.exe
WinRT information: Element not found.
Additional information: Element not found."
From what I could figure out, the PointerVisualizationSettings is not supported from a desktop application so this way is doomed...
If anyone can help me with this issue, please do.
Thanks
I had a similar problem and I was able to remove my tap gesture feedback by adding
Stylus.IsTapFeedbackEnabled = "False" to my root window.
Your TryDisableWindowsVisualFeedback method looks like it has the wrong pinvoke signature so you may be setting the visual feedback instead of clearing it. The configuration argument is a BOOL* not a bool*, and BOOL is a 4 byte integer. You can fix this with the MarshalAs attribute:
[In , MarshalAs(UnmanagedType.Bool)] ref bool configuration
You can call GetWindowFeedbackSetting to confirm that it was set correctly.
With the right pinvoke and hWnd, SetWindowFeedbackSetting should work. I confirmed that it does for me in a native app. WPF handles touch a bit oddly. I wouldn't expect it to affect this, but I haven't looked at WPF in depth for several years.
For your other methods, the Windows.UI.Input classes are documented to work only in Windows Store apps, so errors calling them from a desktop app are expected. Under the covers they'll make the same changes as SetWindowFeedbackSetting.
Using SystemParametersInfo to affect global UI is overkill: you don't want to solve a local problem by causing a global one. That said, it would probably work if you fire change notifications. Using SetWindowFeedbackSetting to target just your window is a much better solution though.
I don't know if this would resolve the OP's original issue (or even makes a difference), but I can confirm that I have successfully disabled all touch related visual feedback for my own Control-derived class selectively with the following method (almost like the one suggested by the OP) - at least on my Windows 10 machine:
public class MyTouchControl: Control
{
// ...a lot of other touch related stuff going on...
enum FEEDBACK_TYPE
{
TOUCH_CONTACTVISUALIZATION = 1,
PEN_BARRELVISUALIZATION = 2,
PEN_TAP = 3,
PEN_DOUBLETAP = 4,
PEN_PRESSANDHOLD = 5,
PEN_RIGHTTAP = 6,
TOUCH_TAP = 7,
TOUCH_DOUBLETAP = 8,
TOUCH_PRESSANDHOLD = 9,
TOUCH_RIGHTTAP = 10,
GESTURE_PRESSANDTAP = 11
}
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SetWindowFeedbackSetting(IntPtr hWnd, FEEDBACK_TYPE feedback, int dwFlags, int size, ref int config);
void disableAllTouchVisualFeedback()
{
int enable = 0;
foreach (FEEDBACK_TYPE type in Enum.GetValues(typeof(FEEDBACK_TYPE)))
{
SetWindowFeedbackSetting(Handle, type, 0, 4, ref enable);
}
}
protected override void OnHandleCreated(EventArgs e)
{
disableAllTouchVisualFeedback();
base.OnHandleCreated(e);
}
}
How can I show/hide the desktop icons programmatically, using C#?
I'm trying to create an alternative desktop, which uses widgets, and I need to hide the old icons.
You can do this using the Windows API. Here is sample code in C# that will toggle desktop icons.
[DllImport("user32.dll", SetLastError = true)] static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", SetLastError = true)] static extern IntPtr GetWindow(IntPtr hWnd, GetWindow_Cmd uCmd);
enum GetWindow_Cmd : uint
{
GW_HWNDFIRST = 0,
GW_HWNDLAST = 1,
GW_HWNDNEXT = 2,
GW_HWNDPREV = 3,
GW_OWNER = 4,
GW_CHILD = 5,
GW_ENABLEDPOPUP = 6
}
[DllImport("user32.dll", CharSet = CharSet.Auto)] static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
private const int WM_COMMAND = 0x111;
static void ToggleDesktopIcons()
{
var toggleDesktopCommand = new IntPtr(0x7402);
IntPtr hWnd = GetWindow(FindWindow("Progman", "Program Manager"), GetWindow_Cmd.GW_CHILD);
SendMessage(hWnd, WM_COMMAND, toggleDesktopCommand, IntPtr.Zero);
}
This sends a message to the SHELLDLL_DefView child window of Progman, which tells it to toggle visibility (by adding or removing the WS_VISIBLE style) of it's only child, "FolderView". "FolderView" is the actual window that contains the icons.
To test to see if icons are visible or not, you can query for the WS_VISIBLE style by using the GetWindowInfo function, shown below:
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("user32.dll", SetLastError = true)]
private static extern bool GetWindowInfo(IntPtr hwnd, ref WINDOWINFO pwi);
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
private int _Left;
private int _Top;
private int _Right;
private int _Bottom;
}
[StructLayout(LayoutKind.Sequential)]
struct WINDOWINFO
{
public uint cbSize;
public RECT rcWindow;
public RECT rcClient;
public uint dwStyle;
public uint dwExStyle;
public uint dwWindowStatus;
public uint cxWindowBorders;
public uint cyWindowBorders;
public ushort atomWindowType;
public ushort wCreatorVersion;
public WINDOWINFO(Boolean? filler)
: this() // Allows automatic initialization of "cbSize" with "new WINDOWINFO(null/true/false)".
{
cbSize = (UInt32)(Marshal.SizeOf(typeof(WINDOWINFO)));
}
}
Here is a function that calls the above code and returns true if the window is visible, false if not.
static bool IsVisible()
{
IntPtr hWnd = GetWindow(GetWindow(FindWindow("Progman", "Program Manager"), GetWindow_Cmd.GW_CHILD), GetWindow_Cmd.GW_CHILD);
WINDOWINFO info = new WINDOWINFO();
info.cbSize = (uint)Marshal.SizeOf(info);
GetWindowInfo(hWnd, ref info);
return (info.dwStyle & 0x10000000) == 0x10000000;
}
The windows API code along with more information about the window styles can be found here: http://www.pinvoke.net/default.aspx/user32/GetWindowInfo.html
Even though this is quite old when I tried Ondrej Balas's answer, one problem I found with this solution is that it does not work if the ToggleDesktop command is used to show the desktop ( also if wallpaper rotation is enabled ).
In both of these cases the SHELLDLL_DefView window, which is the recipient of the toggleDesktopCommand in the ToggleDesktopIcons function, is not a child of the "Program manager" window but of a 'WorkerW" window. (see WinApi - How to obtain SHELLDLL_DefView and Windows Desktop ListView Handle.
Based on those and building upon Ondrej Balas's earlier answer change the ToggleDesktopIcons function to be :
static void ToggleDesktopIcons()
{
var toggleDesktopCommand = new IntPtr(0x7402);
SendMessage(GetDesktopSHELLDLL_DefView(), WM_COMMAND, toggleDesktopCommand, IntPtr.Zero);
}
And add a GetDesktopSHELLDLL_DefView function:
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, string windowTitle);
[DllImport("user32.dll", SetLastError = false)]
static extern IntPtr GetDesktopWindow();
static IntPtr GetDesktopSHELLDLL_DefView()
{
var hShellViewWin = IntPtr.Zero;
var hWorkerW = IntPtr.Zero;
var hProgman = FindWindow("Progman", "Program Manager");
var hDesktopWnd = GetDesktopWindow();
// If the main Program Manager window is found
if (hProgman != IntPtr.Zero)
{
// Get and load the main List view window containing the icons.
hShellViewWin = FindWindowEx(hProgman, IntPtr.Zero, "SHELLDLL_DefView", null);
if (hShellViewWin == IntPtr.Zero)
{
// When this fails (picture rotation is turned ON, toggledesktop shell cmd used ), then look for the WorkerW windows list to get the
// correct desktop list handle.
// As there can be multiple WorkerW windows, iterate through all to get the correct one
do
{
hWorkerW = FindWindowEx(hDesktopWnd, hWorkerW, "WorkerW", null);
hShellViewWin = FindWindowEx(hWorkerW, IntPtr.Zero, "SHELLDLL_DefView", null);
} while (hShellViewWin == IntPtr.Zero && hWorkerW != IntPtr.Zero);
}
}
return hShellViewWin;
}
Now regardless of the desktop toggle or wallpaper rotation the ToggleDesktopIcons should always work.
For reference this is my toggle desktop function which caused the issue with the original ToggleDesktopIcons function
static public void ToggleDesktop(object sender, EventArgs e)
{
var shellObject = new Shell32.Shell();
shellObject.ToggleDesktop();
}
In response to James M, this function returns the current state:
bool IconsVisible()
{
var hWnd = GetDesktopListView();
var info = new User32.WINDOWINFO(null);
User32.GetWindowInfo(hWnd, ref info);
return (info.dwStyle & User32.WindowStyle.WS_VISIBLE) == User32.WindowStyle.WS_VISIBLE;
}
A different approach is to create a separate desktop and show it instead. It will not have icons.
Application running itself on a separate desktop
You can do this in RegEdit
HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced
change HideIcons to 1
static void HideIcons()
{
RegistryKey myKey = Registry.CurrentUser.OpenSubKey(#"SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced", true);
if (myKey != null)
{
myKey.SetValue("HideIcons", 1);
myKey.Close();
}
}
Use the Registry class as described here.
http://msdn.microsoft.com/en-us/library/microsoft.win32.registry.aspx
You can create a full screen view application and make it the top most window.
Then make your application to be start up with windows.
You are going about this the wrong way. What you are really trying to do is to replace the shell. Windows provides for this so you should just take advantage of it. Write your own shell to replace explorer.
Nice topic. Without actually creating a different desktop it would be visually pleasant to have the running applications minimized in the same swoop.