//============================================================================= //SUPERCLASSED EDIT CONTROL - Copyright © 2003,2005 Ken Fitlike //============================================================================= //API functions used: CallWindowProc,ChooseFont,CreateFontIndirect, //CreateWindowEx,DefWindowProc,DeleteObject,DispatchMessage,FreeLibrary, //GetMessage,GetClassInfoEx,GetProcAddress,GetStockObject,GetSystemMetrics, //LoadImage,LoadLibrary,MessageBox,PostQuitMessage,RegisterClassEx,SendMessage, //SetFocus,SetWindowTheme,ShowWindow,UpdateWindow,TranslateMessage,WinMain. //============================================================================= //Demonstrates window superclassing. An edit control is superclassed to give //extra functionality in the form of an additional button that enables font //changes to be made. // //MINGW - Use of the -fomit-frame-pointer compiler switch will generate // an exe that will crash under winxp. //MSVC2003 - Compile with multi-threaded libs (/MT switch) //============================================================================= #include <windows.h> //include all the basics #include <tchar.h> //string and other mapping macros #include <commdlg.h> //for common dialogs #include <string> //define an unicode string type alias typedef std::basic_string<TCHAR> ustring; //============================================================================= //main window message processsing function declarations LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM); int OnCreate(const HWND,CREATESTRUCT*); void OnParentNotify(const HWND,const UINT,const HWND); //superclassed edit control message processing function declarations LRESULT CALLBACK EditProc(HWND,UINT,WPARAM,LPARAM); void OnCommandEdit(const HWND,int,int,const HWND); int OnCreateEdit(const HWND,CREATESTRUCT*); //non-message function declarations HFONT ChangeFont(const HWND); HWND CreateEdit(const HWND,const HINSTANCE,DWORD,const RECT&,const int, const ustring&); inline int ErrMsg(const ustring&); void SetFormattingRect(const HWND); //setup some edit control id's enum { IDC_SUPERCLASSED_EDIT=200 }; namespace { WNDPROC wpOldProc; } //============================================================================= int WINAPI WinMain(HINSTANCE hInst,HINSTANCE,LPSTR,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("Superclassed Window - Edit"), //wnd title WS_OVERLAPPEDWINDOW|WS_CLIPCHILDREN, //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); } //============================================================================= //main window message processing functions //============================================================================= LRESULT CALLBACK WndProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam) { switch (uMsg) { case WM_PARENTNOTIFY: { OnParentNotify(hwnd,LOWORD(wParam),reinterpret_cast<HWND>(lParam)); return 0; } case WM_CREATE: return OnCreate(hwnd,reinterpret_cast<CREATESTRUCT*>(lParam)); case WM_DESTROY: 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={60,10,200,70}; //the various edit control types are created by simply varying the style bits CreateEdit(hwnd,cs->hInstance,ES_MULTILINE|WS_VSCROLL|WS_CLIPCHILDREN,rc, IDC_SUPERCLASSED_EDIT,_T("Superclassed Edit")); return 0; } //============================================================================= void OnParentNotify(const HWND hwnd,const UINT uMsg,const HWND hChild) { //handles parent window's WM_PARENTNOTIFY message if (uMsg==WM_CREATE) { //attempting to set the formatting rectangle in the superclassed edit //control's own WM_CREATE handler fails so do it here instead. Note that the //superclassed edit control's WM_CREATE message is issued prior to the //parent's WM_PARENTNOTIFY message by the system. SetFormattingRect(hChild); } } //============================================================================= //superclassed edit control message functions //============================================================================= LRESULT CALLBACK EditProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam) { switch (uMsg) { case WM_COMMAND: CallWindowProc(wpOldProc,hwnd,uMsg,wParam,lParam); OnCommandEdit(hwnd,LOWORD(wParam),HIWORD(wParam), reinterpret_cast<HWND>(lParam)); return 0; case WM_CREATE: //get default creation first CallWindowProc(wpOldProc,hwnd,uMsg,wParam,lParam); return OnCreateEdit(hwnd,reinterpret_cast<CREATESTRUCT*>(lParam)); default: //pass the message to system handler return CallWindowProc(wpOldProc,hwnd,uMsg,wParam,lParam); } } //============================================================================= void OnCommandEdit(const HWND hwnd,int id,int nNotify,const HWND hChild) { //handles WM_COMMAND message of the superclassed edit control if (hChild && nNotify==BN_CLICKED) { HFONT hFont=ChangeFont(hwnd); if (hFont) { //change the superclassed edit control font and destroy the existing one DeleteObject(reinterpret_cast<HFONT>(SendMessage(hwnd,WM_SETFONT, reinterpret_cast<WPARAM>(hFont),0))); SetFormattingRect(hwnd); } //restore focus to parent superclassed edit control SetFocus(hwnd); } } //============================================================================= int OnCreateEdit(const HWND hwnd,CREATESTRUCT *cs) { //handles the WM_CREATE message of the superclassed edit control; return -1 to //fail window creation //change to gui font SendMessage(hwnd,WM_SETFONT, reinterpret_cast<WPARAM>(GetStockObject(DEFAULT_GUI_FONT)),0); //create a small button and place it in top-left corner of edit control HWND hBtn=CreateWindowEx(0,_T("button"),0, WS_CHILD|WS_VISIBLE, 0,0,10,10, hwnd, 0, cs->hInstance,0); //if winxp themes are used the button will be obscured so turn off themes for //button control but use dynamic linking so that code still works with //pre-winxp systems HINSTANCE hLib=LoadLibrary(_T("UxTheme.dll")); if (hLib) { typedef HRESULT (__stdcall *dllSetWindowTheme)(HWND,LPCWSTR,LPCWSTR); dllSetWindowTheme SetWindowTheme=(dllSetWindowTheme)GetProcAddress(hLib, "SetWindowTheme"); SetWindowTheme(hBtn,L" ",L" "); FreeLibrary(hLib); } //select all the text in the edit control SendMessage(hwnd,EM_SETSEL,0,static_cast<LPARAM>(-1)); SetFocus(hwnd); return 0; } //============================================================================= //non-message functions //============================================================================= HFONT ChangeFont(const HWND hwnd) { //display font common dialog and return any created font based on user //selection CHOOSEFONT cf={0}; LOGFONT lf={0}; cf.lStructSize=sizeof(CHOOSEFONT); cf.hwndOwner=hwnd; cf.lpLogFont=&lf; cf.Flags=CF_SCREENFONTS; //display the font common dialog box if (ChooseFont(&cf)) { return CreateFontIndirect(cf.lpLogFont); } return 0; } //============================================================================= HWND CreateEdit(const HWND hParent,const HINSTANCE hInst,DWORD dwStyle, const RECT& rc,const int id,const ustring& caption) { //superclass the edit control, register the new edit control class and then //create a control of that control class. WNDCLASSEX wcx={0}; wcx.cbSize=sizeof(wcx); //fill out the WNDCLASSEX with system class info for edit control GetClassInfoEx(0,_T("edit"),&wcx); //save important information wpOldProc=wcx.lpfnWndProc; //save original wndproc //now change information to suit requirements ustring classname=_T("superclassed_edit"); wcx.lpszClassName=classname.c_str(); //unique wnd class name wcx.lpfnWndProc=EditProc; //new edit wndproc wcx.hInstance=hInst; //and register the new class with the system if (!RegisterClassEx(&wcx)) { ErrMsg(_T("Failed to register edit control superclass")); return 0; } dwStyle|=WS_CHILD|WS_VISIBLE; return CreateWindowEx(WS_EX_CLIENTEDGE, //extended styles classname.c_str(), //control 'class' name caption.c_str(), //control caption dwStyle, //control 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, //application instance 0); //user defined info } //============================================================================= inline int ErrMsg(const ustring& s) { return MessageBox(0,s.c_str(),_T("ERROR"),MB_OK|MB_ICONEXCLAMATION); } //============================================================================= void SetFormattingRect(const HWND hwnd) { //sets the formatting rectangle for the superclassed edit control ie the //dimensions used to display text. const int MARGIN_X=10; const int MARGIN_Y=10; RECT rc={0}; SendMessage(hwnd,EM_GETRECT,0,reinterpret_cast<LPARAM>(&rc)); rc.left+=MARGIN_X; rc.top+=MARGIN_Y; SendMessage(hwnd,EM_SETRECT,0,reinterpret_cast<LPARAM>(&rc)); } //=============================================================================