"복사 / 잘라 내기 / 붙여 넣기 / 삭제"Windows 기본 상황에 맞는 메뉴 항목에 아이콘을 할당하는 방법은 무엇입니까?


12

Windows 8 / 8.1 x64에서는 기본적으로 아이콘이있는 복사 , 잘라 내기 , 붙여 넣기 , 삭제 , 실행 취소 , 다시 실행보내기 항목과 같은 기본 Windows 컨텍스트 메뉴 항목에 사용자 정의 아이콘을 지정하고 싶습니다 .

여기에 이미지 설명을 입력하십시오

레지스트리에서 해당 컨텍스트 메뉴 항목에 대한 "참조"를 찾은 다음 "아이콘"레지스트리 값을 추가 할 수 있습니까?

즉, SendTo shellex? 와 같은 쉘 확장 메뉴에 아이콘을 할당하는 방법.

연구


@ Sk8erPeter가 논평 한 것처럼,

" Icon예를 들어 HKEY_CLASSES_ROOT\*\shell\MYCUSTOMKEY" 과 같은 사용자 정의 항목에 문자열 값을 추가하면 다른 컨텍스트 메뉴 핸들러에 추가 할 수 없습니다. "


어떤 아이콘을 가리 킵니까? 스크린 샷이 있습니까?
Raystafarian

@Raystafarian 이미지로 질문을 업데이트했습니다.
ElektroStudios

1
@Raystafarian : 질문은 "Cut" , "Copy" , "Delete" , "Rename" 등과 같은 기존 기본 컨텍스트 메뉴 항목에 사용자 정의 아이콘을 추가하는 방법입니다. 컨텍스트 메뉴 에 새 사용자 정의 항목 을 추가 할 때 BTW Icon문자열 값을 같은 키에 추가해야하기 때문에 매우 쉽습니다 HKEY_CLASSES_ROOT\*\shell\MYCUSTOMITEM( Icon예 : %SystemRoot%\System32\shell32.dll,-133또는 sg. else 와 같은 값 ). 그러나 Icon문자열 값을 다른 컨텍스트 메뉴 처리기에 추가하면 이러한 사용자 정의 항목에 문자열 값을 추가 할 때처럼 작동하지 않습니다 .
Sk8erPeter

여기에 또 다른 스크린 샷이 있습니다 (흥미로운 부분은 빨간색 테두리로 표시됨). i.imgur.com/fmewg6L.png . BTW 보시다시피, "Notepad ++로 열기"와 같은 사용자 정의 아이콘이있는 상황에 맞는 메뉴에 일부 사용자 정의 항목 이 있습니다. 이것은 기존 시스템 상황에 맞는 메뉴 항목으로 정확히 달성하려는 것입니다!
Sk8erPeter

1
@ Sk8erPeter 현재 나의 최고의 리드는 SetMenuItemInfo에 응답하여 사용하는 쉘 컨텍스트 메뉴 핸들러를 작성하는 것 QueryContextMenu입니다.
Ben N

답변:


10

제휴 통지 : 본인은이 답변에 언급 된 소프트웨어의 저자입니다.

먼저이 질문에 대해서만 C ++과 Win32를 배웠다는 것을 알게 될 것 입니다.

상황에 맞는 메뉴 처리기로 등록되는 64 비트 셸 확장을 개발했습니다. 호출되면 기존 메뉴 항목을 살펴보고 흥미로운 항목을 찾습니다. 아이콘을 찾으면 아이콘이 붙어 있습니다 (이전에로드되어 있어야 함). 현재는 Copy , Cut , Delete , Paste , Redo , Send toUndo 찾습니다 . 코드를 수정하여 직접 추가 할 수 있습니다. 이에 대한 절차는 아래에 설명되어 있습니다. (미안하지만 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.hBmpItemHBMMENU_SYSTEM와있는 창으로의 핸들을 넣어 mii.dwItemData하단에 설명 된대로 의 MSDN 문서MENUITEMINFO . 쉘 확장에서 창을 만드는 방법을 알 수 없었습니다. LR_LOADTRANSPARENT의 플래그로 유망 해 보이지만 LoadImageA자체 함정이 있습니다. 특히 256 색 비트 맵을 사용하지 않으면 작동하지 않습니다.

이미지로드에 문제가 있으면 호출 에서 LR_DEFAULTSIZE플래그를 제거하십시오 LoadImageA.

C ++에 충분히 숙련 된 사람은 아마도 다른 DLL에서 리소스를 가져 와서 HBITMAPs 로 변환 할 수 는 있지만 누군가는 아닙니다.

그것을 수정

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 인스턴스의 경우 : 인터넷상의 일부 사람들은 단어 옆에 아이콘이있을 수있는 큰 원인으로 사망했습니다.


와! 당신의 노력에 진심으로 감사합니다. 대단히 감사합니다! (+1) 최선을 다했지만 Windows 10 (빌드 10240)에서 컴파일 된 버전을 작동시킬 수 없었습니다. 문제가 무엇인지 모르고 모든 bmp 이미지가 올바른 경로에 존재합니다 ( C:\shellicon\copy.bmp등-BMP 형식의 20x20 픽셀 아이콘) dll을 관리자 권한으로 명령 프롬프트에 관리자로 등록 regsvr32 ContextIcons.dll했지만 성공적으로 실행되었지만 상황에 맞는 메뉴에 변화가 없습니다. 심지어 컴퓨터를 다시 시작하고 등록을 취소하고 dll을 다시 등록했지만 변경 사항은 없습니다. VS2015에서 소스를 컴파일하려고합니다!
Sk8erPeter

@ Sk8erPeter MSDN은 아이콘이 16x16이어야하지만 20x20은 나를 위해 작동한다고 말했다. 아마도 Windows 10에는 16x16이 필요합니까? 변경 사항을 적용하려면 탐색기를 다시 시작해야합니다.
벤 N

2
@ Sk8erPeter 확실히, 당신은 간다 . GitHub에 코드를 올리는 방법에 대해 살펴 보겠습니다. 지금 Windows 10 다운로드 작업 중 ...
Ben N

2
당신은 그것을 믿지 않을 것입니다 ... 그것은 이미지와 함께 작동합니다! : D : D 그것은 Windows가 처리 할 수없는 bmp 파일이 있다는 것을 의미합니다. 이유를 모릅니다 (나중에 그것을 확인할 것입니다). 어쨌든, 대단히 감사합니다. 코드가 실제로 문제를 해결합니다! :)
Sk8erPeter

1
@BenN : 알겠습니다, 감사합니다! :) 조금 더 편리했을 것입니다. 그동안 BTW는 전설적인 그림판 에서 이전에 작동하지 않은 이미지를 열면 "다른 이름으로 저장"> "24 비트 비트 맵 (.bmp; .dip)"을 수행하여 BMP 파일로 저장한다는 것을 깨달았습니다. 다시) 하고이 새 파일을 소스 이미지로 사용하면 작동합니다. 물론 비트 맵의 ​​크기는 정확히 16x16 픽셀이어야합니다. 따라서 Paint는 픽셀 당 24 비트 (1670 만 색상), 96x96 DPI 및 16x16 픽셀의 예상 비트 맵 형식을 만듭니다. 이전에는 IrfanView의 .png 파일을 .bmp 파일로 변환하고 크기를 조정했지만 이러한 아이콘이 작동하지 않았습니다.
Sk8erPeter

1

의견을 남길 충분한 담당자가 없지만이 정보는 shell32.dll에 포함되어 있습니다. 파일이 컴파일되어 어떤 기능이 있는지보기 어렵지만 그 기능은 하나 인 것 같습니다.

관심 분야 (레지스트리 수출) :

HKEY_CLASSES_ROOT \ CLSID {3ad05575-8857-4850-9277-11b85bdb8e09}

(기본값) REG_SZ 복사 / 이동 / 이름 바꾸기 / 삭제 / 링크 개체

AppID REG_SZ {3ad05575-8857-4850-9277-11b85bdb8e09}

LocalizedString REG_EXPAND_SZ @ % SystemRoot % \ system32 \ shell32.dll, -50176

InProcServer32 키 아래에서 shell32.dll을 참조합니다. 적절한 발음 이름을 가진 몇 가지 다른 것들이 있습니다. 아마도 관심이있는 것은 windows.storage.dll


1
흥미로운 정보. 그러나 답이 아닌 의견 인 것 같습니다. 당신은 이제 모든 곳에서 의견
Ben N
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.