제휴 통지 : 본인은이 답변에 언급 된 소프트웨어의 저자입니다.
먼저이 질문에 대해서만 C ++과 Win32를 배웠다는 것을 알게 될 것 입니다.
상황에 맞는 메뉴 처리기로 등록되는 64 비트 셸 확장을 개발했습니다. 호출되면 기존 메뉴 항목을 살펴보고 흥미로운 항목을 찾습니다. 아이콘을 찾으면 아이콘이 붙어 있습니다 (이전에로드되어 있어야 함). 현재는 Copy , Cut , Delete , Paste , Redo , Send to 및 Undo 를 찾습니다 . 코드를 수정하여 직접 추가 할 수 있습니다. 이에 대한 절차는 아래에 설명되어 있습니다. (미안하지만 C ++에서는 구성 가능하게 충분하지 않습니다.)
사람에게 가장 추악한 아이콘이있는 실제 스크린 샷 :
원한다면 이 아이콘을 다운로드 할 수 있습니다 .
설정
Dropbox에서 다운로드하십시오 . 참고 :이 파일은 하나의 VirusTotal 스캐너 에 의해 일종의 맬웨어 형태로 탐지됩니다 . 기존 항목을 해킹하기 위해해야 할 일을 고려할 때 이해할 수 있습니다. 나는 그것이 당신의 컴퓨터에 고의로 해를 끼치 지 않는다는 나의 말을합니다. 의심 스럽거나 수정 및 확장하려면 GitHub 의 코드 를 참조하십시오 !
C 드라이브에 폴더를 작성하십시오 C:\shellicon
.. 다음과 같은 제목으로 BMP 파일을 만듭니다 : copy
, cut
, delete
, paste
, redo
, sendto
, undo
. (어떤 것이 어떤 일을하는지 분명히 알 수 있습니다.)이 이미지는 아마도 16 x 16 픽셀이어야합니다 (또는 DPI 설정이 크면 메뉴 여백이 커지지 만). 아이콘이 투명하게 보이게하려면 배경을 상황에 맞는 메뉴와 동일한 색상으로 만들어야합니다. (이 트릭은 Dropbox에서도 사용됩니다.) MS Paint로 끔찍한 아이콘을 만들었습니다. 다른 프로그램은 호환 가능한 방식으로 저장하거나 저장하지 않을 수 있습니다 LoadImageA
. 인치당 96 픽셀의 24 비트 색 농도에서 16 x 16 은 가장 안정적인 이미지 속성 세트 인 것 같습니다.
DLL을 모든 사용자가 액세스 할 수있는 곳에 두십시오. 방금 만든 폴더가 좋은 선택입니다. DLL이 포함 된 폴더에서 관리자 프롬프트를 열고 수행 regsvr32 ContextIcons.dll
합니다. 이것은 쉘 유형에 대한 등록 정보를 생성 *
, Drive
, Directory
,와 Directory\Background
. 쉘 확장을 제거하려면 다음을 수행하십시오 regsvr32 /u ContextIcons.dll
.
관련 코드
기본적으로 확장 프로그램은 모든 상황에 맞는 메뉴 항목의 텍스트를 쿼리하고 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
의이 정리되지 않습니다,하지만이 문제가 너무 많은 경우 탐색기 닫힌다 아래로 DLL의 물건이 사라질 것을 제공하지 않습니다. 어쨌든 아이콘은 거의 메모리를 차지하지 않습니다.
32 비트 용으로 컴파일 할 경우 첫 번째 매개 변수는 GetCommandString
단지입니다 UINT
대신의 UINT_PTR
.
당신이 정말로 투명 아이콘을 원하는 경우에, 당신은 원하는 아이콘으로 윈도우를 생성하고 설정해야합니다 mii.hBmpItem
에 HBMMENU_SYSTEM
와있는 창으로의 핸들을 넣어 mii.dwItemData
하단에 설명 된대로 의 MSDN 문서MENUITEMINFO
. 쉘 확장에서 창을 만드는 방법을 알 수 없었습니다. LR_LOADTRANSPARENT
의 플래그로 유망 해 보이지만 LoadImageA
자체 함정이 있습니다. 특히 256 색 비트 맵을 사용하지 않으면 작동하지 않습니다.
이미지로드에 문제가 있으면 호출 에서 LR_DEFAULTSIZE
플래그를 제거하십시오 LoadImageA
.
C ++에 충분히 숙련 된 사람은 아마도 다른 DLL에서 리소스를 가져 와서 HBITMAP
s 로 변환 할 수 는 있지만 누군가는 아닙니다.
그것을 수정
Visual Studio에서 이것을 작성했습니다 .Windows C ++의 최고의 편집기라고 생각합니다.
C ++ 도구를 설치 한 후 SLN 파일을 Visual Studio 2015로로드하십시오. 에서가 IconInjector.cpp
, 당신은 추가 할 수 있습니다 HBITMAP
상단에있는 항목과 LoadImageA
의 통화는 Initialize
새로운 아이콘을 추가 할 수 있습니다. else if
섹션 에서 아래로 wcscmp
전화를 걸어 정확히 일치하는 항목 wcsstr
을 찾 거나 하위 문자열이 있는지 찾는 호출을 사용하십시오. 두 경우 모두, &
Shift + F10을 사용할 때 밑줄 / 가속기의 위치를 나타냅니다. 모드를 릴리스로 설정하고 아키텍처를 x64로 설정하고 빌드 → 솔루션 빌드를 수행 하십시오 . 출력 등록 실패에 대한 오류가 발생하지만 걱정하지 마십시오. 어쨌든 수동으로이 작업을 수행하려고합니다. 탐색기를 끝내고 \x64\Release\ContextIcons.dll
솔루션 폴더 의 새 DLL 을 해당 위치로 복사 한 다음 regsvr32
춤을 추십시오.
기여
MSDN 작성자와 " 쉘 확장 작성을위한 완전한 바보 안내서 "를 만든 많은 분들께 감사드립니다 .
찬사
이 셸 확장 프로그램을 제작할 때 죽인 많은 Explorer 인스턴스의 경우 : 인터넷상의 일부 사람들은 단어 옆에 아이콘이있을 수있는 큰 원인으로 사망했습니다.