Уведомление о присоединении: я являюсь автором программного обеспечения, упомянутого в этом ответе.
Прежде всего, я хочу, чтобы вы знали, что я изучил C ++ и Win32 только для этого вопроса .
Я разработал 64-битное расширение оболочки, которое регистрируется как обработчик контекстного меню. Когда он вызывается, он копается в существующих пунктах меню в поисках интересных записей. Если он находит его, он прикрепляет значок (который должен быть загружен ранее). На данный момент он ищет Копировать , Вырезать , Удалить , Вставить , Повторить , Отправить и Отменить . Вы можете добавить свой собственный, изменив код; процедура для этого описана ниже. (Извините, я недостаточно хорош в C ++, чтобы настраивать его.)
Скриншот этого в действии, с самыми уродливыми иконами, известными человеку:
Вы можете скачать эти иконки, если вы действительно хотите.
Настройка его
Загрузите его (из моего Dropbox). Примечание : этот файл обнаруживается одним сканером VirusTotal как разновидность вредоносного ПО. Это понятно, учитывая то, что нужно сделать, чтобы ударить существующие записи. Я даю вам слово, что это не наносит преднамеренного вреда вашему компьютеру. Если вы подозрительны и / или хотите изменить и расширить его, посмотрите код на GitHub !
Создайте папку в диске С: C:\shellicon
. Создание BMP файлов со следующими названиями: copy
, cut
, delete
, paste
, redo
, sendto
, undo
. (Надеюсь, очевидно, кто из них что делает.) Эти изображения, вероятно, должны быть 16 на 16 пикселей (или какими бы большими ни были ваши настройки DPI, чтобы заполнить меню), но я также добился успеха с большими. Если вы хотите, чтобы значки выглядели прозрачными, вы должны просто сделать их фон того же цвета, что и контекстное меню. (Этот прием также используется в Dropbox.) Я сделал свои ужасные иконки с помощью MS Paint; другие программы могут сохранять, а могут и не сохранять, способом, совместимым с LoadImageA
. 16 на 16 с глубиной цвета 24 бита при 96 пикселях на дюйм, кажется, наиболее надежный набор свойств изображения.
Поместите DLL где-нибудь доступным для всех пользователей, эта папка, которую вы только что создали, является хорошим выбором. Откройте приглашение администратора в папке, содержащей DLL и сделайте regsvr32 ContextIcons.dll
. Это создает регистрационную информацию для типов оболочек *
, Drive
, Directory
и Directory\Background
. Если вы хотите удалить расширение оболочки, сделайте regsvr32 /u ContextIcons.dll
.
Соответствующий код
По сути, расширение просто запрашивает текст каждого элемента контекстного меню с помощью GetMenuItemInfo
и, при необходимости, корректирует значок с помощью SetMenuItemInfo
.
Visual Studio генерирует много магического загадочного кода для проектов ATL, но это содержимое IconInjector.cpp
, которое реализует обработчик контекстного меню:
// IconInjector.cpp : Implementation of CIconInjector
#include "stdafx.h"
#include "IconInjector.h"
#include <string>
// CIconInjector
HBITMAP bmpCopy = NULL;
HBITMAP bmpCut = NULL;
HBITMAP bmpUndo = NULL;
HBITMAP bmpRedo = NULL;
HBITMAP bmpSendto = NULL;
HBITMAP bmpDel = NULL;
HBITMAP bmpPaste = NULL;
STDMETHODIMP CIconInjector::Initialize(LPCITEMIDLIST pidlFolder, LPDATAOBJECT pDataObj, HKEY hProgID) {
// Load the images
bmpCopy = (HBITMAP)LoadImageA(NULL, "C:\\shellicon\\copy.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_DEFAULTSIZE);
bmpCut = (HBITMAP)LoadImageA(NULL, "C:\\shellicon\\cut.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_DEFAULTSIZE);
bmpUndo = (HBITMAP)LoadImageA(NULL, "C:\\shellicon\\undo.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_DEFAULTSIZE);
bmpRedo = (HBITMAP)LoadImageA(NULL, "C:\\shellicon\\redo.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_DEFAULTSIZE);
bmpSendto = (HBITMAP)LoadImageA(NULL, "C:\\shellicon\\sendto.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_DEFAULTSIZE);
bmpDel = (HBITMAP)LoadImageA(NULL, "C:\\shellicon\\delete.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_DEFAULTSIZE);
bmpPaste = (HBITMAP)LoadImageA(NULL, "C:\\shellicon\\paste.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_DEFAULTSIZE);
int err = GetLastError();
return S_OK;
}
STDMETHODIMP CIconInjector::QueryContextMenu(HMENU hmenu, UINT uMenuIndex, UINT uidFirst, UINT uidLast, UINT flags) {
using namespace std;
if (flags & CMF_DEFAULTONLY) return S_OK; // Don't do anything if it's just a double-click
int itemsCount = GetMenuItemCount(hmenu);
for (int i = 0; i < itemsCount; i++) { // Iterate over the menu items
MENUITEMINFO mii;
ZeroMemory(&mii, sizeof(mii));
mii.cbSize = sizeof(mii);
mii.fMask = MIIM_FTYPE | MIIM_STRING;
mii.dwTypeData = NULL;
BOOL ok = GetMenuItemInfo(hmenu, i, TRUE, &mii); // Get the string length
if (mii.fType != MFT_STRING) continue;
UINT size = (mii.cch + 1) * 2; // Allocate enough space
LPWSTR menuTitle = (LPWSTR)malloc(size);
mii.cch = size;
mii.fMask = MIIM_TYPE;
mii.dwTypeData = menuTitle;
ok = GetMenuItemInfo(hmenu, i, TRUE, &mii); // Get the actual string data
mii.fMask = MIIM_BITMAP;
bool chIcon = true;
if (wcscmp(menuTitle, L"&Copy") == 0) {
mii.hbmpItem = bmpCopy;
}
else if (wcscmp(menuTitle, L"Cu&t") == 0) {
mii.hbmpItem = bmpCut;
}
else if (wcscmp(menuTitle, L"&Paste") == 0) {
mii.hbmpItem = bmpPaste;
}
else if (wcscmp(menuTitle, L"Se&nd to") == 0) {
mii.hbmpItem = bmpSendto;
}
else if (wcsstr(menuTitle, L"&Undo") != NULL) {
mii.hbmpItem = bmpUndo;
}
else if (wcsstr(menuTitle, L"&Redo") != NULL) {
mii.hbmpItem = bmpRedo;
}
else if (wcscmp(menuTitle, L"&Delete") == 0) {
mii.hbmpItem = bmpDel;
}
else {
chIcon = false;
}
if (chIcon) SetMenuItemInfo(hmenu, i, TRUE, &mii);
free(menuTitle);
}
return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, 0); // Same as S_OK (= 0) but is The Right Thing To Do [TM]
}
STDMETHODIMP CIconInjector::InvokeCommand(LPCMINVOKECOMMANDINFO info) {
return S_OK;
}
STDMETHODIMP CIconInjector::GetCommandString(UINT_PTR, UINT, UINT*, LPSTR, UINT) {
return S_OK;
}
Обратите внимание, что HBITMAP
s никогда не очищаются, но это не имеет большого значения, учитывая, что содержимое DLL исчезнет, когда Explorer отключится. Значки в любом случае едва занимают память.
Если вы компилируете для 32-битной версии, первым параметром GetCommandString
будет просто a UINT
вместо a UINT_PTR
.
Если вы действительно хотите , прозрачные иконки, вам придется создать окно с нужной иконке , а затем установить mii.hBmpItem
на HBMMENU_SYSTEM
и поставить ручку окна в mii.dwItemData
, как описано в нижней части статьи MSDN поMENUITEMINFO
. Я не смог понять, как создавать окна из расширений оболочки. LR_LOADTRANSPARENT
выглядит многообещающе, как флаг LoadImageA
, но у него есть свои подводные камни - в частности, не работает, если вы не используете 256-цветные растровые изображения.
Если у вас возникли проблемы с загрузкой изображений, попробуйте убрать LR_DEFAULTSIZE
флажок из LoadImageA
вызовов.
Кто-то достаточно опытный в C ++ мог бы, вероятно, извлечь ресурсы из других DLL и преобразовать их в HBITMAP
s, но это кто-то не я.
Модифицируя это
Я написал это в Visual Studio, который я считаю лучшим редактором для Windows C ++.
Загрузите файл SLN в Visual Studio 2015 после установки инструментов C ++. В IconInjector.cpp
, вы можете добавить HBITMAP
записи вверху и LoadImageA
звонить, Initialize
чтобы добавить новые значки. Внизу в else if
разделе используйте wcscmp
вызов для поиска точного соответствия или wcsstr
вызов для поиска наличия подстроки. В обоих случаях &
позиция представляет подчеркивание / ускоритель при использовании Shift + F10. Установите режим Release и свою архитектуру x64 и выполните Build → Build Solution . Вы получите сообщение об ошибке при регистрации выхода, но не волнуйтесь; Вы бы все равно хотели сделать это вручную. Завершите работу проводника, скопируйте новую DLL-библиотеку ( \x64\Release\ContextIcons.dll
в папке решения) на место и выполните regsvr32
танец.
Атрибуции
Большое спасибо авторам MSDN и создателю « Полного идиотского руководства по написанию расширений оболочки », на которое я много ссылался.
панегирик
Для многих экземпляров Explorer, которые были убиты при производстве этого расширения оболочки: вы умерли по великой причине, что некоторые люди в Интернете могут иметь значки рядом со своими словами.