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 GetMenuItemInfo
dan, 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 HBITMAP
s 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 GetCommandString
adalah hanya sebagai UINT
ganti a UINT_PTR
.
Jika Anda benar-benar ingin ikon transparan, Anda harus membuat jendela dengan ikon yang diinginkan dan kemudian mengatur mii.hBmpItem
untuk HBMMENU_SYSTEM
dan 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_LOADTRANSPARENT
terlihat 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_DEFAULTSIZE
bendera dari LoadImageA
panggilan.
Seseorang yang cukup cakap dalam C ++ mungkin dapat mengambil sumber daya dari DLL lain dan mengonversinya menjadi HBITMAP
s, 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 HBITMAP
entri di bagian atas dan LoadImageA
memanggil Initialize
untuk menambahkan ikon baru. Di else if
bagian bawah, gunakan wcscmp
panggilan untuk mencari kecocokan yang tepat, atau wcsstr
panggilan 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.dll
dalam folder solusi) ke tempat itu, lalu lakukan regsvr32
dansa.
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.