Autor Beitrag
Kasko
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 126
Erhaltene Danke: 1

Win 10
C# C++ (VS 2017/19), (Java, PHP)
BeitragVerfasst: Sa 26.01.19 23:34 
In C++ ist es ja relativ einfach ein einfaches Fenster mithilfe der Win32-API zu erstellen (wWinMain,WndProc,...).
Ist dies auch in C# möglich ohne Formulare zu verwenden. Es soll wirklich nur ein ganz einfaches Fenster sein.
Christian S.
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 20451
Erhaltene Danke: 2264

Win 10
C# (VS 2019)
BeitragVerfasst: So 27.01.19 00:47 
Du kannst natürlich jede Win32-API-Funktion auch in .NET aufrufen (mittels PInvoke). Aber so richtig sinnvoll klingt das nicht. Was möchtest Du denn letzten Endes damit erreichen?

_________________
Zwei Worte werden Dir im Leben viele Türen öffnen - "ziehen" und "drücken".
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: So 27.01.19 05:09 
"ohne Formulare" und "wirklich nur ein ganz einfaches Fenster" wiederspricht sich ;)

Du kannst natürlich WPF verwenden, da heißen die Fenster nicht mehr "Formular" sondern "Window" :D
Oder ASP.NET (Core), da ist's dann halt eine Website

Welche der drei Optionen (WinForms, WPF, WinAPI, APS.NET) Du verwenden willst, die WinAPI ist vermutlich die am wenigsten einfache Option ;)
Natürlich musst Du dich dazu erst einmal damit auseinander setzen, für einen Umsteiger von C** mag das etwas umständlich und ungewohnt sein, aber glaube mir: Du sparst dir damit sehr viel Arbeit und Nerven. Abgesehen davon sind WinForms und WPF (ohne MVVM, ist aber nicht empfohlen!) sehr einfach in der Anwendung, ein einfaches Fenster mit TextBox und Button kriegst Du in fünf Minuten auf die Beine gestellt.
Frühlingsrolle
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: So 27.01.19 18:36 
- Nachträglich durch die Entwickler-Ecke gelöscht -
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: So 27.01.19 18:51 
Dann wäre es wohl besser, anstatt per P/Invoke die ganzen WinAPI-Funktionen zu benutzen, ein C++/CLI-Projekt (Assembly) dafür zu erstellen und direkt per C++ diese Funktionen aufzurufen.
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 28.01.19 03:48 
Wäre es da nicht besser, eine normale WinForms-Anwendung zu bauen und dann ein Konsolen-Fenster auf zu machen?
Ich meine mich zu erinnern, dass man über die WinAPI und recht geringem Aufwand sowas machen kann - ist allerdings schon eine Weile her, sicher bin ich mir daher nicht.
Frühlingsrolle
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Sa 02.02.19 06:43 
- Nachträglich durch die Entwickler-Ecke gelöscht -


Zuletzt bearbeitet von Frühlingsrolle am Sa 02.02.19 16:33, insgesamt 1-mal bearbeitet
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: Sa 02.02.19 13:33 
Eine überschaubare, kleine Klasse (und eine kleine Helfer-Klasse mit den Kernel32-Methoden):

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:
79:
80:
81:
82:
83:
public static class Kernel32
{
    private const string DLL = "kernel32.dll";
        
    [DllImport(DLL, SetLastError = true, ExactSpelling = true)]
    public static extern bool FreeConsole();

    [DllImport(DLL)]
    public static extern bool AllocConsole();

    [DllImport(DLL, CharSet = CharSet.Auto)]
    public static extern IntPtr CreateFileW(string lpFileName, uint dwDesiredAccess, uint dwShareMode, IntPtr lpSecurityAttributes, uint dwCreationDisposition, uint dwFlagsAndAttributes, IntPtr hTemplateFile);

    [DllImport(DLL)]
    public static extern bool CancelIoEx(IntPtr handle, IntPtr lpOverlapped);
}

public static class WinConsole
{
    private static FileStream _inStream;
    private static FileStream _outStream;

    public static bool IsAttached { get; private set; }

    public static void Open()
    {
        IsAttached = Kernel32.AllocConsole();

        if (IsAttached)
        {
            InitInStream();
            InitOutStream();
        }
    }
    public static void Close()
    {
        if (!IsAttached)
            return;

        Kernel32.CancelIoEx(_inStream.SafeFileHandle.DangerousGetHandle(), IntPtr.Zero);
        Kernel32.CancelIoEx(_outStream.SafeFileHandle.DangerousGetHandle(), IntPtr.Zero);
        Kernel32.FreeConsole();

        _inStream.Dispose();
        _outStream.Dispose();
    }

    private static void InitInStream()
    {
        _inStream = CreateFileStream("CONIN$", GENERIC_READ, FILE_SHARE_READ, FileAccess.Read);

        if (_inStream != null)
            Console.SetIn(new StreamReader(_inStream));
    }
    private static void InitOutStream()
    {
        _outStream = CreateFileStream("CONOUT$", GENERIC_WRITE, FILE_SHARE_WRITE, FileAccess.Write);

        if (_outStream != null)
        {
            var writer = new StreamWriter(_outStream) { AutoFlush = true };

            Console.SetOut(writer);
            Console.SetError(writer);
        }
    }

    private static FileStream CreateFileStream(string name, uint win32DesiredAccess, uint win32ShareMode, FileAccess dotNetFileAccess)
    {
        var file = new SafeFileHandle(Kernel32.CreateFileW(name, win32DesiredAccess, win32ShareMode, IntPtr.Zero, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, IntPtr.Zero), true);

        return file.IsInvalid
            ? null
            : new FileStream(file, dotNetFileAccess);
    }
        
    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;
}


Ein Nutzungs-Beispiel:

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:
public partial class Form1 : Form
{
    private readonly TextBox _consoleTextBox;
    private CancellationTokenSource _readConsoleCancelTokenSource;
    private Task _readConsoleTask;

    public Form1()
    {
        InitializeComponent();

        Controls.Add(_consoleTextBox = new TextBox()
        {
            Multiline = true,
            Dock = DockStyle.Fill,
        });
    }

    protected override void OnLoad(EventArgs e)
    {
        WinConsole.Open();

        _readConsoleCancelTokenSource = new CancellationTokenSource();
        _readConsoleTask = ReadConsoleAsync(_readConsoleCancelTokenSource.Token);

        base.OnLoad(e);
    }
    protected override async void OnClosing(CancelEventArgs e)
    {
        _readConsoleCancelTokenSource.Cancel();
        WinConsole.Close();
        await _readConsoleTask;
        _readConsoleCancelTokenSource.Dispose();

        base.OnClosing(e);
    }

    private async Task ReadConsoleAsync(CancellationToken cancelToken)
    {
        if (cancelToken.IsCancellationRequested)
            return;

        var line = await Task.Run(() =>
        {
            try
            {
                Console.Write("Write something: ");
                return Console.ReadLine();
            }
            catch (OperationCanceledException)
            {
                return null;
            }

        }, cancelToken);

        if (cancelToken.IsCancellationRequested)
            return;

        if (!string.IsNullOrEmpty(line))
            _consoleTextBox.AppendText(line + Environment.NewLine);

        await ReadConsoleAsync(cancelToken);
    }
}


Das Fehler-Handling kann man sicher noch optimieren und ob alles sauber aufgeräumt wird, kann ich auch nicht sagen, aber es funktioniert.

Eine in sich abgeschlossene Klasse, die dafür sorgt, dass eine WinForms-Anwendung eine funktionierende und nutzbare Konsole bekommt - WinForms funktioniert weiterhin.
Ich verstehe nicht ganz, warum es vernünftiger ist, das Window über die WinAPI per Hand nachzubauen - das was WinForms schon vollständig übernimmt. Ich bastel mir lieber eine Konsole nach, die nicht so aufwändig zu nutzen ist.

PS:
Getestet auf Win10 x64. Eine Garantie für ältere Versionen kann ich natürlich nicht bieten.
Frühlingsrolle
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Sa 02.02.19 17:26 
- Nachträglich durch die Entwickler-Ecke gelöscht -
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: Sa 02.02.19 18:58 
Das ist entstanden, indem ich ein bisschen gegoogelt habe :D
Keine Garantie auf Vollständigkeit oder sauberen Code ^^

Das dient nur als Beispiel, wie einfach es ist, eine Konsole zu einer WinForms- oder WPF-Anwendung dazu zu holen und nutzbar zu machen.


Wobei es vielleicht auch eine Idee ist, einfach eine zweite Konsolen-App daneben zu stellen und die kommuniziert dann mit der WinForms- oder WPF-Anwendung.
Das ist nicht viel komplexer als das hier, wenn man z.B. WCF nutzt, denn wenn man eine Konsole dazu holt. Und man spart sich die WinApi
Frühlingsrolle
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Sa 02.02.19 19:11 
- Nachträglich durch die Entwickler-Ecke gelöscht -