Aviso de afiliação: sou o autor do software mencionado nesta resposta.
Primeiro, você saberá que aprendi C ++ e Win32 apenas para esta pergunta .
Eu desenvolvi uma extensão de shell de 64 bits que é registrada como um manipulador de menu de contexto. Quando invocado, ele vasculha os itens de menu existentes, procurando entradas interessantes. Se encontrar um, ele colará um ícone nele (que deve ter sido carregado anteriormente). No momento, ele procura Copiar , Recortar , Excluir , Colar , Refazer , Enviar para e Desfazer . Você pode adicionar seu próprio modificando o código; o procedimento para isso é descrito abaixo. (Desculpe, eu não sou bom o suficiente em C ++ para torná-lo configurável.)
Uma captura de tela em ação, com os ícones mais feios conhecidos pelo homem:
Você pode baixar esses ícones, se realmente quiser.
Configurando
Faça o download (do meu Dropbox). Aviso : este arquivo é detectado por um scanner VirusTotal como sendo algum tipo de malware. Isso é compreensível, dado o tipo de coisa que é necessário fazer para destruir as entradas existentes. Confio na minha palavra de que isso não causa danos intencionais ao seu computador. Se você suspeita e / ou deseja modificá-lo e ampliá-lo, consulte o código no GitHub !
Crie uma pasta na sua unidade C: C:\shellicon
. Criar arquivos BMP com os seguintes títulos: copy
, cut
, delete
, paste
, redo
, sendto
, undo
. (Espero que seja óbvio qual deles faz qual coisa.) Essas imagens provavelmente devem ter 16 por 16 pixels (ou quão grandes as configurações de DPI fazem a margem do menu), mas também tive sucesso com as maiores. Se você deseja que os ícones pareçam transparentes, basta fazer o plano de fundo da mesma cor do menu de contexto. (Esse truque também é empregado pelo Dropbox.) Fiz meus terríveis ícones com o MS Paint; outros programas podem ou não ser salvos de maneira compatível com LoadImageA
. 16 por 16, com profundidade de cor de 24 bits e 96 pixels por polegada, parece ser o conjunto mais confiável de propriedades da imagem.
Coloque a DLL em algum lugar acessível a todos os usuários; essa pasta que você acabou de criar é uma boa escolha. Abra um prompt de administrador na pasta que contém a DLL e faça regsvr32 ContextIcons.dll
. Isso cria informações de registro para os tipos de shell *
,Drive
, Directory
, e Directory\Background
. Se você quiser remover a extensão do shell, faça regsvr32 /u ContextIcons.dll
.
Código relevante
Basicamente, a extensão consulta apenas o texto de cada item de menu de contexto com GetMenuItemInfo
e, se apropriado, ajusta o ícone com SetMenuItemInfo
.
O Visual Studio gera muitos códigos misteriosos mágicos para projetos ATL, mas esse é o conteúdo deIconInjector.cpp
, que implementa o manipulador de menu de contexto:
// 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;
}
Observe que os HBITMAP
s nunca são limpos, mas isso não importa muito, pois o material da DLL desaparece quando o Explorer é encerrado. Os ícones mal tiram qualquer memória de qualquer maneira.
Se você está compilando para 32 bits, o primeiro parâmetro para GetCommandString
é apenas um em UINT
vez de umUINT_PTR
.
Se você realmente quer ícones transparentes, você terá que criar uma janela com o ícone desejado e, em seguida, definir mii.hBmpItem
a HBMMENU_SYSTEM
e colocou a alça para a janela mii.dwItemData
, como descrito na parte inferior do artigo do MSDN sobreMENUITEMINFO
. Não consegui descobrir como criar janelas a partir de extensões de shell. LR_LOADTRANSPARENT
parece promissor como bandeira LoadImageA
, mas tem suas próprias armadilhas - especificamente, não funciona, a menos que você use bitmaps de 256 cores.
Se você tiver problemas com o carregamento de imagens, tente remover o LR_DEFAULTSIZE
sinalizador das LoadImageA
chamadas.
Alguém com experiência em C ++ provavelmente poderia pegar recursos de outras DLLs e convertê-los em HBITMAP
s, mas esse alguém não sou eu.
Modificando-o
Eu escrevi isso no Visual Studio, que acredito ser o melhor editor para Windows C ++.
Carregue o arquivo SLN no Visual Studio 2015 depois de instalar as ferramentas C ++. Em IconInjector.cpp
, você pode adicionar HBITMAP
entradas na parte superior e fazer LoadImageA
chamadas Initialize
para adicionar novos ícones. Na else if
seção, use uma wcscmp
chamada para procurar uma correspondência exata ou uma wcsstr
chamada para procurar a presença de uma subsequência. Nos dois casos, o &
representa a posição do sublinhado / acelerador ao usar Shift + F10. Defina seu modo como Release e sua arquitetura como x64 e faça Build → Build Solution . Você receberá um erro ao não registrar a saída, mas não se preocupe; você faria isso manualmente de qualquer maneira. End Explorer, copie a nova DLL ( \x64\Release\ContextIcons.dll
na pasta da solução) para o local e faça oregsvr32
dança.
Atribuições
Muito obrigado aos escritores do MSDN e ao criador do " Guia Completo para Idiotas de Criação de Extensões de Shell ", ao qual me referi bastante.
Elogio
Nas várias instâncias do Explorer que foram mortas na produção dessa extensão de shell: você morreu por uma grande causa, que algumas pessoas na Internet podem ter ícones ao lado de suas palavras.