CEF在离屏渲染模式下没有tooltips?tooltips创建之后不显示?我以为我又遇到BUG了

时间:2019-01-09
本文章向大家介绍CEF在离屏渲染模式下没有tooltips?tooltips创建之后不显示?我以为我又遇到BUG了,主要包括CEF在离屏渲染模式下没有tooltips?tooltips创建之后不显示?我以为我又遇到BUG了使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

    这次我们在CEF显示的界面里加上了tooltips,也就是html的title属性,结果发现这玩意竟然不会显示,一开始我怀疑是自己的代码问题,很快我又去cefclient这个demo里测试了一下,确认了我的怀疑,只要打开了--off-screen-rendering-enabled,就会导致tooltips无法显示。我当然认为这是一个CEF的bug,于是去反馈issue,但是我同时也做了一堆搜索,一开始看到的都是关于manifest以及InitCommonControlsEx的问题,和这个问题并没有相关性。

    直到我搜到这个issue,https://bitbucket.org/chromiumembedded/cef/issues/854/cef3-title-attribute-of-tags-is-not ,CEF在OSR模式下需要开发者手动处理CefDisplayHandler::OnTooltip事件,这玩意我记得文档上也没说过,也没人说过如何处理这个事件。那我想就直接刚,手动在这里显示tooltips就行了,于是掏出以前的代码,下面是可以抄的作业。

HWND hTips = CreateWindowEx(WS_EX_TOPMOST,
            TOOLTIPS_CLASS,
            NULL,
            WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            hWnd,
            NULL,
            ::GetModuleHandle(NULL),
            NULL);

        if(!hTips)
        {
            return NULL;
        }

        SetWindowPos(hTips, HWND_TOPMOST, 0, 0, 0, 0,
            SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);

        memset(&win_tooltipsinfo, 0, sizeof(TOOLINFO));

        win_tooltipsinfo.cbSize = sizeof(TOOLINFO);
        win_tooltipsinfo.uFlags = TTF_SUBCLASS;
        win_tooltipsinfo.hwnd = hWnd;
        win_tooltipsinfo.lpszText = _tcsdup(pText);
        win_tooltipsinfo.uId = (UINT_PTR) hWnd;

        GetClientRect(hWnd, &win_tooltipsinfo.rect);

        SendMessage(hTips, TTM_ADDTOOL, 0, (LPARAM) (LPTOOLINFO) &win_tooltipsinfo);

        free(win_tooltipsinfo.lpszText);

        return hTips;

    然后我发现这个tooltip并没有显示出来,接着又在https://docs.microsoft.com/en-us/windows/desktop/Controls/using-tooltip-contro这个页面上变着法的尝试了另外几种方法,此时我还是在怀疑创建tooltips的姿势不对。最终无果之后,我开始去测试是不是没调用InitCommonControlsEx,加上之后无果,于是接着又加上manifest,以下是作业

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
    <dependency>
        <dependentAssembly>
            <assemblyIdentity
                type="win32"
                name="Microsoft.Windows.Common-Controls"
                version="6.0.0.0"
                processorArchitecture="*"
                publicKeyToken="6595b64144ccf1df"
                language="*"
                />
        </dependentAssembly>
    </dependency>
</assembly>

    依然无果,这个时候已经一两点了,十分生气。然后我又翻了一些别的老项目代码,终于发现一个奇妙之处……结合之前在搜索结果里也看到有人提到过关于TOOLINFO结构大小不对导致SendMessage返回错误的情况,于是找到了如下代码

#if _WIN32_WINNT > 0x0500
        win_tooltipsinfo.cbSize = sizeof(TOOLINFO) - sizeof(void *);
#else
        win_tooltipsinfo.cbSize = sizeof(TOOLINFO);
#endif
typedef struct tagTOOLINFOA {
    UINT cbSize;
    UINT uFlags;
    HWND hwnd;
    UINT_PTR uId;
    RECT rect;
    HINSTANCE hinst;
    LPSTR lpszText;
    LPARAM lParam;
#if (NTDDI_VERSION >= NTDDI_WINXP)
    void *lpReserved;
#endif
} TTTOOLINFOA, NEAR *PTOOLINFOA, *LPTTTOOLINFOA;

    上面是TOOLINFO在VS2017头文件里的定义,按照常理来说我直接认为,我的SDK版本肯定是>=NTDDI_XP的,于是最后那个void *也就应该是需要算到cbSize里的。但是总之都是MS的复杂兼容性问题,或者保险起见可以直接把cbSize设置为TTTOOLINFO_V1_SIZE。现在tooltips终于正常显示了!

    但是等一会!这个tooltip的样子怎么和我们平时见到的不太一致?看起来像是98时期的老古董。这个时候我的意识还算清醒,这是一个典型的exe manifest导致的问题,可是我在我的cef renderer程序的manifest里写了正确的信息呀?(参见上面的manifest),琢磨和尝试了好一会,然后我抱着试一试的心态,在我的主程序manifest也加上了这段信息……于是结果就正确了

    这里我其实并没有完全理解,我的网页在cef渲染进程里显示,它是主进程的子进程,也就是说,主进程也必须要有正确的manifest才能让子进程得到正确的风格?总之新踩的坑又一次被填平了。