Avviso di affiliazione: sono l'autore del software menzionato in questa risposta.
Prima di tutto, ti farò sapere che ho imparato C ++ e Win32 proprio per questa domanda .
Ho sviluppato un'estensione shell a 64 bit che viene registrata come gestore del menu di scelta rapida. Quando viene invocato, fruga tra le voci di menu esistenti, cercando voci interessanti. Se ne trova una, attacca un'icona (che deve essere stata caricata in precedenza). Al momento, cerca Copia , Taglia , Elimina , Incolla , Ripeti , Invia a e Annulla . Puoi aggiungere il tuo modificando il codice; la procedura per questo è descritta di seguito. (Mi dispiace, non sono abbastanza bravo in C ++ per renderlo configurabile.)
Uno screenshot di esso in azione, con le icone più brutte conosciute dall'uomo:
Puoi scaricare queste icone se vuoi davvero.
Configurandolo
Scaricalo (dal mio Dropbox). Avviso : questo file viene rilevato da uno scanner VirusTotal come una qualche forma di malware. Questo è comprensibile, dato il tipo di cose che deve fare per colpire le voci esistenti. Ti do la mia parola che non danneggia intenzionalmente il tuo computer. Se sei sospettoso e / o vuoi modificarlo ed estenderlo, vedi il codice su GitHub !
Creare una cartella nell'unità C: C:\shellicon
. Creare file BMP con i seguenti titoli: copy
, cut
, delete
, paste
, redo
, sendto
, undo
. (Spero che sia ovvio quale fa la cosa.) Queste immagini dovrebbero probabilmente essere 16 per 16 pixel (o comunque le tue impostazioni DPI rendono il margine del menu), ma ho avuto successo anche con quelle più grandi. Se vuoi che le icone appaiano trasparenti, dovrai semplicemente rendere il loro sfondo dello stesso colore del menu contestuale. (Questo trucco è utilizzato anche da Dropbox.) Ho creato le mie icone terribili con MS Paint; altri programmi possono o meno salvare in modo compatibile con LoadImageA
. 16 per 16 a una profondità di colore di 24 bit a 96 pixel per pollice sembra essere l'insieme più affidabile di proprietà dell'immagine.
Metti la DLL da qualche parte accessibile a tutti gli utenti, quella cartella che hai appena creato è una buona scelta. Aprire un prompt di amministrazione nella cartella contenente la DLL ed eseguire regsvr32 ContextIcons.dll
. Questo crea le informazioni di registrazione per i tipi di shell *
, Drive
, Directory
, e Directory\Background
. Se vuoi rimuovere l'estensione della shell, fallo regsvr32 /u ContextIcons.dll
.
Codice pertinente
Fondamentalmente, l'estensione interroga semplicemente il testo di ogni voce del menu contestuale con GetMenuItemInfo
e, se appropriato, regola l'icona con SetMenuItemInfo
.
Visual Studio genera un sacco di codice misterioso magico per i progetti ATL, ma questo è il contenuto di IconInjector.cpp
, che implementa il gestore del menu di scelta rapida:
// 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;
}
Si noti che gli HBITMAP
s non vengono mai ripuliti, ma questo non importa troppo dato che le cose della DLL spariranno quando Explorer si spegne. Le icone prendono a malapena qualche ricordo comunque.
Se stai compilando per 32-bit, il primo parametro a GetCommandString
è solo a UINT
anziché a UINT_PTR
.
Se si vuole veramente icone trasparenti, dovrete creare una finestra con l'icona desiderata e quindi impostare mii.hBmpItem
per HBMMENU_SYSTEM
e mettere la maniglia per la finestra in mii.dwItemData
, come descritto in fondo l'articolo di MSDN suMENUITEMINFO
. Non sono riuscito a capire come creare finestre dalle estensioni della shell. LR_LOADTRANSPARENT
sembra promettente come una bandiera di LoadImageA
, ma ha le sue insidie - in particolare, non funziona se non si utilizzano bitmap a 256 colori.
Se si verificano problemi con il caricamento delle immagini, provare a rimuovere il LR_DEFAULTSIZE
flag dalle LoadImageA
chiamate.
Qualcuno sufficientemente esperto in C ++ potrebbe probabilmente estrarre risorse da altre DLL e convertirle in HBITMAP
s, ma quel qualcuno non sono io.
Modificandolo
L'ho scritto in Visual Studio, che credo sia il miglior editor per Windows C ++.
Caricare il file SLN in Visual Studio 2015 dopo aver installato gli strumenti C ++. In IconInjector.cpp
, è possibile aggiungere HBITMAP
voci in alto e LoadImageA
chiamate Initialize
per aggiungere nuove icone. Nella parte inferiore della else if
sezione, utilizzare awcscmp
chiamata per cercare una corrispondenza esatta o una wcsstr
chiamata per cercare la presenza di una sottostringa. In entrambi i casi, &
rappresenta la posizione della sottolineatura / dell'acceleratore quando si usa Maiusc + F10. Imposta la tua modalità su Release e la tua architettura su x64, quindi fai Build → Build Solution . Verrà visualizzato un errore per non riuscire a registrare l'output, ma non preoccuparti; vorresti farlo manualmente comunque. End Explorer, copia la nuova DLL ( \x64\Release\ContextIcons.dll
nella cartella della soluzione) nella posizione, quindi esegui la regsvr32
danza.
Attribuzioni
Mille grazie agli scrittori MSDN e al creatore di " The Complete Idiot's Guide to Writing Extensions Shell ", a cui ho fatto riferimento pesantemente.
Elogio
Alle molte istanze di Explorer che sono state uccise nella produzione di questa estensione shell: sei morto per una grande causa, che alcune persone su Internet possono avere icone accanto alle loro parole.