The Screen Saver

InitInstance() Method

This page discusses the InitInstance() method of the screen saver's application class, and shows the code that needs to be inserted.


I've had enough! I want to go home

I want to see the previous page

Take me to the next page


The InitInstance() method

InitInstance() is a method of the CWinApp class, and it gets executed when your screen saver starts execution. This method needs to examine the command line arguments, then cause the appropriate windows to be created and displayed.

The App Wizard generates a default InitInstance() body for you. One of the first steps you made was to delete most of the code from it.

Now display the InitInstance() method again, and make the changes that follow.


Specifying the registry key

You should change the ‘SetRegistryKey’ call that gets automatically generatedcall to use a name that is appropriate to you. The string you specify is used as the company name in the registry key that your program will create and use :


I just use my name ("Mindcaster").

The application name () will be the same as your screen saver file name, unless you put a value into the ‘m_lpszAppName’ member of your CWinApp object, or set up a resource string (as explained previously).

The ‘SetRegistryKey’ function lets you use the ‘GetProfileInt’, ‘GetProfileString’, ‘WriteProfileInt’ and ‘WriteProfileString’ functions to retrieve and store registry values.

If you are going to use the proper registry API’s instead (‘RegCreateKeyEx’, ‘RegSetValueEx’, ‘RegOpenKeyEx’, ‘RegQueryValueEx’ and ‘RegCloseKey’) then you can delete the ‘SetRegistryKey’ call, although you'll have to figure out how to do this yourself.

Replacement Code :

// Change the registry key under which our settings are stored.
SetRegistryKey(_T("Mindcaster"));


The rest of the code is inserted after the 'SetRegistryKey' call.


Examine the first command line parameter

This code examines the first command line parameter, which tells your screen saver what it should do. This will be :

For ‘/a’, ‘/p’ and ‘/c’, a window handle may follow, in the form of a string containing an integer value. Sometimes a space character separates the command from the handle, and sometimes it is a colon character. The code below looks for either a space or a colon.

One of the examples I read mentioned that the command may have a hyphen ("-") instead of a slash ("/") in front of the letter, or no character at all. The code also caters for this, just in case.

Code :

char token[201] ;

for ( int i = 0 ; i < 200 && i < strlen(m_lpCmdLine) && m_lpCmdLine[i] != ' ' 
                    && m_lpCmdLine[i] != ':' ; i++ )
    token[i] = m_lpCmdLine[i] ;

token[i] = '\0' ; 


Run the full-screen saver ("/s")

If the first command line parameter is "/s", the screen saver should be run in full-screen mode.

All that needs to be done is to create an instance of the full-screen window, and call its ‘Create’ function.

if ( !strcmpi(token,"/s") || 
     !strcmpi(token,"-s") || 
     !strcmpi(token,"s") ) 
{
    // Run as screen saver
    FullScreenWnd* pWnd = new FullScreenWnd;
    pWnd->Create();
    m_pMainWnd = pWnd;
    return TRUE;
}


Display the ‘change password’ dialog box ("/a")

If the first command line parameter is "/a", it is a request to display the "change password" dialog box.

This code converts the string containing the window handle to its integer value and recasts it as a window handle. It then dynamically links to the standard password change dialog box, specifying the window handle to be the parent window.

If no window handle was supplied, the current foreground window gets used as the parent.

if ( !strcmpi(token,"/a") || 
     !strcmpi(token,"-a") || 
     !strcmpi(token,"a") )
{
    int iHandle = 0 ;
    if ( i < 200 && i < strlen(m_lpCmdLine) )
    {
        // skip spaces up to the number

        for ( ; 
              i < 200 && i < strlen(m_lpCmdLine) 
                      && m_lpCmdLine[i] == ' ' ; 
              i++ ) ;
        if ( i < 200 && i < strlen(m_lpCmdLine) ) 
        {
            for ( ; 
                  i < 200 && i < strlen(m_lpCmdLine) 
                          && m_lpCmdLine[i] >= '0'
                          && m_lpCmdLine[i] <= '9' ; 
                  i++ )
               iHandle = iHandle * 10 + m_lpCmdLine[i] - '0' ;
       }
    }
    // display "standard" screensaver password change screen

    HWND hParent = (iHandle == 0 ) ? ::GetForegroundWindow() : (HWND)iHandle ;

    // Load dynamically, because Windows NT doesn't have this

    HINSTANCE hMprDll = ::LoadLibrary("MPR.DLL") ;
    if ( hMprDll != NULL ) 
    {
        // dynamic call of standard screen saver password change screen

        typedef VOID (WINAPI *PWDCHANGEPASSWORDA)(LPSTR,HWND,UINT,UINT) ;
        PWDCHANGEPASSWORDA PwdChangePasswordA =
          (PWDCHANGEPASSWORDA)::GetProcAddress(hMprDll, "PwdChangePasswordA");
       if ( PwdChangePasswordA != NULL )
           PwdChangePasswordA("SCRSAVE", hParent, 0, 0 );
    }
    ::FreeLibrary ( hMprDll ) ;

    return TRUE ;
}

I suppose I could have used 'strtol' to get the window handle value instead of doing it myself. Change the code if you want!


Display the preview window

If the first command line parameter is "/p", it is a request to display the preview window, i.e. the small screen that sits in the Control Panel "Display Properties" screen saver window.

The code converts the string containing the window handle to an integer value, then recasts it as a window handle. It then creates the preview window, specifying the window handle as the parent.

If there is no window handle, the preview window is not shown.

Note that when running the Debug version to test the preview window, you will need to specify a value (doesn’t matter what it is) in the command line parameters. For example, "/p 1234". (Remember my bit of code that ignores the parent window handle for the preview window in the Debug version?)

if ( !strcmpi(token,"/p") || 
     !strcmpi(token,"-p") || 
     !strcmpi(token,"p") ) 
{
    // display preview window
    // get window handle

    int iHandle = 0 ;

    if ( i < 200 && i < strlen(m_lpCmdLine) )
    {
        // skip spaces up to the number

        for ( ; 
              i < 200 && i < strlen(m_lpCmdLine) 
                      && m_lpCmdLine[i] == ' '
                      && m_lpCmdLine[i] != ':' ; 
              i++ ) ;
        if ( i < 200 && i < strlen(m_lpCmdLine) ) 
        {
            for ( ; 
                  i < 200 && i < strlen(m_lpCmdLine) 
                          && m_lpCmdLine[i] >= '0'
                          && m_lpCmdLine[i] <= '9' ; i++ )
                iHandle = iHandle * 10 + m_lpCmdLine[i] - '0' ;
        }
        HWND hWnd = (HWND)iHandle ;
	 PreviewWnd * pWnd = new PreviewWnd ;
        pWnd->Create(hWnd);
        m_pMainWnd = pWnd;
        return TRUE ;
    }
    return FALSE ;		
}

Once again, you can use 'strtol' instead to get the window handle value, if you want to.


Display the Configuration dialog box

If the first command line parameter is "/c" or there are no command line parameters, it is a request to display the configuration dialog box.

If a window handle is given, it is used as the parent window (Windows NT does this).

If there is no window handle, but the "/c" command was given, use the current foreground window as the parent window (Windows 95 does this).

If there were no command parameters, run the configuration dialog box with no parent window.

Insert this code into ‘InitInstance’ :

if (!strcmpi(token,"/c") ||
    !strcmpi(token,"-c") || 
    !strcmpi(token,"c") ) 
{
    // Run config with a parent window
    // get window handle

    int iHandle = 0 ;

    if ( i < 200 && i < strlen(m_lpCmdLine) )
    {
        // skip spaces up to the number

        for ( ; 
              i < 200 && i < strlen(m_lpCmdLine) 
                      && (m_lpCmdLine[i] == ' ' 
                            || m_lpCmdLine[i] == ':') ; 
              i++ ) ;
        if ( i < 200 && i < strlen(m_lpCmdLine) ) 
        {
            for ( ; i < 200 && i < strlen(m_lpCmdLine) 
                            && m_lpCmdLine[i] >= '0'
                            && m_lpCmdLine[i] <= '9' ; i++ )
                iHandle = iHandle * 10 + m_lpCmdLine[i] - '0' ;
        }
    }
			
    HWND hWnd ;

    CWnd * pParent = NULL ;

    if ( iHandle > 0 )
    {
        hWnd = (HWND)iHandle ;
        pParent = CWnd::FromHandle(hWnd) ;
    }
    else
        pParent = CWnd::GetForegroundWindow() ;

    DoConfig(pParent) ; 
} 
else 
{
    // Run the config dlg with no parent (probably called from Explorer)
    DoConfig(NULL);
}

Insert a new class method, 'DoConfig'. This method transfers values between the registry and the configuration dialog box, and causes the configuration dialog box to be displayed.

The code below includes examples of how you can transfer values between the registry and the dialog box.

Remember to put a prototype for it into the header file.

void CSaverApp::DoConfig(CWnd* pParent)
{
    CCfgDialog dlg(pParent);

    // Set up the current params
    dlg.m_CheckSounds = 
         ( GetProfileInt("Config","Sounds",0) == 0 ) ? FALSE : TRUE ;

    dlg.m_EditMaxNum  = GetProfileInt("Config" , "Maximum Sprites" , 8 ) ;

    // Do the dialog
    if (dlg.DoModal() != IDOK) 
        return;

    // Save the new params

    WriteProfileInt("Config","Sounds", dlg.m_CheckSounds ? 1 : 0 );
    WriteProfileInt("Config","Maximum Sprites", dlg.m_EditMaxNum ) ;
}


That's it! The next page mentions the other bits and pieces that you need to actually get the screen saver displaying something.


Next | Previous | Home

1