Position a small console window to the bottom left of the screen? - c#

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.

Related

Looking to force Alt + Enter full screen and a forced zoom (Ctrl + Scroll) Inside of a console application in C#

Essentially cannot find and answer to this question, or if it is even possible.
I have a game I am creating for a class, and it simply looks better when forced full screen and when the zoom is set to a particular size. I was wonder if I could recreate this without the player being necessary to change it themselves.
ALT + ENTER Full screen
And
CTRL + Scroll wheel zoom
For a literal answer to your question on how to:
Send keys to go Fullscreen, and
Send a Ctrl+MouseWheel
You want some help from the Win32 interop to send keyboard & mouse messages to your console window.
using System.Runtime.InteropServices;
public class Win32
{
public const int VK_F11 = 0x7A;
public const int SW_MAXIMIZE = 3;
public const uint WM_KEYDOWN = 0x100;
public const uint WM_MOUSEWHEEL = 0x20A;
public const uint WHEEL_DELTA = 120;
public const uint MK_CONTROL = 0x00008 << 16;
[DllImport("kernel32.dll")]
public static extern IntPtr GetConsoleWindow();
[DllImport("user32.dll")]
public static extern IntPtr PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll")]
public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
}
As reference the magic numbers are from:
Virtual Keys (VK_*)
Window input messages (WM_*)
Mousewheel params (WHEEL_DELTA & MK_*)
and the ShowWindow params (SW_*)
You could then simply send your keypress and mousewheel like so:
using static Win32;
// Get window handle of the console
var hwnd = GetConsoleWindow();
// Go fullscreen by sending the F11 keydown message.
PostMessage(hwnd, WM_KEYDOWN, (IntPtr)VK_F11, IntPtr.Zero);
// Or maximize the window instead. Your users may not know how to get out of fullscreen...
/// ShowWindow(hwnd, SW_MAXIMIZE);
// Send mouse wheel message.
// MK_CONTROL: Holds the Ctrl key. WHEEL_DELTA: Positive=Up, Negative=Down.
PostMessage(hwnd, WM_MOUSEWHEEL, (IntPtr)(MK_CONTROL | WHEEL_DELTA), IntPtr.Zero);
Alternatively, as #JeremyLakerman mentioned in a comment to your question, you could set the console font to a larger size; which is a lot better, but also a bit more involved than sending Ctrl+MouseWheel.

Hijacking another processes form

So, I have been asked to figure out a way to make a program containing sensitive data more secure since we have staff that go afk and put potentially put data at risk.
I have loaded up Visual Studio for C# and found a nice way to get process of the fore mentioned application. Then grab the main window and attach a panel of my very own. This panel will basically now be used like a blind covering the application when its not in use.
Now, I have a program running in system tray waiting for the sensitive data to come on screen and my little panel hijacks the entire window and now nothing can be seen.
My problem now is how ever, that whilst my panel is attacked the main window of the application i am trying to lock out seems to just crash. I am guessing that is because my panel and the application belong to different processes.
Anyway I could do with some advise here.
Here is my panels class.
class LockingPanel : System.Windows.Forms.Panel
{
private IntPtr prn;
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
public void SetParent(IntPtr parent)
{
prn = parent;
SetParent(this.Handle, prn);
}
public IntPtr GetParent() {
return prn;
}
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool GetWindowRect(IntPtr hWnd, ref RECT Rect);
[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
}
public void FillParent()
{
RECT rtc = new RECT();
GetWindowRect(prn, ref rtc);
this.Location = new System.Drawing.Point(0, 0);
this.Size = new System.Drawing.Size(rtc.Right, rtc.Bottom);
}
Anybody got a better idea on how I can go about this, or at least make it so that my panel inst going to crash the application.

Virtual ListView with artifacts in short list for Windows 8 and higher

I have a ListView in a Winform User Control. The VirtualMode is true and the VirtualListSize is 200. When there are less items in the ListView than visible rows, I get weird characters below the (real) items. These "artifacts" appear when the software is run on Windows 8, 10 or Windows Server 2012, but not on Windows 7.
Does anyone know what could be causing these "artifacts"? I added a character "A" "B", etc. to the Title of all the places where ListViewItems are created. So I know that none of the code in this user control is creating them. I added a sample solution that shows the problem below.
Sometimes they appear as chinese characters, sometimes just a random letter and character combination. Usually they are not longer than 4 characters.
[Update] It does not occur on the latest Version of Windows 10.
[Update2] I was able to reproduce the problem on a small sample solution. Find the zip file here.
I ended up assigning the number of visible lines of the ListView to the VirtualListSize property, whenever the number of items in the ListView changed.
I used the following class to determine the number of visible lines in the ListView:
public static class ListViewSizer
{
const UInt32 LVM_FIRST = 0x1000;
const UInt32 LVM_GETHEADER = (LVM_FIRST + 31);
private static int GetHeaderHeight(ListView listView)
{
Rect rect = new Rect();
IntPtr hwnd = SendMessage((IntPtr)listView.Handle, LVM_GETHEADER, IntPtr.Zero, IntPtr.Zero);
if (hwnd != null)
{
if (GetWindowRect(new System.Runtime.InteropServices.HandleRef(null, hwnd), out rect))
{
return rect.Bottom - rect.Top;
}
}
return -1;
}
public static int GetLastVisibleLine(ListView listView)
{
int firstVisibleIndex = listView.TopItem.Index;
int heightOfFirstItem = listView.GetItemRect(firstVisibleIndex, ItemBoundsPortion.Entire).Height;
// assuming each item has the same height (I think this is true for list view and details view)
const int DefaultVisibleLines = 11;
int visibleLines = heightOfFirstItem != 0 ? (int)Math.Ceiling((decimal)((listView.Height - GetHeaderHeight(listView)) / heightOfFirstItem)) : DefaultVisibleLines;
int lastVisibleIndexInDetailsMode = firstVisibleIndex + visibleLines;
return lastVisibleIndexInDetailsMode;
}
[System.Runtime.InteropServices.DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
private static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern bool GetWindowRect(System.Runtime.InteropServices.HandleRef hwnd, out Rect lpRect);
[Serializable, System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct Rect
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
}
I know this is a bit of a hack. The artifacts would still be there, but you just can't see them anymore, because the ListView always has as many lines as can be displayed. This is the best I could come up with without changing the control.

How to get window properties of a desktop application

So, I am having an application which is intended to operate with another application autonomously.
Example:
Open application A, which start application B
Click on a button 1 and click on the input text
The problem is that Application B is not mine and I want to automate a button click there. I know that button 1 is located 20px from bottom right corner, but I don't know height and width of the window of application B. Is it possible to get width and height of that window in C#?
It sure is. You can use the Windows API to get its handle, then from there get its window properties.
Import the API.
[StructLayout(LayoutKind.Sequential)]
private struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
public static extern IntPtr GetWindowRect(IntPtr hWnd,ref RECT rect);
Then in your function you can:
IntPtr hWnd;
hWnd = GetWindows.FindWindow(null, "Application Title");
User32.RECT windowRect = new User32.RECT();
User32.GetWindowRect(hWnd,ref windowRect);
int width = windowRect.right - windowRect.left;
int height = windowRect.bottom - windowRect.top;

How do I set the focus to the Desktop from within my C# application

Winforms App. .Net 3.5.
I need to set the focus from my C# application to the user's desktop (almost like simulating a mouse click on the desktop).
Can someone please show me how to do this with C#? I just want to set focus on the desktop so the focus is no longer on my application but I want to do this from within my application.
Edit: An answer below works by setting the focus to the desktop, but it minimizes all the open windows on the user's desktop.
Is there a way I can maybe set the focus to the next open window on the desktop instead? I just want to get the focus off of my application (without minimizing my application or hiding it). I just want to move focus to somewhere else. Maybe the desktop was not the best choice if it will minimize all the user's open windows/applications.
This should do it for you.
using System;
using System.Runtime.InteropServices;
namespace ConsoleApplication1 {
class Program {
[DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", EntryPoint = "SendMessage", SetLastError = true)]
static extern IntPtr SendMessage(IntPtr hWnd, Int32 Msg, IntPtr wParam, IntPtr lParam);
const int WM_COMMAND = 0x111;
const int MIN_ALL = 419;
const int MIN_ALL_UNDO = 416;
static void Main(string[] args) {
IntPtr lHwnd = FindWindow("Shell_TrayWnd", null);
SendMessage(lHwnd, WM_COMMAND, (IntPtr)MIN_ALL, IntPtr.Zero);
System.Threading.Thread.Sleep(2000);
SendMessage(lHwnd, WM_COMMAND, (IntPtr)MIN_ALL_UNDO, IntPtr.Zero);
}
}
}
Get Next Window
I don't have a code example ready for these two but I'm going to give you the links to both. The first think you need to do is call GetWindow. After doing that you'll want to call SwitchToThisWindow passing in the pointer you received from GetWindow.
You can add this COM object in your project:
Microsoft Shell Controls And Automation
And then just call:
Shell32.ShellClass shell = new Shell32.ShellClass();
shell.MinimizeAll();
This will minimize all the windows and then focus the desktop. Otherwise, if you have your window non-full screen then you can simulate the mouse click using:
//This is a replacement for Cursor.Position in WinForms
[System.Runtime.InteropServices.DllImport("user32.dll")]
static extern bool SetCursorPos(int x, int y);
[System.Runtime.InteropServices.DllImport("user32.dll")]
public static extern void mouse_event(int dwFlags, int dx, int dy, int cButtons, int dwExtraInfo);
public const int MOUSEEVENTF_LEFTDOWN = 0x02;
public const int MOUSEEVENTF_LEFTUP = 0x04;
//This simulates a left mouse click
public static void LeftMouseClick(int xpos, int ypos)
{
SetCursorPos(xpos, ypos);
mouse_event(MOUSEEVENTF_LEFTDOWN, xpos, ypos, 0, 0);
mouse_event(MOUSEEVENTF_LEFTUP, xpos, ypos, 0, 0);
}
You can calculate coordinates by looking at your window startup location plus height/width and select a available space (that will be the desktop indeed).

Categories