Home Articles Books Downloads FAQs Tips

Q: Start a program so it obeys the nCmdShow argument (passed by a shortcut)


Answer:

This entire FAQ applies only to C++Builder 1.0. Programs written in C++Builder 1.0 would not obey the nCmdShow argument that was passed to WinMain. C++Builder 3.0 fixed this problem. If you use C++Builder 3.0 or newer, this FAQ should be ignored.

This is an extenstion to the "Starting a program minimized" FAQ. The infamous line in SYSTEM.PAS causes VCL programs to ignore the nCmdShow parameter that is passed to the program. One impact of this is that the user will not be able to choose how to start a program (minimized, maximized, etc) using shortcuts. Plus, a VCL app that is started by the registry Run key or by a line in WIN.INI will be passed an nCmdShow value of SW_SHOWMINNOACTIVATE. Because the VCL ignores the nCmdShow value, C++Builder programs will not conform to the OS requests. You can fix this problem by calling an API function to determine the original nCmdShow value, and placing the program in its proper state based on the value.

Step 1: Choose View|Project Source from the C++Builder menu so you can edit the WinMain function. Call the API GetStartupInfo function to determine the original nCmdShow value. Then react based on the value.

WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
    int MyCmdShow = SW_SHOWDEFAULT;
    STARTUPINFO StartupInfo;
    GetStartupInfo(&StartupInfo);
    if(StartupInfo.dwFlags & STARTF_USESHOWWINDOW)
        MyCmdShow = StartupInfo.wShowWindow;

    try
    {
        Application->Initialize();
        Application->CreateForm(__classid(TForm1), &Form1);

        switch(MyCmdShow)
        {
        case SW_SHOWMINNOACTIVE:   // 7, this is what came from the shortcut
        case SW_MINIMIZE:          // 6
        case SW_SHOWMINIMIZED:     // 2
            Application->ShowMainForm = false;
            Application->Minimize();
            break;
        case SW_SHOWMAXIMIZED:    // SW_SHOWMAXIMIZED and SW_MAXIMIZE are
        case SW_MAXIMIZE:         // same value now. Used to be different
            Application->MainForm->WindowState = wsMaximized;
            break;
        case SW_HIDE:
            Application->ShowMainForm = false;
            ShowWindow(Application->Handle, SW_HIDE);
            break;
        default:
            Application->MainForm->WindowState = wsNormal;
        }

        Application->Run();
    }
    catch (Exception &exception)
    {
        Application->ShowException(&exception);
    }
    return 0;
}

Step 2: Setting ShowMainForm to false has one bad side effect. The form will not appear when the user restores the program by clicking on the taskbar icon. You can solve this problem by creating an OnRestore handler for the application. Open the header file for the main form and add this prototype to your main form's class.

private:	// User declarations
  void __fastcall AppRestore(TObject *Sender);

Step 3: Open the main form's CPP file and code the AppRestore function.

void __fastcall TForm1::AppRestore(TObject *Sender)
{
  Visible = true;
}

Step 4: Assign the AppRestore function to the OnRestore handler of TApplication. Make this assignment in the constructor of the main form.

__fastcall TForm1::TForm1(TComponent* Owner)
	: TForm(Owner)
{
  Application->OnRestore = AppRestore;
}

Final Note: The code works find except for one small glitch. The taskbar icon for the program should not be selected when the program is started with nCmdShow set to SW_SHOWMINNOACTIVATE. The TApplication::CreateHandle function contains code that creates the taskbar icon, and because of the way Windows works, focuses the newly created icon. By the time WinMain executes, its too late to respond to nCmdShow without activating the icon.



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