Avis d'affiliation: je suis l'auteur du logiciel mentionné dans cette réponse.
Tout d'abord, je vous ferai savoir que j'ai appris C ++ et Win32 juste pour cette question .
J'ai développé une extension shell 64 bits qui est enregistrée en tant que gestionnaire de menu contextuel. Lorsqu'il est invoqué, il fouille dans les éléments de menu existants, à la recherche d'entrées intéressantes. S'il en trouve un, il y colle une icône (qui doit avoir été chargée plus tôt). À l'heure actuelle, il recherche Copier , Couper , Supprimer , Coller , Rétablir , Envoyer vers et Annuler . Vous pouvez ajouter le vôtre en modifiant le code; la procédure à suivre est décrite ci-dessous. (Désolé, je ne suis pas assez bon en C ++ pour le rendre configurable.)
Une capture d'écran de celui-ci en action, avec les icônes les plus laides connues de l'homme:

Vous pouvez télécharger ces icônes si vous le souhaitez.
Configuration
Téléchargez-le (depuis ma Dropbox). Remarque : ce fichier est détecté par un analyseur VirusTotal comme étant une forme de malware. Ceci est compréhensible, étant donné le genre de choses qu'il doit faire pour supprimer les entrées existantes. Je vous donne ma parole qu'il ne fait aucun mal intentionnel à votre ordinateur. Si vous êtes suspect et / ou que vous souhaitez le modifier et l'étendre, consultez le code sur GitHub !
Créez un dossier dans votre lecteur C: C:\shellicon. Créer des fichiers BMP avec les titres suivants: copy, cut, delete, paste, redo, sendto, undo. (J'espère qu'il est évident que l'on fait quelle chose.) Ces images devraient probablement être de 16 x 16 pixels (ou quelle que soit la taille de vos paramètres DPI, cela fait la marge du menu), mais j'ai également réussi avec des images plus grandes. Si vous voulez que les icônes soient transparentes, vous devrez simplement faire en sorte que leur arrière-plan soit de la même couleur que le menu contextuel. (Cette astuce est également utilisée par Dropbox.) J'ai créé mes terribles icônes avec MS Paint; d'autres programmes peuvent ou non enregistrer d'une manière compatible avec LoadImageA. 16 par 16 à une profondeur de couleur de 24 bits à 96 pixels par pouce semble être l'ensemble de propriétés d'image le plus fiable.
Mettez la DLL dans un endroit accessible à tous les utilisateurs, ce dossier que vous venez de créer est un bon choix. Ouvrez une invite d'administration dans le dossier contenant la DLL et faites regsvr32 ContextIcons.dll. Cela crée des informations d'inscription pour les types de coquillages *, Drive, Directoryet Directory\Background. Si vous souhaitez supprimer l'extension shell, faites-le regsvr32 /u ContextIcons.dll.
Code pertinent
Fondamentalement, l'extension interroge simplement le texte de chaque élément du menu contextuel avec GetMenuItemInfoet, le cas échéant, ajuste l'icône avec SetMenuItemInfo.
Visual Studio génère beaucoup de code mystérieux magique pour les projets ATL, mais voici le contenu de IconInjector.cpp, qui implémente le gestionnaire de menu contextuel:
// 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;
}
Notez que les HBITMAPs ne sont jamais nettoyés, mais cela n'a pas trop d'importance étant donné que le contenu de la DLL disparaîtra lorsque l'Explorateur s'arrêtera. Les icônes prennent à peine de la mémoire de toute façon.
Si vous compilez pour 32 bits, le premier paramètre de GetCommandStringest juste un UINTau lieu d'un UINT_PTR.
Si vous voulez vraiment des icônes transparentes, vous devrez créer une fenêtre avec l'icône désirée, puis mis mii.hBmpItemà HBMMENU_SYSTEMet mettre la poignée à la fenêtre mii.dwItemData, comme décrit au bas de l'article MSDN surMENUITEMINFO . Je n'ai pas pu comprendre comment créer des fenêtres à partir d'extensions shell. LR_LOADTRANSPARENTsemble prometteur comme indicateur LoadImageA, mais il a ses propres pièges - en particulier, ne fonctionne pas à moins que vous n'utilisiez des bitmaps 256 couleurs.
Si vous rencontrez des problèmes avec le chargement de l'image, essayez de supprimer l' LR_DEFAULTSIZEindicateur des LoadImageAappels.
Quelqu'un suffisamment compétent en C ++ pourrait probablement extraire des ressources d'autres DLL et les convertir en HBITMAPs, mais ce n'est pas moi.
Le modifier
J'ai écrit cela dans Visual Studio, qui je pense être le meilleur éditeur pour Windows C ++.
Chargez le fichier SLN dans Visual Studio 2015 après avoir installé les outils C ++. Dans IconInjector.cpp, vous pouvez ajouter des HBITMAPentrées en haut et LoadImageAappeler Initializepour ajouter de nouvelles icônes. Dans la else ifsection, utilisez un wcscmpappel pour rechercher une correspondance exacte ou un wcsstrappel pour rechercher la présence d'une sous-chaîne. Dans les deux cas, le &représente la position du soulignement / accélérateur lors de l'utilisation de Maj + F10. Définissez votre mode sur Release et votre architecture sur x64, et faites Build → Build Solution . Vous obtiendrez une erreur sur l'échec de l'enregistrement de la sortie, mais ne vous inquiétez pas; vous voudriez quand même le faire manuellement. End Explorer, copiez la nouvelle DLL ( \x64\Release\ContextIcons.dlldans le dossier de la solution) à l'endroit, puis faites la regsvr32danse.
Attributions
Un grand merci aux rédacteurs MSDN et au créateur du " Guide complet de l'idiot pour l'écriture d'extensions de shell ", auquel j'ai fait référence de manière intensive.
Éloge
Aux nombreuses instances d'Explorer qui ont été tuées lors de la production de cette extension de shell: vous êtes mort pour une bonne cause, que certaines personnes sur Internet peuvent avoir des icônes à côté de leurs mots.