Create Rebar Controls
//=============================================================================
//COMMON CONTROLS: REBAR - Copyright © 2000,2005 Ken Fitlike
//=============================================================================
//API functions used: CreateWindowEx,DefWindowProc,DeletObject,DispatchMessage,
//GetMessage,GetSysColor,GetSystemMetrics,GetWindowLongPtr,
//InitCommonControlsEx,LoadImage,lstrcpy,MessageBox,PostQuitMessage,
//RegisterClassEx,SendMessage,SetRect,SetWindowLongPtr,ShowWindow,UpdateWindow,
//TranslateMessage,WinMain.
//=============================================================================
//This demonstrates the creation of a rebar common control. Note that use of 
//winxp manifests, either included as a resource or as a separate manifest 
//file affects the text color of the rebar control ie. it always appears
//grayed out. The RB_SETTEXTCOLOR does not affect this.
//
//BCC55 - Link with comctl32.lib
//MINGW - Link with libcomctl32.a (-lcomctl32)
//MSVC  - Link with comctl32.lib
//=============================================================================
#include <windows.h>  //include all the basics
#include <tchar.h>    //string and other mapping macros

#if defined __MINGW_H
#define _WIN32_IE 0x0400
#endif
#include <commctrl.h>

#include <string>

//define an unicode string type alias
typedef std::basic_string<TCHAR> ustring;
//=============================================================================
//message processing function declarations
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
int OnCreate(const HWND,CREATESTRUCT*);
void OnDestroy(const HWND hwnd);
void OnSize(const HWND,int,int,UINT);

//non-message function declarations
HWND CreateControl(const ustring&,const ustring&,const HWND,const HINSTANCE,
                   DWORD,const RECT&,const int);
inline int ErrMsg(const ustring&);                     
void StartCommonControls(DWORD);

//setup some control id's
enum {
  IDC_REBAR=200,
  IDC_COMBOBOX,
  IDC_BUTTON
};

struct RebarHandles
{
HBITMAP hBmp;
HWND    hRebar;
};
//=============================================================================
int WINAPI WinMain(HINSTANCE hInst,HINSTANCE,LPSTR pStr,int nCmd)
{
ustring classname=_T("SIMPLEWND");
WNDCLASSEX wcx={0};  //used for storing information about the wnd 'class'

wcx.cbSize         = sizeof(WNDCLASSEX);           
wcx.lpfnWndProc    = WndProc;             //wnd Procedure pointer
wcx.hInstance      = hInst;               //app instance
//use 'LoadImage' to load wnd class icon and cursor as it supersedes the 
//obsolete functions 'LoadIcon' and 'LoadCursor', although these functions will 
//still work. Because the icon and cursor are loaded from system resources ie 
//they are shared, it is not necessary to free the image resources with either 
//'DestroyIcon' or 'DestroyCursor'.
wcx.hIcon         = reinterpret_cast<HICON>(LoadImage(0,IDI_APPLICATION,
                                            IMAGE_ICON,0,0,LR_SHARED));
wcx.hCursor       = reinterpret_cast<HCURSOR>(LoadImage(0,IDC_ARROW,
                                              IMAGE_CURSOR,0,0,LR_SHARED));
wcx.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_BTNFACE+1);   
wcx.lpszClassName = classname.c_str(); 
//the window 'class' (not c++ class) has to be registered with the system
//before windows of that 'class' can be created
if (!RegisterClassEx(&wcx))
  {
  ErrMsg(_T("Failed to register wnd class"));
  return -1;
  }

int desktopwidth=GetSystemMetrics(SM_CXSCREEN);
int desktopheight=GetSystemMetrics(SM_CYSCREEN);

HWND hwnd=CreateWindowEx(0,                     //extended styles
                         classname.c_str(),     //name: wnd 'class'
                         _T("Common Controls - Rebar"), //wnd title
                         WS_OVERLAPPEDWINDOW,   //wnd style
                         desktopwidth/4,        //position:left
                         desktopheight/4,       //position: top
                         desktopwidth/2,        //width
                         desktopheight/2,       //height
                         0,                     //parent wnd handle
                         0,                     //menu handle/wnd id
                         hInst,                 //app instance
                         0);                    //user defined info
if (!hwnd)
  {
  ErrMsg(_T("Failed to create wnd"));
  return -1;
  }

ShowWindow(hwnd,nCmd); 
UpdateWindow(hwnd);
//start message loop - windows applications are 'event driven' waiting on user,
//application or system signals to determine what action, if any, to take. Note 
//that an error may cause GetMessage to return a negative value so, ideally,  
//this result should be tested for and appropriate action taken to deal with 
//it(the approach taken here is to simply quit the application).
MSG msg;
while (GetMessage(&msg,0,0,0)>0)
  {
  TranslateMessage(&msg);
  DispatchMessage(&msg);
  }
return static_cast<int>(msg.wParam);
}
//=============================================================================
LRESULT CALLBACK WndProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
switch (uMsg)
  {
  case WM_CREATE:
    {
    return OnCreate(hwnd,reinterpret_cast<CREATESTRUCT*>(lParam));
    }
  case WM_DESTROY:
    {
    OnDestroy(hwnd);
    return 0;
    }
  case WM_SIZE:
    {
    OnSize(hwnd,LOWORD(lParam),HIWORD(lParam),static_cast<UINT>(wParam));
    return 0;
    }
  default:
    //let system deal with msg
    return DefWindowProc(hwnd,uMsg,wParam,lParam);  
  }
}
//=============================================================================
int OnCreate(const HWND hwnd,CREATESTRUCT *cs)
{
//handles the WM_CREATE message of the main, parent window; return -1 to fail
//window creation
RECT rc={0,0,0,0};  //set dimensions in parent window's WM_SIZE handler 
StartCommonControls(ICC_COOL_CLASSES);  

//create storage for struct to contain information about the rebar (window
//and bitmap handles).
RebarHandles *rh=new RebarHandles;

//now store that pointer as the user data associated with the
//parent window so that it can be retrieved for later use. This will emit a 
//C4244 warning if /wp64 is enabled with ms compilers under win32 due to how 
//SetWindowLongPtr is typedef'd for 32bit and 64bit compatibility. The warning
//in this context can be safely ignored. Despite this being identified as a 
//glitch under msvc.net 2003, it still exists in the later msvc express 2005. 
//A workaround would be to wrap the offending call in #pragma warning 
//directives, or to typedef the fn properly for 32/64 bit compatibility. 
//See http://msdn.microsoft.com/msdnmag/issues/01/08/bugslayer/
//for details.
SetWindowLongPtr(hwnd,GWLP_USERDATA,reinterpret_cast<LONG_PTR>(rh));

rh->hRebar=CreateControl(_T(""),REBARCLASSNAME,hwnd,cs->hInstance,
                          WS_CLIPSIBLINGS|WS_CLIPCHILDREN|RBS_VARHEIGHT|
                          CCS_NODIVIDER|WS_BORDER,rc,IDC_REBAR);
if (rh->hRebar==0)
  {
  ErrMsg(_T("Failed to create rebar"));
  return -1; //fail main window creation
  }

//The rebar control has been succesfully created so attach two bands, each with
//a single standard control (combobox and button).
REBARINFO ri={0};
//no imagelist to attach to rebar
ri.cbSize=sizeof(REBARINFO); 
SendMessage(rh->hRebar,RB_SETBARINFO,0,reinterpret_cast<LPARAM>(&ri));

//setup REBARBANDINFO with details common to both bands such as text colour
//or background bitmap. Note that the text colour can only be set for rebars
//not using winxp styles (ie. no manifest).
REBARBANDINFO rbi={0};
rbi.cbSize=sizeof(REBARBANDINFO);
rbi.fMask=RBBIM_COLORS|RBBIM_TEXT|RBBIM_BACKGROUND|RBBIM_STYLE|
          RBBIM_CHILD|RBBIM_CHILDSIZE|RBBIM_SIZE;
rbi.fStyle=RBBS_CHILDEDGE|RBBS_FIXEDBMP|RBBS_GRIPPERALWAYS;

//Load a bitmap from file to use as rebar band background paying close 
//attention to the required syntax for the relative path to the bitmap. 
//Alternatively you can just replace this with an absolute path.
//use this with DevC++ and running msvc++ apps within IDE
ustring file;
//file=_T(".\\Resources\\tex01.bmp")
//use this with bcc5.5 and running msvc++ apps outside IDE  
file=_T("..\\Resources\\tex01.bmp");

rh->hBmp=reinterpret_cast<HBITMAP>(LoadImage(0,file.c_str(),IMAGE_BITMAP,0,0,
                                             LR_LOADFROMFILE));
rbi.hbmBack=rh->hBmp;
rbi.clrFore=RGB(222,255,255);    //text colour(only for non-winxp styles)
rbi.clrBack=GetSysColor(COLOR_BTNFACE);

//create the combobox control
SetRect(&rc,40,4,100,60);
HWND hCombo=CreateControl(_T(""),_T("COMBOBOX"),rh->hRebar,cs->hInstance,
                          CBS_DROPDOWN,rc,IDC_COMBOBOX);
                          
//set unique REBARBANDINFO values for the combobox control rebar band
GetClientRect(hCombo,&rc);    //get dimensions of combobox control
rbi.lpText=_T("Rebar Band#1");
rbi.hwndChild=hCombo;
rbi.cxMinChild=0;
rbi.cyMinChild=rc.bottom-rc.top;
rbi.cx=200;
//Attach combobox band to rebar common control
SendMessage(rh->hRebar,RB_INSERTBAND,static_cast<WPARAM>(-1),
            reinterpret_cast<LPARAM>(&rbi));

//create the button control
SetRect(&rc,164,4,100,20);
HWND hBtn=CreateControl(_T("Button"),_T("BUTTON"),rh->hRebar,cs->hInstance,0,
                        rc,IDC_BUTTON);

//set unique REBARBANDINFO values for the button control rebar band
GetClientRect(hBtn,&rc);    //get dimensions of button control
rbi.lpText=_T("Rebar Band#2");
rbi.hwndChild=hBtn;
rbi.cxMinChild=0;
rbi.cyMinChild=rc.bottom-rc.top;
rbi.cx=250;
//Attach button band to rebar common control
SendMessage(rh->hRebar,RB_INSERTBAND,static_cast<WPARAM>(-1),
            reinterpret_cast<LPARAM>(&rbi));

return 0;
}
//=============================================================================
void OnDestroy(const HWND hwnd)
{
//free up resources - first get the information which has been previously
//stored as the user data of the main window
RebarHandles *rh=reinterpret_cast<RebarHandles*>(static_cast<LONG_PTR>
                                   (GetWindowLongPtr(hwnd,GWLP_USERDATA)));
DeleteObject(rh->hBmp);
delete rh;
    
PostQuitMessage(0);    //signal end of application
}
//=============================================================================
void OnSize(const HWND hwnd,int cx,int cy,UINT flags)
{
//get the pointer to rebar information which has been previously stored in the 
//user data associated with the parent window.
RebarHandles *rh=reinterpret_cast<RebarHandles*>(static_cast<LONG_PTR>
                                   (GetWindowLongPtr(hwnd,GWLP_USERDATA)));
//resize rebar common control so that it is always the width of the parent
SendMessage(rh->hRebar,WM_SIZE,0,0);
}
//=============================================================================
HWND CreateControl(const ustring& caption,const ustring& classname,
                   const HWND hParent,const HINSTANCE hInst,DWORD dwStyle,
                   const RECT& rc,const int id)
{
dwStyle|=WS_CHILD|WS_VISIBLE;
return CreateWindowEx(0,                  //extended styles
                      classname.c_str(),  //control 'class' name
                      caption.c_str(),    //control caption
                      dwStyle,            //wnd style
                      rc.left,            //position: left
                      rc.top,             //position: top
                      rc.right,           //width
                      rc.bottom,          //height
                      hParent,            //parent window handle
                      //control's ID
                      reinterpret_cast<HMENU>(static_cast<INT_PTR>(id)),
                      hInst,              //instance
                      0);                 //user defined info
}
//=============================================================================
inline int ErrMsg(const ustring& s)
{
return MessageBox(0,s.c_str(),_T("ERROR"),MB_OK|MB_ICONEXCLAMATION);
}
//=============================================================================
void StartCommonControls(DWORD flags)
{
//load the common controls dll, specifying the type of control(s) required 
INITCOMMONCONTROLSEX iccx;
iccx.dwSize=sizeof(INITCOMMONCONTROLSEX);
iccx.dwICC=flags;
InitCommonControlsEx(&iccx);
}
//=============================================================================