~ruther/NosSmooth.Comms

ref: 732cdbfc1478a3a9c4722c8b7c59b1c325d3258a NosSmooth.Comms/src/Local/NosSmooth.Comms.Inject/WinConsole.cs -rw-r--r-- 3.9 KiB
732cdbfc — František Boháček feat: safely call message responders to catch exceptions 2 years ago
                                                                                
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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
//
//  WinConsole.cs
//
//  Copyright (c) František Boháček. All rights reserved.
//  Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;

namespace NosSmooth.Comms.Inject;

/// <summary>
/// A class for managing Windows console.
/// </summary>
internal static class WinConsole
{
    /// <summary>
    /// Initialize a console.
    /// </summary>
    /// <param name="alwaysCreateNewConsole">Whether to create (true) or attach (false) to a console.</param>
    public static void Initialize(bool alwaysCreateNewConsole = true)
    {
#if WINDOWS
        bool consoleAttached = true;
        if (alwaysCreateNewConsole
            || (AttachConsole(ATTACH_PARRENT) == 0
                && Marshal.GetLastWin32Error() != ERROR_ACCESS_DENIED))
        {
            consoleAttached = AllocConsole() != 0;
        }

        if (consoleAttached)
        {
            InitializeOutStream();
            InitializeInStream();
        }
#endif
    }

    /// <summary>
    /// Close a console.
    /// </summary>
    public static void Close()
    {
#if WINDOWS
        FreeConsole();
#endif
    }
#if WINDOWS
    private static void InitializeOutStream()
    {
        var fs = CreateFileStream("CONOUT$", GENERIC_WRITE, FILE_SHARE_WRITE, FileAccess.Write);
        if (fs != null)
        {
            var writer = new StreamWriter(fs) { AutoFlush = true };
            Console.SetOut(writer);
            Console.SetError(writer);
        }
    }

    private static void InitializeInStream()
    {
        var fs = CreateFileStream("CONIN$", GENERIC_READ, FILE_SHARE_READ, FileAccess.Read);
        if (fs != null)
        {
            Console.SetIn(new StreamReader(fs));
        }
    }

    private static FileStream? CreateFileStream
    (
        string name,
        uint win32DesiredAccess,
        uint win32ShareMode,
        FileAccess dotNetFileAccess
    )
    {
        var file = new SafeFileHandle
        (
            CreateFileW
            (
                name,
                win32DesiredAccess,
                win32ShareMode,
                IntPtr.Zero,
                OPEN_EXISTING,
                FILE_ATTRIBUTE_NORMAL,
                IntPtr.Zero
            ),
            true
        );
        if (!file.IsInvalid)
        {
            var fs = new FileStream(file, dotNetFileAccess);
            return fs;
        }
        return null;
    }

    [DllImport
    (
        "kernel32.dll",
        EntryPoint = "AllocConsole",
        SetLastError = true,
        CharSet = CharSet.Auto,
        CallingConvention = CallingConvention.StdCall
    )]
    private static extern int AllocConsole();

    [DllImport
    (
        "kernel32.dll",
        EntryPoint = "AttachConsole",
        SetLastError = true,
        CharSet = CharSet.Auto,
        CallingConvention = CallingConvention.StdCall
    )]
    private static extern uint AttachConsole(uint dwProcessId);

    [DllImport
    (
        "kernel32.dll",
        EntryPoint = "CreateFileW",
        SetLastError = true,
        CharSet = CharSet.Auto,
        CallingConvention = CallingConvention.StdCall
    )]
    private static extern IntPtr CreateFileW
    (
        string lpFileName,
        uint dwDesiredAccess,
        uint dwShareMode,
        IntPtr lpSecurityAttributes,
        uint dwCreationDisposition,
        uint dwFlagsAndAttributes,
        IntPtr hTemplateFile
    );

    [DllImport("kernel32")]
    private static extern bool FreeConsole();
#endif

    private const uint GENERIC_WRITE = 0x40000000;
    private const uint GENERIC_READ = 0x80000000;
    private const uint FILE_SHARE_READ = 0x00000001;
    private const uint FILE_SHARE_WRITE = 0x00000002;
    private const uint OPEN_EXISTING = 0x00000003;
    private const uint FILE_ATTRIBUTE_NORMAL = 0x80;
    private const uint ERROR_ACCESS_DENIED = 5;

    private const uint ATTACH_PARRENT = 0xFFFFFFFF;
}
Do not follow this link