一、目标:
- windows中,打开chromium,任务栏中会出现一个chromium的图标。
- 我们的目标是给这个图标的右上角,加上"有1条新消息"的小提示图标,也叫徽章(badge)
- 注意:本章节纯属娱乐,有需要的集帅可以学习模仿。
具体效果如下:
二、修改源码:
- 打开:\ui\views\view.cc
1.头部追加:
#include <Shobjidl.h>
#include <windows.h>
#include <shellapi.h>
2.找到:
bool View::OnMousePressed(const ui::MouseEvent& event) {
return false;
}
OnMousePressed()
函数是可以点击事件,每次点击浏览器头部时都会触发这个函数。
3.替换为:
void UpdateTaskbarIcon(HWND hwnd, HICON hIcon) {
ITaskbarList3* pTaskbarList = nullptr;
HRESULT hr = CoCreateInstance(CLSID_TaskbarList, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pTaskbarList));
if (SUCCEEDED(hr)) {
pTaskbarList->SetOverlayIcon(hwnd, hIcon, L"有1条新消息");
pTaskbarList->Release();
LOG(ERROR) << "SetOverlayIcon成功调用";
}else{
LOG(ERROR) << "ERRORERRORERROR";
}
}
void SetTaskbarIconOverlay(HWND hwnd) {
wchar_t className[256];
GetClassName(hwnd, className, sizeof(className) / sizeof(wchar_t));
LOG(ERROR) << "窗口类名";
LOG(ERROR) << className;
LPCWSTR iconPath = L"C:/Users/Administrator/Desktop/favicon.ico";
HICON hIcon = (HICON)LoadImage(NULL, iconPath, IMAGE_ICON, 16, 16, LR_LOADFROMFILE);
if (!hIcon) {
MessageBox(hwnd, L"无法加载图标。", L"错误", MB_OK | MB_ICONERROR);
} else {
UpdateTaskbarIcon(hwnd, hIcon);
}
}
bool View::OnMousePressed(const ui::MouseEvent& event) {
CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
LPCWSTR className = L"Chrome_WidgetWin_1";
LPCWSTR windowName = nullptr; // 如果你不知道窗口的标题,可以设置为nullptr
// 获取窗口句柄
HWND hwnd = FindWindow(className, windowName);
if (hwnd != NULL) {
HWND parentHwnd = GetParent(hwnd);
if (parentHwnd == NULL) {
LOG(ERROR) << "hwnd 是一个顶级窗口";
} else {
LOG(ERROR) << "hwnd 不是一个顶级窗口";
}
}
LOG(ERROR) << hwnd;
wchar_t windowTitle[256];
GetWindowText(hwnd, windowTitle, sizeof(windowTitle) / sizeof(wchar_t));
LOG(ERROR) << "窗口标题";
LOG(ERROR) << windowTitle;
bool isVisible = IsWindowVisible(hwnd);
LOG(ERROR) << "isVisible";
LOG(ERROR) << isVisible;
DWORD processId;
GetWindowThreadProcessId(hwnd, &processId);
LOG(ERROR) << "processId";
LOG(ERROR) << processId;
SetTaskbarIconOverlay(hwnd);
CoUninitialize();
return false;
}
注意:
- 将ico图标位置(变量iconPath )替换成你图标的位置,必须是ico其他格式不行。
LOG(ERROR)
是用来打印错误日志的,可以忽略- 最终实现原理是调用win32编程api里的SetOverlayIcon()函数。
4.编译
ninja -C out/Default chrome
- 编译完成后,打开浏览器,一旦点击浏览器头部,图标就出现啦!
三、代码生成数字ico
- 有的同学想到要右上角希望是数字图标,我们总不能准备99张ico图标吧。
- 于是我们用代码在内存中生成ico
将上面的代码改成:
HICON CreateNumberIcon(int number) {
if (number > 99) {
number = 99;
}
// 创建一个16x16的位图
HDC hdcScreen = GetDC(NULL);
HDC hdcMem = CreateCompatibleDC(hdcScreen);
BITMAPINFO bmi = {};
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth = 16;
bmi.bmiHeader.biHeight = -16; // 负值表示自上而下
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 32; // 32位带透明通道
bmi.bmiHeader.biCompression = BI_RGB;
bmi.bmiHeader.biSizeImage = 0;
bmi.bmiHeader.biXPelsPerMeter = 0;
bmi.bmiHeader.biYPelsPerMeter = 0;
bmi.bmiHeader.biClrUsed = 0;
bmi.bmiHeader.biClrImportant = 0;
void* pBits;
HBITMAP hBitmap = CreateDIBSection(hdcMem, &bmi, DIB_RGB_COLORS, &pBits, NULL, 0);
HBITMAP hOldBitmap = (HBITMAP)SelectObject(hdcMem, hBitmap);
// 设置背景为透明
memset(pBits, 0, 16 * 16 * 4); // 初始化位图为透明
// 设置字体和颜色
HFONT hFont = CreateFont(14, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, DEFAULT_PITCH | FF_DONTCARE, L"Arial");
HFONT hOldFont = (HFONT)SelectObject(hdcMem, hFont);
SetTextColor(hdcMem, RGB(255, 0, 0)); // 设置数字颜色为红色
SetBkMode(hdcMem, TRANSPARENT);
// 计算数字的居中位置
std::wstring text = std::to_wstring(number);
RECT rect = {0, 0, 16, 16};
DrawText(hdcMem, text.c_str(), text.length(), &rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
// 清理
SelectObject(hdcMem, hOldFont);
DeleteObject(hFont);
SelectObject(hdcMem, hOldBitmap);
DeleteDC(hdcMem);
ReleaseDC(NULL, hdcScreen);
// 将位图转换为图标
ICONINFO iconInfo = { TRUE, 0, 0, hBitmap, hBitmap };
HICON hIcon = CreateIconIndirect(&iconInfo);
DeleteObject(hBitmap);
return hIcon;
}
void UpdateTaskbarIcon(HWND hwnd, HICON hIcon) {
ITaskbarList3* pTaskbarList = nullptr;
HRESULT hr = CoCreateInstance(CLSID_TaskbarList, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pTaskbarList));
if (SUCCEEDED(hr)) {
pTaskbarList->SetOverlayIcon(hwnd, hIcon, L"新消息");
pTaskbarList->Release();
LOG(ERROR) << "SetOverlayIcon成功调用";
}else{
LOG(ERROR) << "ERRORERRORERROR";
}
}
void SetTaskbarIconOverlay(HWND hwnd) {
wchar_t className[256];
GetClassName(hwnd, className, sizeof(className) / sizeof(wchar_t));
LOG(ERROR) << "窗口类名";
LOG(ERROR) << className;
//LPCWSTR iconPath = L"C:/Users/Administrator/Desktop/favicon.ico";
//HICON hIcon = (HICON)LoadImage(NULL, iconPath, IMAGE_ICON, 16, 16, LR_LOADFROMFILE);
HICON hIcon = CreateNumberIcon(72);
if (!hIcon) {
MessageBox(hwnd, L"无法加载图标。", L"错误", MB_OK | MB_ICONERROR);
} else {
UpdateTaskbarIcon(hwnd, hIcon);
}
}
bool View::OnMousePressed(const ui::MouseEvent& event) {
CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
LPCWSTR className = L"Chrome_WidgetWin_1";
LPCWSTR windowName = nullptr; // 如果你不知道窗口的标题,可以设置为nullptr
// 获取窗口句柄
HWND hwnd = FindWindow(className, windowName);
SetTaskbarIconOverlay(hwnd);
bool isVisible = IsWindowVisible(hwnd);
LOG(ERROR) << "isVisible";
LOG(ERROR) << isVisible;
CoUninitialize();
return false;
}
- 效果:
五、优化
- 还需要优化的是想改成,白色圆形,透明背景。但稍微尝试了下,没改对。
- 就这样吧,调试太费时间了。题主懒,集帅自行优化吧