Angehängte Console soll nicht geschlossen werden können

  • C#

Es gibt 14 Antworten in diesem Thema. Der letzte Beitrag () ist von RodFromGermany.

    Angehängte Console soll nicht geschlossen werden können

    Moin Leute.
    Zum Loggen von Meldungen habe ich mit AllocConsole() ein Console-Fenster an mein Programm angehängt, die mit Console.WriteLine("bla") beschrieben wird.
    Mit

    C#-Quellcode

    1. NativeMethods.DeleteMenu(menu, NativeMethods.SC_CLOSE, NativeMethods.MF_BYCOMMAND);
    wird das Schließen-Kreuz oben rechts ge-disabled, so dass die Console über diesen Weg nicht geschlossen werden kann.
    Nun wird aber die Console in der Taskbar angezeigt, und über das Kreuz dort kann sie geschlossen werden, was ich verhindern möchte, da mit dem Schließen der Console das Hauptfenster ebenfalls geschlossen wird.
    Spoiler anzeigen

    C#-Quellcode

    1. using System;
    2. using System.Windows.Forms;
    3. using System.Runtime.InteropServices;
    4. namespace AppendConsole
    5. {
    6. /// <summary>
    7. /// Klasse zum Aufruf und zur Positionierung der Console,
    8. /// das Close-Systemmenu wird ge-disabled.
    9. /// </summary>
    10. static class NativeMethods
    11. {
    12. private const int SWP_NOSIZE = 0x0001;
    13. private const int MF_BYCOMMAND = 0x00000000;
    14. private const int SC_CLOSE = 0xF060;
    15. private const int SC_MINIMIZE = 0xF020;
    16. private const int SC_MAXIMIZE = 0xF030;
    17. [DllImport("user32.dll")]
    18. public static extern int DeleteMenu(IntPtr hMenu, int nPosition, int wFlags);
    19. [DllImport("user32.dll")]
    20. private static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);
    21. [DllImport("kernel32.dll")]
    22. private static extern bool AllocConsole();
    23. [DllImport("user32.dll", EntryPoint = "SetWindowPos")]
    24. public static extern IntPtr SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int Y, int cx, int cy, int wFlags);
    25. [DllImport("kernel32.dll", SetLastError = true)]
    26. public static extern IntPtr GetConsoleWindow();
    27. internal static void ShowConsole()
    28. {
    29. NativeMethods.AllocConsole();
    30. IntPtr console = NativeMethods.GetConsoleWindow();
    31. IntPtr menu = NativeMethods.GetSystemMenu(console, false);
    32. NativeMethods.DeleteMenu(menu, NativeMethods.SC_CLOSE, NativeMethods.MF_BYCOMMAND);
    33. NativeMethods.DeleteMenu(menu, NativeMethods.SC_MINIMIZE, NativeMethods.MF_BYCOMMAND);
    34. NativeMethods.DeleteMenu(menu, NativeMethods.SC_MAXIMIZE, NativeMethods.MF_BYCOMMAND);
    35. int x = 1400; // unten rechts
    36. int y = 700;
    37. NativeMethods.SetWindowPos(console, IntPtr.Zero, x, y, 0, 0, NativeMethods.SWP_NOSIZE);
    38. }
    39. }
    40. }

    Weiß jemand von Euch, wie entweder dieses Schließen-Kreuz umgangen werden kann
    oder
    wie die Console aus der Taskbar rausgenommen werden kann, so was: Console.ShowInTaskbar = false;
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Unter Windows 10 wird auch im Hauptfenster ein Schließen-Kreuz angezeigt. Was spricht dagegen, die Konsole umzuleiten und z.B. in einer TextBox oder ähnlichem anzuzeigen (Mittels Console.SetOut und eigens definiertem TextWriter) ?
    Huhu,

    ich weiß nicht ob dir das auch weiterhilft es gibt ja eine Möglichkeit die Fenster nicht anzuzeigen.

    Es gibt da in der MSDN folgendes: msdn.microsoft.com/en-us/libra…aspx#Managing_Taskbar_But
    Dazu hat Raymond Chen damals auch noch bissl mehr geschrieben hier: blogs.msdn.microsoft.com/oldnewthing/20031229-00/?p=41283
    Das sind Links die ich mir mal speicherte für den Fall der Fälle und nun brauch sie mal jemand ^^

    Daraus entstand dann folgender Code:

    C#-Quellcode

    1. private const int SW_HIDE = 0x00;
    2. private const int SW_SHOW = 0x05;
    3. private const int WS_EX_APPWINDOW = 0x40000;
    4. private const int GWL_EXSTYLE = -0x14;
    5. private const int WS_EX_TOOLWINDOW = 0x0080;
    6. private static void TaskBarHide()
    7. {
    8. var Handle = FindWindowByCaption(IntPtr.Zero, "fenstername");
    9. ShowWindow(Handle, SW_HIDE);
    10. SetWindowLong(Handle, GWL_EXSTYLE, GetWindowLong(Handle, GWL_EXSTYLE) | WS_EX_TOOLWINDOW);
    11. ShowWindow(Handle, SW_SHOW);
    12. }


    Hier noch für "FindWindowByCaption":
    pinvoke.net/default.aspx/user32.FindWindow

    Den Code oben habe ich mal benutz um Fenster zu wegzumachen in der Taskbar. Sollte eigentlich bis W10 noch funktionieren.
    Kann das jetzt grad nur leider nicht testen ;) Aber laut MSDN / Chen hat sich daran nicht viel geändert.
    Da kann man bestimmt noch bissl mehr machen aber so Profi bin ich dann nun auch wieder nicht.
    Hoffe ich konnte wenigstens ein wenig helfen.
    Grüße , xChRoNiKx

    Nützliche Links:
    Visual Studio Empfohlene Einstellungen | Try-Catch heißes Eisen

    Quadsoft schrieb:

    wird auch im Hauptfenster ein Schließen-Kreuz angezeigt.
    Klar. Über dieses frage ich im FormClosing-Event auch ab, ob ungespeicherte Daten noch gespeichert werden sollen.
    Leider läuft das direkte Schließen der Console daran vorbei.
    Das mit dem Umleiten werd ich mal probieren.
    @xChRoNiKx Dein Code macht aus der Console ein ToolWindow, das Verhalten bezüglich Close ändert sich dabei nicht.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    @nafets Das SC_CLOSE ist bereits deletet worden, außerdem funktioniert dieses Snippet nicht mal beim Console-Fenster selbst. ;(
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    RodFromGermany schrieb:

    Quadsoft schrieb:

    wird auch im Hauptfenster ein Schließen-Kreuz angezeigt.
    Klar. Über dieses frage ich im FormClosing-Event auch ab, ob ungespeicherte Daten noch gespeichert werden sollen.

    Ich meinte eigentlich, dass das Konsolenfenster trotzdem noch den X-Button hat. (nicht das Fenster der .NET-Anwendung)
    @Quadsoft Das Fenster der Console hat einen (x)-Button, der kann ge-disabled werden.
    Das Console-Icon in der Taskbar hat einen weiteren (x)-Button, der nicht ge-disabled werden kann, der aber das anhängende Programm ohne Warnung beendet.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    RodFromGermany schrieb:

    @Quadsoft Das Fenster der Console hat einen (x)-Button, der kann ge-disabled werden.

    Eben dieser Button wird bei mir unter Windows 10 trotzdem angezeigt ;)

    RodFromGermany schrieb:

    wie die Console aus der Taskbar rausgenommen werden kann

    Dafür könntest du auf das Interface TaskbarList zurückgreifen. Dabei besteht aber das Problem, dass bei Aktivierung des Fensters, der TaskbarButton wieder hergestellt wird. Du müsstest also, so lange die Console aufgeführt wird, kontinuierlich das ForegroundWindow prüfen und ggf. den TaskbarButton der Console wieder entfernen.
    Alternativ kannst du versuchen den WindowStyle der Console um WS_EX_TOOLWINDOW zu erweitern.

    Quadsoft schrieb:

    angezeigt
    wird er auch unter W7, da wird er bei MouseMove grau.
    @Fakiz Das werd ich mir mal näher ansehen.
    Das WS_EX_TOOLWINDOW nimmt nur die Min-Max-Buttons raus und verkleinert den (x)-Button.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    @Fakiz Ich hab mal versucht das umzusetzen (Quelle von pinvoke):
    Spoiler anzeigen

    C#-Quellcode

    1. using System;
    2. using System.Runtime.CompilerServices;
    3. using System.Runtime.InteropServices;
    4. //http://pinvoke.net/default.aspx/shell32/ITaskbarList.html
    5. namespace ConsoleDoNotClose
    6. {
    7. [ComImport,
    8. Guid("56fdf342-fd6d-11d0-958a-006097c9a090"),
    9. InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    10. public interface ITaskbarList
    11. {
    12. /// <summary>
    13. /// Initializes the taskbar list object. This method must be called before any other ITaskbarList methods can be called.
    14. /// </summary>
    15. int HrInit();
    16. /// <summary>
    17. /// Adds an item to the taskbar.
    18. /// </summary>
    19. /// <param name="hWnd">A handle to the window to be added to the taskbar.</param>
    20. int AddTab([In] IntPtr hWnd);
    21. /// <summary>
    22. /// Deletes an item from the taskbar.
    23. /// </summary>
    24. /// <param name="hWnd">A handle to the window to be deleted from the taskbar.</param>
    25. int DeleteTab([In] IntPtr hWnd);
    26. /// <summary>
    27. /// Activates an item on the taskbar. The window is not actually activated; the window's item on the taskbar is merely displayed as active.
    28. /// </summary>
    29. /// <param name="hWnd">A handle to the window on the taskbar to be displayed as active.</param>
    30. int ActivateTab([In] IntPtr hWnd);
    31. /// <summary>
    32. /// Marks a taskbar item as active but does not visually activate it.
    33. /// </summary>
    34. /// <param name="hWnd">A handle to the window to be marked as active.</param>
    35. int SetActivateAlt([In] IntPtr hWnd);
    36. }
    37. [ComImport]
    38. [Guid("56fdf344-fd6d-11d0-958a-006097c9a090")]
    39. public class CoTaskbarList
    40. : ITaskbarList
    41. {
    42. public extern int HrInit();
    43. public extern int AddTab(IntPtr hwnd);
    44. public extern int DeleteTab(IntPtr hwnd);
    45. public extern int ActivateTab(IntPtr hwnd);
    46. public extern int SetActivateAlt(IntPtr hwnd);
    47. }
    48. }
    Beim Aufruf über

    C#-Quellcode

    1. IntPtr windowHandle = NativeMethods.GetConsoleWindow();
    2. CoTaskbarList taskbarList = new CoTaskbarList();
    3. taskbarList.HrInit(); // <- hier
    4. taskbarList.DeleteTab(windowHandle);
    kommt die Exception
    Der Typ "ConsoleDoNotClose.CoTaskbarList" der Assembly "ConsoleDoNotClose, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" konnte nicht geladen werden, da die Methode "HrInit" keine Implementierung (keine RVA) hat.
    Kann mir jemand von Euch sagen, wie ich an die eigentliche Implementierung komme?
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Hi,
    frag mich nicht wie man's in .Net ändert, aber in C++ machte der Wechsel von CLSCTX_INPROC_HANDLER zu CLSCTX_INPROC_SERVER den Unterschied. Vorher > Interface nicht registriert, nacher > i.O.
    Spoiler anzeigen

    C-Quellcode

    1. int main()
    2. {
    3. if (FAILED(CoInitialize(0)))
    4. {
    5. cerr << "Can't init COM";
    6. return EXIT_FAILURE;
    7. }
    8. ITaskbarList* tl = 0;
    9. if (FAILED(CoCreateInstance(CLSID_TaskbarList, 0, CLSCTX_SERVER, IID_ITaskbarList, (void**)&tl)))
    10. {
    11. cerr << "Unsupported" << endl;
    12. return EXIT_FAILURE;
    13. }
    14. HWND hWnd = GetConsoleWindow();
    15. HMENU hMenu = GetSystemMenu(hWnd, FALSE);
    16. DeleteMenu(hMenu, SC_CLOSE, MF_BYCOMMAND);
    17. tl->HrInit();
    18. tl->DeleteTab(hWnd);
    19. cin.get();
    20. tl->Release();
    21. CoUninitialize();
    22. return EXIT_SUCCESS;
    23. }

    Die Konsole kann man nur noch über Alt+F4 schließen, alles Andere ist erstmal weg.
    Es ist vollbracht. :thumbsup:
    Dank der Hilfe und der Hinweise von @Gonger96 und @Fakiz kann ich nun den Zielcode

    C#-Quellcode

    1. Console.ShowInTaskbar = false;
    umsetzen.
    Falls das noch jemanden interessieren sollte, packe ich das Resultat in den Sourcecode-Austausch.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „RodFromGermany“ ()