//============================================================================= //COMMON CONTROLS: COMBOBOXEX - Copyright © 2000,2005 Ken Fitlike //============================================================================= //API functions used: CreateWindowEx,DefWindowProc,DestroyIcon,DispatchMessage, //GetMessage,GetSystemMetrics,GetWindowLongPtr,ImageList_AddIcon, //ImageList_Create,ImageList_Destroy,InitCommonControlsEx,LoadImage,MessageBox, //PostQuitMessage,RegisterClassEx,SendMessage,SetWindowLongPtr,ShowWindow, //UpdateWindow,TranslateMessage,WinMain. //============================================================================= //This demonstrates the creation of an comboboxex common control. // //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> #include <vector> //define an unicode string type alias typedef std::basic_string<TCHAR> ustring; //============================================================================= //convenience constant const UINT CBX_ITEM_MASK=CBEIF_IMAGE|CBEIF_TEXT|CBEIF_SELECTEDIMAGE; //message processing function declarations LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM); int OnCreate(const HWND,CREATESTRUCT*); //non-message function declarations HWND CreateComboboxex(const HWND,const HINSTANCE,DWORD,const RECT&,const int); inline int ErrMsg(const ustring&); int InsertItem(HWND,const ustring&,int,int,INT_PTR index=-1, UINT mask=CBX_ITEM_MASK); void StartCommonControls(DWORD flags); //setup some control id's enum { IDC_COMBOBOXEX=200 }; //============================================================================= 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 - Comboboxex"), //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: { ImageList_Destroy(reinterpret_cast<HIMAGELIST>(static_cast<LONG_PTR> (GetWindowLongPtr(hwnd,GWLP_USERDATA)))); PostQuitMessage(0); //signal end of application 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={10,10,300,160}; StartCommonControls(ICC_USEREX_CLASSES); HWND hwndComboEx=CreateComboboxex(hwnd,cs->hInstance,CBS_DROPDOWN,rc, IDC_COMBOBOXEX); //create imagelist to hold icons for use by ComboBoxEx common control LPCTSTR lpszResID[]={IDI_APPLICATION,IDI_INFORMATION,IDI_QUESTION}; HIMAGELIST hImageList=ImageList_Create(16,16,ILC_MASK|ILC_COLOR32, sizeof(lpszResID)/sizeof(lpszResID[0]), 0); //store the image list handle as the user data of the parent window so that //it can be destroyed when the parent window is destroyed. 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>(hImageList)); UINT i; HICON hIcon; for (i=0;i<sizeof(lpszResID)/sizeof(lpszResID[0]);++i) { hIcon=reinterpret_cast<HICON>(LoadImage(0,lpszResID[i],IMAGE_ICON,0,0, LR_SHARED)); ImageList_AddIcon(hImageList,hIcon); } //associate the imagelist with the ComboBoxEx common control SendMessage(hwndComboEx,CBEM_SETIMAGELIST,0, reinterpret_cast<LPARAM>(hImageList)); //add some items to the ComboBoxEx common control InsertItem(hwndComboEx,_T("First Item"),0,0); InsertItem(hwndComboEx,_T("Second Item"),1,1); InsertItem(hwndComboEx,_T("Third Item"),2,2); return 0; } //============================================================================= HWND CreateComboboxex(const HWND hParent,const HINSTANCE hInst,DWORD dwStyle, const RECT& rc,const int id) { dwStyle|=WS_CHILD|WS_VISIBLE; return CreateWindowEx(0, //extended styles WC_COMBOBOXEX, //control 'class' name 0, //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); } //============================================================================= int InsertItem(HWND hCbx,const ustring& txt,int img_index, int selimg_index,INT_PTR index,UINT mask) { //insert in item into the comboboxex,'hCbx' with zero-based index of //'index'(default value is -1 which adds item to end of list), //text of 'txt', image index of 'img_index', selected image index of //'selimg_index' and mask which defines which of these parameters are actually //used. //copy the text into a temporary array (vector) so it's in a suitable form //for the pszText member of the COMBOBOXEXITEM struct to use. This avoids using //const_cast on 'txt.c_str()' or variations applied directly to the string that //break its constant nature. std::vector<TCHAR> tmp(txt.begin(),txt.end()); tmp.push_back(_T('\0')); COMBOBOXEXITEM cbei={0}; cbei.mask=mask; cbei.iItem=index; cbei.pszText=&tmp[0]; cbei.iImage=img_index; cbei.iSelectedImage=selimg_index; return static_cast<int>(SendMessage(hCbx,CBEM_INSERTITEM,0, reinterpret_cast<LPARAM>(&cbei))); } //=============================================================================