Модераторы: feodorv, GremlinProg, xvr, Fixin
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Обёртка (инкапсулирование) WinAPI целиком в классы, Проблема с созданием окна 
V
    Опции темы
nobody0
Дата 8.8.2012, 09:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 13
Регистрация: 20.12.2010

Репутация: нет
Всего: нет



Добрый день.

Пытаюсь построить простенькую классовую оболочку для WinAPI (т.е. крайне простенький аналог MFC), но никак не могу разобраться с проблемой. Для простоты пока попытка реализовать без MDI.

Интерфейс базового класса окна (файл KWnd.h):
Код

#include <Windows.h>

class KWnd
{
    virtual void OnDraw(HDC hDC)
    {}
    virtual void OnKeyDown(WPARAM wParam, LPARAM lParam)
    {}
    virtual LRESULT WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
    bool RegClass(LPCTSTR lpszClass, LPCSTR lpszMenuName, HINSTANCE hInst, UINT classStyle);
    static LRESULT CALLBACK StaticWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
public:
    HWND m_hWnd;
    KWnd()
    {
        m_hWnd = NULL;
    }
    virtual ~KWnd()
    {}

    virtual bool CreateEx(DWORD dwExStyle, LPCTSTR lpszClass, LPCTSTR lpszName, UINT classStyle, DWORD dwStyle,
                          int x, int y, int nWidth, int nHeight, HWND hParent, LPCSTR lpszMenuName, HINSTANCE hInst);
    virtual WPARAM MessageLoop(void);
    BOOL ShowWindow(int nCmdShow) const
    {
        return ::ShowWindow(m_hWnd, nCmdShow);
    }
    BOOL UpdateWindow() const
    {
        return ::UpdateWindow(m_hWnd);
    }
};


Реализация методов  (файл KWnd.cpp):
Код

#include "KWnd.h"
LRESULT KWnd::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch(uMsg)
    {
    case WM_KEYDOWN:
        OnKeyDown(wParam, lParam);
        return 0;
    case WM_PAINT:
        {
            PAINTSTRUCT ps;

            BeginPaint(m_hWnd, &ps);
            OnDraw(ps.hdc);
            EndPaint(m_hWnd, &ps);
        }
        return 0;
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    default:
        return DefWindowProc(hWnd, uMsg, wParam, lParam);
    }
}

LRESULT CALLBACK KWnd::StaticWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    KWnd *pWnd = 0;
    if ( uMsg == WM_NCCREATE )
    {
        if ( IsBadReadPtr((void*) lParam, sizeof(CREATESTRUCT)) ) // проверка, имеет ли процесс право чтения указанного региона памяти
            MessageBox(NULL, "The lParam for new window does not have read access to all bytes.", "Error", MB_OK | MB_ICONSTOP);
        pWnd = (KWnd *)(((LPCREATESTRUCT)lParam)->lpCreateParams);
        if ( IsBadReadPtr(pWnd, sizeof(KWnd)))
            MessageBox(NULL, "The pointer to new window does not have read access to all bytes.", "Error", MB_OK | MB_ICONSTOP);
        SetWindowLongPtr(hWnd, GWL_USERDATA, (LONG_PTR)(pWnd));
    } else
        pWnd = (KWnd *)(GetWindowLongPtr(hWnd, GWL_USERDATA));
    if ( pWnd )
        return pWnd -> WndProc(hWnd, uMsg, wParam, lParam);
    else
        return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

bool KWnd::RegClass(LPCTSTR lpszClass, LPCSTR lpszMenuName, HINSTANCE hInst, UINT classStyle)
{
    WNDCLASSEX wc;
    if( !GetClassInfoEx(hInst, lpszClass, &wc) )
    {
        wc.cbSize         = sizeof(wc);
        wc.lpfnWndProc    = StaticWndProc;
        wc.cbClsExtra     = 0;
        wc.cbWndExtra     = 0;
        wc.hInstance      = NULL;
        wc.hIcon          = LoadIcon(NULL, IDI_APPLICATION);
        wc.hCursor        = LoadCursor(NULL, IDC_ARROW);
        wc.hbrBackground  = (HBRUSH) GetStockObject(GRAY_BRUSH);
        wc.lpszMenuName   = lpszMenuName;
        wc.lpszClassName  = NULL;
        wc.hIconSm        = LoadIcon(NULL, IDI_APPLICATION);
        wc.hInstance      = hInst;
        wc.lpszClassName  = lpszClass;
        wc.style          = classStyle;

        if( !RegisterClassEx(&wc) )
        {
            char msg[100] = "Cannot register class: ";
            strcat(msg, lpszClass);
            MessageBox(NULL, msg, "Error", MB_OK | MB_ICONSTOP);
            return false;
        }
    }
    return true;
}

bool KWnd::CreateEx(DWORD dwExStyle, LPCTSTR lpszClass, LPCTSTR lpszName, UINT classStyle, DWORD dwStyle,
              int x, int y, int nWidth, int nHeight,
              HWND hParent, LPCSTR lpszMenuName, HINSTANCE hInst)
{
    if ( !RegClass(lpszClass, lpszMenuName, hInst, classStyle) )
        return false;

    m_hWnd = CreateWindowEx(dwExStyle, lpszClass, lpszName, dwStyle,
                            x, y, nWidth, nHeight,
                            hParent, (HMENU)NULL, hInst, NULL);
    if(!m_hWnd)
        MessageBox(NULL, "Cannot create main window", "Error",MB_OK);
    return m_hWnd != NULL;
}


WPARAM KWnd::MessageLoop()
{
    MSG msg;

    while ( GetMessage(&msg, NULL, 0, 0) )
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return msg.wParam;
}



На базе этого класса создается класс основного окна приложения:
Код

#include <Windows.h>
#include "KWnd.h"

class MainWindow : public KWnd
{
    RECT rect;

    void OnKetDown(WPARAM wParam, LPARAM lParam );
    void OnDraw(HDC hDC);

    // процедура для диалогового окна о создании нового изображения
    //static BOOL DlgNewProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
    static BOOL CALLBACK StaticDlgNewProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
    LRESULT WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
public:
    MainWindow()
    {
        m_hWnd = NULL;
    }
};

// реализация методов
void MainWindow::OnKetDown(WPARAM wParam, LPARAM lParam )
{
    switch(wParam)
    {
    case VK_ESCAPE:
        SendMessage(m_hWnd, WM_CLOSE, 0, 0);
        break;
    }
}
void MainWindow::OnDraw(HDC hDC)
{
    // тестовый вывод
    GetClientRect (m_hWnd, &rect);
    DrawText(hDC, "Некий текст.", -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
    SetPixel(hDC, 50, 50, RGB(255,0,0));
}

LRESULT MainWindow::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch(uMsg)
    {
    case WM_PAINT:
    {
        PAINTSTRUCT ps;
        BeginPaint(hWnd, &ps);
        OnDraw(ps.hdc);
        EndPaint(hWnd, &ps);
        break;
    }
    case WM_COMMAND:
        switch(LOWORD(wParam))
        {
        case ID_EXIT:
            SendMessage(hWnd, WM_CLOSE, 0, 0);
            break;
        default: break;
        }
        InvalidateRect(hWnd, NULL, TRUE);
        break;
    case WM_CLOSE:
        if (IDYES == MessageBox(hWnd, "Точно закрыть приложение?", "", MB_YESNO | MB_ICONQUESTION))
            DestroyWindow(hWnd);
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, uMsg, wParam, lParam);
    }
    return 0;
}




Основная функция программы:
Код

int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nCmdShow)
{
    MainWindow MainWnd;
    MainWnd.CreateEx(0, "MainWnd","Основное окно",
                     CS_HREDRAW | CS_VREDRAW, WS_OVERLAPPEDWINDOW,
                     CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, NULL, NULL, hInst);
    MainWnd.ShowWindow(nCmdShow);
    MainWnd.UpdateWindow();
    return MainWnd.MessageLoop();
}


А теперь к проблеме. При попытке запуска всего этого возникает сообщение из строки 35 второго куска кода (статический метод базового класса), вследствие чего окно худо бедно создается, но ненормальное — в нем ничего не рисуется функцией OnDraw(...), а когда закрываешь с помощью крестика выполнение программы не прекращается (и соответственно сообщения о закрытии тоже нет, т.к. не обрабатываются события). 

В чем может быть проблема?


P.S. Сразу замечу, что если использовать MDI, то главное окно функционирует должным образом, но я не хочу лезть в разбирательства еще и с этим MDI, поэтому хотелось бы без этого. Модификация с MDI заключается в следующем: содержимое функции  StaticWndProc заменяется на:
Код

LRESULT CALLBACK KWnd::StaticWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    KWnd *pWnd = 0;
    if ( uMsg == WM_NCCREATE )
    {
        if ( IsBadReadPtr((void*) lParam, sizeof(CREATESTRUCT)) ) // проверка, имеет ли процесс право чтения указанного региона памяти
            MessageBox(NULL, "The lParam for new window does not have read access to all bytes.", "Error", MB_OK | MB_ICONSTOP);
        MDICREATESTRUCT * pMDIC = (MDICREATESTRUCT *) ((LPCREATESTRUCT) lParam) -> lpCreateParams;
        pWnd = (KWnd *) (pMDIC -> lParam);
        if ( IsBadReadPtr(pWnd, sizeof(KWnd)))
            MessageBox(NULL, "The pointer to new window does not have read access to all bytes.", "Error", MB_OK | MB_ICONSTOP);
        SetWindowLongPtr(hWnd, GWL_USERDATA, (LONG_PTR)(pWnd));
    } else
        pWnd = (KWnd *)(GetWindowLongPtr(hWnd, GWL_USERDATA));
    if ( pWnd )
        return pWnd -> WndProc(hWnd, uMsg, wParam, lParam);
    else
        return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

А содержимое функции создания окна CreateEx заменяется на:
Код

bool KWnd::CreateEx(DWORD dwExStyle, LPCTSTR lpszClass, LPCTSTR lpszName, UINT classStyle, DWORD dwStyle,
              int x, int y, int nWidth, int nHeight,
              HWND hParent, LPCSTR lpszMenuName, HINSTANCE hInst)
{
    if ( !RegClass(lpszClass, lpszMenuName, hInst, classStyle) )
        return false;

    MDICREATESTRUCT mdic;
    memset(&mdic, 0, sizeof(mdic));
    mdic.lParam = (LPARAM) this;
    m_hWnd = CreateWindowEx(dwExStyle, lpszClass, lpszName, dwStyle,
                            x, y, nWidth, nHeight,
                            hParent, (HMENU)NULL, hInst, &mdic);
    if(!m_hWnd)
        MessageBox(NULL, "Cannot create main window", "Error",MB_OK);
    return m_hWnd != NULL;
}


Вследствие чего полагаю, что проблемы именно в базовом классе с этими двумя функциями... Может, не вижу какой-то мелочи?

Это сообщение отредактировал(а) nobody0 - 8.8.2012, 09:40
PM   Вверх
borisbn
Дата 8.8.2012, 14:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 6
Всего: 135



Я тебе сразу скажу, что помощи отменя не жди (я просто не знаю этой области), но не мог бы ты посмотреть профиль участника форума Shaggie и ответить на вопрос, содержащийся в его подписи ?


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
nobody0
Дата 8.8.2012, 16:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 13
Регистрация: 20.12.2010

Репутация: нет
Всего: нет



borisbn, для нормального познания рассматриваемой темы, это же всего лишь база в учебном процессе. Если не использовать классы, то будет много глобальных переменных, что не очень приятно. А использовать готовые классы — это уже следующая стадия обучения.
PM   Вверх
nobody0
Дата 8.8.2012, 19:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 13
Регистрация: 20.12.2010

Репутация: нет
Всего: нет



Проблема разрешена:
В функции создания окна CreateEx нужно последний параметр функции CreateWindowEx заменить на this, т.к. в функции StaticWndProc вызывается оно вызывается как lpCreateParams.
PM   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Системное программирование и WinAPI"
Fixin
GremlinProg
xvr
feodorv
  • Большое количество информации и примеров с использованием функций WinAPI можно найти в MSDN
  • Описание сообщений, уведомлений и примеров с использованием компонент WinAPI (BUTTON, EDIT, STATIC, и т.п.), можно найти в MSDN Control Library
  • Непосредственно, перед созданием новой темы, проверьте заголовок и удостоверьтесь, что он отражает суть обсуждения.
  • После заполнения поля "Название темы", обратите внимание на наличие и содержание панели "А здесь смотрели?", возможно Ваш вопрос уже был решен.
  • Приводите часть кода, в которой предположительно находится проблема или ошибка.
  • Если указываете код, пользуйтесь тегами [code][/code], или их кнопочными аналогами.
  • Если вопрос решен, воспользуйтесь соответствующей ссылкой, расположенной напротив названия темы.
  • Один топик - один вопрос!
  • Перед тем как создать тему - прочтите это .

На данный раздел распространяются Правила форума и Правила раздела С++:Общие вопросы .


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Chipset, Step, Fixin, GremlinProg, xvr. feodorv.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Системное программирование и WinAPI | Следующая тема »


 




[ Время генерации скрипта: 0.0855 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.