Делаю что-то типа не большой библиотеки классов(типа кнопки,списки и тп) для интерфейса... Столкнулся с такой не приятной штукой когда захотел обернуть основное окно в класс. А именно когда регистрируем класс( RegisterClassEx), требуется структура WNDCLASSEX и среди прочего нужен указатель на WNDPROC . Так как у меня класс то не все так просто(. Нужно как то указать дополнительный указатель чтоб вызвать из процедуру обработки сообщений окна из класса. Пока что вариант один: Так как WNDPROC всегда получает hwnd, то есть надежда что он всегда равен тому значению которое возвратила CreateWindow, и тем самым делать поиск нужного объекта и уже из него делать вызов... Может есть лучшее варианты ? Язык программирования С++.
Просьба к модераторам удалить этот топик, так как только что пришол к выводу что mfc будет здесь более правильно.
XshStasX Сделай процедуру окна статической Свяжи указатель на экземпляр своего класса с хендлом созданного окна, через SetWindowLong. А впроцедуре окна получай этот указатель, через GetWindowLong.
В ней работает оператор this ? если да, как он туда передается?? Не совсем уверен, пытаюсь сделать что - то типа плагинной системы к интерфейсу. После чего это может быть шаблоном для визуальной части программы.
Приветствую, XshStasX. Если тебе всё еще интересен вопрос, смотри код ниже. На вопрос "В ней работает оператор this ? если да, как он туда передается??" он отвечает. Оговорюсь сразу, этот код - всего лишь демонстрация, на что-то серьёзное не претендует. MFC навяжет тебе ЕГО правила построения кода. Тебе это надо? Напиши все сам и почувствуй себя богом Удачи! main.c Код (Text): #define UNICODE #include <windows.h> #include "lib\gui\CWnd.h" #include "lib\gui\gui.h" int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR szCmdLine, int iCmdShow) { CWnd wnd; wnd.Create(true); ExitProcess(Gui_Cycle()); } gui.h Код (Text): #pragma once #define UNICODE // Параметр обработчика события может быть NULL, или содержать // указатель на структуру с параметрами, характерными для // данного обработчика typedef void(*Gui_EVENTFUNC)(void*); MSG Gui_MSG; UINT Gui_Cycle(void) { while(GetMessage(&Gui_MSG, 0, 0, 0)) { TranslateMessage(&Gui_MSG); DispatchMessage(&Gui_MSG); } return Gui_MSG.wParam; } CWnd.h Код (Text): #pragma once #define UNICODE #include <windows.h> #include "gui.h" class CWnd { HWND CWndHandle; WNDCLASSEX CWndClassEx; HINSTANCE CWndHInstance; wchar_t* CWndClassName; wchar_t* CWndTitle; static LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); public: CWnd(); void Create(boolean); void Show(); void Hide(); // Адреса функций-обработчиков событий Gui_EVENTFUNC EventOnClick; }; typedef CWnd* LPCWnd; CWnd :: CWnd() { CWndClassName = L"CWnd";; CWndTitle = L"Window";; CWndHInstance = GetModuleHandle(0); CWndClassEx.cbSize = sizeof(CWndClassEx); CWndClassEx.style = CS_HREDRAW | CS_VREDRAW; CWndClassEx.lpfnWndProc = WndProc; CWndClassEx.cbClsExtra = 0; CWndClassEx.cbWndExtra = 0; CWndClassEx.hInstance = CWndHInstance; CWndClassEx.hIcon = LoadIcon(NULL, IDI_APPLICATION); CWndClassEx.hCursor = LoadCursor(NULL, IDC_ARROW); CWndClassEx.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); CWndClassEx.lpszMenuName = 0; CWndClassEx.lpszClassName = CWndClassName; CWndClassEx.hIconSm = 0; EventOnClick = NULL; } LRESULT CALLBACK CWnd :: WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) { HDC wnd_HDC; RECT wnd_Rect; PAINTSTRUCT wnd_PS; LPCWnd p_This = (LPCWnd)GetWindowLong(hwnd, GWL_USERDATA); switch(iMsg) { case WM_CREATE: break; case WM_PAINT: wnd_HDC = BeginPaint(hwnd, &wnd_PS); GetClientRect(hwnd, &wnd_Rect); DrawText(wnd_HDC, L"Hello, World!", -1, &wnd_Rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER); EndPaint(hwnd, &wnd_PS); return 0; case WM_DESTROY: PostQuitMessage(0); // DestroyWindow(hwnd); return 0; } return DefWindowProc(hwnd, iMsg, wParam, lParam); } void CWnd :: Create(boolean ShowWindow) { RegisterClassEx(&CWndClassEx); CWndHandle = CreateWindow(CWndClassName, CWndTitle, WS_OVERLAPPEDWINDOW, 0, 0, 200, 200, 0, 0, CWndHInstance, 0); SetWindowLong(CWndHandle, GWL_USERDATA, (LONG)this); if (ShowWindow) Show(); } void CWnd :: Show() { ShowWindow(CWndHandle, SW_SHOWNORMAL); UpdateWindow(CWndHandle); } void CWnd :: Hide() { ShowWindow(CWndHandle, SW_HIDE); }
Код (Text): class TWindow { private: HWND m_Handle; public: TWindow () { m_Handle = NULL; }; virtual ~TWindow () {}; // // A single WNDPROC for all windows and for all classes // static LRESULT CALLBACK WndProc (HWND hWnd, UINT uiMsg, WPARAM wp, LPARAM lp) { // // If 'this' already attached - then simply call // virtual message map // TWindow* p = (TWindow*) ::GetWindowLong (hWnd, 0); if (p) return p -> MsgMap (uiMsg, wp, lp); // // 'this' is not attached yet. Check if it should be attached. // if (uiMsg == WM_CREATE) { p = ((TWindow**) lp) [0]; p -> OnCreate (hWnd); return 0; } // // No 'this' yet, so let Windows process all messages // before WM_CREATE will be received. // return ::DefWindowProc (hWnd, uiMsg, wp, lp); }; // // May be overriden in a child classes to provide additional // message handling, like painting and mouse response, etc. // If overriden, child ALWAYS CALLS it in 'default' case. // virtual LRESULT MsgMap (UINT uiMsg, WPARAM wp, LPARAM lp) { if (uiMsg == WM_DESTROY) { OnDestroy (); return 0; } return ::DefWindowProc (m_Handle, uiMsg, wp, lp); }; // // Child class MUST ALWAYS CALL this method BEFORE its own // processing, because here HWND and 'this' are cross // attached to each other. // virtual void OnCreate (HWND hWnd) { ::SetWindowLong (m_Handle=hWnd, 0, (LONG) this); }; // // Child class MUST ALWAYS CALL this method AFTER its own // processing, because here HWND and 'this' are cross // detached from each other. // virtual void OnDestroy () { ::SetWindowLong (m_Handle, 0, 0); m_Handle = NULL; }; // // If anything needs to be adjusted in WNDCLASS structure, then // this method must be overriden in child class and different // class name must be provided. // virtual LPCTSTR ProvideClassName () { return _T ("TWindow"); }; // // Filling WNDCLASS structure. // Child class MUST ALWAYS CALL this method BEFORE its own code. // virtual void RegisterMe (WNDCLASS& wc) { wc.lpfnWndProc = &TWindow::WndProc; wc.cbWndExtra = sizeof (this); wc.hInstance = ::GetModuleHandle (NULL); wc.hCursor = ::LoadCursor (NULL, IDC_ARROW); wc.lpszClassName = ProvideClassName (); }; // // Finally, creating a handle! // HWND CreateEx ( HWND hParent, DWORD style, DWORD xstyle, LPCTSTR title, int x, int y, int width, int height, HMENU menu_or_child_ID) { WNDCLASS wc = {0}; RegisterMe (wc); ::RegisterClass (&wc); return ::CreateWindowEx ( xstyle, wc.lpszClassName, title, style, x, y, width, height, hParent, menu_or_child_ID, wc.hInstance, this); }; }; // // Child class - main app window. // class TAppWindow : public TWindow { public: // // Different name here will trigger the proper registration by Windows // virtual LPCTSTR ProvideClassName () { return _T ("TAppWindow"); }; virtual void RegisterMe (WNDCLASS& wc) { // // First ask base class to set it up // TWindow::RegisterMe (wc); // // Then adjust some properties just for this class // wc.hbrBackground = (HBRUSH) ::GetStockObject (LTGRAY_BRUSH); wc.style = CS_VREDRAW | CS_HREDRAW; }; virtual void OnCreate (HWND hWnd) { // // First ask base class to initialise // TWindow::OnCreate (hWnd); // // Then additional setup is done: creating child windows, // loading data, configuration, etc. // //... }; virtual void OnDestroy () { // // First, do own code // ::PostQuitMessage (0); // // Then call base class to clean-up // TWindow::OnDestroy (); }; };