Autor Beitrag
Palladin007
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1282
Erhaltene Danke: 182

Windows 11 x64 Pro
C# (Visual Studio Preview)
BeitragVerfasst: Mo 09.09.13 12:39 
Moin,


Kennt jemand eine Möglichkeit, wie ich aus der Kodierung der Konsole heraus finden kann, ob die Konsole ein Zeichen darstellen kann, oder nicht?

Ich möchte einen Adapter schreiben, der Zeichen für Zeichen prüft, ob die Eingabe akzeptiert wird und andernfalls einfach nichts tut.
Wenn aber kein Zeichensatz angegeben wurde, dann soll der Satz genommen werden, der alle Zeichen enthält, die dargestellt werden können.


Kennt da wer eine Möglichkeit, bei allen 65535 möglichen Zeichen?


Gruß



PS:
Da ich darauf leider ziemlich schnell eine Antwort benötige, habe ich die gleiche Frage auf einem anderen Forum gestellt. Hier der [url=www.mycsharp.de/wbb2...d=109327]Link[/URL].
Wurde geschlossen -.-
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4798
Erhaltene Danke: 1059

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Mo 09.09.13 13:25 
Hallo Palladin007,

unter WPF (genauer der PresentationCore.dll) gibt es die GlyphTypeface-Klasse, welche Informationen über einen Font enthält. Ansonsten direkt die WinAPI-Funktion GetGlyphIndices() benutzen, s. z.B. C#: Check for unsupported characters/glyphs in a font.
Palladin007 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1282
Erhaltene Danke: 182

Windows 11 x64 Pro
C# (Visual Studio Preview)
BeitragVerfasst: Mo 09.09.13 13:41 
Da ich WPF gerne außen vor lassen möchte, habe ich mir gleich die zweite Möglichkeit angeschaut und das scheint bisher genau das zu sein, was ich suche. :D


Aber eine Frage hab ich noch: Der Font, kann ich davon aus gehen, dass "Courier New" der Font der Konsole ist, oder gibt es da Andere?


Gruß
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4708
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Mo 09.09.13 13:43 
Consolas und Lucida Console. Das ist zumindest bis Windows 7 noch einstellbar. Weiß nicht ob ab 8 da nochwas hinzugekommen ist.


Edit: Raymond Chen mit der Historie zum Thema. Kann also theoretisch ein fast beliebiger Font sein.
Palladin007 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1282
Erhaltene Danke: 182

Windows 11 x64 Pro
C# (Visual Studio Preview)
BeitragVerfasst: Mo 09.09.13 13:52 
Leider hat sich damit jetzt ein weiteres Problem ergeben :(


Scheinbar ist es nicht ohne Weiteres möglich, den aktuellen Font der Konsole heraus zu finden, da es auf der einen Seite einen Font gibt, der von der Konsole selber gerendert wird (Rasterschrift, hab ich irgendwo gelesen) und eine Reihe anderer Fonts, die der Nutzer aber selber fest legen und ich von der Konsole nicht abfragen kann.

Gibt es in C# und .NET eine Möglichkeit, das irgendwie heraus zu finden?
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4798
Erhaltene Danke: 1059

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Mo 09.09.13 13:59 
Hallo nochmal,

das müßte mit der GetCurrentConsoleFontEx-Funktion gehen, d.h. per P/Invoke: pinvoke.net/default....ntConsoleFontEx.html (schau dir die Benutzung dazu bei pinvoke.net/default....rentConsoleFont.html an): FaceName sollte dann der Name des Fonts sein.
Palladin007 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1282
Erhaltene Danke: 182

Windows 11 x64 Pro
C# (Visual Studio Preview)
BeitragVerfasst: Mo 09.09.13 14:44 
Ich hab es jetzt so versucht:

ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    public class CONSOLE_FONT_INFOEX
    {
        private int cbSize;
        public CONSOLE_FONT_INFOEX()
        {
            cbSize = Marshal.SizeOf(typeof(CONSOLE_FONT_INFOEX));
        }
        public int FontIndex;
        public short FontWidth;
        public short FontHeight;
        public int FontFamily;
        public int FontWeight;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
        public string FaceName;
    }

    class ConsoleHelper
    {
        [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
        extern static bool GetCurrentConsoleFontEx(IntPtr hConsoleOutput, bool bMaximumWindow, [In, Out] CONSOLE_FONT_INFOEX lpConsoleCurrentFont);

        public static void GetConsoleFont()
        {
            //Need to use reflection to obtain pointer to the console output buffer
            Type consoleType = typeof(Console);

            IntPtr _consoleOutputHandle = (IntPtr)consoleType.InvokeMember(
              "_consoleOutputHandle",
              BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.GetField,
              null,
              null,
              null);

            //Obtain the current console font index
            CONSOLE_FONT_INFOEX currentFont = new CONSOLE_FONT_INFOEX();
            bool success = GetCurrentConsoleFontEx( _consoleOutputHandle, false, currentFont);


            // Hier ein BreakPoint um mir den Inhalt von currentFont anzusehen
        }
    }



Ich verstehe nur wenig, daher fällt es mir ziemlich schwer, den Fehler zu finden, aber der Inhalt von currentFont ist leer. :/
Ich habe testweise auch mal den Font der Konsole immer geändert und dann geschaut, was drin steht, aber es bleibt leer.





Edit:

Ich habe gerade gesehen, dass ich diese Methode aus deinem dritten Link nutzen kann:

ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
        /// <summary>
        /// returns the current console's output handle as an IntPtr, if it exists
        /// </summary>
        /// <returns>either the current console's output handle, or IntPtr.Zero</returns>
        public static IntPtr getConsoleOutputHandle()
        {
            Type consoleType = typeof(System.Console);

            // for some reason .InvokeMember wasn't working for me, but this strikes me
            // as a bit more clear anyway.  might just be me.  but, it does seem to work.
            FieldInfo _consoleOutputHandle_fieldinfo =
                consoleType.GetField("_consoleOutputHandle", BindingFlags.NonPublic | BindingFlags.Static);

            IntPtr RetVal;

            // after some testing, i realized that the only time i got a value back for the
            // handle was when i poked around in System.Console in the watch window.  after
            // much playing around i finally found that the following works to initialize
            // the handles.  this may have been my issue with the OP's code as well
            System.Console.BackgroundColor = System.Console.BackgroundColor;

            // this is probably a pretty safe operation as System.Console is a static type,
            // but just to be on the safe side might as well do a little exception handling.
            try
            {
                // since System.Console is a static class/type, you just pass null where an
                // object is requested, apparently. i have checked this in the debugger and
                // it does work, so i'll just take people's word for it.
                RetVal = (IntPtr)_consoleOutputHandle_fieldinfo.GetValue(null);
            }

            // not really doing anything if there's an exception; not much to do. could give a
            // parameter name if you wanted to for logging and such.
            catch (Exception)
            {
                RetVal = IntPtr.Zero;
            }

            return RetVal;
        }


Und damit funktioniert es jetzt :D


Ich schreibe das ganze noch ordentlich zusammen und poste dann die ganze Klasse, wenn jemand Anderes das gleiche Problem haben sollte ^^
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4708
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Mo 09.09.13 14:55 
Schreib mal vor den currentFont Parameter ref beim GetCurrentConsoleFontEx Aufruf. hat sich erledigt.
Palladin007 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1282
Erhaltene Danke: 182

Windows 11 x64 Pro
C# (Visual Studio Preview)
BeitragVerfasst: Mo 09.09.13 15:13 
Ein Problem hab ich noch:

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    private class CONSOLE_FONT_INFOEX
    {
        private int cbSize;

        public int FontIndex;
        public short FontWidth;
        public short FontHeight;
        public int FontFamily;
        public int FontWeight;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
        public string FaceName;

        public CONSOLE_FONT_INFOEX()
        {
            cbSize = Marshal.SizeOf(typeof(CONSOLE_FONT_INFOEX));
        }
    }


Das Objeckt davon enthält ja die ausgelesenen Daten.
Aber wie bekomme ich aus Diesen jetzt den passenden Font raus?

Der Name ist ja der Anzeigename des Fonts, nicht der Familien-Namen. Außerdem - wie bekomme ich emSize raus?
Oder die FontFamilie aus dieser Zahl?
Der Style sollte ja unwichtig sein, für das, was ich brauche.



Edit:

Ich hab es jetzt erst einmal so gelöst:

ausblenden C#-Quelltext
1:
new Font(fontInfo.FaceName, fontInfo.FontHeight)					


Es funktioniert, wenn aber da ein Fehler drin sein sollte, oder das nicht ganz genau ist, würde ich mich über Korrekturen freuen.



Für die Neugierigen, hier die ganze Klasse (neben der Klasse CONSOLE_FONT_INFOEX):
ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
    public class ConsoleHelper
    {
        [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
        private extern static bool GetCurrentConsoleFontEx(IntPtr hConsoleOutput, bool bMaximumWindow, [In, Out] CONSOLE_FONT_INFOEX lpConsoleCurrentFont);

        [DllImport("gdi32.dll", EntryPoint = "GetGlyphIndicesW")]
        private static extern uint GetGlyphIndices([In] IntPtr hdc, [In] [MarshalAs(UnmanagedType.LPTStr)] string lpsz, int c, [Out] ushort[] pgi, uint fl);

        [DllImport("gdi32.dll")]
        private static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobj);

        private const uint GGI_MARK_NONEXISTING_GLYPHS = 0x01;
        private static Graphics _graphics = Graphics.FromImage(new Bitmap(11));


        public static bool DoesGlyphExist(char c)
        {
            var fontInfo = GetCurrentConsoleFontEx();
            return DoesGlyphExist(c, new Font(fontInfo.FaceName, fontInfo.FontHeight));
        }


        public static bool DoesGlyphExist(char c, Font font)
        {
            IntPtr hdc = _graphics.GetHdc();
            ushort[] glyphIndices;

            try
            {
                IntPtr hfont = font.ToHfont();

                SelectObject(hdc, hfont);

                string testString = new string(c, 1);
                glyphIndices = new ushort[testString.Length];

                GetGlyphIndices(hdc, testString, testString.Length, glyphIndices, GGI_MARK_NONEXISTING_GLYPHS);

            }
            finally
            {
                _graphics.ReleaseHdc(hdc);
            }

            return (glyphIndices[0] != 0xffff);
        }

        public static CONSOLE_FONT_INFOEX GetCurrentConsoleFontEx()
        {
            Type consoleType = typeof(Console);
            IntPtr _consoleOutputHandle = getConsoleOutputHandle();

            CONSOLE_FONT_INFOEX currentFont = new CONSOLE_FONT_INFOEX();
            bool success = GetCurrentConsoleFontEx( _consoleOutputHandle, false, currentFont);

            return currentFont;
        }

        private static IntPtr getConsoleOutputHandle()
        {
            Type consoleType = typeof(System.Console);
            FieldInfo _consoleOutputHandle_fieldinfo = consoleType.GetField("_consoleOutputHandle", BindingFlags.NonPublic | BindingFlags.Static);
            Console.BackgroundColor = System.Console.BackgroundColor;

            IntPtr RetVal;

            try
            {
                RetVal = (IntPtr)_consoleOutputHandle_fieldinfo.GetValue(null);
            }
            catch (Exception)
            {
                RetVal = IntPtr.Zero;
            }

            return RetVal;
        }    
    }