Unicode工具提示未显示。

4

我正在尝试在我的应用程序窗口中显示Unicode工具提示,但它们似乎无法显示。非Unicode文本可以正确显示,但一旦我尝试使用Unicode,就没有工具提示显示出来。以下是我目前正在做的事情,任何帮助都将不胜感激。

     HWND parentHwnd = pickInfo->getViewer().getCachedHwnd();
  CWnd *pWnd = CWnd::FromHandlePermanent(parentHwnd);
  HINSTANCE hInstance = GetModuleHandle(NULL);

  if (isUnicode)
   m_toolInfoW.lpszText = L"This tooltip does not show up at all.";
  else
   m_toolInfoA.lpszText = "Non unicode text";

  if (!m_bTooltipInitialized){
   ::SendMessage(m_tooltipHwnd, WM_DESTROY, 0,0);

   if(isUnicode)
    m_tooltipHwnd = CreateWindowExW(WS_EX_TOPMOST,
     TOOLTIPS_CLASSW, NULL,
     WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP,  
     CW_USEDEFAULT, CW_USEDEFAULT,
     CW_USEDEFAULT, CW_USEDEFAULT,
     parentHwnd, NULL, hInstance, NULL);
   else 
    m_tooltipHwnd = CreateWindowEx(WS_EX_TOPMOST,
     TOOLTIPS_CLASS, NULL,
     WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP,  
     CW_USEDEFAULT, CW_USEDEFAULT,
     CW_USEDEFAULT, CW_USEDEFAULT,
     parentHwnd, NULL, hInstance, NULL);

   if (GetLastError() != 0)
    return;

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

   // Set the max text width before multi-line tooltip is used.
   ::SendMessage(m_tooltipHwnd, TTM_SETMAXTIPWIDTH, 0, m_nMaxWinTooltipWidth);

   if (isUnicode){
    m_toolInfoW.uFlags = TTF_SUBCLASS | TTF_IDISHWND | TTF_TRACK;
    m_toolInfoW.hinst = hInstance;
    m_toolInfoW.hwnd = parentHwnd;
    m_toolInfoW.uId = (UINT_PTR)parentHwnd;
    ::GetClientRect (parentHwnd, &m_toolInfoW.rect);

    ::SendMessage(m_tooltipHwnd, TTM_ADDTOOLW, 0, (LPARAM) (LPTOOLINFOW) &m_toolInfoW);
    ::SendMessage(m_tooltipHwnd, TTM_ACTIVATE, TRUE, (LPARAM)(LPTOOLINFOW) &m_toolInfoW);
   }
   else{
    m_toolInfoA.uFlags = TTF_SUBCLASS | TTF_IDISHWND;
    m_toolInfoA.hinst = hInstance;
    m_toolInfoA.hwnd = parentHwnd;
    m_toolInfoA.uId = (UINT_PTR)parentHwnd;
    ::GetClientRect (parentHwnd, &m_toolInfoA.rect);

    ::SendMessage(m_tooltipHwnd, TTM_ADDTOOL, 0, (LPARAM) (LPTOOLINFO) &m_toolInfoA);
    ::SendMessage(m_tooltipHwnd, TTM_ACTIVATE, TRUE, (LPARAM)(LPTOOLINFO) &m_toolInfoA);
   }
   m_bTooltipInitialized = true;
  }

  if (isUnicode)
   ::SendMessage(m_tooltipHwnd, TTM_UPDATETIPTEXTW, 0, (LPARAM) (LPTOOLINFOW) &m_toolInfoW);
  else
   ::SendMessage(m_tooltipHwnd, TTM_UPDATETIPTEXT, 0, (LPARAM) (LPTOOLINFO) &m_toolInfoA);

  //Repaint the screen so that the area beneath the previous location of the tooltip is restored correctly.
  ::UpdateWindow(pWnd->GetParentOwner()->GetSafeHwnd());
  pWnd = NULL;
3个回答

10
问题在于您尝试使用通用控件版本6,但未能成功使用它。
更详细地说,
typedef struct tagTOOLINFOW {
    UINT cbSize;
    UINT uFlags;
    HWND hwnd;
    UINT_PTR uId;
    RECT rect;
    HINSTANCE hinst;
    LPWSTR lpszText;
    LPARAM lParam;
#if (NTDDI_VERSION >= NTDDI_WINXP)
    void *lpReserved;
#endif
} TTTOOLINFOW, NEAR *PTOOLINFOW, *LPTTTOOLINFOW;

对于XP及以上版本,头文件CommCtrl.h假定您将使用comctl版本6,但如果您没有通过清单文件显式启用它,则仍将使用旧的comctl版本5.x。然后问题来了,版本5.x的TOOLINFO大小与版本6.x不同。

因此,如果您需要在Windows XP+下使用comctl版本5,您应该使用以下代码初始化TOOLINFO:

TOOLINFO ti;
ti.cbSize = sizeof(TOOLINFO) - 4;

否则,您应该通过清单文件或程序指令启用视觉样式外观:
#pragma comment(linker,"\"/manifestdependency:type='win32' \
name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")

最后,我建议您始终在xp+中启用视觉外观。以下是视觉效果的比较:

常见控件5.x

常见控件6.x

注意:如果您使用ANSI/MBCS编译程序,则TOOLINFO的sizeof大小将为48,并已删除lpReserved成员。因此,ANSI版本可以工作,但UNICODE会失败。


1
非常感谢。我正在尝试在Windows 7上使用VS2008从MSDN中获取简单的工具提示示例代码,但很快遇到了一个问题,即ANSI构建显示工具提示,但Unicode构建从未显示。发送TTM_ADDTOOL返回0(失败)。通过谷歌搜索,我找到了您的帖子并得到了确切的答案。这是微软的一大成就!但我仍然无法解释为什么ANSI构建不会触发错误。如果M$ comctl32 pre-6.0代码检查来自调用者的不兼容的“TOOLINFO.cbSize”,则ANSI和Unicode应该表现出相同的行为。 - Jimm Chen
真是救命稻草!还有一个小提示,如果编译x64,请记得减去8。实际上,只需执行.cbSize = sizeof(TOOLINFO) - sizeof(void*),如果您没有使用那个pragma的话。 - sz ppeter

2
以上Jichao提供了一个好的解释和解决方案,但是硬编码TOOLINFO结构的大小只能修复工具提示。如果问题是程序在编译时考虑了6.0+通用控件,但可能在Windows XP系统上运行,而6.0+通用控件未安装或未完全安装(例如某人安装了IE,但从未使用或更新它),则更通用的解决方案是限制应用程序仅使用5.x通用控件。
此处所示,除了工具提示之外,还有其他结构大小发生变化的东西。
为确保所有内容都可以在Windows XP上正常工作,我在程序的最顶部放置了以下内容,在任何包含文件之前(在Visual Studio的情况下,一个好的位置是在targetver.h的顶部,如果您有这个文件):
#define _WIN32_WINNT    0x0500

1

谢谢您注意到了这个问题。您说得对,那个应该不在那里,我测试的时候忘记删除它了。然而,这并没有解决我的问题。即使没有那个标志,仍然没有工具提示显示出来。 - Martin
父窗口也是Unicode吗?也许使用具有ANSI父窗口的Unicode工具提示存在不兼容性。 - Adrian McCarthy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接