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


Автор: GGoga 18.7.2007, 18:41
Здравствуйте, уважаемые господа программисты! Помогите, пожалуйста, начинающему программисту smile

Как можно реализовать следующую задачу: необходимо, чтобы при наступлении определенного события, обрабатывать его в функции WindowProc. Я так понимаю, что необходимо определить свое сообщение, для этого я пишу следующий код:

Код

#define WM_GAMEOVER (WM_USER + 1)


После этого ловлю данное сообщение в функции WindowProc:
Код

long FAR PASCAL WindowProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
    using namespace arcadeworks;
    switch( message )
    {
    case WM_GAMEOVER:
        AfxMessageBox(_T("Game Over!"), MB_OK);
        break;
    case WM_ACTIVATEAPP:
...
}


И отправляю данное сообщение при наступлении события:
Код

if(ball)
{
...
    if(ball && ball->GetCollObj() == bottom)
        WindowProc(AfxGetMainWnd()->GetSafeHwnd(), WM_GAMEOVER, 0, 0);
...
}


Однако при этом ничего не происходит, сообщение "Game Over!" на экран не выводится :(

Я просто уверен, что я что-то делаю не так или не все! Вот только не знаю, что именно нужно изменить или добавить. Подскажите кто-нибудь решение проблемы. Заранее ОГРОМНОЕ СПАСИБО!

Автор: zkv 18.7.2007, 19:00
Код

if(ball && ball->GetCollObj() == bottom)
        AfxGetMainWnd()->PostMessage( WM_GAMEOVER, 0, 0 );//либо SendMessage() если нужно дождаться обработки сообщения 

интересная сигнатура у твоей WindowProc если работаешь в МФС, то перегружай соответствующий метод (WindowProc) у главного окна, и там лови 

Автор: GGoga 18.7.2007, 22:16
Цитата(zkv @ 18.7.2007,  19:00)
...
интересная сигнатура у твоей WindowProc если работаешь в МФС, то перегружай соответствующий метод (WindowProc) у главного окна, и там лови

Работаю с WinAPI с поддержкой MFC. Пробовал вариант c SendMessage(), только при этом приложение вылетает с неизвестной ошибкой :( Как ее избежать я не знаю, при троссировке показывает доступ к неизвестной области памяти... 

Автор: zkv 18.7.2007, 22:52
Цитата(GGoga @  18.7.2007,  18:41 Найти цитируемый пост)
ловлю данное сообщение в функции WindowProc

эта функция - оконная процедура главного окна?

Цитата(GGoga @  18.7.2007,  22:16 Найти цитируемый пост)
Пробовал вариант c SendMessage(), только при этом приложение вылетает с неизвестной ошибкой

видимо не приходит сообщение до адреса. Где-то напутал чего-то...

Автор: zkv 18.7.2007, 23:44
вот тебе пример рабочий:
Код

#include <windows.h>
#include "resource.h"

LRESULT CALLBACK MainProc(HWND, UINT, UINT, LONG);

#define WM_MYMESSAGE (WM_USER+1)

HINSTANCE hInst; 

int WINAPI WinMain(HINSTANCE hInstance,
        HINSTANCE hPrevInstance,
        LPSTR lpCmdLine,
        int nCmdShow)
{
    MSG msg;

    hInst = hInstance;
    ::CreateDialog( hInst, MAKEINTRESOURCE( IDD_DIALOG1 ), NULL, (DLGPROC)MainProc );

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

    return 0;
}


LRESULT CALLBACK MainProc(HWND hDlg, UINT message, UINT wParam, LONG lParam)
{
    switch(message)
    {
    case WM_MYMESSAGE:
        MessageBox( hDlg, "WM_MYMESSAGE has been received", "MyApp", MB_ICONINFORMATION | MB_OK );
        break;
    
    case WM_COMMAND:
    {
        switch( LOWORD(wParam) )
        {
        case IDCANCEL: 
            PostQuitMessage( 0 );
            break;
        case IDC_BUTTON1: 
            SendMessage( hDlg, WM_MYMESSAGE, 0, 0 );
            break;
        }
    }
    break;

    case WM_DESTROY:
        PostQuitMessage (0);
        break;
    }

    return 0;
}

проект на всякий случай прикладываю (VC7.1)

Автор: CMD 19.7.2007, 00:22
Здравствуй.
1) Ход мыслей почти правильный, только свои сообщения нужно отлавливать соответствующе, а отправляються они окну не напрямую, а через сообщение WM_COMMAND, в параметре wParam. Для твоего случая это будет выглядить так:
Код

long FAR PASCAL WindowProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
    using namespace arcadeworks;
    switch( message )
    {
          case WM_COMMAND:
                switch( LOWORD(wParam))
                {
                 case WM_GAMEOVER:
                 AfxMessageBox(_T("Game Over!"), MB_OK);
                 break;
                 
                 case WM_СООБЩЕНИЕ
                 ...
                 break;
                 }
          return 0; // Не забывай, что WM_COMMAND должен либо что-то вернуть, либо должна продолжиться обработка остальных оконных сообщений.
    case WM_ACTIVATEAPP:
...
}


2) Исходя из первого пункта думаю понятно, что ты пытаешься вызвать неопределённое действие.

Если хочешь, стучи в аську 367-й0й, й=5. Я - BO$$.

Автор: zkv 19.7.2007, 07:39
Цитата(CMD @  19.7.2007,  00:22 Найти цитируемый пост)
а отправляються они окну не напрямую, а через сообщение WM_COMMAND, в параметре wParam.

можно ссылку на источник этой информации?
почему мой код работает?

Автор: W4FhLF 19.7.2007, 08:58
Цитата(zkv @  19.7.2007,  07:39 Найти цитируемый пост)
можно ссылку на источник этой информации?


Я так понял, так делается в случае, когда в программе используется Accelerator. Но с чего решили, что он здесь используется?

http://msdn2.microsoft.com/en-us/library/ms645526.aspx
http://msdn2.microsoft.com/en-us/library/ms647591.aspx

Автор: CMD 19.7.2007, 12:42
Цитата

можно ссылку на источник этой информации?
почему мой код работает? 

Ты ж его не сам писал, вот и непотрудился разобраться, что к чему:
http://msdn2.microsoft.com/en-us/library/ms644931.aspx
Там чётко написано, какие бывают сообщения, я не видел всего твоего кода, но думаю, что целесообразнее использовать WM_APP, вместо WM_USER.

Цитата

Я так понял, так делается в случае, когда в программе используется Accelerator. Но с чего решили, что он здесь используется?

http://msdn2.microsoft.com/en-us/library/ms645526.aspx
http://msdn2.microsoft.com/en-us/library/ms647591.aspx 

Неправильно ты понял, там же доступным языком написано, что:
Цитата(http://msdn2.microsoft.com/en-us/library/aa930761.aspx)

This message is sent when the user selects a command item from a menu, when a control sends a message to its parent window, or when an accelerator keystroke is translated.

А parent window - это контрол.
Акселераторы тут непричём.

Автор: zkv 19.7.2007, 13:53
Цитата(CMD @  19.7.2007,  12:42 Найти цитируемый пост)
Ты ж его не сам писал, вот и непотрудился разобраться, что к чему:

сам, от первой до последней строчки. Хамите сударь! 

Цитата(CMD @  19.7.2007,  12:42 Найти цитируемый пост)
Там чётко написано, какие бывают сообщения, я не видел всего твоего кода, но думаю, что целесообразнее использовать WM_APP, вместо WM_USER.

почитал информацию по вашей ссылке, интересно, не знал, всегда работал с WM_USER, проблем не было. Спасибо.

Цитата(CMD @  19.7.2007,  12:42 Найти цитируемый пост)
А parent window - это контрол.

чего?

CMD, WM_COMMAND точно такое же сообщение как и все остальные в системе. 
Что пошлем, то и ловить надо, или вы хотите сказать, что если мы делаем SendMessage( WM_USER+1 ) своему окну, то ловить придется WM_COMMAND? smile
Вот поэтому и работает мой пример. В вашей ссылке говорится, что такое сообщение может использоваться другими классами окон, те возможны конфликты (в моей практике не было, кто-нить сталкивался? интересно), но кто говорил о том, что обрабатывать надо WM_COMMAND, если мы сами его не слали? Не путайте пожалуйста пользовательские сообщения с notifications контролов.

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

Автор: CMD 19.7.2007, 15:25
Цитата

сам, от первой до последней строчки. Хамите сударь! 

zkv, извини, я ошибся ибо имел ввиду автора темы - GGoga.

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

Автор: zkv 19.7.2007, 15:38
Цитата(CMD @  19.7.2007,  15:25 Найти цитируемый пост)
Что косаеться контролов - то это тоже окна

в курсе. только контрол по отношению к форме это child window, а форма по отношению к контролу как раз  parent window
Цитата(CMD @  19.7.2007,  15:25 Найти цитируемый пост)
А про конфликты - видимо имелось ввиду, что если определить сообщение, которое уже зарезервировано системой, то тогда и будут конфликты.

я тоже так понял, но до конца еще не уверен, что понял правильно, множество исходников есть, где люди используют WM_USER и не стесняются.

Автор: CMD 19.7.2007, 19:08
Цитата

я тоже так понял, но до конца еще не уверен, что понял правильно, множество исходников есть, где люди используют WM_USER и не стесняются. 


А чего тут стесняться? Из приведенных мною выше ссылок следует, что есть несколько типов сообщений, для каждого типа - есть область идентификаторов сообщений. По этому можно совершенно спокойно наплодить довольно большую кучку собственных сообщений и ни о чём не беспокоиться.

Автор: GGoga 20.7.2007, 21:59
Цитата(zkv @ 18.7.2007,  23:44)
вот тебе пример рабочий:
...

Спасибо Вам за пример!
Я вот только не могу получить указатель на окно :( Я пытаюсь вызвать функцию AfxGetMainWnd(), однако она возвращает NULL. Может она и не должна возвращать указатель, ведь приложение не MFC (хотя с его поддержкой). Если этой функцией нельзя, то как в такой ситуации быть?

А вот если сделать так:
Код

AfxGetMainWnd()->MessageBox(_T("Game Over!"), _T("Attention"), MB_OK);


То сообщение нормально, без каких-либо проблем, будет выведено на экран.

Подскажите, пожалуйста, как в такой ситуации поступить? Как правильно получить указатель на окно, если AfxGetMainWnd() возвращает NULL?

Заранее, СПАСИБО!

Автор: CMD 20.7.2007, 23:35
Цитата

А вот если сделать так:
Выделить всёБез подсветки
1:
    
AfxGetMainWnd()->MessageBox(_T("Game Over!"), _T("Attention"), MB_OK);


То сообщение нормально, без каких-либо проблем, будет выведено на экран.

Функция MessageBox будет выполянться в любом случае, при любом hWnd, даже если он равен нулю.

Цитата

Я вот только не могу получить указатель на окно :( Я пытаюсь вызвать функцию AfxGetMainWnd(), однако она возвращает NULL

А как же ты его интересно создавал? Если средствами WinAPI, то при создании сам определяешь указатель на него. Лучше приведи свой код для ясности. http://msdn2.microsoft.com/en-us/library/ms633499.aspx найдёт окно по названию.

Автор: zkv 21.7.2007, 01:44
Цитата(GGoga @  20.7.2007,  21:59 Найти цитируемый пост)
Я вот только не могу получить указатель на окно 

так а в списке параметров, тут, что приходит:
Цитата(CMD @  19.7.2007,  00:22 Найти цитируемый пост)
long FAR PASCAL WindowProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )

видимо, я ввел в заблуждение своим примером, сорри.

Цитата(CMD @  20.7.2007,  23:35 Найти цитируемый пост)
Функция MessageBox будет выполянться в любом случае, при любом hWnd, даже если он равен нулю.

да только не будет модАльности по отношению к родительскому окну

Цитата(GGoga @  20.7.2007,  21:59 Найти цитируемый пост)
А вот если сделать так:

AfxGetMainWnd() - это фича MFC, если  он у тебя подключен - используй

Автор: zkv 21.7.2007, 02:02
Цитата(GGoga @  20.7.2007,  21:59 Найти цитируемый пост)
Я вот только не могу получить указатель на окно

конечно это все дело определения терминов, но все же лучше употреблять слово хендл (HANDLE), а то возникает конфликт с понятием "указатель" в С/С++ smile
Понятно, что указатель - штука совсем другого рода?

Автор: GGoga 21.7.2007, 10:46
Цитата(CMD @ 20.7.2007,  23:35)
А как же ты его интересно создавал? Если средствами WinAPI, то при создании сам определяешь указатель на него. Лучше приведи свой код для ясности.
FindWindow найдёт окно по названию.

Спасибо!!! Это как раз и помогло, да, действительно указал имя класса и имя окна, отправил сообщение и оно обработалось!!!


Всем СПАСИБО!!! Тема закрыта!

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