Figure 1   INITCOMMONCONTROLSEX dwICC Values

Value

Description

ICC_LISTVIEW_CLASSES

Initializes the ListView and Header controls.

ICC_TREEVIEW_CLASSES

Initializes the TreeView and ToolTip controls.

ICC_BAR_CLASSES

Initializes the Toolbar, StatusBar, TrackBar, and ToolTip controls.

ICC_TAB_CLASSES

Initializes the Tab and ToolTip controls.

ICC_UPDOWN_CLASS

Initializes the UpDown control.

ICC_PROGRESS_CLASS

Initializes the Progress Bar control.

ICC_HOTKEY_CLASS

Initializes the Hot Key control.

ICC_ANIMATE_CLASS

Initializes the Animation control.

ICC_WIN95_CLASSES

Initializes the Animation, Header, HotKey, ListView, ProgressBar, StatusBar, Tab, ToolTip, ToolBar, TrackBar, TreeView, and UpDown controls.

ICC_DATE_CLASSES

Initializes the Date and Time Picker controls.

ICC_USEREX_CLASSES

Initializes the ComboBoxEx control.

ICC_COOL_CLASSES

Initializes the CoolBar control.

Figure 2   NMCUSTOMDRAW Structure

Member

Description

NMHDR hdr

Standard NMHDR structure for all notification messages.

DWORD dwDrawStage

Specifies the current drawing stage.

HDC hdc

The HDC of the control. Use this HDC to perform any GDI functions.

RECT rc

The rectangle to be drawn in.

DWORD dwItemSpec

This is control-specific, but it's how to specify an item. Valid only when the CDDS_ITEM bit is set in dwDrawStage.

LPARAM lItemlParam

The lParam of the item.

Figure 3   Custom Draw Drawing Stages

Value

Description

CDDS_PREPAINT

Received before any part of the control is about to be drawn.

CDDS_POSTPAINT

Received after the control has completed the painting cycle.

CDDS_PREERASE

Received before the control starts the erasing cycle. Currently only supported by the ToolBar control.

CDDS_POSTERASE

Received after the control completes the erasing cycle. Currently only supported by the ToolBar control.

CDDS_ITEMPREPAINT

Received before the item is drawn.

CDDS_ITEMPOSTPAINT

Received after the item has been drawn.

CDDS_ITEMPREERASE

Received when the item is about to be erased. Currently only supported by the ToolBar control.

CDDS_ITEMPOSTERASE

Received after the item has been erased. Currently only supported by the ToolBar control.

Figure 4   Custom Draw Return Values

Return Value

Response

CDRF_DODEFAULT

Causes the control to use its default painting. If returned from CDDS_PREPAINT, no other custom draw messages will be sent.

CDRF_NOTIFYPOSTPAINT

Causes the control to send the NM_CUSTOMDRAW notification with dwDrawStage equal to CDDS_POSTPAINT after the control has been painted. If returning this value in response to CDDS_ITEMPREPAINT, you will receive the CDDS_ITEMPOSTPAINT notification.

CDRF_NOTIFYPOSTERASE

Causes the control to send the NM_CUSTOMDRAW notification with dwDrawStage equal to CDDS_POSTERASE after the control has been erased.

CDRF_NOTIFYITEMDRAW

Causes the control to send the NM_CUSTOMDRAW notification with dwDrawStage equal to CDDS_ITEMPREPAINT when an item is about to be drawn and dwDrawStage equal to CDDS_ITEMPOSTPAINT after the item is drawn.

CDRF_NOTIFYITEMERASE

Causes the control to send the NM_CUSTOMDRAW notification with dwDrawStage equal to CDDS_ITEMPREERASE when an item is about to be erased and dwDrawStage equal to CDDS_ITEMPOSTERASE after the control is erased.

CDRF_NEWFONT

Use this return value when you change the font while processing the CDDS_ITEMPREPAINT notification. This tells the control to recalculate text extents based on the new font.

CDRF_SKIPDEFAULT

Use this return value to tell the control not to do any drawing for this notification. This is normally used when you are doing all of the drawing yourself.

Figure 5   NMLVCUSTOMDRAW Structure

Member

Description

NMCUSTOMDRAW nmcd

Standard custom draw notification structure.

COLORREF clrText

Receives the desired text color during the CDDS_ITEMPREPAINT notification. Do not change this value if the default text color is desired.

COLORREF clrTextBk

Receives the desired text background color during the CDDS_ITEMPREPAINT notification. Do not change this value if the default text background color is desired.

Figure 6   NMTTCUSTOMDRAW Structure

Member

Description

NMCUSTOMDRAW nmcd

Standard custom draw notification structure.

UINT uDrawFlags

DrawText flags.

Figure 7   Implementing Custom Draw ToolTips

 case NM_CUSTOMDRAW:
   {
   LPNMTTCUSTOMDRAW  lpttcd = (LPNMTTCUSTOMDRAW)lParam;

   if(lpttcd->nmcd.dwDrawStage == CDDS_PREPAINT)
      {
      UINT  uDrawFlags =   DT_WORDBREAK | DT_CENTER;

      /*
      If the DT_CALCRECT bit is set, then the ToolTip is asking us to 
      adjust the DrawText bits. After returning from this notification, 
      it will call DrawText with DT_CALCRECT to calculate the rectangle. 
      
      What this allows you to do is specify a maximum width for a 
      ToolTip. If the text is too big, then the ToolTip will wrap the 
      text for you.
      
      In this case, we just make the rectangle really small so that 
      DrawText will take into account the word wrapping. Make sure to 
      keep the DT_CALCRECT flag.
      */
      if(lpttcd->uDrawFlags & DT_CALCRECT)
         {
         lpttcd->uDrawFlags = uDrawFlags | DT_CALCRECT;
                              
         /*
         We set these to 1 because, in this case, the ToolTip will be 
         asking DrawText to calculate the rectangle for us.
         */
         lpttcd->nmcd.rc.right = 1;
         lpttcd->nmcd.rc.bottom = 1;
         }
      else
         {
         /*
         Don't change the rectangle here. It was adjusted when 
         DT_CALCRECT was set.
         */
         lpttcd->uDrawFlags = uDrawFlags;
         }

      return CDRF_DODEFAULT;
      }
   }
   return CDRF_DODEFAULT;

Figure 10   CoolBar Styles

Style Flag

Description

RBS_VARHEIGHT

With this style, each row may be a different height. Without this style, each row will be the height of the tallest band.

RBS_BANDBORDERS

The control places a border around each band, which separates it from adjacent bands.

RBS_FIXEDORDER

Prevents the user from re-ordering the bands. Without this style, the user can place any band in front of or on top of any other band. With this style, the user can only resize bands that are in the same row or place bands under each other in the same order that they are inserted.

Figure 11   REBARINFO Structure

Member

Description

UINT cbSize

The size of the REBARINFO structure, in bytes.

UINT fMask

Specifies which of the members contain valid information. At present, only the RBIM_IMAGELIST flag is used.

HIMAGELIST himl

An image list handle that the CoolBar will use to obtain images.

Figure 12   REBARBANDINFO Structure

Member

Description

UINT cbSize

The size of the REBARBANDINFO structure, in bytes.

UINT fMask

Specifies which of the members contain valid information.

UINT fStyle

One or more flags that indicate which members contain valid information or which members are being requested.

COLORREF clrFore

Specifies the foreground (text) color of the band.

COLORREF clrBack

Specifies the background color of the band.

LPTSTR lpText

A pointer to a buffer that contains the display text for the band. If band information is being requested from the control, then this member needs to be initialized to point to a character buffer before sending the message.

UINT cch

The size of the buffer pointed to by lpText. This member is only used when information is being requested from the control.

INT iImage

Zero-based index of the image that should be displayed in the band.

HWND hwndChild

Specifies the handle of the child window contained in the band.

UINT cxMinChild

Specifies the minimum horizontal size of the child window. The band cannot be sized smaller than this value.

UINT cyMinChild

Specifies the minimum vertical size of the child window. The band cannot be sized smaller than this value.

UINT cx

Specifies the initial size of the band. This value is only used if there is more than one band in a row and this value is greater than cxMinChild.

HBITMAP hbmBack

Specifies the bitmap that should be used to paint the background.

UINT wID

Specifies an optional band identifier. This is user-defined and should be unique among all bands.

Figure 13   REBARBANDINFO Mask Values

Value

Description

RBBIM_STYLE

The fStyle member is valid.

RBBIM_COLORS

The clrFore and clrBack members are valid.

RBBIM_TEXT

The lpText member is valid.

RBBIM_IMAGE

The iImage member is valid.

RBBIM_CHILD

The hwndChild member is valid.

RBBIM_CHILDSIZE

The cxMinChild and cyMinChild members are valid.

RBBIM_SIZE

The cx member is valid.

RBBIM_BACKGROUND

The hbmBack member is valid.

RBBIM_ID

The wID member is valid.

Figure 14   REBARBANDINFO Style Values

Value

Description

RBBS_BREAK

The band is on a new line.

RBBS_FIXEDSIZE

This band can't be sized. The sizing grip is not displayed on this band.

RBBS_CHILDEDGE

Draw an edge around the top and bottom of the child window.

RBBS_HIDDEN

Hide this band.

RBBS_NOVERT

Don't display this band when the CoolBar is vertical.

RBBS_FIXEDBMP

The background bitmap doesn't move when the band is resized. It is also displayed as being common (unbroken) through all of the bands.

Figure 15   CoolBar Messages

Message

Description

wParam

lParam

Return Value

RB_SETBARINFO

Sets the general information for the CoolBar control.

Not used.

Pointer to a REBARINFO structure.

BOOL value indicating success or failure.

RB_GETBARINFO

Retrieves the general information for the CoolBar control.

Not used.

Pointer to a REBARINFO structure.

BOOL value indicating success or failure.

RB_SETBANDINFO

Sets the information for an existing band in the CoolBar control.

Index of the band to set this information for.

Pointer to a REBARBANDINFO structure.

BOOL value indicating success or failure.

RB_GETBANDINFO

Retrieves the information for a band in the CoolBar control.

Index of the band to retrieve the information for.

Pointer to a REBARBANDINFO structure.

BOOL value indicating success or failure.

RB_INSERTBAND

Inserts a new band into the CoolBar control.

Indicates the position at which the band should be inserted. Pass -1 to add a new band.

Pointer to a REBARBANDINFO structure.

BOOL value indicating success or failure.

RB_DELETEBAND

Deletes a band from the CoolBar control.

Index of the band to be deleted.

Not used.

BOOL value indicating success or failure.

RB_GETBANDCOUNT

Retrieves the number of bands currently in the CoolBar control.

Not used.

Not used.

The number of bands contained in the CoolBar.

RB_GETROWCOUNT

Retrieves the number of rows in the CoolBar control.

Not used.

Not used.

The number of rows in the CoolBar.

RB_GETROWHEIGHT

Retrieves the height of a row in the CoolBar control.

Zero-based index of the band in the row to get the height for.

Not used.

The height of the row that contains the specified band in pixels.

Figure 17   CoolBar.c

 /**************************************************************************
   File:          CoolBar.c
**************************************************************************/
#define STRICT
//#define UNICODE

/**************************************************************************
   Include Files
**************************************************************************/
#include <windows.h>
#include <windowsx.h>
#include <commctrl.h>
#include "resource.h"

/**************************************************************************
   Local Function Prototypes
**************************************************************************/
int PASCAL WinMain(HINSTANCE, HINSTANCE, LPSTR, int);
BOOL InitApplication(HINSTANCE);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK MainWndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT HandleCommand(HWND, WPARAM, LPARAM);
BOOL CALLBACK About(HWND, UINT, WPARAM, LPARAM);
HWND BuildCoolBar(HWND);
LRESULT HandleNotify(HWND, WPARAM, LPARAM);
void MoveCoolBar(HWND);
void UpdateMenu(HWND, HMENU);

/**************************************************************************
   Global Variables
**************************************************************************/
#define ID_COOLBAR   1000
#define ID_COMBOBOX  2000
#define ID_BUTTON    2001

#define TOP    0x00
#define LEFT   0x01
#define BOTTOM 0x02
#define RIGHT  0x03

HINSTANCE   g_hInst;
WORD        g_wSide;
TCHAR       g_szClassName[] = TEXT("CoolBarSampleClass");

/******************************************************************************
   WinMain
******************************************************************************/
int PASCAL WinMain(  HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR lpCmdLine,
                     int nCmdShow)
{
MSG      msg;
INITCOMMONCONTROLSEX iccex;

iccex.dwSize = sizeof(INITCOMMONCONTROLSEX);
iccex.dwICC = ICC_COOL_CLASSES;
InitCommonControlsEx(&iccex);

if(!hPrevInstance)
   if(!InitApplication(hInstance))
      return FALSE;

if (!InitInstance(hInstance, nCmdShow))
   return FALSE;

while(GetMessage( &msg, NULL, 0x00, 0x00))
   {
   TranslateMessage(&msg);
   DispatchMessage(&msg);
   }

return msg.wParam;
}

/*****************************************************************************
   InitApplication
*****************************************************************************/
BOOL InitApplication(HINSTANCE hInstance)
{
WNDCLASS  wc;

wc.style          = 0;
wc.lpfnWndProc    = (WNDPROC)MainWndProc;
wc.cbClsExtra     = 0;
wc.cbWndExtra     = 0;
wc.hInstance      = hInstance;
wc.hIcon          = LoadIcon(NULL, MAKEINTRESOURCE(IDI_MAINICON));
wc.hCursor        = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
wc.lpszMenuName   = MAKEINTRESOURCE(IDM_MAINMENU);
wc.lpszClassName  = g_szClassName;

return RegisterClass(&wc);
}

/*****************************************************************************
   InitInstance
*****************************************************************************/
BOOL InitInstance(   HINSTANCE hInstance,
                     int nCmdShow)
{
HWND  hWnd;

g_hInst = hInstance;

hWnd = CreateWindowEx(  0,
                        g_szClassName,
                        TEXT("CoolBar Application"),
                        WS_OVERLAPPEDWINDOW,
                        CW_USEDEFAULT,
                        CW_USEDEFAULT,
                        CW_USEDEFAULT,
                        CW_USEDEFAULT,
                        NULL,
                        NULL,
                        hInstance,
                        NULL);

if (!hWnd)
   return FALSE;

ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);

return TRUE;

}

/*****************************************************************************
   MainWndProc
*****************************************************************************/
LRESULT CALLBACK MainWndProc( HWND hWnd,
                              UINT uMessage,
                              WPARAM wParam,
                              LPARAM lParam)
{switch (uMessage)
   {      case WM_CREATE:  g_wSide = TOP;
                           BuildCoolBarBhWnd);
                           break;
          case WM_NOTIFY:  return HandleNotify(hWnd, wParam, lParam);
   case WM_INITMENUPOPUP:  UpdateMenu(hWnd, (HMENU)wParam);
                           break;
            case WM_SIZE:  MoveCoolB....arBhWnd);
                           break;
         case WM_DESTROY:  PostQuitMessage(0);
                           break;
         case WM_COMMAND:  return HandleCommand(hWnd, wParam, lParam);
   default:                break;
   }
return DefWindowProc(hWnd, uMessage, wParam, lParam);
}

/*****************************************************************************

   HandleCommand

*****************************************************************************/

LRESULT HandleCommand(HWND hWnd, WPARAM wParam, LPARAM lParam)
{switch (wParam)
   {  case ID_BUTTON:  MessageBeep(MB_OK);
                       break;
    case ID_COMBOBOX:  MessageBeep(MB_OK);
                       break;
        case IDM_TOP: if(g_wSide != TOP)
            {
            DestroyWindow(GetDlgItem(hWnd, ID_COOLBAR)); //86 existing CoolBar                    
            g_wSide = TOP;  //change to the new side
            
            BuildCoolBar(hWnd);  //create the new CoolBar
            /* We have to do this because the CoolBar will recalculate its 
            rectangle after the first time it is sized. */
            MoveCoolBar(hWnd);
            }
            break;
     case IDM_BOTTOM: if(g_wSide != BOTTOM)
            {
            DestroyWindow(GetDlgItem(hWnd, ID_COOLBAR)); //86 existing CoolBar
         
            g_wSide = BOTTOM;
            
            BuildCoolBar(hWnd); //create the new CoolBar
            /* We have to do this because the CoolBar will recalculate its 
            rectangle after the first time it is sized. */
            MoveCoolBar(hWnd);
            }
            break;
       case IDM_LEFT: if(g_wSide != LEFT)
            {
            DestroyWindow(GetDlgItem(hWnd, ID_COOLBAR)); //86 existing CoolBar
            
            g_wSide = LEFT;
            
            BuildCoolBar(hWnd); //create the new CoolBar

            /* We have to do this because the CoolBar will recalculate its 
            rectangle after the first time it is sized. */
            MoveCoolBar(hWnd);
            }
            break;
      case IDM_RIGHT: if(g_wSide != RIGHT)
            {
            DestroyWindow(GetDlgItem(hWnd, ID_COOLBAR)); //86 existing CoolBar
            
            g_wSide = RIGHT;
            
            BuildCoolBar(hWnd);  //create the new CoolBar

            /* We have to do this because the CoolBar will recalculate its 
            rectangle after the first time it is sized. */
            MoveCoolBar(hWnd);
            }
            break;
       case IDM_EXIT: DestroyWindow(hWnd);
                      break;
      case IDM_ABOUT: DialogBox(g_hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd,
                                About);
                      break;   
         }
return 0;
}

/*****************************************************************************
   About
*****************************************************************************/
BOOL CALLBACK About( HWND hDlg, 
                     UINT uMessage, 
                     WPARAM wParam, 
                     LPARAM lParam)
{
switch (uMessage)
   {
   case WM_INITDIALOG:
      return TRUE;
      
   case WM_COMMAND:
      switch(wParam)
         {
         case IDOK:
            EndDialog(hDlg, IDOK);
            return TRUE;

         case IDCANCEL:
            EndDialog(hDlg, IDCANCEL);
            return TRUE;
         }
      break;
    } 
    
return FALSE;
}

/*****************************************************************************
   BuildCoolBar
*****************************************************************************/
HWND BuildCoolBar(HWND hwndParent)
{
HWND     hwndCoolBar = NULL;
LRESULT  lResult;

hwndCoolBar = CreateWindowEx( WS_EX_TOOLWINDOW, 
                              REBARCLASSNAME, 
                              NULL,
                              WS_VISIBLE | WS_BORDER | WS_CHILD |
                              WS_CLIPCHILDREN | WS_CLIPSIBLINGS | 
                              RBS_TOOLTIPS | RBS_VARHEIGHT | RBS_BANDBORDERS |
                              CCS_NODIVIDER | CCS_NOPARENTALIGN |
                              ((g_wSide & 0x01) ? CCS_VERT : 0),  
                              //g_wSide is odd if this is a vertical bar
                              0, 0, 200, 100, hwndParent, (HMENU)ID_COOLBAR, 
                              g_hInst, NULL);

if(hwndCoolBar)
   {
   REBARINFO      rbi;
   HIMAGELIST     himlCoolBar;
   HICON          hIcon;
   REBARBANDINFO  rbbi;
   HWND           hwndChild;
   RECT           rc;
   TCHAR          szString[64];

   //set up the CoolBar
   himlCoolBar = ImageList_Create(32, 32, ILC_COLORDDB | ILC_MASK, 1, 0);
   hIcon = LoadIcon(g_hInst, MAKEINTRESOURCE(IDI_MAINICON));

   ImageList_AddIcon(himlCoolbar, hIcon);

   rbi.cbSize  = sizeof(rbi);
   rbi.fMask   = RBIM_IMAGELIST;
   rbi.himl    = himlCoolBar;
   lResult = SendMessage(hwndCoolBar, RB_SETBARINFO, 0, (LPARAM)&rbi);
   
   //add a band that contains a combobox
   hwndChild = CreateWindowEx(   0, 
                                 TEXT("combobox"), 
                                 NULL,
                                 WS_VISIBLE | WS_CHILD | WS_TABSTOP |
                                 WS_VSCROLL | WS_CLIPCHILDREN |
                                 WS_CLIPSIBLINGS | CBS_AUTOHSCROLL | 
                                 CBS_DROPDOWN,
                                 0, 0, 100, 200, hwndCoolBar,
                                 (HMENU)ID_COMBOBOX, g_hInst, NULL);

   //add some stuff to the combobox
   {
   int   i;

   for(i = 0; i < 25; i++)
      {
      wsprintf(szString, TEXT("Item %d"), i + 1);
      SendMessage(hwndChild, CB_ADDSTRING, 0, (LPARAM)szString);
      }
   }
   
   GetWindowRect(hwndChild, &rc);
   
   ZeroMemory(&rbbi, sizeof(rbbi));
   rbbi.cbSize       = sizeof(REBARBANDINFO);
   rbbi.fMask        = RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_ID | RBBIM_STYLE | 
                          RBBIM_COLORS | RBBIM_TEXT | RBBIM_BACKGROUND |
                          RBBIM_IMAGE;
   rbbi.cxMinChild   = rc.right - rc.left;
   rbbi.cyMinChild   = rc.bottom - rc.top;
   rbbi.clrFore      = GetSysColor(COLOR_BTNTEXT);
   rbbi.clrBack      = GetSysColor(COLOR_BTNFACE);
   rbbi.fStyle       = RBBS_CHILDEDGE | 
                        RBBS_FIXEDBMP;
   rbbi.wID          = ID_COMBOBOX;
   rbbi.hwndChild    = hwndChild;
   rbbi.lpText       = TEXT("ComboBox");
   rbbi.hbmBack      = LoadBitmap(g_hInst, MAKEINTRESOURCE(IDB_BACKGROUND));
   rbbi.iImage       = 0;

   lResult = SendMessage(hwndCoolBar, RB_INSERTBAND, (WPARAM)-1, (LPARAM)(LPREBARBANDINFO)&rbbi);

   //add a band that contains a button
   hwndChild = CreateWindowEx(   0, 
                                 TEXT("button"), 
                                 TEXT("Button"),
                                 WS_CHILD | 
                                    BS_PUSHBUTTON,
                                 0, 0, 100, 50, 
                                 hwndCoolbar, 
                                 (HMENU)ID_BUTTON, 
                                 g_hInst, 
                                 NULL);
   
   GetWindowRect(hwndChild, &rc);
   
   ZeroMemory(&rbbi, sizeof(rbbi));
   rbbi.cbSize       = sizeof(REBARBANDINFO);
   rbbi.fMask        =  RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_ID |
                           RBBIM_STYLE | RBBIM_COLORS | RBBIM_TEXT |
                           RBBIM_BACKGROUND;
   rbbi.cxMinChild   = rc.right - rc.left;
   rbbi.cyMinChild   = rc.bottom - rc.top;
   rbbi.clrFore      = GetSysColor(COLOR_BTNTEXT);
   rbbi.clrBack      = GetSysColor(COLOR_BTNFACE);
   rbbi.fStyle       = RBBS_CHILDEDGE | 
                        RBBS_FIXEDBMP;
   rbbi.wID          = ID_BUTTON;
   rbbi.hwndChild    = hwndChild;
   rbbi.lpText       = TEXT("Button");
   rbbi.hbmBack      = LoadBitmap(g_hInst, MAKEINTRESOURCE(IDB_BACKGROUND));

   lResult = SendMessage(hwndCoolBar, RB_INSERTBAND, (WPARAM)-1, (LPARAM)(LPREBARBANDINFO)&rbbi);
   }

MoveCoolBar(hwndParent);

return hwndCoolBar;
}

/*****************************************************************************
   HandleNotify
*****************************************************************************/
LRESULT HandleNotify(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
LPNMHDR  lpNM = (LPNMHDR)lParam;

switch(lpNM->code)
   {
   case RBN_HEIGHTCHANGE:
      break;
   }

return FALSE;
}

/**************************************************************************
   MoveCoolBar()
  
**************************************************************************/
void MoveCoolBar(HWND hWnd)
{
RECT  rc,
      rcCoolBar;
int   x, y,
      cx,cy;

GetClientRect(hWnd, &rc);
GetWindowRect(GetDlgItem(hWnd, ID_COOLBAR), &rcCoolBar);

switch(g_wSide)
   {
   default:
   case TOP:
      //align the CoolBar along the top of the window
      x = 0; y = 0;
      cx = rc.right - rc.left;
      cy = rc.bottom - rc.top;
      break;
   case LEFT:
      //align the CoolBar along the left side of the window
      x = 0;
      y = 0;
      cx = rcCoolBar.right - rcCoolBar.left;
      cy = rc.bottom - rc.top;
      break;
   case BOTTOM:
      //align the CoolBar along the bottom of the window
      x = 0;
      y = rc.bottom - (rcCoolBar.bottom - rcCoolBar.top);
      cx = rc.right - rc.left;
      cy = rcCoolBar.bottom - rcCoolBar.top;
      break;
   case RIGHT:
      //align the CoolBar along the right side of the window
      x = rc.right - (rcCoolBar.right - rcCoolBar.left);
      y = 0;
      cx = rcCoolBar.right - rcCoolBar.left;
      cy = rc.bottom - rc.top;
      break;
   }

MoveWindow( GetDlgItem(hWnd, ID_COOLBAR), 
            x, y, 
            cx,cy, 
            TRUE);
}

/**************************************************************************
  UpdateMenu()
**************************************************************************/
void UpdateMenu(HWND hWnd, HMENU hMenu)
{
UINT  uCheck;

switch(g_wSide)
   {
   default:
   case TOP:    uCheck = IDM_TOP;
      break;
   case LEFT:   uCheck = IDM_LEFT;
      break;
   case RIGHT:  uCheck = IDM_RIGHT;
      break;
   case BOTTOM: uCheck = IDM_BOTTOM;
      break;
   }

CheckMenuRadioItem(hMenu, IDM_TOP, IDM_BOTTOM, uCheck, MF_BYCOMMAND);
}

Figure 19   ComboBoxEx Messages

Message

Description

wParam

lParam

Return Value

CBEM_DELETEITEM

Deletes an item from a ComboBoxEx control.

Index of the item to be deleted.

Not used.

The number of items remaining in the control after the item has been deleted.

CBEM_GETCOMBOCONTROL

Retrieves the window handle of the drop-down list box portion of the ComboBoxEx control.

Not used.

Not used.

Window handle of the drop-down list box.

CBEM_GETEDITCONTROL

Retrieves the window handle of the edit control portion of the ComboBoxEx control. This message is only applicable if the ComboBoxEx has the CBS_DROPDOWN style.

Not used.

Not used.

Window handle of the edit control.

CBEM_GETEXSTYLE

Retrieves the extended styles for the ComboBoxEx control.

Not used.

Not used.

A DWORD value representing the currently set ComboBoxEx extended style flags.

CBEM_SETEXSTYLE

Sets the extended styles for the ComboBoxEx control.

A DWORD value representing the ComboBoxEx extended style flags to set.

Not used.

A DWORD value representing the previously set ComboBoxEx extended style flags. This return value may be zero if no flags were previously set.

CBEM_GETIMAGELIST

Retrieves the handle to the image list that the ComboBoxEx control is currently using.

Not used.

Not used.

An HIMAGELIST that is the handle to the image list that is currently set in the ComboBoxEx control.

CBEM_GETITEM

Retrieves the information for a particular item in a ComboBoxEx control.

Not used.

A pointer to a COMBOBOXEXITEM structure. Before sending this message, the iItem member of this structure indicates the item to be retrieved and the mask member indicates what attributes should be retrieved.

A BOOL value indicating the success or failure of the message.

CBEM_SETITEM

Sets the specified attributes for an existing item in a ComboBoxEx control.

Not used.

A pointer to a COMBOBOXEXITEM structure. The iItem member of this structure indicates the item whose attributes should be set. The mask member indicates what members of the structure contain valid information to be set.

A BOOL value indicating the success or failure of the message.

CBEM_HASEDITCHANGED

Determines if the user has changed the contents of the edit control portion of the ComboBoxEx control. This message is only valid if the ComboBoxEx control has the CBS_DROPDOWN style.

Not used.

Not used.

A BOOL value indicating if the contents of the edit control have changed.

CBEM_INSERTITEM

Insert an item into a ComboBoxEx control.

Not used.

A pointer to a COMBOBOXEXITEM structure. The iItem member of this structure indicates the zero-based index at which to insert the item. Setting iItem to -1 adds the item to the end of the list.

The index at which the item was inserted or -1 if the insertion failed.

CBEM_SETIMAGELIST

Sets the image list that ComboBoxEx control will use to draw item images.

Not used.

The HIMAGELIST of the image list to be set.

The HIMAGELIST of the image list previously associated with the control. This message may return NULL if no image list was previously set.

Figure 20   ComboBoxEx Extended Styles

Style Flag

Description

CBES_EX_NOEDITIMAGE

When set, the edit control portion of the ComboBoxEx will not display an image for selected items.

CBES_EX_NOEDITIMAGEINDENT

When set, the edit control portion of the ComboBoxEx will not indent text to make room for an item image.

CBES_EX_PATHWORDBREAKPROC

When set, the edit control portion of the ComboBoxEx will use the forward slash (/), back slash (\), and period (.) characters as word delimiters. This makes keyboard shortcuts for word-by-word cursor movement (Ctrl + arrow keys) effective in path names and URLs.

Figure 21   COMBOBOXEXITEM St

Member

Description

UINT mask

Specifies which of the members contain valid information. Or, when retrieving information, which members are being requested. See Figure 23 for a list of the ComboBoxEx mask values.

int iItem

Zero-based index of the item.

LPTSTR pszText

Pointer to a zero-terminated character buffer that contains the display text for the item. If information is being requested from the control, then this member needs to be initialized to point to a character buffer before sending the message. When setting or inserting an item, setting this member to LPSTR_TEXTCALLBACK will cause the control to request the text by sending a CBEN_GETDISPINFO notification message.

int cchTextMax

The size of the buffer pointed to by pszText. This member is only used when information is being requested from the control.

int iImage

Zero-based index of an image within the image list that the control will use to display the item when it is not selected. When setting or inserting an item, setting this member to I_IMAGECALLBACK will cause the control to request the image by sending a CBEN_GETDISPINFO notification message.

int iSelectedImage

Zero-based index of an image within the image list that the control will use to display the item when it is selected. When setting or inserting an item, setting this member to I_IMAGECALLBACK will cause the control to request the selected image by sending a CBEN_GETDISPINFO notification message.

int iOverlay

One-based index of an overlay image within the image list that the control will use to overlay the item's image. When setting or inserting an item, setting this member to I_IMAGECALLBACK will cause the control to request the overlay by sending a CBEN_GETDISPINFO notification message.

int iIndent

Number of indent spaces that this item should be indented. Each indent space is equal to 10 pixels. When setting or inserting an item, setting this member to I_INDENTCALLBACK will cause the control to request the indent value by sending a CBEN_GETDISPINFO notification message.

LPARAM lParam

A 32-bit user-defined value.

ructure

Figure 22   ComboBoxEx Notification Codes

Notification Code

Description

lParam

Return Value

CBEN_BEGINEDIT

Sent by the control when the user activates the drop-down list or clicks the mouse in the edit portion of the ComboBoxEx control.

Pointer to an NMHDR structure.

Ignored.

CBEN_DELETEITEM

Sent by the control when an item is about to be deleted.

Pointer to an NMCOMBOBOXEX structure. The COMBOXEXITEM member of the NMCOMBOBOXEX structure contains information about the item being deleted.

Ignored.

CBEN_ENDEDIT

Sent by the control when the user has concluded an operation in the edit control or made a selection in the drop-down list portion of the ComboBoxEx control.

Pointer to an NMCBEENDEDIT structure, which contains information about the edit event just completed.

Return FALSE to accept the new information. Return TRUE to abort the edit and reject the new information.

CBEN_GETDISPINFO

Sent by the control when information necessary to display a callback item is required

Pointer to an NMCOMBOBOXEX structure. The mask member of the COMBOBOXEXITEM member of the NMCOMBOBOXEX structure indicates which items are being requested.

Ignored.

CBEN_INSERTITEM

Sent by the control when an item is about to be inserted.

Pointer to an NMCOMBOBOXEX structure. The COMBOXEXITEM member of the NMCOMBOBOXEX structure contains information about the item being inserted.

Ignored.

Figure 23   COMBOBOXEXITEM Mask Values

Value

Description

CBEIF_TEXT

The pszText member is valid or needs to be filled in.

CBEIF_IMAGE

The iImage member is valid or needs to be filled in.

CBEIF_SELECTEDIMAGE

The iSelectedImage member is valid or needs to be filled in.

CBEIF_OVERLAY

The iOverlay member is valid or needs to be filled in.

CBEIF_INDENT

The iIndent member is valid or needs to be filled in.

CBEIF_LPARAM

The lParam member is valid or needs to be filled in.

CBEIF_DI_SETITEM

The control should store the item data and not ask for it again. This flag is only used with the CBEN_GETDISPINFO notification message.

Figure 24   NMCBEENDEDIT Structure

Member

Description

NMHDR hdr

Standard NMHDR structure.

BOOL fChanged

A BOOL indicating if the contents of the edit control have changed. Zero if the contents have not changed, nonzero if the contents have changed.

int iNewSelection

Zero-based index of the item that will be selected after the edit is completed. This value may be CB_ERR if no item will be selected.

TCHAR szText[CBEMAXSTRLEN]

Zero-terminated string buffer that contains the text of the edit control.

int iWhy

Specifies the action that generated the notification. This can be one of the following values:

CBENF_KILLFOCUS - The edit box lost the keyboard focus.

CBENF_RETURN - The user completed the edit operation by pressing the ENTER key.

CBENF_ESCAPE - The user pressed the ESCAPE key.

CBENF_DROPDOWN - The user activated the drop-down list.

Figure 27   Date/Time Picker Styles

Style Flag

Description

DTS_TIMEFORMAT

Without this style, the control is in date mode. When this style is set, then the control is in time mode.

DTS_UPDOWN

When in date mode, this causes the control to act like an UpDown control rather than a ComboBox. This style has no effect when the control is in time mode.

DTS_SHOWNONE

This style allows the control to have no set date or time. When this style is specified, a checkbox will appear next to the date or time. The state of this checkbox determines if no date or time is selected. To obtain the state of the checkbox, examine the return value from the DTM_GETSYSTEMTIME message. If this value is GDT_NONE, then no date or time is currently selected in the control.

DTS_SHORTDATEFORMAT

This is the default style when in date mode or when a format string has been specified. This style causes the control to display the date in the form "7/08/96", rather than "Monday, July 8, 1996". This style has no effect when in time mode.

DTS_LONGDATEFORMAT

This style causes the control to display the date in the form "Monday, July 8, 1996", rather than "7/08/96". This style has no effect when in time mode. This style has no effect if a format string has been specified for the control.

DTS_APPCANPARSE

Allows the application to parse text that the user enters. The application must respond to the DTN_USERSTRING notification.

DTS_RIGHTALIGN

Causes the drop-down calendar to be right-aligned with the control rather than left-aligned, which is the default.

Figure 28   DTM_SETMCCOLOR/DTM_GETMCCOLOR Constants

wParam

Description

MCSC_BACKGROUND

Specifies the background color displayed between months in the drop-down calendar.

MCSC_TEXT

Specifies the text color of the dates that are in the currently selected month in the drop-down calendar.

MCSC_TITLEBK

Specifies the background color of the title bar in the drop-down calendar.

MCSC_TITLETEXT

Specifies the text color of the title bar in the drop-down calendar.

MCSC_MONTHBK

Specifies the background color of the drop-down calendar.

MCSC_TRAILINGTEXT

Specifies the text color of the dates that are not in the currently selected month in the drop-down calendar.

Figure 29   Date/Time Picker Messages

Message

Description

wParam

lParam

Return Value

DTM_GETMCCOLOR

Retrieves the colors used in the drop-down calendar portion of the control.

One of the color constants defined in Figure 28.

Not used.

The COLORREF representing the specified color.

DTM_SETMCCOLOR

Sets the colors used in the drop-down calendar portion of the control.

One of the color constants defined in Figure 28.

The COLORREF specifying the new color.

The previouslI selected color for the index specified by wParam.

DTM_GETMONTHCAL

Retrieves the window handle of the drop-down calendar portion of the Date/Time Picker control.

Not used.

Not used.

The HWND of the calendar drop-down. The calendar drop-down is not static. The control creates and destroys this window as needed, so do not rely on this value.

DTM_GETRANGE

Retrieves the allowable range of dates that the Date/Time Picker uses.

Not used.

Pointer to a two-element array of SYSTEMTIME structures.

A DWORD that is a combination of the GDTR_MIN and GDTR_MAX flags. If GDTR_MIN is set, then the first element of the array contains the minimum allowable time. If GDTR_MAX is set, then the second element contains the maximum allowable time.

DTM_SETRANGE

Sets the range of allowable dates for the Date/Time Picker control.

Any combination of the GDTR_MIN and GDTR_MAX flags. If GDTR_MIN is specified, the first element of the SYSTEMTIME array specifies the minimum allowable time. If GDTR_MAX is specified, the second element of the array specifies the maximum allowable time.

Pointer to a two-element array of SYSTEMTIME structures.

BOOL value indicating success or failure.

DTM_GETSYSTEMTIME

Retrieves the date and time currently set in the Date/Time Picker control.

Not used.

A pointer to a SYSTEMTIME structure.

GDT_VALID if the time information was successfully placed in the given structure. GDT_NONE if the control has the DTS_SHOWNONE style and the control check box was unchecked. GDT_ERROR if an error occured.

DTM_SETSYSTEMTIME

Sets the date and time in the Date/Time Picker control.

If set to GDT_VALID, sets the control according to the data within the structure that lParam points to. If set to GDT_NONE, sets the control to "no date" and clears its check box. The GDT_NONE flag only applies to controls that have the DTS_SHOWNONE style.

Pointer to a SYSTEMTIME structure that contains the desired time to set the control to.

BOOL value indicating success or failure.

DTM_SETFORMAT

Sets the format string for the Date/Time Picker control.

Not used.

Pointer to a zero-terminated string specifying the format string. If this is NULL, then the control will use the date or time format specified in the local settings.

Figure 30   Date/Time Picker Notification Codes

Notification Code

Description

lParam

Return Value

DTN_CLOSEUP

Sent when the drop-down calendar portion of the control is about to be closed.

Pointer to an NMHDR structure.

Must be zero.

DTN_DATETIMECHANGE

Sent by the control whenever the user changes the date or time in the control. Notification is not sent if the control is programmatically changed using the DTM_SETSYSTEMTIME message.

Pointer to an NMDATETIMECHANGE structure.

Must be zero.

DTN_DROPDOWN

Sent when the drop-down calendar portion of the control is about to be displayed.

Pointer to an NMHDR structure.

Must be zero.

DTN_FORMAT

Sent when the control is requesting formatted text for a callback field. pszFormat contains the callback field substring. The application must place the formatted text in szDisplay or set pszDisplay to point to a zero- terminated string that contains the formatted text.

Pointer to an NMDATETIMEFORMAT structure.

Must be zero.

DTN_FORMATQUERY

Sent when the control is requesting the maximum allowable size for a callback field. pszFormat contains the callback field substring. The application must calculate the maximum possible width of the formatted string, place that value in szMax, and return zero.

Pointer to an NMDATETIMEFORMAT-QUERY structure.

Must be zero.

DTN_USERSTRING

Sent by the control after the user has finished editing text in the edit control. This notification is only sent by Date/Time Picker controls that have the DTS_CANPARSE style.

Pointer to an NMDATETIMESTRING structure.

Must be zero.

DTN_WMKEYDOWN

Sent by the control when the user has provided keyboard input in a callback field. The NMDATETIMEWMKEYDOWN structure contains information about the keyboard event, the affected format string, and the current date and time of the control.

The lParam points to an NMDATETIMEWMKEY-DOWN structure.

Must be zero.