Як призначити піктограму "Копіювати / вирізати / вставити / видалити" елементи контекстного меню Windows за замовчуванням?


12

У Windows 8 / 8.1 x64 я хотів би призначити спеціальний значок для елементів контекстного меню Windows за замовчуванням, таких як " Копіювати" , " Вирізати" , " Вставити" , " Видалити" , " Скасувати" , " Повторити" та " Надіслати на елементи", який за замовчуванням має будь-який значок:

введіть тут опис зображення

Де я можу знайти "посилання" на ці елементи контекстного меню в реєстрі, а потім додати для них значення "реєстру"?

Або іншими словами, як призначити піктограму меню розширення оболонки, як шелекс SendTo ?.

Дослідження


Як коментує @ Sk8erPeter , здається, що:

"Додавання Iconзначення рядка до різних обробників контекстного меню не працює як додавання його до спеціального елемента, наприклад, наприклад HKEY_CLASSES_ROOT\*\shell\MYCUSTOMKEY"


На яку іконку ви звертаєтесь? У вас є скріншот?
Райстафаріан

@Raystafarian Я оновив питання із зображенням.
ElektroStudios

1
@Raystafarian: питання полягає в тому, як додати спеціальну піктограму до існуючих елементів базового контекстного меню, таких як "Вирізати" , "Копіювати" , "Видалити" , "Перейменувати" тощо. BTW при додаванні нового спеціального елемента до контекстного меню, це це дуже просто, тому що вам потрібно лише додати значення IconString у такому ключі HKEY_CLASSES_ROOT\*\shell\MYCUSTOMITEM(і значення значення Iconбуло б, наприклад, наприклад, %SystemRoot%\System32\shell32.dll,-133або sg. else). АЛЕ додавання Iconзначення рядка до різних обробників контекстного меню не працює як додавання його до цих спеціальних елементів.
Sk8erPeter

Ось ще один скріншот, щоб зробити це зрозумілим (цікава частина - червоними рамками ): i.imgur.com/fmewg6L.png . До речі, як ви бачите, у контекстному меню у мене є декілька спеціальних елементів із спеціальними піктограмами (наприклад, "Відкрити за допомогою блокнота ++" ) - саме цього ми б хотіли досягти із існуючими пунктами контекстного меню системи!
Sk8erPeter

1
@ Sk8erPeter Моїм найкращим на даний момент є перспектива створення обробника контекстного меню оболонки, який використовується SetMenuItemInfoу відповідь на QueryContextMenu.
Бен N

Відповіді:


10

Повідомлення про належність: Я автор програмного забезпечення, згаданого в цій відповіді.

По-перше, я дам вам знати, що я навчився 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;
}

Зауважте, що HBITMAPs ніколи не прибираються, але це не має великого значення, враховуючи, що речі DLL зникнуть, коли Explorer вимкнеться. Ікони ледь не забирають жодної пам’яті.

Якщо ви компілюєте для 32-бітового, перший параметр до GetCommandString- це лише UINTзамість а UINT_PTR.

Якщо ви дійсно хочете , прозорі іконки, вам доведеться створити вікно з потрібною іконці , а потім встановити mii.hBmpItemна HBMMENU_SYSTEMі поставити ручку вікна в mii.dwItemData, як описано в нижній частині статті MSDN поMENUITEMINFO . Я не зміг зрозуміти, як створити вікна з розширень оболонок. LR_LOADTRANSPARENTвиглядає як прапор перспективного LoadImageA, але у нього є свої підводні камені - зокрема, не працює, якщо ви не використовуєте 256-кольорові растрові карти.

Якщо у вас виникли проблеми із завантаженням зображення, спробуйте видалити LR_DEFAULTSIZEпрапор із LoadImageAдзвінків.

Хтось із достатньо кваліфікованих C ++, можливо, міг би схопити ресурси з інших DLL та перетворити їх на HBITMAPs, але це хтось не я.

Модифікація

Я написав це у Visual Studio, який вважаю найкращим редактором для Windows C ++.

Завантажте файл SLN в Visual Studio 2015 після встановлення інструментів C ++. В IconInjector.cpp, ви можете додати HBITMAPзаписи у верхній і LoadImageAдзвінки в Initializeдодавати нові іконки. Внизу в else ifрозділі використовуйте wcscmpдзвінок, щоб шукати точну відповідність, або wcsstrвиклик, щоб шукати наявність підрядка. В обох випадках &являє собою положення підкреслення / прискорювача при використанні Shift + F10. Встановіть для режиму Release та вашу архітектуру x64 та виконайте BuildBuild Solution . Ви отримаєте помилку щодо невдалої реєстрації виводу, але не хвилюйтесь; ви хочете зробити це в будь-якому випадку вручну. Кінець Провідника, скопіюйте нову DLL ( \x64\Release\ContextIcons.dllу папку з рішеннями) на місце, після чого виконайте regsvr32танець.

Атрибути

Величезне спасибі письменникам MSDN та творцеві " Повного довідника про написання розширень оболонок ", на який я багато посилався.

Евлогія

Для багатьох екземплярів Explorer, які загинули при виробництві цього розширення оболонки: ви померли з великої причини, що деякі люди в Інтернеті можуть мати піктограми поруч зі своїми словами.


Оце Так! Я дуже ціную ваші зусилля, дуже дякую! (+1) Я спробував усе можливе, але не зміг змусити складену версію працювати в Windows 10 (Build 10240). Я не знаю, в чому проблема, всі зображення bmp існують у правильному шляху ( C:\shellicon\copy.bmpі т. Д. - це значки 20x20 пікселів у форматі BMP), і я зареєстрував dll як адміністратор у командному рядку, з regsvr32 ContextIcons.dllяким успішно запускався, але Я не бачу змін у контекстному меню. Я навіть перезапустив комп’ютер, ще не зареєстрував і перереєстрував dll знову, але ніяких змін. Я намагаюся скласти джерело у VS2015!
Sk8erPeter

@ Sk8erPeter MSDN сказав, що іконки повинні бути 16x16, але 20x20 працює для мене. Можливо, для Windows 10 потрібен 16x16? Зауважте, що вам потрібно перезапустити Провідник, щоб зміни вступили в силу.
Бен Н

2
@ Sk8erPeter Звичайно, тут . Я побачу, як поставити код на GitHub. Зараз працюємо над завантаженням Windows 10 ...
Ben N

2
Ви не повірите ... ВІН ПРАЦЮЄ з вашими образами! : D: D Це означає, що у мене є деякі файли bmp, з якими Windows не міг обробитись, не знаю, чому (пізніше я теж це перевірю). У будь-якому випадку, дуже дякую, ваш код справді вирішує проблему! :)
Sk8erPeter

1
@BenN: Добре, дякую! :) Це було б трохи зручніше. BTW тим часом зрозумів, що якщо я відкрию свої раніше не працюючі зображення в легендарній Paint, і я роблю "Зберегти як"> "24-бітну бітмапу (.bmp; .dip)" (тому збережіть її у файлі BMP знову), і я використовую цей новий файл як вихідне зображення, він працює. Звичайно, розмір растрової карти повинен бути рівно 16х16 пікселів. Таким чином Paint створює очікуваний формат растрового зображення, який становить 24 біти на піксель (16,7 мільйона кольорів), розміром 96x96 DPI та 16x16 пікселів. Раніше я перетворював і змінював розміри .png файлів у IrfanView у .bmp файли, ці значки не працювали.
Sk8erPeter

1

У мене недостатньо респондентів, щоб залишити коментар, але, здається, ця інформація міститься всередині shell32.dll. Файли були складені, тому важко зрозуміти, які функції в ньому є, але, здається, це одна.

Цікаві (експорт реєстру):

HKEY_CLASSES_ROOT \ CLSID {3ad05575-8857-4850-9277-11b85bdb8e09}

(За замовчуванням) REG_SZ Копіювати / Перемістити / Перейменувати / Видалити / Пов'язати об’єкт

AppID REG_SZ {3ad05575-8857-4850-9277-11b85bdb8e09}

LocalizedString REG_EXPAND_SZ @% SystemRoot% \ system32 \ shell32.dll, -50176

Під ключем InProcServer32 він посилається на shell32.dll. Є ще кілька інших, а також відповідні звукові назви. Можливо, також інтерес представляє windows.storage.dll


1
Цікава інформація. Однак це, здається, є коментарем, а не відповіддю. Тепер у вас є достатня кількість представників для коментарів скрізь :)
Ben N
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.