//============================================================================= //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); } //=============================================================================