Вспоминаем Си. Превращаем элемент управления в hyper-link

Оказалось нужным открытие браузера с нужным адресом при нажатии на тексте. Все довольно простенько.
Файл ресурсов:

#include <windows.h>

#define IDD_DIALOG1     1000
#define IDC_LINK_GOOGLE 1100

LANGUAGE LANG_NEUTRAL, SUBLANG_DEFAULT
IDD_DIALOG1 DIALOGEX 0, 0, 186, 27
STYLE DS_3DLOOK | DS_CENTER | DS_MODALFRAME | DS_FIXEDSYS | WS_VISIBLE
      | WS_BORDER | WS_CAPTION | WS_DLGFRAME | WS_POPUP | WS_SYSMENU
CAPTION "Dialog"
FONT 8, "Ms Shell Dlg 2", 400, 0, 1
{
    DEFPUSHBUTTON   "Quit", IDOK, 129, 7, 45, 14
    LTEXT           "Click for google", IDC_LINK_GOOGLE, 25, 9, 53, 8, SS_LEFT
                    | SS_NOTIFY
}

Сырец:

#include <windows.h>

#define IDD_DIALOG1     1000
#define IDC_LINK_GOOGLE 1100

// Main window callback function
LRESULT CALLBACK DlgProc(HWND hwnd,UINT msg,WPARAM wparam,LPARAM lparam) {
    switch (msg) {
        case WM_CLOSE:
            // close dialog box
            EndDialog(hwnd, 0);
            return 1L;
        case WM_COMMAND:
            switch (LOWORD(wparam)) {
                case IDOK:
                    EndDialog(hwnd, 0);
                    return 1L;
                case IDC_LINK_GOOGLE:
                    ShellExecute(hwnd,"open","http://google.ru",0,0,0);
                    return 1L;
            }
    }
    return 0L;
}

// winmain entry point
int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrev,LPSTR line,int CmdShow)
{
    DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG1),HWND_DESKTOP,
              reinterpret_cast(DlgProc));
}

компилим:

rc res.rc
cl -c hyperlink.cpp
link hyperlink.obj res.res user32.lib shell32.lib

Главный момент в этом сырце выделен красным цветом. Обязательно надо поставить флаг SS_NOTIFY, иначе элемент управления не будет сообщать нашей функции о клике на нем.

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

Итак, узнаем, что за данный финт ушами у нас отвечает сообщение WM_SETCURSOR и добавляем в обработчик наш код:

...
    case WM_SETCURSOR:
        // сравниваем ID элемента с нашим
        if (GetDlgCtrlID((HWND)wparam) == IDC_LINK_GOOGLE) {
            // если это наш STATIC, то устанавливаем курсор в виде руки
            SetCursor(LoadCursor(NULL,IDC_HAND));
            return 1L;
        }
        break;
...

Компилим, запускаем и, как результат, получаем полное зеро, никаких отличий. Сиё действие замечательно работает в обычном окне, созданном при помощи CreateWindow(Ex), а вот в диалоге почему-то не прокатывает.

MSDN нам всем поможет :) Внимательно читаем про DialogProc Callback Function. Оказывается,

If the dialog box procedure processes a message that requires a specific return
value, the dialog box procedure should set the desired return value by calling
SetWindowLong(hwndDlg, DWL_MSGRESULT, lResult) immediately before returning
TRUE. Note that you must call SetWindowLong immediately before returning TRUE;
doing so earlier may result in the DWL_MSGRESULT value being overwritten by a
nested dialog box message.

Вооружившись «новым» знанием добавляем строчечку:

...
    case WM_SETCURSOR:
        // сравниваем ID элемента с нашим
        if (GetDlgCtrlID((HWND)wparam) == IDC_LINK_GOOGLE) {
            // если это наш STATIC, то устанавливаем курсор в виде руки
            SetCursor(LoadCursor(NULL,IDC_HAND));
            SetWindowLong(hwnd, DWL_MSGRESULT, TRUE);
            return 1L;
        }
        break;
...

Теперь при наведении курсора мыши на наш STATIC (да и любой другой элемент), мы можем установить любой выбранный нами курсор. Вот такая вот сказочка про гиперссылки.

Запись опубликована в рубрике Программирование с метками , . Добавьте в закладки постоянную ссылку.

Добавить комментарий