Значок уведомления получает WM_LBUTTONDBLCLK, но не WM_CONTEXTMENU - PullRequest
3 голосов
/ 06 декабря 2011

Я добавил значок уведомления в свое диалоговое приложение, и он получил WM_LBUTTONDBLCLK при двойном щелчке по значку, но не получает WM_CONTEXTMENU, когда по щелчку правой кнопкой мыши значок или когда значок подсвечивается с помощью клавиатуры и контекста нажата кнопка меню. Я использовал значок уведомления на примере в примерах SDK для Windows 7.1. Итак, я понятия не имею, где я иду не так или почему это не работает.

Примечание. Если я изменю WM_CONTEXTMENU на WM_RBUTTONUP, он получит событие, но координаты курсора будут неправильными.

/******************************************************************************/
/* Menu Resource                                                              */
/******************************************************************************/
LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
IDR_TRAYMENU MENU
{
    POPUP ""
    {
        MENUITEM "&Show Status Window", IDM__SHOW_STATUS_WINDOW
        MENUITEM "&About", IDM__ABOUT
        MENUITEM SEPARATOR
        MENUITEM "&Exit", IDM__EXIT
    }
}

/******************************************************************************/
/* WinMain()                                                                  */
/******************************************************************************/
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{

    // ... code unrelated to icon

    // Enable Visual Styles
    InitCommonControls();

    // create the main dialog
    if( NULL == (hWnd=CreateDialog(hInstance,MAKEINTRESOURCE(IDD_MAINDLG),NULL,(DLGPROC)WndProc)) )
    {
        MessageBox( NULL, "Error creating the main dialog!", NULL, MB_OK | MB_ICONERROR );
        return -1;
    }

    // ... code unrelated to icon

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

    return 0; 

}    
/******************************************************************************/
/* WndProc()                                                                  */
/******************************************************************************/
BOOL CALLBACK WndProc(HWND hWndDlg, UINT Message, WPARAM wParam, LPARAM lParam)
{

    switch(Message)
    {
        case WM_INITDIALOG:
        {

            // ... code unrelated to icon
            hIcon = (HICON)LoadImage( GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_DDCMP), IMAGE_ICON, 16, 16, LR_DEFAULTSIZE );

            // Setup the system tray icon
            memset( &nid, 0, sizeof(NOTIFYICONDATA) );
            nid.cbSize = sizeof(NOTIFYICONDATA);
            nid.hWnd = hWndDlg;
            nid.uID = 0xDDC;
            nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP | NIF_SHOWTIP;
            nid.uCallbackMessage = WM_APP + 0xDDC;
            nid.hIcon = hIcon;
            strcpy( nid.szTip, "DDCMP Driver" );
            Shell_NotifyIcon( NIM_ADD, &nid );

            // ... code unrelated to icon

            return true;
        } break;

        case WM_APP + 0xDDC:
        {
            switch( LOWORD(lParam) )
            {
                case WM_CONTEXTMENU:
                {
                    MessageBox( hWndDlg, "This message box never shows up.", NULL, MB_OK | MB_SYSTEMMODAL );
                    HMENU hMenu = LoadMenu(GetModuleHandle(NULL),MAKEINTRESOURCE(IDR_TRAYMENU));
                    if( hMenu )
                    {
                        HMENU hSubMenu = GetSubMenu(hMenu,0);
                        if( hSubMenu )
                        {
                            SetForegroundWindow( hWndDlg );
                            POINT pt = { LOWORD(wParam), HIWORD(wParam) };
                            UINT uFlags = TPM_RIGHTBUTTON;
                            if( 0 != GetSystemMetrics(SM_MENUDROPALIGNMENT) )
                                uFlags |= TPM_RIGHTALIGN;
                            else
                                uFlags |= TPM_LEFTALIGN;
                            TrackPopupMenuEx( hSubMenu, uFlags, pt.x, pt.y, hWndDlg, NULL );

                        }
                        DestroyMenu( hMenu );
                    }
                } break;
                case WM_LBUTTONDBLCLK:
                    if( IsWindowVisible(hWndDlg) )
                        ShowWindow( hWnd, SW_HIDE );
                    else
                        ShowWindow( hWnd, SW_SHOW );
                    break;
            }
            return true;
        } break;

        case WM_CLOSE:
            ShowWindow( hWndDlg, SW_HIDE );
            break;

        case WM_DESTROY:
        case WM_QUIT:
        {
            Shell_NotifyIcon( NIM_DELETE, &nid );

            // ... code unrelated to icon

            return true;
        } break;
    }

    return false;
}

Это WndProc из Windows 7.1 SDK Образец

    LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    static HWND s_hwndFlyout = NULL;
    static BOOL s_fCanShowFlyout = TRUE;

    switch (message)
    {
    case WM_CREATE:
        // add the notification icon
        if (!AddNotificationIcon(hwnd))
        {
            MessageBox(hwnd,
                L"Please read the ReadMe.txt file for troubleshooting",
                L"Error adding icon", MB_OK);
            return -1;
        }
        break;
    case WM_COMMAND:
        {
            int const wmId = LOWORD(wParam);
            // Parse the menu selections:
            switch (wmId)
            {
            case IDM_LOWINK:
                ShowLowInkBalloon();
                break;

            case IDM_NOINK:
                ShowNoInkBalloon();
                break;

            case IDM_PRINTJOB:
                ShowPrintJobBalloon();
                break;

            case IDM_OPTIONS:
                // placeholder for an options dialog
                MessageBox(hwnd,  L"Display the options dialog here.", L"Options", MB_OK);
                break;

            case IDM_EXIT:
                DestroyWindow(hwnd);
                break;

            case IDM_FLYOUT:
                s_hwndFlyout = ShowFlyout(hwnd);
                break;

            default:
                return DefWindowProc(hwnd, message, wParam, lParam);
            }
        }
        break;

    case WMAPP_NOTIFYCALLBACK:
        switch (LOWORD(lParam))
        {
        case NIN_SELECT:
            // for NOTIFYICON_VERSION_4 clients, NIN_SELECT is prerable to listening to mouse clicks and key presses
            // directly.
            if (IsWindowVisible(s_hwndFlyout))
            {
                HideFlyout(hwnd, s_hwndFlyout);
                s_hwndFlyout = NULL;
                s_fCanShowFlyout = FALSE;
            }
            else if (s_fCanShowFlyout)
            {
                s_hwndFlyout = ShowFlyout(hwnd);
            }
            break;

        case NIN_BALLOONTIMEOUT:
            RestoreTooltip();
            break;

        case NIN_BALLOONUSERCLICK:
            RestoreTooltip();
            // placeholder for the user clicking on the balloon.
            MessageBox(hwnd, L"The user clicked on the balloon.", L"User click", MB_OK);
            break;


        // 
        //
        // As you can very plainly see, the Windows SDK Sample ONLY used WM_CONTEXTMNEU
        // 
        //

        case WM_CONTEXTMENU:
            {
                POINT const pt = { LOWORD(wParam), HIWORD(wParam) };
                ShowContextMenu(hwnd, pt);
            }
            break;
        }
        break;

    case WMAPP_HIDEFLYOUT:
        HideFlyout(hwnd, s_hwndFlyout);
        s_hwndFlyout = NULL;
        s_fCanShowFlyout = FALSE;
        break;

    case WM_TIMER:
        if (wParam == HIDEFLYOUT_TIMER_ID)
        {
            // please see the comment in HideFlyout() for an explanation of this code.
            KillTimer(hwnd, HIDEFLYOUT_TIMER_ID);
            s_fCanShowFlyout = TRUE;
        }
        break;
    case WM_DESTROY:
        DeleteNotificationIcon();
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hwnd, message, wParam, lParam);
    }
    return 0;
}

Ответы [ 2 ]

4 голосов
/ 06 декабря 2011

Я думаю, что вам следует попробовать изменить uVersion член структуры NOTIFYICONDATA на NOTIFYICON_VERSION_4, в документации указано, что значение этого элемента скажет, как параметры uCallbackMessage будут интерпретироваться припередается функции обратного вызова.

Вы также можете взглянуть на это: Основное использование Shell_NotifyIcon в Win32

Я провел небольшое исследование, и следующееработать для вас:

memset( &nid, 0, sizeof(NOTIFYICONDATA) );
nid.cbSize = sizeof(NOTIFYICONDATA);
nid.hWnd = hWndDlg;
nid.uID = 0xDDC;
nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP | NIF_SHOWTIP;
nid.uCallbackMessage = WM_APP + 0xDDC;
nid.hIcon = hIcon;
nid.uVersion = NOTIFYICON_VERSION_4;
strcpy( nid.szTip, "DDCMP Driver" );
Shell_NotifyIcon( NIM_ADD, &nid );
Shell_NotifyIcon(NIM_SETVERSION, &nid);

NIM_SETVERSION (MSDN):

Shell32.dll версии 5.0 и выше только.Указывает области уведомлений вести себя в соответствии с номером версии, указанным в элементе uVersion структуры, на которую указывает lpdata.Номер версии указывает, какие участники распознаются.

3 голосов
/ 06 декабря 2011

Значок уведомления изменил поведение за последние годы. По соображениям совместимости с уже существующим кодом вы должны включить новое поведение. Если вы не согласны, вы не получите WM_CONTEXTMENU сообщений. Вместо этого вы должны ответить на WM_RBUTTONUP. Даже если вы вызываете контекстное меню с клавиатуры, система все равно отправляет WM_RBUTTONUP. Вы должны получить позицию курсора, чтобы узнать, где показывать меню, вызвав GetCursorPos.

Вы можете включить новое поведение (и WM_CONTEXTMENU), как описано в документации , вызвав Shell_NotifyIcon, передав NIM_SETVERSION после вызова NIM_ADD. Предположительно пример SDK, который вы смотрите, делает это где-то. Я думаю, это то, чего не хватает в вашем коде.

Выдержка из документации приведена в разделе замечаний:

Начиная с Windows 2000 (Shell32.dll версии 5.0), события мыши и клавиатуры Shell_NotifyIcon обрабатываются иначе, чем в более ранних версиях оболочки, найденных в Microsoft Windows NT 4.0, Windows 95 и Windows 98. Различия заключаются в следующем:

  • Если пользователь выбирает контекстное меню значка уведомления с помощью клавиатуры, оболочка теперь отправляет соответствующему приложению сообщение WM_CONTEXTMENU. Более ранние версии отправляют сообщения WM_RBUTTONDOWN и WM_RBUTTONUP.
  • Если пользователь выбирает значок уведомления с помощью клавиатуры и активирует его с помощью клавиши ПРОБЕЛ или ВВОД, оболочка версии 5.0 отправляет соответствующему приложению уведомление NIN_KEYSELECT. Более ранние версии отправляют сообщения WM_RBUTTONDOWN и WM_RBUTTONUP.
  • Если пользователь выбирает значок уведомления мышью и активирует его клавишей ENTER, оболочка теперь отправляет ассоциированному приложению уведомление NIN_SELECT. Более ранние версии отправляют сообщения WM_RBUTTONDOWN и WM_RBUTTONUP.
...