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
, Directory
et 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 GetMenuItemInfo
et, 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 HBITMAP
s 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 GetCommandString
est juste un UINT
au 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_SYSTEM
et 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_LOADTRANSPARENT
semble 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_DEFAULTSIZE
indicateur des LoadImageA
appels.
Quelqu'un suffisamment compétent en C ++ pourrait probablement extraire des ressources d'autres DLL et les convertir en HBITMAP
s, 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 HBITMAP
entrées en haut et LoadImageA
appeler Initialize
pour ajouter de nouvelles icônes. Dans la else if
section, utilisez un wcscmp
appel pour rechercher une correspondance exacte ou un wcsstr
appel 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.dll
dans le dossier de la solution) à l'endroit, puis faites la regsvr32
danse.
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.