Динамические подсказки C

#c #tooltip

#c #всплывающая подсказка

Вопрос:

Мы пытаемся создать динамические всплывающие подсказки, в которых всплывающая подсказка изменяется в зависимости от выбранного пользователем языка. (64-разрядное приложение C win api, внешние библиотеки не используются)

Однако мы не можем заставить это работать. Всплывающая подсказка отображает только первую букву текста. Снипет кода:

 wchar_t* ws = new wchar_t[200];
swprintf(ws, 200, L"Hello");

TTTOOLINFOW toolInfoW = { 0 };
toolInfoW.cbSize = sizeof(toolInfoW);
toolInfoW.hwnd = hDlg;
toolInfoW.uFlags = TTF_IDISHWND | TTF_SUBCLASS;
toolInfoW.uId = (UINT_PTR)hwndTool;
toolInfoW.lpszText = ws;
 

Даже если мы жестко закодируем «Привет», отображается только первая буква

 TTTOOLINFOW toolInfoW = { 0 };
toolInfoW.cbSize = sizeof(toolInfoW);
toolInfoW.hwnd = hDlg;
toolInfoW.uFlags = TTF_IDISHWND | TTF_SUBCLASS;
toolInfoW.uId = (UINT_PTR)hwndTool;
toolInfoW.lpszText = L"Hello";
 

Должно быть, мы упускаем что-то чрезвычайно очевидное, потому что заставить это работать не может быть так сложно.

Заранее спасибо за любые советы.

Комментарии:

1. Вероятно, вам нужно убедиться, что более новая версия общей библиотеки элементов управления (comctl32.dll ) используется путем указания манифеста. Например, добавьте в свой код следующую директиву: #pragma comment(linker, ""/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'"")

2. Кроме того, у вас есть UNICODE и _UNICODE определено?

3. Спасибо за советы — у нас уже были реализованы оба из них. Все еще нет радости.

Ответ №1:

Из любопытства я попробовал это, и следующий код действительно работал при компиляции для x64 с использованием MSVC 2019 в Windows 10. Он создает простое окно с кнопкой в нем, и при наведении курсора мыши на эту кнопку отображается всплывающая подсказка с текстом This works! ☺ (содержащим символ смайлика в Юникоде).

Обязательно скомпилируйте этот пример с включенным C 17, иначе буфер, возвращаемый с помощью data() , будет иметь тип const wchar_t* и, следовательно, будет несовместим с lpszText (членом TTTOOLINFOW структуры), который имеет тип LPWSTR , т.е. Просто wchar_t* .

 #pragma comment(linker, ""/manifestdependency:type='win32' 
    name='Microsoft.Windows.Common-Controls' version='6.0.0.0' 
    processorArchitecture='*' publicKeyToken='6595b64144ccf1df' 
    language='*'"")
#pragma comment(lib, "comctl32.lib")

#define _WIN32_WINNT _WIN32_WINNT_WIN10

#ifndef UNICODE
#define UNICODE
#endif
#ifndef _UNICODE
#define _UNICODE
#endif

#include <SDKDDKVer.h>
#include <windows.h>
#include <commctrl.h>

#include <string>

HINSTANCE g_hInstance{ nullptr };

HWND CreateMyButton(HINSTANCE hInstance, HWND hWndApp)
{
    return ::CreateWindowExW(0UL, L"BUTTON", L"Hover over this button",
        WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, 45, 10, 200, 35,
        hWndApp, nullptr, hInstance, nullptr);
}

void CreateMyTooltip(HWND hWndParent, HWND hWndControl)
{
    HWND hWndTip{ ::CreateWindowExW(WS_EX_TOPMOST, TOOLTIPS_CLASSW,
        nullptr, WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP, 0, 0, 0, 0,
        hWndParent, nullptr, nullptr, nullptr) };

    ::SetWindowPos(hWndTip, HWND_TOPMOST, 0, 0, 0, 0,
        SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);

    std::wstring wsTooltipText{ L"This works! u263A" };

    TTTOOLINFOW ti{};
    ti.cbSize   = sizeof ti;
    ti.uFlags   = TTF_IDISHWND | TTF_SUBCLASS;
    ti.hwnd     = hWndParent;
    ti.uId      = reinterpret_cast<UINT_PTR>(hWndControl);
    ti.lpszText = wsTooltipText.data();

    ::SendMessageW(hWndTip, TTM_ADDTOOL, 0U, reinterpret_cast<LPARAM>(amp;ti));
}

LRESULT CALLBACK MyWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
    case WM_CREATE:
        CreateMyTooltip(hWnd, CreateMyButton(g_hInstance, hWnd));
        break;

    case WM_DESTROY:
        ::PostQuitMessage(0);
        break;

    default:
        break;
    }

    return ::DefWindowProcW(hWnd, msg, wParam, lParam);
}

int WINAPI wWinMain(_In_ HINSTANCE hInstance,
    _In_opt_ HINSTANCE, _In_ LPWSTR, _In_ int)
{
    g_hInstance = hInstance;

    const INITCOMMONCONTROLSEX initControls
    {
        sizeof(INITCOMMONCONTROLSEX),
        ICC_STANDARD_CLASSES | ICC_WIN95_CLASSES
    };
    ::InitCommonControlsEx(amp;initControls);

    WNDCLASSW wc{};
    wc.lpfnWndProc   = MyWndProc;
    wc.hInstance     = hInstance;
    wc.hCursor       = ::LoadCursorW(nullptr, IDC_ARROW);
    wc.hbrBackground = ::GetSysColorBrush(COLOR_3DFACE);
    wc.lpszClassName = L"Tooltip";

    ::RegisterClassW(amp;wc);
    ::CreateWindowExW(0UL, wc.lpszClassName, L"Tooltip Example",
        WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT,
        300, 100, nullptr, nullptr, hInstance, nullptr);

    MSG msg{};
    while (::GetMessageW(amp;msg, nullptr, 0U, 0U))
    {
        ::TranslateMessage(amp;msg);
        ::DispatchMessageW(amp;msg);
    }

    return static_cast<int>(msg.wParam);
}