CONSOLE_CURSOR_INFO in .NET setzen?



  • Hallo, ich hatte früher mit C++ WinAPI in einer Konsolenanwendung die Cursor Größe verändert:

    void BigCursor(bool big)
    {
    	CONSOLE_CURSOR_INFO cci;
    	if(big) cci.dwSize = 99;
    	else    cci.dwSize =  1;
    	cci.bVisible = true;
    	SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cci);
    }
    

    Die hat mir ein dicke Cursor in der Konsole angezeigt(wie bei Amiga früher 🙂

    Nun wollte ich das in einer C# .NET Konsolenanwendung verwenden, nun hab ich gehört das Unmanaged Code eingebunden werden muss.
    Hoffe ihr könnt mir ein Beispiel zeigen.

    Die SetConsoleCursorInfo befindet sich in der Kernel32.lib


  • Administrator

    Dazu musst du die WinAPI nicht selber aufrufen, da gibt es bereits eine fertige Möglichkeit: System.Console.CursorSize

    Grüssli



  • Ahh Vielen Dank!!

    Nun würde ich gerne die Hintergrundfarbe ändern, doch es wird immer nur die aktuelle Zeile geändert aber nicht das ganze Konsolenfenster, der Rest ist Schwarz.

    Console.BackgroundColor = ConsoleColor.DarkBlue;
    

    In CMD Eigenschaften kann man ja auch für die ganze Konsole die Farben ändern, wie würde man das hier machen=?


  • Administrator

    Direkt mit C# kannst du dies über Console.Clear erreichen. Also zum Beispiel:

    // Farbe setzen.
    Console.ForegroundColor = ConsoleColor.Black;
    Console.BackgroundColor = ConsoleColor.White;
    
    // Clear aufrufen.
    Console.Clear();
    

    Console.Clear löscht aber alles, was in der Konsole bereits vorhanden ist. Falls du die Inhalte behalten willst, dann wird es etwas komplizierter. Daher warte ich zuerst ab, ob diese Lösung dir nicht bereits reicht 🙂

    Grüssli



  • Perfekt danke!!

    Eine Frage habe ich noch, ist es möglich das Konsolenfenster zu maximieren, also nicht Fullscreen(ALT+ENTER), sondern wenn man neben dem Schließen Button auf maximieren klicken würde?
    Ich glaub das ´ging mit WinForms ohne Probleme, aber hier mit der Konsolenanwendung weiß ich es nicht.


  • Administrator

    Ohne P/Invoke geht das AFAIK nicht. Naja, nachfolgend einen Beispiel Code, wie man das Fenster maximiert und die aktuellen Attribute im ganzen Screen Buffer setzt, ohne den Inhalt zu verändern.

    using System;
    using System.Runtime.InteropServices;
    
    namespace ConsoleTest
    {
        [StructLayout(LayoutKind.Sequential)]
        public struct ConsoleCoord
        {
            public short x;
            public short y;
    
            public ConsoleCoord(short x, short y)
            {
                this.x = x;
                this.y = y;
            }
        }
    
        [StructLayout(LayoutKind.Sequential)]
        public struct ConsoleRect
        {
            public short top;
            public short left;
            public short right;
            public short bottom;
        }
    
        [StructLayout(LayoutKind.Sequential)]
        struct ConsoleScreenBufferInfo
        {
            public ConsoleCoord size;
            public ConsoleCoord cursorPosition;
            public ushort attributes;
            public ConsoleRect window;
            public ConsoleCoord maximumWindowSize;
        }
    
        public enum ConsoleHandle
            : uint
        {
            Input = unchecked((uint)-10),
            Output = unchecked((uint)-11),
            Error = unchecked((uint)-12)
        }
    
        public enum ShowWindowCmd
            : int
        {
            HIDE = 0,
            MAXIMIZE = 3,
            MINIMIZE = 6,
            RESTORE = 9
        }
    
        public sealed class WindowApi
        {
            [DllImport(@"user32.dll", ExactSpelling = true)]
            public static extern bool ShowWindow(IntPtr wnd, ShowWindowCmd cmd);
        }
    
        public sealed class ExtendedConsole
        {
            [DllImport(@"kernel32.dll", ExactSpelling = true)]
            private static extern IntPtr GetStdHandle(ConsoleHandle handle);
    
            [DllImport(@"kernel32.dll", ExactSpelling = true)]
            private static extern bool GetConsoleScreenBufferInfo(
                IntPtr handle,
                out ConsoleScreenBufferInfo info);
    
            [DllImport(@"kernel32.dll", ExactSpelling = true)]
            private static extern bool FillConsoleOutputAttribute(
                IntPtr handle,
                ushort attributes,
                uint length,
                ConsoleCoord writeCoord,
                out uint numberOfAttrsWritten);
    
            [DllImport(@"kernel32.dll", ExactSpelling = true)]
            public static extern IntPtr GetConsoleWindow();
    
            public static void FillCurrentAttributes()
            {
                IntPtr output = GetStdHandle(ConsoleHandle.Output);
    
                ConsoleScreenBufferInfo info;
                GetConsoleScreenBufferInfo(output, out info);
    
                uint written;
                FillConsoleOutputAttribute(
                    output,
                    info.attributes,
                    (uint)(info.size.x * info.size.y),
                    new ConsoleCoord(0, 0),
                    out written);
            }
    
            public static void MaximizeWindow()
            {
                IntPtr wnd = GetConsoleWindow();
                WindowApi.ShowWindow(wnd, ShowWindowCmd.MAXIMIZE);
            }
    
            public static void RestoreWindow()
            {
                IntPtr wnd = GetConsoleWindow();
                WindowApi.ShowWindow(wnd, ShowWindowCmd.RESTORE);
            }
        }
    
        public class Program
        {
            static private void WaitNext(String title)
            {
                Console.WriteLine();
                Console.WriteLine(title);
                Console.WriteLine("Press any key to continue...");
    
                Console.ReadKey(true);
            }
    
            static public void Main(string[] args)
            {
                WaitNext("Start");
    
                ExtendedConsole.MaximizeWindow();
                WaitNext("Simple maximize");
    
                ExtendedConsole.RestoreWindow();
                WaitNext("Window restored");
    
                WaitNext("Current colors");
    
                Console.ForegroundColor = ConsoleColor.Black;
                Console.BackgroundColor = ConsoleColor.Gray;
                ExtendedConsole.FillCurrentAttributes();
    
                Console.WriteLine("\nNew colors");
                Console.WriteLine("Press any key to close...");
                Console.ReadKey(true);
            }
        }
    }
    

    Ich möchte aber noch einen Hinweis anbringen:
    Wenn du solche Dinge veränderst, solltest du nicht vergessen, dass Konsolenprogramme eigentlich dazu gedacht worden sind, aus der Konsole zu starten. Wenn du nun auf die Konsole zugreifst, könntest du Dinge verändern oder löschen, welche der Benutzer eigentlich behalten wollte. Daher sollte man eher vorsichtig mit solchen Dingen umgehen. Schreib allenfalls beim Programm dazu, dass man es nicht über die Konsole starten soll, weil es die Konsole selber verändert.

    Grüssli



  • Perfekt, hab noch die Maximize Funktion so modifiziert, es wird die maximale Konsolenbreite/höhe gesetzt, klappt super:

    public static void MaximizeWindow()
            {
                IntPtr wnd = GetConsoleWindow();
                WindowApi.ShowWindow(wnd, ShowWindowCmd.MAXIMIZE);
    
                int maxHeight = Console.LargestWindowHeight;
                int maxWidth = Console.LargestWindowWidth;
    
                Console.WindowHeight = maxHeight;
                Console.BufferHeight = maxHeight;
                Console.WindowWidth = maxWidth;
                Console.BufferWidth = maxWidth;
            }
    

    Nun wollte ich beim Restore die vertikale und horizontale Scrolleiste entfernen da die noch von der Maximize gesetzt wurden, hab es auf die Standardgröße geändert aber diese werden immer noch angezeigt:

    public static void RestoreWindow()
            {
                IntPtr wnd = GetConsoleWindow();
                WindowApi.ShowWindow(wnd, ShowWindowCmd.RESTORE);
    
                Console.BufferHeight = 80;
                Console.BufferWidth = 210;
            }
    

  • Administrator

    Wenn du keine Scrollbars willst, dann musst du die Puffergrösse auf die Fenstergrösse setzen:

    int width = Console.WindowWidth;
    int height = Console.WindowHeight;
    
    Console.SetBufferSize(width, height);
    

    Und im übrigen:
    Dein modifiziertes MaximizeWindow dürfte mit hoher Wahrscheinlichkeit nicht funktionieren, wie es sollte. Du modifizierst die Höhe und Breite des Fensters nach dem maximieren. Ich tippe darauf, dass gewisse Bereiche des Fenster ausserhalb des Bildschirmes sind.

    Das maximieren eines Konsolenfenster ist eben ein wenig speziell gehalten, merkst du auch, wenn du es manuell maximierst. Die Fenstergrösse orientiert sich immer an den Anzahl Zeilen und Spalten des Konsolenpuffers. Wahrscheinlich gäbe es Wege, dies zu umgehen, doch wie sinnvoll diese Wege sind, darüber lässt sich streiten.

    Ich frage mich allerdings gerade auch, ob dir eigentlich bewusst ist, was der Konsolenpuffer ist und wie das Fenster und der Puffer miteinander funktionieren?
    Wenn du dies nicht weisst, solltest du dich vielleicht darüber noch ein wenig Informieren. Steht einiges dazu in der Dokumentation zur Klasse Console . Aber auch in den Console Functions der WinAPI findest du viele Informationen.

    Grüssli



  • So nun wird die Maximieren Funktion richtig ausgeführt. Die Minimize wird mit den Standard Werten zurückgesetzt, hier musste ich die Werte im Code angeben:

    public static void MaximizeWindow()
            {
                int maxHeight = Console.LargestWindowHeight;
                int maxWidth = Console.LargestWindowWidth;
    
                Console.SetWindowSize(maxWidth, maxHeight);
    
                IntPtr wnd = GetConsoleWindow();
                WindowApi.ShowWindow(wnd, ShowWindowCmd.MAXIMIZE);
            }
    
            public static void RestoreWindow()
            {
                IntPtr wnd = GetConsoleWindow();
                WindowApi.ShowWindow(wnd, ShowWindowCmd.RESTORE);
    
                int defaultWidth = 80;
                int defaultHeight = 25;
    
                Console.SetWindowSize(defaultWidth, defaultHeight);
                Console.SetBufferSize(defaultWidth, 300);  //300 Standard Puffer
            }
    

    Gibt es eine Möglichkeit die Werte dynamisch zuzuweisen ohne die Werte im Code zu setzen=?
    Anonsten super die Funktion 🙂


  • Administrator

    kernel64 schrieb:

    Gibt es eine Möglichkeit die Werte dynamisch zuzuweisen ohne die Werte im Code zu setzen=?

    Ehm, wie bitte?

    int val;
    String answer;
    
    do
    {
      Console.Write("Geben sie eine Zahl ein: ");
      answer = Console.ReadLine();
    }
    while(!Int32.TryParse(answer, out val))
    
    Console.BufferWidth = val;
    

    Oder sowas ähnliches...
    Oder was hast du gemeint? 😕

    Grüssli



  • Ich denke das hat er gemeint. Damit der Benutzer aber nicht immer die Größe festlegen muss, könnte man vielleicht noch mit einer XML oder Ini Datei arbeiten.


Anmelden zum Antworten