ประกาศการเป็นพันธมิตร: ฉันเป็นผู้เขียนซอฟต์แวร์ที่กล่าวถึงในคำตอบนี้
ก่อนอื่นฉันจะให้คุณรู้ว่าฉันได้เรียนรู้ C ++ และ Win32 สำหรับคำถามนี้เท่านั้น
ฉันได้พัฒนาส่วนขยายของเชลล์ 64 บิตที่ได้รับการลงทะเบียนเป็นตัวจัดการเมนูบริบท เมื่อมีการเรียกใช้มันจะค้นหาผ่านรายการเมนูที่มีอยู่เพื่อค้นหารายการที่น่าสนใจ หากพบหนึ่งไอคอนจะติดไอคอนไว้ (ซึ่งจะต้องโหลดก่อนหน้านี้) ในขณะที่จะมองหาคัดลอก , ตัด , ลบ , วาง , ทำซ้ำ , ส่งไปและเลิกทำ คุณสามารถเพิ่มของคุณเองโดยการแก้ไขรหัส; ขั้นตอนนี้อธิบายไว้ด้านล่าง (ขออภัยฉันไม่ดีพอที่ C ++ เพื่อให้สามารถกำหนดค่าได้)
ภาพหน้าจอของอุปกรณ์ที่ใช้งานโดยมีไอคอนน่าเกลียดที่สุดที่มนุษย์รู้จัก:
คุณสามารถดาวน์โหลดไอคอนเหล่านี้หากคุณต้องการ
การตั้งค่า
ดาวน์โหลด (จาก Dropbox ของฉัน) ประกาศ : ไฟล์นี้ถูกตรวจจับโดยสแกนเนอร์ VirusTotal หนึ่งตัวว่าเป็นมัลแวร์บางรูปแบบ สิ่งนี้สามารถเข้าใจได้โดยกำหนดประเภทของสิ่งที่ต้องทำเพื่อตีสิ่งที่มีอยู่ ฉันให้คุณคำของฉันว่ามันไม่เป็นอันตรายต่อคอมพิวเตอร์ของคุณ หากคุณสงสัยและ / หรือคุณต้องการแก้ไขและขยายให้ดูรหัสใน GitHub !
สร้างโฟลเดอร์ในไดรฟ์ C C:\shellicon
ของคุณ: สร้างไฟล์ BMP ที่มีชื่อดังต่อไปนี้: copy
, cut
, delete
, paste
, redo
, ,sendto
undo
(หวังว่าจะเห็นได้อย่างชัดเจนว่าสิ่งใดที่ทำสิ่งนั้น) ภาพเหล่านี้น่าจะเป็น 16 x 16 พิกเซล (หรือการตั้งค่า DPI ที่ยิ่งใหญ่ของคุณทำให้เมนูอยู่ด้านบน) แต่ฉันก็ประสบความสำเร็จด้วยเช่นกัน หากคุณต้องการให้ไอคอนดูโปร่งใสคุณจะต้องทำให้พื้นหลังเป็นสีเดียวกับเมนูบริบท (เคล็ดลับนี้ใช้โดย Dropbox ด้วย) ฉันสร้างไอคอนที่น่ากลัวด้วย MS Paint; โปรแกรมอื่น ๆ LoadImageA
หรืออาจจะไม่บันทึกในลักษณะเข้ากันได้กับ 16 16 โดยที่ความลึกของสี 24 บิตที่ 96 พิกเซลต่อนิ้วดูเหมือนจะเป็นชุดของคุณสมบัติภาพที่น่าเชื่อถือที่สุด
วาง DLL ให้ผู้ใช้ทุกคนสามารถเข้าถึงได้โฟลเดอร์ที่คุณเพิ่งสร้างเป็นตัวเลือกที่ดี เปิดผู้ดูแลระบบพรอมต์ในโฟลเดอร์ที่มี DLL regsvr32 ContextIcons.dll
และทำ นี้จะสร้างข้อมูลการลงทะเบียนประเภทเปลือก*
, Drive
, และDirectory
ถ้าคุณเคยต้องการที่จะลบส่วนขยายของเชลล์ทำDirectory\Background
regsvr32 /u ContextIcons.dll
รหัสที่เกี่ยวข้อง
โดยทั่วไปส่วนขยายเพียง queries ข้อความทุกเมนูบริบทของรายการด้วยและหากเหมาะสมปรับไอคอนที่มีGetMenuItemInfo
SetMenuItemInfo
Visual Studio สร้างรหัสลึกลับลึกลับจำนวนมากสำหรับโครงการ ATL แต่นี่คือเนื้อหาของIconInjector.cpp
ซึ่งใช้ตัวจัดการเมนูบริบท:
// 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;
}
โปรดทราบว่าตัวHBITMAP
s นั้นไม่เคยทำความสะอาด แต่สิ่งนี้ไม่สำคัญมากนักเนื่องจากข้อมูลของ DLL จะหายไปเมื่อ Explorer ปิดตัวลง ไอคอนแทบจะใช้หน่วยความจำใด ๆ อยู่แล้ว
หากคุณกำลังรวบรวมสำหรับ 32 บิตพารามิเตอร์แรกจะGetCommandString
เป็นเพียงการแทนUINT
UINT_PTR
หากคุณต้องการไอคอนโปร่งใสจริงๆคุณจะต้องสร้างหน้าต่างที่มีไอคอนที่ต้องการและจากนั้นตั้งค่าmii.hBmpItem
ไปHBMMENU_SYSTEM
และใส่หมายเลขอ้างอิงไปยังหน้าต่างในmii.dwItemData
ตามที่อธิบายไว้ที่ด้านล่างของบทความ MSDN MENUITEMINFO
บน ฉันไม่สามารถหาวิธีสร้าง windows จากส่วนขยายของเชลล์ได้ LR_LOADTRANSPARENT
ดูมีแนวโน้มว่าเป็นธงLoadImageA
แต่มีข้อผิดพลาดของตัวเองโดยเฉพาะไม่ทำงานจนกว่าคุณจะใช้บิตแมป 256 สี
หากคุณประสบปัญหาในการโหลดภาพลองลบการLR_DEFAULTSIZE
ตั้งค่าสถานะจากการLoadImageA
โทร
ใครบางคนที่มีทักษะเพียงพอใน C ++ อาจจะสามารถดึงทรัพยากรออกจาก DLLs อื่น ๆ และแปลงเป็นHBITMAP
s แต่บางคนไม่ใช่ฉัน
แก้ไขมัน
ฉันเขียนสิ่งนี้ใน Visual Studio ซึ่งฉันเชื่อว่าเป็นตัวแก้ไขที่ดีที่สุดสำหรับ Windows C ++
โหลดไฟล์ SLN ลงใน Visual Studio 2015 หลังจากที่คุณติดตั้งเครื่องมือ C ++ ในIconInjector.cpp
คุณสามารถเพิ่มHBITMAP
รายการที่ด้านบนและLoadImageA
โทรเข้าInitialize
เพื่อเพิ่มไอคอนใหม่ ด้านล่างในelse if
ส่วนใช้การwcscmp
โทรเพื่อค้นหาการจับคู่ที่ตรงกันหรือการwcsstr
เรียกเพื่อค้นหาการมีอยู่ของสายอักขระย่อย ในทั้งสองกรณีนี้&
แสดงถึงตำแหน่งของขีดเส้นใต้ / คันเร่งเมื่อใช้ Shift + F10 ตั้งโหมดของคุณเพื่อวางจำหน่ายและสถาปัตยกรรมของคุณเพื่อ x64 และทำรูปร่าง → สร้างโซลูชัน คุณจะได้รับข้อผิดพลาดเกี่ยวกับการไม่ลงทะเบียนเอาต์พุต แต่ไม่ต้องกังวล คุณต้องการทำสิ่งนี้ด้วยตนเอง End Explorer คัดลอก DLL ใหม่ ( \x64\Release\ContextIcons.dll
ในโฟลเดอร์โซลูชัน) ไปยังสถานที่จากนั้นทำการregsvr32
เต้น
การอ้างเหตุผล
ขอบคุณมากสำหรับนักเขียน MSDN และผู้สร้าง " คู่มือคนโง่ที่สมบูรณ์เกี่ยวกับการเขียนส่วนขยายของเชลล์ " ซึ่งฉันอ้างอิงอย่างหนัก
คำสรรเสริญเยินยอ
สำหรับอินสแตนซ์ Explorer จำนวนมากที่ถูกฆ่าตายในการผลิตส่วนขยายของเชลล์นี้: คุณเสียชีวิตด้วยสาเหตุที่ยิ่งใหญ่ซึ่งบางคนบนอินเทอร์เน็ตสามารถมีไอคอนถัดจากคำพูดของพวกเขา