Shell 资源管理器上下文菜单的扩展,图标在经典 Windows 设计中打破对齐
Shell extension for explorer context menu, icon breaks alignment in classic Windows design
我遇到了以下问题,
为 windows 资源管理器的上下文菜单添加条目并且 windows 7 设计设置为经典时,图标会破坏菜单的对齐方式。
此图为添加条目前的菜单(请注意Microsoft Security Essentials图标):
添加菜单条目后如下所示:
您看到 Microsoft Security Essentials 的图标和菜单标题之间有一个 space。使用的位图是标准的 bmp 16 x 16。
有人知道为什么会这样吗?再一次,这只发生在 Win 7 经典设计中,其他设计按预期工作。
在此先感谢您的帮助
编辑:
这是我添加项目的初始代码:
iconHandle = LoadImageW(NULL, iconPath.c_str(), IMAGE_BITMAP, 0, 0, LR_DEFAULTSIZE | LR_LOADTRANSPARENT | LR_LOADFROMFILE);
MENUITEMINFOW contextEntryAppSuite = { sizeof(contextEntryAppSuite) };
contextMenuItem.fMask = MIIM_STRING | MIIM_STATE | MIIM_BITMAP | MIIM_FTYPE | MIIM_ID;
contextMenuItem.dwTypeData = caption;
contextMenuItem.wID = 0;
contextMenuItem.fType = MFT_STRING;
contextMenuItem.fState = MFS_ENABLED;
contextMenuItem.hbmpItem = static_cast<HBITMAP>(iconHandle);
if(!InsertMenuItemW(hMenu, indexMenu, TRUE, &contextMenuItem))
{
return HRESULT_FROM_WIN32(GetLastError());
}
在你的帮助下我改变了:
contextMenuItem.hbmpItem = static_cast<HBITMAP>(iconHandle);
至:
contextMenuItem.hbmpItem = IconToBitmap(pathToIcon);
// the function from your posted link
HBITMAP IconToBitmap(std::string sIcon)
{
RECT rect;
rect.right = ::GetSystemMetrics(SM_CXMENUCHECK);
rect.bottom = ::GetSystemMetrics(SM_CYMENUCHECK);
rect.left = rect.top = 0;
HICON hIcon = (HICON)LoadImageA(NULL, sIcon.c_str(), IMAGE_ICON, rect.right, rect.bottom, LR_DEFAULTCOLOR | LR_LOADFROMFILE);
if (!hIcon)
return NULL;
HWND desktop = ::GetDesktopWindow();
if (desktop == NULL)
{
DestroyIcon(hIcon);
return NULL;
}
HDC screen_dev = ::GetDC(desktop);
if (screen_dev == NULL)
{
DestroyIcon(hIcon);
return NULL;
}
// Create a compatible DC
HDC dst_hdc = ::CreateCompatibleDC(screen_dev);
if (dst_hdc == NULL)
{
DestroyIcon(hIcon);
::ReleaseDC(desktop, screen_dev);
return NULL;
}
// Create a new bitmap of icon size
HBITMAP bmp = ::CreateCompatibleBitmap(screen_dev, rect.right, rect.bottom);
if (bmp == NULL)
{
DestroyIcon(hIcon);
::DeleteDC(dst_hdc);
::ReleaseDC(desktop, screen_dev);
return NULL;
}
// Select it into the compatible DC
HBITMAP old_dst_bmp = (HBITMAP)::SelectObject(dst_hdc, bmp);
if (old_dst_bmp == NULL)
{
DestroyIcon(hIcon);
return NULL;
}
// Fill the background of the compatible DC with the given colour
::SetBkColor(dst_hdc, RGB(255, 255, 255));
::ExtTextOut(dst_hdc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
// Draw the icon into the compatible DC
::DrawIconEx(dst_hdc, 0, 0, hIcon, rect.right, rect.bottom, 0, NULL, DI_NORMAL);
// Restore settings
::SelectObject(dst_hdc, old_dst_bmp);
::DeleteDC(dst_hdc);
::ReleaseDC(desktop, screen_dev);
DestroyIcon(hIcon);
return bmp;
}
您的原始代码是正确的...不要理会 IconToBitmap 函数,因为当指定 IMAGE_BITMAP 时您的 LoadImageW returns HBITMAP。
在 XP 上使用位图的菜单或在更高版本的 Windows 上使用经典主题似乎保留了 space 复选标记,您有时需要使用 MNS_CHECKORBMP 调用 SetMenuInfo...试试下面的代码:
iconHandle = LoadImageW(NULL, iconPath.c_str(), IMAGE_BITMAP, 0, 0, LR_DEFAULTSIZE | LR_LOADTRANSPARENT | LR_LOADFROMFILE);
MENUITEMINFOW contextEntryAppSuite = { sizeof(contextEntryAppSuite) };
contextMenuItem.fMask = MIIM_STRING | MIIM_STATE | MIIM_BITMAP | MIIM_FTYPE | MIIM_ID;
contextMenuItem.dwTypeData = caption;
contextMenuItem.wID = 0;
contextMenuItem.fType = MFT_STRING;
contextMenuItem.fState = MFS_ENABLED;
contextMenuItem.hbmpItem = static_cast<HBITMAP>(iconHandle);
MENUINFO menuInfo;
menuInfo.cbSize = sizeof(MENUINFO);
menuInfo.fMask = MIM_STYLE;
menuInfo.dwStyle = MNS_CHECKORBMP;
SetMenuInfo(hMenu, &menuInfo);
if(!InsertMenuItemW(hMenu, indexMenu, TRUE, &contextMenuItem))
{
return HRESULT_FROM_WIN32(GetLastError());
}
我遇到了以下问题,
为 windows 资源管理器的上下文菜单添加条目并且 windows 7 设计设置为经典时,图标会破坏菜单的对齐方式。
此图为添加条目前的菜单(请注意Microsoft Security Essentials图标):
添加菜单条目后如下所示:
您看到 Microsoft Security Essentials 的图标和菜单标题之间有一个 space。使用的位图是标准的 bmp 16 x 16。
有人知道为什么会这样吗?再一次,这只发生在 Win 7 经典设计中,其他设计按预期工作。
在此先感谢您的帮助
编辑:
这是我添加项目的初始代码:
iconHandle = LoadImageW(NULL, iconPath.c_str(), IMAGE_BITMAP, 0, 0, LR_DEFAULTSIZE | LR_LOADTRANSPARENT | LR_LOADFROMFILE);
MENUITEMINFOW contextEntryAppSuite = { sizeof(contextEntryAppSuite) };
contextMenuItem.fMask = MIIM_STRING | MIIM_STATE | MIIM_BITMAP | MIIM_FTYPE | MIIM_ID;
contextMenuItem.dwTypeData = caption;
contextMenuItem.wID = 0;
contextMenuItem.fType = MFT_STRING;
contextMenuItem.fState = MFS_ENABLED;
contextMenuItem.hbmpItem = static_cast<HBITMAP>(iconHandle);
if(!InsertMenuItemW(hMenu, indexMenu, TRUE, &contextMenuItem))
{
return HRESULT_FROM_WIN32(GetLastError());
}
在你的帮助下我改变了:
contextMenuItem.hbmpItem = static_cast<HBITMAP>(iconHandle);
至:
contextMenuItem.hbmpItem = IconToBitmap(pathToIcon);
// the function from your posted link
HBITMAP IconToBitmap(std::string sIcon)
{
RECT rect;
rect.right = ::GetSystemMetrics(SM_CXMENUCHECK);
rect.bottom = ::GetSystemMetrics(SM_CYMENUCHECK);
rect.left = rect.top = 0;
HICON hIcon = (HICON)LoadImageA(NULL, sIcon.c_str(), IMAGE_ICON, rect.right, rect.bottom, LR_DEFAULTCOLOR | LR_LOADFROMFILE);
if (!hIcon)
return NULL;
HWND desktop = ::GetDesktopWindow();
if (desktop == NULL)
{
DestroyIcon(hIcon);
return NULL;
}
HDC screen_dev = ::GetDC(desktop);
if (screen_dev == NULL)
{
DestroyIcon(hIcon);
return NULL;
}
// Create a compatible DC
HDC dst_hdc = ::CreateCompatibleDC(screen_dev);
if (dst_hdc == NULL)
{
DestroyIcon(hIcon);
::ReleaseDC(desktop, screen_dev);
return NULL;
}
// Create a new bitmap of icon size
HBITMAP bmp = ::CreateCompatibleBitmap(screen_dev, rect.right, rect.bottom);
if (bmp == NULL)
{
DestroyIcon(hIcon);
::DeleteDC(dst_hdc);
::ReleaseDC(desktop, screen_dev);
return NULL;
}
// Select it into the compatible DC
HBITMAP old_dst_bmp = (HBITMAP)::SelectObject(dst_hdc, bmp);
if (old_dst_bmp == NULL)
{
DestroyIcon(hIcon);
return NULL;
}
// Fill the background of the compatible DC with the given colour
::SetBkColor(dst_hdc, RGB(255, 255, 255));
::ExtTextOut(dst_hdc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
// Draw the icon into the compatible DC
::DrawIconEx(dst_hdc, 0, 0, hIcon, rect.right, rect.bottom, 0, NULL, DI_NORMAL);
// Restore settings
::SelectObject(dst_hdc, old_dst_bmp);
::DeleteDC(dst_hdc);
::ReleaseDC(desktop, screen_dev);
DestroyIcon(hIcon);
return bmp;
}
您的原始代码是正确的...不要理会 IconToBitmap 函数,因为当指定 IMAGE_BITMAP 时您的 LoadImageW returns HBITMAP。
在 XP 上使用位图的菜单或在更高版本的 Windows 上使用经典主题似乎保留了 space 复选标记,您有时需要使用 MNS_CHECKORBMP 调用 SetMenuInfo...试试下面的代码:
iconHandle = LoadImageW(NULL, iconPath.c_str(), IMAGE_BITMAP, 0, 0, LR_DEFAULTSIZE | LR_LOADTRANSPARENT | LR_LOADFROMFILE);
MENUITEMINFOW contextEntryAppSuite = { sizeof(contextEntryAppSuite) };
contextMenuItem.fMask = MIIM_STRING | MIIM_STATE | MIIM_BITMAP | MIIM_FTYPE | MIIM_ID;
contextMenuItem.dwTypeData = caption;
contextMenuItem.wID = 0;
contextMenuItem.fType = MFT_STRING;
contextMenuItem.fState = MFS_ENABLED;
contextMenuItem.hbmpItem = static_cast<HBITMAP>(iconHandle);
MENUINFO menuInfo;
menuInfo.cbSize = sizeof(MENUINFO);
menuInfo.fMask = MIM_STYLE;
menuInfo.dwStyle = MNS_CHECKORBMP;
SetMenuInfo(hMenu, &menuInfo);
if(!InsertMenuItemW(hMenu, indexMenu, TRUE, &contextMenuItem))
{
return HRESULT_FROM_WIN32(GetLastError());
}