locked
My Own C++Framework (MFC-like), i can create child window, but cant create edit box when WM_CREATE

    Question

  • I built my own c++framwork that is similar with MFC, i can create child window when WM_CREATE message was received, but i can not deal with Edit Box, i got the idea from Ivan Shcherbakov's post, i post a WM_CREATEMYWINDOW message after call OnCreate, and Create something in OnCreateMyWindow function when the message was received, and, of course, it works. but i want to know why and how to fix this problem.

    my CWnd is CMyWindow, i created a CBT-hook to hold the HWND and CMyWindow* of new window, then add to a HWND-WINDOW map as WindowManager, the message loop callback function MyWndProc, got the CMyWindow* from WindowManger by hWnd parameter, then call CMyWindow's message fuctions OnCreate, OnSize, OnMove ..., etc. it just like the CWnd class.

    CMyWindow seems work well, it can hold all messages and do something to response, can not create a edit box in WM_CREATE, it's so wired, because it create a new window with any style in WM_CREATE.

    the WindowManager (HWND-WINDOW map) in MyWindow.h


    //CMyWindow class is similar with CWnd of MFC

    #define WM_CREATEMYWINDOW WM_USER + 123 //the CWindowManager is a map of HWND-CMyWindow class CMyWindow; //define the HWND-CMyWindow map typedef map <HWND, CMyWindow*> CWindowMap; typedef pair<HWND, CMyWindow*> WindowPair; typedef map <HWND, CMyWindow*>::iterator WndIterator; typedef pair<WndIterator, bool> IterBool; class CWindowManager : private CWindowMap { private: CWindowManager(void); ~CWindowManager(void); public: bool Add(CMyWindow* pwnd); //add a window to map bool Remove(HWND hwnd); //remove a window by hwnd void Clear(); //remove all items CMyWindow* Find(HWND hwnd); //find the window by hwnd public: //get CWindowManager instance as singleton pattern static CWindowManager * GetInstance(); };

    WindowManager and CBT-HOOK part in MyWindow.cpp
        #include "StdAfx.h"
        #include "LockEx.h"
        #include "MyWindow.h"
    
        //window class name
        static TCHAR * _MY_WINDOW_CLASS_NAME_ = L"MYWINDOWCLASS";
    
        //window-proc
        LRESULT CALLBACK MyWindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
    
        ///an Mutex-Lock class for keep current hwnd of new window, but you can ignore it when using single thread to crate window
        static CLockEx   gLockInitWnd;
        ///keep current hwnd of new window
        static CMyWindow * gpInitWnd = 0;
        ///an hook to create new window
        static HHOOK ghook = 0;
    
    
        ///set gpInitWnd when create a new window
        static void SetInitWnd(CMyWindow * pWnd)
        {
            CLockEx::Scoped lock(gLockInitWnd);
    
            gpInitWnd = pWnd;
        }
    
        ///clear gpInitWnd after new window created
        static void UnsetInitWnd()
        {
            CLockEx::Scoped lock(gLockInitWnd);
    
            gpInitWnd = 0;
        }
    
        ///get the HWND of new window that is creating
        static CMyWindow * GetInitPwnd()
        {
            CLockEx::Scoped lock(gLockInitWnd);
    
            return gpInitWnd;
        }
    
        //CBT-Proc for SetWindowsHookEx
        static LRESULT CALLBACK MyCBTProc(int nCode, WPARAM wParam, LPARAM lParam)
        {
            if (nCode == HCBT_CREATEWND) {
                //get the new window from gpInitWnd
                CMyWindow * pwnd = GetInitPwnd();
    
                if (pwnd) {
                    //first time call this proc
                    //add this window to WindowManager
                    pwnd->Attach((HWND)wParam);
                    return (0);
                } else {
                    //sencond time call this proc
                    CREATESTRUCT * cs = ((CBT_CREATEWND *)lParam)->lpcs;
                    if (!(cs->style & WS_CHILD)) {
                        //we can do something here
                        return (0);
                    } else {
                        return (1); //error, destroy the window
                                    //or, maybe, CallNextHookEx
                    }
                }
            } else
                return CallNextHookEx(ghook, nCode, wParam, lParam);
        }
    
        //Create a WH_CBT Hook
        static bool HookCrate()
        {
           HANDLE hThread = GetCurrentThread();
           DWORD dwThreadId = GetThreadId(hThread);
           if (hThread) {
                ghook = SetWindowsHookEx(
                    WH_CBT,
                    MyCBTProc,    //set the CBT proc
                    0,
                    dwThreadId);
                if (!ghook)
                    return false;
           }
    
           return (0);
        }
    
        //Destroy WH_CBT Hook
        static void HookDestroy()
        {
           if (ghook) {
                UnhookWindowsHookEx(ghook);
                ghook = 0;
           }
        }
    
        ///////////////////////////////////////////////
        //this is a vector for keep all CMyWindow*
        CWindowManager::CWindowManager(void)
        {
        }
    
        CWindowManager::~CWindowManager(void)
        {
            clear();
        }
    
        //insert new window
        bool CWindowManager::Add(CMyWindow* pwnd)
        {
            IterBool ib = insert(WindowPair(pwnd->GetSafeHwnd(), pwnd));
            return ib.second;
        }
    
        //remove a window by hwnd
        bool CWindowManager::Remove(HWND hwnd)
        {
            WndIterator wi = find(hwnd);
    
            if (wi == end( )) {
                return false;
            } else {
                erase(wi);
                return true;
            }
        }
    
        //find a window by hwnd
        CMyWindow* CWindowManager::Find(HWND hwnd)
        {
            WndIterator wi = find(hwnd);
    
            if (wi == end( )) {
                return (0);
            } else {
                return wi->second;
            }
        }
    
        //remove all items
        void CWindowManager::Clear()
        {
            clear();
        }
    
        //get instance as singleton pattern.
        CWindowManager * CWindowManager::GetInstance()
        {
            static CWindowManager wm;
            return &wm;
        }
    
    
    


    register window class, set the WndProc to MyWIndowProc

        ATOM RegisteWindowClass(HINSTANCE hInstance, TCHAR * szClassName)
        {
            WNDCLASSEX wcex;
    
            wcex.cbSize = sizeof(WNDCLASSEX);
    
            wcex.style      = CS_HREDRAW | CS_VREDRAW;
            wcex.lpfnWndProc    = MyWindowProc;
            wcex.cbClsExtra     = 0;
            wcex.cbWndExtra     = 0;
            wcex.hInstance      = hInstance;
            wcex.hIcon          = 0;
            wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);
            wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW + 1);
            wcex.lpszMenuName   = 0;
            wcex.lpszClassName  = szClassName;
            wcex.hIconSm        = 0;    
            return RegisterClassEx(&wcex);
        }
    
    

    CMyWindow class, please pay attention on my trouble at WM_CREATE and WM_CREATEMYWINDOW message

        CMyWindow::CMyWindow(void)
            : _hwnd(0)
            , _hInst(0)
        {
        }
    
    
        CMyWindow::~CMyWindow(void)
        {
        }
    
        inline HWND CMyWindow::GetSafeHwnd()
        {
            return _hwnd;
        }
    
        //Craete a window
        bool CMyWindow::Create( HINSTANCE hInstance,
                                TCHAR * szWindowName,
                                DWORD dwStyle,
                                RECT& rect,
                                HWND hParentWnd,
                                HMENU hMenu,
                                LPVOID lpParam)
        {
            //get safe instance
            HINSTANCE hInst = hInstance;
            if (!hInstance)
                if (!hParentWnd)
                    return false;
                else
                    hInst = (HINSTANCE) GetWindowLong(hParentWnd, GWL_HINSTANCE);
            if (!hInst)
                return false;
    
            //register window class
            if (!RegisteWindowClass(hInst, _MY_WINDOW_CLASS_NAME_)) {
                DWORD dwErr = GetLastError();
                if (dwErr != ERROR_CLASS_ALREADY_EXISTS) //0x00000582
                    return false;
            }
    
            //claim i am creating
            SetInitWnd(this);
            //create CBT hook, then this window will add to WindowManager
            HookCrate();
            //create window
            HWND hwnd = CreateWindow(
                            _MY_WINDOW_CLASS_NAME_,
                            szWindowName,
                            dwStyle,
                            rect.left, rect.right, rect.right - rect.left, rect.bottom - rect.top,
                            hParentWnd,
                            hMenu,
                            hInstance,
                            lpParam);
            //destroy CBT hook
            HookDestroy();
    
            if (!hwnd)
                return false;
    
            _hwnd = hwnd;
            _hInst = hInst;
    
            //show window
            ShowWindow(_hwnd, SW_SHOW);
            UpdateWindow(_hwnd);
            return true;    
        }
    
        //add the this window to WindowManager
        void CMyWindow::Attach(HWND hwnd)
        {
            _hwnd = hwnd;
            CWindowManager::GetInstance()->Add(this);
    
            UnsetInitWnd();
        }
    
        //remove the this window to WindowManager
        void CMyWindow::Dettach()
        {
            CWindowManager::GetInstance()->Remove(_hwnd);
            _hwnd = 0;
        }
    
    
    
        int CMyWindow::OnCreate(LPCREATESTRUCT ps)
        {
            return (0);
        }
    
        void CMyWindow::OnCreateMyWindow()
        {
        }
    
        //the WndProc callback function
        LRESULT CALLBACK MyWindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
        {
            //Get the CMyWindow instance from WindowManager by hWnd
            CMyWindow * pwnd = CWindowManager::GetInstance()->Find(hWnd);
            //can not find thi window in WindowManager
            if (!pwnd) return DefWindowProc(hWnd, message, wParam, lParam);
    
            switch (message)
            {
            case WM_CREATE:
                {
                    //perform the OnCreate function, just like MFC's OnCreate
                    int r = pwnd->OnCreate(reinterpret_cast<LPCREATESTRUCT>(lParam));
                    if (r)  //some error occurred, will destory the window
                        return (r);
                    //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
                    //I can not create any edit box in OnCreate function,
                    //I must do it leater, when the window was created and
                    //WM_CREATEMYWINDOW was received
                    ::PostMessage(hWnd, WM_CREATEMYWINDOW, 0, 0);
                }
                break;
            /*
            case WM_.....
                other message
            case WM_.....
            */
            case WM_DESTROY:
                ::PostQuitMessage(0);
                break;
            case WM_CREATEMYWINDOW:
                //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
                //I can not create any edit box in OnCreate function,
                //I must do it when WM_CREATEMYWINDOW was received
                pwnd->OnCreateMyWindow();
                break;
            }
    
            return DefWindowProc(hWnd, message, wParam, lParam);
        }
    
    Now, inherit the class CMyWindow to create 2 windows, first window will create the second one that with a edit box
        class CMyWnd2 : public CMyWindow
        {
        public:
            CMyWnd2(void) : _hCmdEdit(0) {}
            ~CMyWnd2(void){}
    
        protected:
            HWND _hCmdEdit;
    
            //create edit box
            virtual void OnCreateMyWindow();
        };
    
    
        class CMyWnd1 : public CMyWindow
        {
        public:
            CMyWnd1(void) {}
            ~CMyWnd1(void){}
    
        protected:
            virtual int OnCreate(LPCREATESTRUCT ps);
    
            //create window2
            virtual void OnCreateMyWindow();
    
            CMyWnd2 _wnd2;
        };
    
        int CMyWnd1::OnCreate(LPCREATESTRUCT /*ps*/)
        {
            //Can create window2, but can not crate window2's edit-boxs
            return (0);
        }
    
        //create window2 with edit box
        void CMyWnd1::OnCreateMyWindow()
        {
            RECT rect = {0, 0, 400, 300};
    
            _wnd2.Create(this->_hInst,
                0,
                WS_VISIBLE | WS_POPUP,
                rect,
                _hwnd,
                0,
                0);
        }
    
    
        //create edit box
        void CMyWnd2::OnCreateMyWindow()
        {
            RECT rect;
            GetClientRect(_hwnd, &rect);
            _hCmdEdit = CreateWindowEx(
                                    WS_EX_STATICEDGE,
                                    L"EDIT",
                                    NULL,
                                    WS_CHILD | WS_VISIBLE | WS_VSCROLL | ES_LEFT | ES_MULTILINE | ES_AUTOVSCROLL,
                                    0,
                                    rect.bottom - 80,
                                    rect.right - rect.left,
                                    80,
                                    _hwnd,
                                    (HMENU) 100,
                                    (HINSTANCE) GetWindowLong(_hwnd, GWL_HINSTANCE),
                                    NULL);
        }
    
    
    Finally, WinMain function create a instance of CMyWnd1
        CMyWnd1 mainwnd;
        RECT rect;
        rect.left = rect.top = 0, rect.right = 500, rect.bottom = 400;
        mainwnd.Create(hInstance,
            L"MyWindow",
            WS_OVERLAPPEDWINDOW,
            rect,
            0,
            0,
            0);
    
        while (GetMessage(&msg, NULL, 0, 0))
        {
            if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
            {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
        }
    

    here must have something i missed, any one can help me fix this problem? Thanks again!                                                                                                                                                             

    Tuesday, August 28, 2012 6:54 PM

All replies

  • Why don't you use MFC immediately?

    Lazylamb loves smelly cat.

    Friday, August 31, 2012 6:17 PM