Search code examples
delphiconsole-applicationdelphi-2010taskbar

How to hide console application into Tray?


I want my console application to be hidden in the system tray after it starts. When working with a GUI application, I used TTrayIcon, and it worked without any problems. For the console application, I used the ShowWindow function with SW_HIDE and TNotifyIconData to create an icon in the tray, but I encountered a problem with the console icon still appearing in the Windows taskbar.

procedure HideShowConsoleWindow(isShowForm: Boolean);
var
  Style: LongInt;
  app: THandle;
begin
  app := GetConsoleWindow;
  Style := GetWindowLong(GetConsoleWindow, GWL_EXSTYLE);
  if isShowForm then
  begin
    SetWindowLong(app, GWL_EXSTYLE, Style or WS_EX_TOOLWINDOW and not WS_EX_APPWINDOW);
    ShowWindow(app, SW_HIDE);
  end
  else
  begin
    SetWindowLong(app, GWL_EXSTYLE, Style and not WS_EX_TOOLWINDOW or WS_EX_APPWINDOW);
    ShowWindow(app, SW_SHOW);
  end;
end;

procedure AddTrayIcon;
var
  NotifyIconData: TNotifyIconData;
begin
  FillChar(NotifyIconData, SizeOf(TNotifyIconData), 0);
  NotifyIconData.cbSize := SizeOf(TNotifyIconData);
  NotifyIconData.Wnd := GetConsoleWindow;
  NotifyIconData.uID := 1;
  NotifyIconData.uFlags := NIF_ICON or NIF_MESSAGE or NIF_TIP;
  NotifyIconData.uCallbackMessage := $0400 + 1;
  NotifyIconData.hIcon := LoadIcon(0, IDI_APPLICATION);
  StrPCopy(NotifyIconData.szTip, 'My Console App');
  Shell_NotifyIcon(NIM_ADD, @NotifyIconData);
end;

Is there any way to hide the console application from the taskbar and add it to the system tray?


Solution

  • Cannot reproduce using Delphi 7 on Windows 7x64: my program succeeds in hiding both the console window and its task button:

    program HideConsoleWindow;
    
    {$APPTYPE CONSOLE}
    
    const
      SW_HIDE= 0;
      user32= 'user32.dll';
      kernel32= 'kernel32.dll';
    
    type
      HWND= type LongWord;
      BOOL= LongBool;
    
      function GetConsoleWindow(): HWND; stdcall; external kernel32 name 'GetConsoleWindow';
      function GetForegroundWindow(): HWND; stdcall; external user32 name 'GetForegroundWindow';
      function SetForegroundWindow( h: HWND ): BOOL; stdcall; external user32 name 'SetForegroundWindow';
      function ShowWindow( h: HWND; nCmdShow: Integer ): BOOL; stdcall; external user32 name 'ShowWindow';
    
    var
      hConsole, hFore: HWND;
    
    begin
      hConsole:= GetConsoleWindow();
      if hConsole<> 0 then begin
        if SetForegroundWindow( hConsole ) then begin
          hFore:= GetForegroundWindow();
          if hFore<> 0 then begin
            ShowWindow( hFore, SW_HIDE );
            // Task button should be gone also in recent Windows versions.
          end else begin
            // No foreground window available - still try to set window.
            ShowWindow( hConsole, SW_HIDE );
          end;
        end else begin
          // Console wasn't brought to foreground - still try to set window.
          ShowWindow( hConsole, SW_HIDE );
        end;
      end else begin
        // Couldn't get console window.
      end;
    end.
    

    You shouldn't fiddle with GWL_EXSTYLE at all. And you should be aware of that if you start this program in an existing console you'll also hide that console window - maybe that's something you don't want to do, as it still lives on and then you're only left with killing its process.