简体   繁体   中英

How to get position of c# console application

I am a beginner at coding and I want to create an application that says the width, height, and position of the window. The problem is that I don't know how to GET the position of the window. I searched the internet but couldn't find the answer to my question.

Here is the code I have:

using System;

namespace WindowSizeChecker
{
    class Program
    {
        const bool alwaysTrue = true;

        static void Main(string[] args)
        {
            while (alwaysTrue == true)
            {
                Console.Write("Set your console window to your prefered size and position. Then press Enter");
                Console.ReadLine();
                screenSizeAndPosition();
                Console.WriteLine("\n\nPress enter to repeat\n\n");
                Console.ReadLine();
            }
        }

        public static void screenSizeAndPosition()
        {
            int consoleWidth = Console.WindowWidth;
            int consoleHeight = Console.WindowHeight;
            string consoleWidthString = consoleWidth.ToString();
            string consoleHeightString = consoleHeight.ToString();
            Console.WriteLine("\nThe width of the window is: {0}\nAnd the height of the window is: {1}", consoleWidthString, consoleHeightString);

            int largestWindowWidth = Console.LargestWindowWidth;
            int largestWindowHeight = Console.LargestWindowHeight;
            string largestWindowWidthString = largestWindowWidth.ToString();
            string largestWindowHeightString = largestWindowHeight.ToString();
            Console.WriteLine("\nThe largest width of the window is: {0}\nAnd the largest height of the window is: {1}", largestWindowWidthString, largestWindowHeightString);
        }
    }
}

Here is the program running: enter image description here

I am a beginner at coding and I want to create an application that says the width, height, and position of the window. The problem is that I don't know how to GET the position of the window. I searched the internet but couldn't find the answer to my question.

The information is out there, but I admit, it's not necessarily presented in the easiest to understand manner, especially for a beginner.

IMHO, two of the most relevant Stack Overflow questions you probably should read are these:
Position a small console window to the bottom left of the screen?
DwmGetWindowAttribute returns 0 with PInvoke

They aren't really duplicates of your question, and for a beginner it's probably hard to see how they answer it. But they do in fact contain almost all of the information you would need.

There are a couple of things you need to understand, besides the "how":

  1. The Console properties you're looking at now are not pixel dimensions, but rather are in terms of character columns and rows. That is, how many characters can fit across the window in a single row, and how many rows of those characters can fit vertically.
  2. When it comes to pixels, there are actually (at least ) two different ways to look at the window size: raw screen coordinates, and "DPI-adjusted". The latter is IMHO a misnomer, because it's not taking into account any actual screen resolution (ie "dots per inch"), but rather the scaling factor that is set for your desktop. It's considered "DPI-adjusted" because setting the scaling factor is the Windows mechanism for attempting to keep the visual presentation of a program consistent across displays of different resolution.

As you already have seen, you can get the character-oriented dimensions straight from the .NET Console class. But to get the pixel information, you need to use .NET's native interop support to call the Windows API directly. Here are some helper classes I put together, based on available documentation and Stack Overflow posts, to do that for your scenario:

[StructLayout(LayoutKind.Sequential)]
struct Rect
{
    public int Left;
    public int Top;
    public int Right;
    public int Bottom;

    public int Width => Right - Left;
    public int Height => Bottom - Top;
}
class NativeConsole
{
    [DllImport("kernel32")]
    public static extern IntPtr GetConsoleWindow();
}
class Winuser
{
    [DllImport(@"user32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool GetWindowRect(IntPtr hWnd, out Rect lpRect);

    public static Rect GetWindowRect(IntPtr handle)
    {
        if (!GetWindowRect(handle, out Rect rect))
        {
            throw Marshal.GetExceptionForHR(Marshal.GetLastWin32Error());
        }

        return rect;
    }
}
class DwmApi
{
    private const int DWMWA_EXTENDED_FRAME_BOUNDS = 9;

    [DllImport(@"dwmapi.dll")]
    private static extern int DwmGetWindowAttribute(IntPtr hwnd, int dwAttribute, out Rect pvAttribute, int cbAttribute);

    public static Rect GetExtendedFrameBounds(IntPtr hwnd)
    {
        int hresult = DwmGetWindowAttribute(hwnd, DWMWA_EXTENDED_FRAME_BOUNDS, out Rect rect, Marshal.SizeOf(typeof(Rect)));

        if (hresult != 0)
        {
            throw Marshal.GetExceptionForHR(hresult);
        }

        return rect;
    }
}

You could, of course, lump all of the above together in a single class, but I prefer to keep things organized. The above groups the various parts of the API into the same organization used in the native Win32 API itself.

With those pieces in hand, now we can put together a program similar to the one you have above, except that it will display the window position (which is what you want), along with the width and height as well (since those come for free from the native API anyway).

That looks like this:

using static System.Console;

class Program
{
    static void Main(string[] args)
    {
        Clear();

        string prompt = "Set your console window to your preferred size and position. Press X to exit";

        while (true)
        {
            if (KeyAvailable && ReadKey(intercept: true).Key == ConsoleKey.X)
            {
                break;
            }

            ScreenSizeAndPosition(prompt);
            System.Threading.Thread.Sleep(TimeSpan.FromSeconds(0.25));
        }
    }

    static void ScreenSizeAndPosition(string prompt)
    {
        string format = $"{{0, {-WindowWidth}}}";

        SetCursorPosition(0, 0);
        Write(format, prompt);
        Write(format, $"Window is {WindowWidth} columns wide and {WindowHeight} rows high");
        Write(format, $"The largest window that can fit on the screen is {LargestWindowWidth} columns wide and {LargestWindowHeight} rows high");

        IntPtr consoleHwnd = NativeConsole.GetConsoleWindow();

        Rect winuserRect = Winuser.GetWindowRect(consoleHwnd),
            dwmRect = DwmApi.GetExtendedFrameBounds(consoleHwnd);

        Write(format, $"DPI-adjusted screen values: location is {{{winuserRect.Left}, {winuserRect.Top}}}, window is {winuserRect.Width} pixels wide, {winuserRect.Height} pixels high");
        Write(format, $"Desktop Window Manager values: location is {{{dwmRect.Left}, {dwmRect.Top}}}, window is {dwmRect.Width} pixels wide, {dwmRect.Height} pixels high");

        for (int i = 0; i < WindowHeight - 5; i++)
        {
            Write(format, "");
        }
    }
}

I did change your basic logic in the program a bit, so that it just checks every quarter second rather than waiting for the user to press a key, displaying whatever the current values are as the user changes the window size and position.

For more details on the Windows functions used above, you should read the documentation:

GetConsoleWindow()
GetWindowRect()
DwmGetWindowAttribute()

There are some additional subtleties in the ways that GetWindowRect() and DwmGetWindowAttribute() work, so it's worth checking out the docs so that you understand better what they are returning in terms of the window dimensional values.

You should call a Win32 API DwmGetWindowAttribute via PInovke to the current window position. Refer to the document and see how to use it .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM