Home Articles Books Downloads FAQs Tips

Q: Start a program hidden


Answer:

To start a program hidden, you must edit the WinMain function and hide the program's main form and the program's taskbar icon.

Step 1: Choose View|Project Source from the C++Builder menu so you can edit the WinMain function. Hide the program's taskbar icon by calling ShowWindow for the application's window handle. Set ShowMainForm to false to keep the main form from appearing on the screen.

WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
    try
    {
        Application->Initialize();
        Application->CreateForm(__classid(TForm1), &Form1);
        Application->ShowMainForm = false;
        ShowWindow(Application->Handle, SW_HIDE);
        Application->Run();
    }
    catch (Exception &exception)
    {
        Application->ShowException(&exception);
    }
    return 0;
}

Step 2: Execute these two code statements when you want to show the application. Note that Application->MainForm->Visible=true can be shortened to just Visible=true if the code is located in a method of the main form's class.

ShowWindow(Application->Handle, SW_SHOW);
Application->MainForm->Visible = true;

Final Note (C++Builder 1.0 only): In C++Builder 1.0, the constructor for the global TApplication object called the CreateHandle method. CreateHandle executed API functions to create a window handle for the application. Creating the window handle resulted in a taskbar icon appearing on the screen. This icon would appear before WinMain ran. This icon would appear to flash if WinMain was trying to create a program that started in a hidden state. The rest of this FAQ explains how to eliminate the taskbar icon flash that occurred in C++Builder 1.0 programs. C++Builder 3.0 contained a fix for the shortcoming in TApplication. If you use C++Builder 3.0, ignore what follows.

Because of the way the VCL works, the application's icon will flash briefly on the taskbar before the ShowWindow call executes inside of WinMain.

The VCL creates the global application object before WinMain is called. The TApplication constructor executes a function called CreateHandle that creates a window handle and places an icon on the taskbar. The only way to keep the icon from flashing is to provide a different version of CreateHandle. This isn't too hard if you have the professional or client/server versions of C++Builder. You can simply copy \SOURCE\VCL\FORMS.PAS to your project directory, add this file to your project, and fix the flaws in CreateHandle. CreateHandle contains two statements that force an icon to appear on the taskbar. The first is the CreateWindow call, which looks like this:

    FHandle := CreateWindow(WindowClass.lpszClassName, PChar(FTitle),
      WS_POPUP or WS_CAPTION or WS_VISIBLE or WS_CLIPSIBLINGS or
      WS_SYSMENU or WS_MINIMIZEBOX,
      GetSystemMetrics(SM_CXSCREEN) div 2,
      GetSystemMetrics(SM_CYSCREEN) div 2,
      0, 0, 0, 0, HInstance, nil);

The second call is the call to ShowWinNoAnimate. ShowWinNoAnimate is a VCL function whose arguments reflect a ShowWindow API call.

    ShowWinNoAnimate(FHandle, SW_RESTORE);

In the CreateWindow call, the WS_VISIBLE style causes the taskbar icon to appear. You can fix this by simply deleting the WS_VISIBLE style. The ShowWinNoAnimate call ends up passing SW_RESTORE to the API ShowWindow function. SW_RESTORE shows and restores a window, and showing the form places the icon on the taskbar. You can prevent this by changing SW_RESTORE to SW_HIDE, or by commenting out the call altogether. The new version of CreateHandle should look like this:

    procedure TApplication.CreateHandle;
    var
      TempClass: TWndClass;
      SysMenu: HMenu;
    begin
      if not FHandleCreated then
      begin
        FObjectInstance := MakeObjectInstance(WndProc);
        if not GetClassInfo(HInstance, WindowClass.lpszClassName, TempClass)
        then
        begin
          WindowClass.hInstance := HInstance;
          if Windows.RegisterClass(WindowClass) = 0 then
            raise EOutOfResources.CreateRes(SWindowClass);
        end;
        FHandle := CreateWindow(WindowClass.lpszClassName, PChar(FTitle),
          WS_POPUP or WS_CAPTION or WS_CLIPSIBLINGS or
          WS_SYSMENU or WS_MINIMIZEBOX,
          GetSystemMetrics(SM_CXSCREEN) div 2,
          GetSystemMetrics(SM_CYSCREEN) div 2,
          0, 0, 0, 0, HInstance, nil);
        FTitle := '';
        FHandleCreated := True;
        ShowWinNoAnimate(FHandle, SW_HIDE);
        SetWindowLong(FHandle, GWL_WNDPROC, Longint(FObjectInstance));
        if NewStyleControls then
          SendMessage(FHandle, WM_SETICON, 1, GetIconHandle);
        SysMenu := GetSystemMenu(FHandle, False);
        DeleteMenu(SysMenu, SC_MAXIMIZE, MF_BYCOMMAND);
        DeleteMenu(SysMenu, SC_SIZE, MF_BYCOMMAND);
        if NewStyleControls then DeleteMenu(SysMenu, SC_MOVE, MF_BYCOMMAND);
      end;
    end;

Important: Make sure you modify the version of FORMS.PAS that you copied to your project directory and added to your project. Do not modify the file in \SOURCE\VCL.

So what if you have the standard version of C++Builder and don't have access to the VCL source? You can code your own version of TApplication::CreateHandle in your project source file using C++. The linker will utilize your updated version of the function instead of the function in the VCL library files. The C++ function should look like this (insert this just before the WinMain function).

void __fastcall TApplication::CreateHandle(void)
{
    WNDCLASS WindowClass ;
    WindowClass.style=0;
    WindowClass.lpfnWndProc=DefWindowProc;
    WindowClass.cbClsExtra=0;
    WindowClass.cbWndExtra=0;
    WindowClass.hInstance =0;
    WindowClass.hIcon= 0;
    WindowClass.hCursor= 0;
    WindowClass.hbrBackground= 0;
    WindowClass.lpszMenuName = NULL;
    WindowClass.lpszClassName= "TApplication";

    TWndClass TempClass;
    HMENU     SysMenu;

    if(!FHandleCreated)
    {
        FObjectInstance = MakeObjectInstance(WndProc);
        if (!GetClassInfo(HInstance, WindowClass.lpszClassName, &TempClass))
        {
            WindowClass.hInstance = HInstance;
            if (RegisterClass(&WindowClass) == 0)
                throw EOutOfResources("Error registering window class");
        }
        FHandle = CreateWindow(WindowClass.lpszClassName, FTitle.c_str(),
                               WS_POPUP | WS_CAPTION | WS_CLIPSIBLINGS |
                               WS_SYSMENU | WS_MINIMIZEBOX,
                               GetSystemMetrics(SM_CXSCREEN) / 2,
                               GetSystemMetrics(SM_CYSCREEN) / 2,
                               0, 0, 0, 0, HInstance, NULL);
        FTitle = "";
        FHandleCreated = True;
        // ShowWinNoAnimate(FHandle, SW_HIDE);
        SetWindowLong(FHandle, GWL_WNDPROC, Longint(FObjectInstance));
        if (NewStyleControls)
            SendMessage(FHandle, WM_SETICON, 1, (LPARAM)GetIconHandle());
        SysMenu = GetSystemMenu(FHandle, False);
        DeleteMenu(SysMenu, SC_MAXIMIZE, MF_BYCOMMAND);
        DeleteMenu(SysMenu, SC_SIZE, MF_BYCOMMAND);
        if (NewStyleControls)
            DeleteMenu(SysMenu, SC_MOVE, MF_BYCOMMAND);
    }
}



Copyright © 1997-2000 by Harold Howe.
All rights reserved.