Powiadomienie o stowarzyszeniu: Jestem autorem oprogramowania wymienionego w tej odpowiedzi.
Po pierwsze, chcę wiedzieć, że nauczyłem się C ++ i Win32 tylko na to pytanie .
Opracowałem 64-bitowe rozszerzenie powłoki, które jest rejestrowane jako moduł obsługi menu kontekstowego. Po wywołaniu przeszukuje istniejące pozycje menu, szukając interesujących pozycji. Jeśli ją znajdzie, nakleja na nią ikonę (która musiała zostać wcześniej załadowana). Obecnie wyszukuje opcje Kopiuj , Wytnij , Usuń , Wklej , Ponów , Wyślij do i Cofnij . Możesz dodać własny, modyfikując kod; procedura jest opisana poniżej. (Przepraszam, nie jestem wystarczająco dobry w C ++, aby można go było konfigurować).
Zrzut ekranu przedstawiający najbrzydsze ikony znane człowiekowi:
Możesz pobrać te ikony, jeśli naprawdę chcesz.
Konfiguracja
Pobierz go (z mojego Dropbox). Uwaga : ten plik jest wykrywany przez jeden skaner VirusTotal jako pewna forma złośliwego oprogramowania. Jest to zrozumiałe, biorąc pod uwagę rodzaj rzeczy, które należy zrobić, aby zlikwidować istniejące wpisy. Daję wam słowo, że nie wyrządza celowo szkody komputerowi. Jeśli jesteś podejrzany i / lub chcesz go zmodyfikować i rozszerzyć, zobacz kod na GitHub !
Utwórz folder w dysku C: C:\shellicon
. Tworzenie plików BMP z następujących tytułów: copy
, cut
, delete
, paste
, redo
, sendto
, undo
. (Mam nadzieję, że jest oczywiste, który z nich robi jakąś rzecz.) Te obrazy powinny prawdopodobnie mieć rozmiar 16 na 16 pikseli (lub jak duże ustawienia DPI robią margines menu), ale udało mi się również z większymi. Jeśli chcesz, aby ikony wyglądały na przezroczyste, musisz po prostu ustawić ich tło w tym samym kolorze co menu kontekstowe. (Ta sztuczka jest również stosowana przez Dropbox.) Zrobiłem moje straszne ikony za pomocą MS Paint; inne programy mogą, ale nie muszą, zapisywać w sposób zgodny z LoadImageA
. 16 na 16 przy 24-bitowej głębi kolorów przy 96 pikselach na cal wydaje się być najbardziej niezawodnym zestawem właściwości obrazu.
Umieść bibliotekę DLL w miejscu dostępnym dla wszystkich użytkowników, właśnie utworzony folder jest dobrym wyborem. Otwórz monit administratora w folderze zawierającym bibliotekę DLL i wykonaj regsvr32 ContextIcons.dll
. Stwarza informacji rejestracyjnych dla typów muszli *
, Drive
, Directory
, i Directory\Background
. Jeśli kiedykolwiek chcesz usunąć rozszerzenie powłoki, zrób to regsvr32 /u ContextIcons.dll
.
Odpowiedni kod
Zasadniczo rozszerzenie tylko odpytuje tekst każdego elementu menu kontekstowego GetMenuItemInfo
i, w razie potrzeby, dostosowuje ikonę za pomocą SetMenuItemInfo
.
Visual Studio generuje wiele magicznego tajemniczego kodu dla projektów ATL, ale jest to zawartość IconInjector.cpp
, która implementuje moduł obsługi menu kontekstowego:
// 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;
}
Zauważ, że HBITMAP
s nigdy nie są czyszczone, ale nie ma to większego znaczenia, biorąc pod uwagę, że pliki DLL znikną po wyłączeniu Explorera. Ikony i tak ledwo zajmują pamięć.
Jeśli kompilujesz dla wersji 32-bitowej, pierwszym parametrem GetCommandString
jest po prostu UINT
zamiast a UINT_PTR
.
Jeśli naprawdę chcesz, przejrzyste ikony, musisz utworzyć okno z żądaną ikonę, a następnie ustawić mii.hBmpItem
się HBMMENU_SYSTEM
i umieścić uchwyt do okna, w mii.dwItemData
sposób opisany na dole artykułu na MSDNMENUITEMINFO
. Nie byłem w stanie dowiedzieć się, jak tworzyć okna z rozszerzeń powłoki. LR_LOADTRANSPARENT
wygląda obiecująco LoadImageA
, ale ma swoje własne pułapki - w szczególności nie działa, chyba że użyjesz 256-bitowych map bitowych.
Jeśli występują problemy z ładowaniem obrazu, spróbuj usunąć LR_DEFAULTSIZE
flagę z LoadImageA
połączeń.
Ktoś wystarczająco wykwalifikowany w C ++ mógłby prawdopodobnie pobrać zasoby z innych bibliotek DLL i przekonwertować je na HBITMAP
s, ale tym kimś nie jestem ja.
Modyfikując to
Napisałem to w Visual Studio, które uważam za najlepszy edytor dla Windows C ++.
Załaduj plik SLN do programu Visual Studio 2015 po zainstalowaniu narzędzi C ++. W IconInjector.cpp
możesz dodać HBITMAP
wpisy u góry i LoadImageA
wywołać, Initialize
aby dodać nowe ikony. W dolnej else if
części sekcji użyj wcscmp
połączenia, aby wyszukać dokładne dopasowanie lub wcsstr
połączenia, aby sprawdzić obecność podłańcucha. W obu przypadkach &
reprezentuje pozycję podkreślenia / akceleratora przy użyciu Shift + F10. Ustaw tryb na Release, a architekturę na x64 i wykonaj Kompilacja → Kompiluj rozwiązanie . Pojawi się błąd związany z niezarejestrowaniem danych wyjściowych, ale nie martw się; i tak chcesz to zrobić ręcznie. Zakończ Eksploratora, skopiuj nową bibliotekę DLL ( \x64\Release\ContextIcons.dll
w folderze rozwiązania) na miejsce, a następnie wykonaj regsvr32
taniec.
Atrybucje
Wielkie podziękowania dla pisarzy MSDN i twórcy „ The Complete Idiot's Guide to Writing Shell Extensions ”, do którego bardzo się odwoływałem.
Pochwała
Do wielu wystąpień Eksploratora, które zostały zabite podczas produkcji tego rozszerzenia powłoki: zginąłeś z wielkiej przyczyny, że niektóre osoby w Internecie mogą mieć ikony obok swoich słów.