Pemberitahuan afiliasi: Saya adalah pembuat perangkat lunak yang disebutkan dalam jawaban ini.
Pertama, saya ingin Anda tahu bahwa saya belajar C ++ dan Win32 hanya untuk pertanyaan ini .
Saya telah mengembangkan ekstensi shell 64-bit yang terdaftar sebagai penangan menu konteks. Ketika dipanggil, ia menggeledah item menu yang ada, mencari entri yang menarik. Jika menemukan satu, itu menempel ikon di atasnya (yang harus dimuat sebelumnya). Saat ini, ia mencari Copy , Cut , Delete , Paste , Redo , Send to , dan Undo . Anda dapat menambahkan sendiri dengan mengubah kode; prosedur untuk ini dijelaskan di bawah ini. (Maaf, saya tidak cukup baik di C ++ untuk membuatnya dapat dikonfigurasi.)
Tangkapan layar itu sedang beraksi, dengan ikon-ikon paling jelek diketahui manusia:

Anda dapat mengunduh ikon-ikon ini jika Anda benar-benar mau.
Menyiapkannya
Unduh (dari Dropbox saya). Perhatikan : file ini terdeteksi oleh satu pemindai VirusTotal sebagai bentuk malware. Ini bisa dimengerti, mengingat hal-hal yang harus dilakukan untuk memukul entri yang ada. Saya memberi Anda kata-kata saya bahwa itu tidak membahayakan komputer Anda. Jika Anda curiga dan / atau ingin memodifikasi dan memperluasnya, lihat kode di GitHub !
Buat folder di drive C Anda: C:\shellicon. Buat file BMP dengan judul berikut: copy, cut, delete, paste, redo, sendto, undo. (Semoga jelas yang mana melakukan hal yang mana.) Gambar-gambar ini mungkin harus 16 x 16 piksel (atau seberapa besar pengaturan DPI Anda membuat margin menu), tapi saya sudah sukses dengan yang lebih besar juga. Jika Anda ingin ikon terlihat transparan, Anda harus membuat latar belakangnya dengan warna yang sama dengan menu konteks. (Trik ini digunakan oleh Dropbox juga.) Saya membuat ikon mengerikan saya dengan MS Paint; program lain mungkin atau mungkin tidak menyimpan dengan cara yang kompatibel dengan LoadImageA. 16 dengan 16 pada kedalaman warna 24-bit pada 96 piksel per inci tampaknya merupakan properti gambar yang paling dapat diandalkan.
Letakkan DLL di tempat yang dapat diakses oleh semua pengguna, folder yang baru saja Anda buat adalah pilihan yang baik. Buka prompt admin di folder yang berisi DLL dan lakukan regsvr32 ContextIcons.dll. Hal ini menciptakan informasi pendaftaran untuk jenis shell *, Drive, Directory, dan Directory\Background. Jika Anda ingin menghapus ekstensi shell, lakukan regsvr32 /u ContextIcons.dll.
Kode yang relevan
Pada dasarnya, ekstensi hanya menanyakan teks setiap item menu konteks dengan GetMenuItemInfodan, jika sesuai, menyesuaikan ikon dengan SetMenuItemInfo.
Visual Studio menghasilkan banyak kode ajaib ajaib untuk proyek ATL, tetapi ini adalah isinya IconInjector.cpp, yang mengimplementasikan penangan menu konteks:
// 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;
}
Perhatikan bahwa HBITMAPs tidak pernah dibersihkan, tetapi ini tidak terlalu penting mengingat barang-barang DLL akan hilang ketika Explorer dimatikan. Ikon hampir tidak mengambil memori apa pun.
Jika Anda mengompilasi untuk 32-bit, parameter pertama GetCommandStringadalah hanya sebagai UINTganti a UINT_PTR.
Jika Anda benar-benar ingin ikon transparan, Anda harus membuat jendela dengan ikon yang diinginkan dan kemudian mengatur mii.hBmpItemuntuk HBMMENU_SYSTEMdan menempatkan pegangan untuk jendela di mii.dwItemData, seperti yang dijelaskan di bagian bawah artikel MSDN padaMENUITEMINFO . Saya tidak dapat menemukan cara membuat windows dari ekstensi shell. LR_LOADTRANSPARENTterlihat menjanjikan sebagai bendera LoadImageA, tetapi memiliki perangkapnya sendiri - khususnya, tidak berfungsi kecuali jika Anda menggunakan bitmap 256-warna.
Jika Anda mengalami masalah dengan pemuatan gambar, coba hapus LR_DEFAULTSIZEbendera dari LoadImageApanggilan.
Seseorang yang cukup cakap dalam C ++ mungkin dapat mengambil sumber daya dari DLL lain dan mengonversinya menjadi HBITMAPs, tetapi seseorang itu bukan saya.
Memodifikasinya
Saya menulis ini di Visual Studio, yang saya yakini sebagai editor terbaik untuk Windows C ++.
Memuat file SLN ke dalam Visual Studio 2015 setelah Anda menginstal alat C ++. Di IconInjector.cpp, Anda dapat menambahkan HBITMAPentri di bagian atas dan LoadImageAmemanggil Initializeuntuk menambahkan ikon baru. Di else ifbagian bawah, gunakan wcscmppanggilan untuk mencari kecocokan yang tepat, atau wcsstrpanggilan untuk mencari keberadaan substring. Dalam kedua kasus, &mewakili posisi garis bawah / akselerator saat menggunakan Shift + F10. Atur mode Anda ke Release dan arsitektur Anda ke x64, dan lakukan Build → Build Solution . Anda akan mendapatkan kesalahan tentang gagal mendaftarkan output, tetapi jangan khawatir; Anda tetap ingin melakukan ini secara manual. End Explorer, salin DLL baru ( \x64\Release\ContextIcons.dlldalam folder solusi) ke tempat itu, lalu lakukan regsvr32dansa.
Atribusi
Terima kasih banyak kepada penulis MSDN, dan kepada pencipta " Panduan Lengkap Idiot untuk Menulis Ekstensi Shell ", yang sangat saya referensikan.
Sanjungan
Untuk banyak contoh Explorer yang terbunuh dalam produksi ekstensi shell ini: Anda mati karena suatu alasan, bahwa beberapa orang di Internet dapat memiliki ikon di sebelah kata-kata mereka.