[software development] wine 修复winhex菜单栏中ICON底色是黑色的问题
Tofloor
poster avatar
zheenyuan
deepin
2025-11-28 15:19
Author

被实验的wine 来资源winehq原版10.0(32位)。

被实验的程序 Winhex(32位)

实验开始

1.git clone wine

下载wine 并添加安装好编译环境(略)

2. 解决好中文问题

3.编译以下新下载的wine

config 和make即可 ,里面其他模块(如win32u)直接进去运行里面的make即可编译这个模块。

4.问题展示

可以看到图标显示错误(底色是黑色)

image.png

尝试解决问题

通过winedbg log下菜单打开时调用的函数

很快就定位到下面这个函数(dlls/win32u/menu.c)

static void draw_menu_item( HWND hwnd, struct menu *menu, HWND owner, HDC hdc,
                            struct menu_item *item, BOOL menu_bar, UINT odaction )
//找到这个函数中的下面这个位置
//不是系统菜单(不是顶级菜单)
if (!menu_bar)
    {
        HBITMAP bm;
        INT y = rect.top + rect.bottom;
        BOOL checked = FALSE;
        UINT check_bitmap_width = get_system_metrics( SM_CXMENUCHECK );
        UINT check_bitmap_height = get_system_metrics( SM_CYMENUCHECK );

        /* Draw the check mark */
        if (!(menu->dwStyle & MNS_NOCHECK))
        {
            bm = (item->fState & MF_CHECKED) ? item->hCheckBit :
                item->hUnCheckBit;
            if (bm)  /* we have a custom bitmap */
            {
                BITMAP bm_info;
                HDC mem_hdc;
                TRACE("-------Icon HBITMAP Check: ID=0x%x, Handle=%p.\n", item->wID, bm);
                // 获取位图信息
                // **新增:获取位图尺寸**
                if (!NtGdiExtGetObjectW( bm, sizeof(bm_info), &bm_info)) 
                {
                    TRACE("Attempting TransparentBlt for custom menu icon failed! (bm_info: 0x%08x).\n", (ULONG)&bm_info);
                }
                mem_hdc = NtGdiCreateCompatibleDC( hdc );

                NtGdiSelectBitmap( mem_hdc, bm );
                /*
                NtGdiBitBlt( hdc, rect.left, (y - check_bitmap_height) / 2,
                             check_bitmap_width, check_bitmap_height,
                             mem_hdc, 0, 0, SRCCOPY, 0, 0 );
                             */
                            // --- 替换开始 ---
                //COLORREF transparent_color = 0x000000; // 假定黑色为透明色

                TRACE("Attempting TransparentBlt for custom menu icon (ColorKey: 0x%06x).\n", (ULONG)0x000000);
                if (!NtGdiTransparentBlt( hdc, 
                                        rect.left, (y - bm_info.bmHeight) / 2, // 使用位图实际高度进行居中
                                        bm_info.bmWidth, bm_info.bmHeight, 
                                        mem_hdc, 0, 0, 
                                        bm_info.bmWidth, bm_info.bmHeight, 
                                        0x000000))
                {
                    // Fallback to original BitBlt (如果 TransparentBlt 失败)
                    TRACE("NtGdiTransparentBlt failed, falling back to SRCCOPY.\n");
                    NtGdiBitBlt( hdc, rect.left, (y - check_bitmap_height) / 2,
                                 check_bitmap_width, check_bitmap_height,
                                 mem_hdc, 0, 0, SRCCOPY, 0, 0 );
                }
                else
                {
                    TRACE("NtGdiTransparentBlt succeeded.\n");
                }
                // --- 替换结束 ---
                NtGdiDeleteObjectApp( mem_hdc );
                checked = TRUE;
            }
            else if (item->fState & MF_CHECKED) /* standard bitmaps */
            {
                RECT r;
                HBITMAP bm = NtGdiCreateBitmap( check_bitmap_width,
                        check_bitmap_height, 1, 1, NULL );
                HDC mem_hdc = NtGdiCreateCompatibleDC( hdc );

                NtGdiSelectBitmap( mem_hdc, bm );
                SetRect( &r, 0, 0, check_bitmap_width, check_bitmap_height);
                draw_frame_menu( mem_hdc, &r,
                                 (item->fType & MFT_RADIOCHECK) ? DFCS_MENUBULLET : DFCS_MENUCHECK );
                NtGdiBitBlt( hdc, rect.left, (y - r.bottom) / 2, r.right, r.bottom,
                             mem_hdc, 0, 0, SRCCOPY, 0, 0 );
                NtGdiDeleteObjectApp( mem_hdc );
                NtGdiDeleteObjectApp( bm );
                checked = TRUE;
            }
        }
        if (item->hbmpItem && !(checked && (menu->dwStyle & MNS_CHECKORBMP)))
        {
            POINT origorg;
            /* some applications make this assumption on the DC's origin */
            set_viewport_org( hdc, rect.left, rect.top, &origorg );
            draw_bitmap_item( hwnd, hdc, item, &bmprc, menu, owner, odaction );
            set_viewport_org( hdc, origorg.x, origorg.y, NULL );
        }
        /* Draw the popup-menu arrow */
        if (item->fType & MF_POPUP)
            draw_popup_arrow( hdc, rect, arrow_width, arrow_height);
        rect.left += 4;
        if (!(menu->dwStyle & MNS_NOCHECK))
            rect.left += check_bitmap_width;
        rect.right -= arrow_width;
    }

重新编译dll/win32u这个模块

cd /wine/dlls/win32u# make

结果展示

image.png

!完美

记录下第一次尝试修wine。

欢迎大家给我一些其他简单wine的小问题以便继续写文章。

分享从wine小白到精通的过程。

Reply Favorite View the author
All Replies

No replies yet