Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Системное программирование и WinAPI > Классы и WindowProc


Автор: Vizator 10.12.2007, 16:24
В структуре WNDCLASS есть параметр lpfnWndProc.
У меня есть класс, который будет рулить всеми действимя с окном, хотлеосьбы чтобы и калл бэк функция была внутри класса, возможно ли это и как это сделать ?

Автор: Lazin 10.12.2007, 16:50
Можно, но только если она статическая.

Автор: Vizator 10.12.2007, 16:55
Цитата(Lazin @  10.12.2007,  16:50 Найти цитируемый пост)
Можно, но только если она статическая. 


Как это сделать ?

Автор: Lazin 10.12.2007, 17:13
Вот так
Код

class MyClass
{
 static LRESULT CALLBACK MainWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
 {
    return ::DefWindowProc(hwnd, uMsg, wParam, lParam);
 }
};

Если метод не будет статическим, его нельзя будет передать в качестве ф-ии обратного вызова, так как там неявно передается указатель на this

Автор: Vizator 10.12.2007, 17:17
Спасибо, разобрался

Добавлено через 14 минут
А не статический вариант невозможен ?

Автор: SABROG 10.12.2007, 17:31
Сначала как-то так
Код

LRESULT APIENTRY CallbackProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 

...


или

LRESULT CALLBACK MainWndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
...
}


а потом как-то так

Код

MyClass *pClass = new MyClass((WNDPROC) CallbackProc);


И там уже присваиваешь переданную ссылку внутреннему указателю-члену класса.

Или попробывать объявить статический метод:

Код

#include

class menu

{
public:
static void clear_screen(void);
// Здесь должны быть другие методы
private:
int number_of_menu_options;
};

void menu::clear_screen(void)

{
cout << '\033' << "[2J";
}

void main(void)

{
menu::clear_screen();
}

Автор: Vizator 10.12.2007, 17:44
Это немного не то, хотелось бы чтобы кал бэк функция лежала внутри класса и принадлежала ему. Т.е. что то типа

Код

class cMainWnd
{
private:
       WNDCLASS wnd;
       .......
       LRESULT CALLBACK WindowProc(HWND,UINT,WPARAM,LPARAM); 

}


и чтобы в wnd.lpfnWndProc указывать именно ее , а не определенную в глобальном контексте, а статический метод накладывает ряд ограничений и неудобств

Автор: SABROG 10.12.2007, 17:59
Вот, почитай, может поможет http://www.gamedev.ru/faq/?id=34

Автор: 586 10.12.2007, 19:20
Код
wc.cbWndExtra=sizeof(long);
...
CMyClass *MyClass;
...
SetWindowLong(hWnd, 0, (long)MyClass);
...
LRESULT CALLBACK CMyClass::StaticWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    return ((CMyClass*)GetWindowLong(hWnd, 0))->WndProc(hWnd, uMsg, wParam, lParam);
}

Автор: Cycle 11.12.2007, 13:24
586, Правильно пишет. Добавлю только маленькое замечание. Для использования SetWindowLong необходимо установить значение атрибута cbWndExtra равным sizeof(LONG) при регистрации класса окна.

Автор: Simargl 13.12.2007, 00:22
там ещё с помощью "асма" можно сделать.

Автор: EnergoHokum 14.12.2007, 09:14
А там, где
Код

CMyClass* MyClass;
...
SetWindowLong(hWnd, 0, (long)MyClass);
...

Не должно-ли быть
Код

CMyClass* MyClass;
...
MyClass=(CMyClass*)SetWindowLong(hWnd, 0, (long)MyClass);
...


Хотя нет, что-то у меня не так. Что именно --  не пойму пока.

Автор: 586 14.12.2007, 15:20
Цитата(EnergoHokum @  14.12.2007,  09:14 Найти цитируемый пост)
Не должно-ли быть ...

НЕТ. 
Цитата
Что именно --  не пойму пока.

Может внутри класса?

Код
void CMyClass::Create()
{
    ...
    SetWindowLong(hWnd, 0, (long)this);
    ...
}

Автор: EnergoHokum 14.12.2007, 15:46
Использую MinGW и GCC, не получилось внутрь класса вкрячить перенастройку на собственную нестатическую функцию (тоже внутри класса) обработки сообщений. Тут ведь что получается (в моём понимании):

1. Создаём замещающую функцию-обработчик сообщений
2. Получаем указатель на стандартную функцию-обработчик сообщений графпримитива, который тоже в классе создаётся  (GetWindowLong)
3. Перенастраиваем (SetWindowLong) графпримитив на новую функцию-обработчик

Так вот, уже при получении указателя на стандартный обработчик начиналась ругань. Сейчас наворотил костылей, вынес и создание графпримитивов, и новые обработчики, и перенастройку за пределы класса. Но это костыли, а как нормально сделать -- пока не знаю.

Автор: 586 14.12.2007, 16:02
Цитата(EnergoHokum @  14.12.2007,  15:46 Найти цитируемый пост)
Так вот, уже при получении указателя на стандартный обработчик начиналась ругань.

Можно подробнее? И код, где ошибка.

Автор: EnergoHokum 14.12.2007, 16:23
Я определил указатель на функцию-обработчик (которая внутри класса) вне класса,
Код

typedef LRESULT (TestClass::*pButton10Proc) (HWND,UINT,WPARAM,LPARAM);
pButton10Proc pTCB10P;

В классе определил саму функцию-обработчик
Код

// dll5.h
class TestClass
{
 public:
    TestClass(HWND hwnd);
    ~TestClass();
    LRESULT CALLBACK Button10Proc(HWND hwnd,UINT message,            \
                            WPARAM wParam,LPARAM lParam    \
                            );
};

Код

// dll5.cpp

TestClass::TestClass(HWND hwnd)
{
    hButton10=::CreateWindowEx(WS_EX_STATICEDGE,                \
                             "Button","Button 10",        \
                             WS_CHILD | WS_VISIBLE,        \
                             180,25,180,35,                        \
                             hWnd,0,NULL,NULL                    \
                             );

    pTCB10P=(pButton10Proc) (::SetWindowLong(hButton10,GWL_WNDPROC,(LONG)pTC));// pTC - указатель на TestClass, определён в h-ке
}

LRESULT CALLBACK TestClass::Button10Proc(HWND hwnd,UINT message,        \
                                 WPARAM wParam,LPARAM lParam    \
                                 )
{// пока пустая, потому что не работает
    return 0;
}


И на вызове SetWindowLong говорит, что не может привести результат SetWindowLong (LONG) к указателю, и про (LONG)pTC тоже говорит, что так нельзя.
Я скоро уйду, приду только в понедельник (может, в воскресенье). Если что надумаю -- напишу.

Автор: 586 14.12.2007, 16:44
Код
class TestClass
{
 public:
    TestClass(HWND hwnd);
    ~TestClass();
    static LRESULT  CALLBACK StaticButton10Proc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
    LRESULT Button10Proc(HWND hwnd,UINT message,            \
                            WPARAM wParam,LPARAM lParam    \
                            );
};


Код
TestClass::TestClass(HWND hwnd)
{
    hButton10=::CreateWindowEx(WS_EX_STATICEDGE,                \
                             "Button","Button 10",        \
                             WS_CHILD | WS_VISIBLE,        \
                             180,25,180,35,                        \
                             hWnd,0,NULL,NULL                    \
                             );

    pTCB10P=(pButton10Proc) (::SetWindowLong(hButton10,GWL_WNDPROC,(LONG)StaticButton10Proc));
    SetWindowLong(hButton10, GWL_USERDATA, (long)this);
}

LRESULT CALLBACK TestClass::StaticButton10Proc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
     return ((TestClass*)GetWindowLong(hWnd, GWL_USERDATA))->Button10Proc(hWnd, uMsg, wParam, lParam);
}

LRESULT TestClass::Button10Proc(HWND hwnd,UINT message,        \
                                 WPARAM wParam,LPARAM lParam    \
                                 )
{
    return CallWindowProc(pTCB10P, hWnd, uMsg, wParam, lParam);
}

Код не проверял, могут быть ошибки

Автор: Earnest 14.12.2007, 18:50
EnergoHokum, ты с упорством, достойным лучшего применения, пытаешься таки подсунуть метод класса в качестве WndProc. Что показывает, что ты не понимаешь сути. Это не просто придурь компилятора. Ты думаешь, раз сигнатуры статической или глобальной функции выглядят так же как сигнатура метода, то одно можно подсунуть вместо другого? У метода есть дополнительный неявный аргумент - this, который и нарушает похожесть сигнатур. При вызове метода он идет первым аргументом. А CALLBACK-функции его просто взять неокуда. Поэтому оконная функция может быть только статической. Далее, она может как-то определить, какой объект твоего класса соответствует hWnd и вызвать для этого объекта метод. Как определить - дело техники. Можно, как тебе показали, засунуть указатель в доп. память hWnd. Можно поддерживать внешний глобальный map hWnd->pWnd. Можно еще что-нибуль придумать. Но обойтись без этого "что-нибудь" не удастся. 

Автор: EnergoHokum 17.12.2007, 07:46
Я понимал, но "местами" (какими -- не скажу smile). Теперь ясно. Спасибо за разъяснение!

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)