Adding a Control Panel Application

This section describes how you can add an application to the Control Panel either as a stand-alone application, or as an extension of another application.

The code examples are part of a complete sample application, Sysinfo.dsp, included in the SDK. Sysinfo.dsp creates a display-only Control Panel application that provides information about system memory.

In Sysinfo.dsp, the three .cpp files are:

C++ files
Description
Syssink.cpp Implements the application message sink
Sysapp.cpp Implements the application CSysInfoApp class
Sysmain.cpp Provides the entry point into the application

    To create a Control Panel application

  1. Call CoCreateInstance to create an instance of a Forms Manager.
  2. Call LoadFormResource to load a form from a resource file.
  3. Create a message sink.
  4. Call DllMain to create a DLL that is the entry point to the application and handles all Control Panel messages.
  5. Use the CALLBACK CplApplet prototype to create a callback function.
  6. Compile your application as a .cpl file instead of a .dll file.

    Design your application install program to copy your .cpl file into the Windows directory.

The following table show the messages the application callback function must process.

Message
Description
CPL_INIT Sent to a Control Panel application to prompt it to perform global initialization, especially memory allocation. Returns 1 when it succeeds.
CPL_GETCOUNT Sent to a Control Panel application to retrieve the number of applications supported by the application. Returns the number of applications.
CPL_NEWINQUIRE Sent to a Control Panel application to request information about a dialog box that the application supports
CPL_APCINQUIRE Requests data from the application
CPL_DBLCLK Sent to a Control Panel application when the user double-clicks an icon in the Control Panel
CPL_STOP Sent once for each application when the application that controls the Control Panel closes
CPL_EXIT Sent once to a Control Panel application before the controlling application releases the DLL that contains the application

The following code example shows how to create a message sink that handles VK_ESCAPE messages.

STDMETHODIMP 
CSysInfoSink::HandleKeyPress(IDispatch *pdispControl, long lKeyDown)
{
   switch(lKeyDown)
   {
    case VK_ESCAPE:
       // Send a quit message to the current thread.
       PostThreadMessage(GetCurrentThreadId(), WM_QUIT, 0, 0);
       return S_OK; // Returns S_OK if message should stop here
   }

   return S_FALSE; // Returns S_FALSE, if the message should continue 
                   // down the message path
}

The following code example shows how to create a callback function that processes Control Panel messages for Sysinfo.dsp.

LONG CALLBACK CPlApplication(HWND hwndCPL, UINT uMsg, LONG lParam1, LONG
                             lParam2)
{
    DEBUGMSG(ZONE_FUNCTION,(TEXT("+CPlApplication(0x%x, 0x%x, 0x%x,
             0x%x)\r\n"), hwndCPL, uMsg, lParam1, lParam2));

   int iStringLen;
   NEWCPLINFO* pCPLInfo;
   APCCPLINFO* pAPCInfo;

    switch (uMsg) 
    {
    case CPL_INIT:              // The first message received from
                                // Control Panel.exe is sent once.
        return TRUE;                // Return success

    case CPL_GETCOUNT:          // The second message is sent once.
        return 1;               // Only one application is in this DLL.

    case CPL_NEWINQUIRE:           // Query for information on the
                               // application.
        pCPLInfo = (NEWCPLINFO*) lParam2;            // Where to
                                                     // put inquiry
                                                     // information
        memset(pCPLInfo, NULL, sizeof(NEWCPLINFO));  // Clear out
                                                     // inquiry
                                                     // structure 

        // Fill NEWCPLINFO with required information
        pCPLInfo->dwSize  = (DWORD) sizeof(NEWCPLINFO);

        // The display cpl supports a faceplate, but not a VGA screen.
        pCPLInfo->dwFlags = CPL_DISPLAY_FACEPLATE | CPL_DISPLAY_NOVGA;

        // Load the icon that Control Panel uses.
        pCPLInfo->hIcon   = LoadIcon(g_hInst,
        (LPWSTR)MAKEINTRESOURCE(ICON_APP_SHELL));
        
        // Load the application name into NEWCPLINFO.szName 
        // with a maximum of 32 characters.
        iStringLen = 32;  
        LoadString(g_hInst, STR_APP_SHELL_NAME, pCPLInfo->szName,
                   iStringLen );

        if( pCPLInfo->hIcon == NULL || pCPLInfo->szName == NULL ) 
          {
            DEBUGCHK(0);
            return E_FAIL;    //Return Error.
          }
          return NOERROR;

    case CPL_APCINQUIRE:
        pAPCInfo = (APCCPLINFO*) lParam2;
        memset(pAPCInfo, NULL, sizeof(APCCPLINFO));

        // Fill APCINQUIRE with the required data.
        pAPCInfo->dwSize = (DWORD) sizeof(APCCPLINFO);

        // Load the application name into APCCPLINFO.szTTSName with a 
        // maximum of 32 characters.
        iStringLen = 32;  
        LoadString(g_hInst, STR_APP_SHELL_NAME, pAPCInfo->szTTSName,
                   iStringLen );
        return NOERROR;

/***********************************************************************
*CPL_DBLCLK message
*   This application should act just as it would in a WinMain.
*   Create a message loop, a Forms Manager, a form, and so on.
----------------------------------------------------------------------*/
    case CPL_DBLCLK:    
        MSG     msg;

        // Create a new application class instance.
        g_pApp = new CSysInfoApp(g_hInst);
        if( g_pApp == NULL ) 
          {
            DEBUGCHK(0);
            return FALSE;    
          }

        if(FAILED(g_pApp->Init())) 
          {
            DEBUGCHK(0);
            delete g_pApp;    
            return FALSE;
          }

    // Start a message loop.
        while (GetMessage(&msg, NULL, 0, 0)) 
        {
            if (msg.hwnd) 
            {
                DispatchMessage(&msg);
            }
        }
        
        delete g_pApp;
        return TRUE;

    case CPL_STOP:              // Sent once per application before
                                // CPL_EXIT
    break;

    case CPL_EXIT:             // Sent once before FreeLibrary called
    break;

    default:
    break;
    }

    DEBUGMSG(ZONE_FUNCTION,(TEXT("-CPlApplication(0x%x)\r\n")));

    return TRUE;
}