「コピー/カット/貼り付け/削除」Windowsのデフォルトのコンテキストメニュー項目にアイコンを割り当てる方法


12

Windows 8 / 8.1 x64では、コピーカットペースト削除元に戻すやり直し送信などのデフォルトのWindowsコンテキストメニュー項目にカスタムアイコンを割り当てたいのですが、デフォルトではアイコンがあります:

ここに画像の説明を入力してください

レジストリ内のコンテキストメニュー項目への「参照」を見つけて、それらの「アイコン」レジストリ値を追加できる場所

または、言い換えると、SendTo shellexのようなシェル拡張メニューにアイコンを割り当てる方法。

研究


@ Sk8erPeterがコメントしたように、

Icon文字列値を別のコンテキストメニューハンドラに追加しても、たとえば次のようなカスタム項目に追加するときのように機能しません HKEY_CLASSES_ROOT\*\shell\MYCUSTOMKEY


どのアイコンを指しているのですか?スクリーンショットはありますか?
レイスタファリアン

@Raystafarian画像で質問を更新しました。
ElektroStudios

1
@Raystafarian:問題は、Cut」「Copy」「Delete」「Rename」などの既存の基本的なコンテキストメニュー項目にカスタムアイコンを追加する方法です。新しいカスタム項目をコンテキストメニューに追加する場合のIconようなキーに文字列値を追加するだけでよいため、非常に簡単ですHKEY_CLASSES_ROOT\*\shell\MYCUSTOMITEM(そして、値はIconeg %SystemRoot%\System32\shell32.dll,-133またはsg。elseのようになります)。ただし、Icon異なるコンテキストメニューハンドラーに文字列値を追加しても、これらのカスタム項目に追加するときのようには機能しません
Sk8erPeter

明確にするための別のスクリーンショットを次に示します(興味深い部分は赤い境界線です):i.imgur.com/fmewg6L.png。ところで、ご覧のように、コンテキストメニューにカスタムアイコンのあるカスタム項目(「Notepad ++で開く」など)があります。これは、既存のシステムコンテキストメニュー項目で実現したいことです。
Sk8erPeter

1
@ Sk8erPeter現時点での私の最高のリードは、SetMenuItemInfoに応答して使用するシェルコンテキストメニューハンドラーを作成する見込みですQueryContextMenu
ベンN

回答:


10

所属通知:私はこの回答に記載されているソフトウェアの著者です。

最初に、この質問のために C ++とWin32を学んだことを知ってもらいます。

コンテキストメニューハンドラーとして登録される64ビットシェル拡張を開発しました。呼び出されると、既存のメニュー項目を調べ、興味深いエントリを探します。見つかった場合、アイコンを貼り付けます(以前に読み込まれている必要があります)。現時点では、CopyCutDeletePasteRedoSend toUndoを探しています。コードを変更して独自のコードを追加できます。この手順を以下に説明します。(申し訳ありませんが、C ++を構成するのに十分ではありません。)

人に知られている最もgliいアイコンが付いた、動作中のスクリーンショット:

実行中

本当に必要な場合は、これらのアイコンダウンロードできます

設定する

(私のDropboxから)ダウンロードします。注意:このファイルは、ある種のマルウェアとしてVirusTotalスキャナーによって検出されます。これは、既存のエントリを強打するために行う必要があることを考えると理解できます。私はあなたのコンピュータに意図的な害を与えないという私の言葉を与えます。疑わしい場合、および/または変更および拡張したい場合は、GitHubのコード参照してください!

Cドライブにフォルダーを作成しますC:\shellicon。以下のタイトルでBMPファイルを作成します:copycutdeletepasteredosendtoundo。(願わくば、どちらがどのことをするのか明らかです。)これらの画像はおそらく16 x 16ピクセル(またはDPI設定が大きいとメニューのマージンが大きくなります)になるはずですが、より大きなものでも成功しました。アイコンを透明に見せたい場合は、背景をコンテキストメニューと同じ色にする必要があります。(このトリックはDropboxでも採用されています。)私はひどいアイコンをMSペイントで作りました。他のプログラムは、と互換性のある方法で保存する場合と保存しない場合がありますLoadImageA1インチあたり96ピクセルの24ビット色深度での16 x 16は、最も信頼性の高い画像プロパティのセットのようです。

DLLをすべてのユーザーがアクセスできる場所に配置します。作成したフォルダーは適切な選択です。DLLを含むフォルダーで管理プロンプトを開き、実行しますregsvr32 ContextIcons.dll。これは、シェルタイプの登録情報を作成し*DriveDirectory、と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のがクリーンアップされることはありませんが、これは問題が多すぎるときExplorerをシャットダウンしてDLLのものは離れて行くことを考えることはありません。とにかくアイコンはほとんどメモリを消費しません。

32ビット用にコンパイルしている場合、最初のパラメーターGetCommandStringはのUINT代わりに単なるUINT_PTRです。

本当に透明なアイコンが必要な場合は、MSDN記事の下部に記載されているように、目的のアイコンでウィンドウを作成し、ウィンドウのハンドルを設定mii.hBmpItemHBMMENU_SYSTEMて配置する必要があります。シェル拡張からウィンドウを作成する方法を理解できませんでした。はのフラグとして有望に見えますが、独自の落とし穴があります。具体的には、256色のビットマップを使用しない限り機能しません。mii.dwItemDataMENUITEMINFOLR_LOADTRANSPARENTLoadImageA

画像の読み込みで問題が発生した場合LR_DEFAULTSIZEは、LoadImageA呼び出しからフラグを削除してみてください。

C ++に十分熟練しHBITMAPている人は、おそらく他のDLLからリソースを取得してsに変換できますが、その人は私ではありません。

変更する

これをVisual Studioで作成しました。これはWindows C ++の最高のエディターだと思います。

C ++ツールをインストールした後、SLNファイルをVisual Studio 2015にロードします。ではIconInjector.cppHBITMAP上部にエントリを追加し、LoadImageA呼び出してInitialize新しいアイコンを追加できます。else ifセクションの下で、wcscmp呼び出しを使用して完全一致wcsstrを検索するか、呼び出しを使用して部分文字列の存在を検索します。どちらの場合も、&Shift + F10を使用したときの下線/アクセラレータの位置を表します。モードをReleaseに、アーキテクチャをx64に設定し、BuildBuild Solutionを実行します。出力の登録に失敗したというエラーが表示されますが、心配する必要はありません。とにかくこれを手動で行いたいでしょう。エクスプローラーを終了し、新しいDLL(\x64\Release\ContextIcons.dllソリューションフォルダー内)をその場所にコピーしてから、regsvr32ダンスを行います。

帰属

MSDNライター、および「シェル拡張の作成に関する完全な白痴のガイド作成者に感謝します。

Eu辞

このシェル拡張の作成で殺された多くの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をダウンロードするに取り組んで
ベン・N

2
あなたはそれを信じないでしょう...あなたの画像で動作します!:D:Dこれは、Windowsで処理できなかったbmpファイルがいくつかあることを意味します。理由はわかりません(後で確認します)。とにかく、ありがとうございます、あなたのコードは本当に問題を解決します!:)
Sk8erPeter

1
@BenN:OK、ありがとう!:)それはもう少し便利だったでしょう。ところで、伝説のペイントで以前は動作していなかった画像を開き、「名前を付けて保存」>「24ビットビットマップ(.bmp; .dip)」を実行すると(BMPファイルに保存すると再び)、そしてこの新しいファイルをソース画像として使用します、それは動作します。もちろん、ビットマップのサイズは正確に16x16ピクセルでなければなりません。したがって、ペイントは24ビット/ピクセル(1670万色)、96x96 DPI、および16x16ピクセルのサイズの予想されるビットマップ形式を作成します。以前、IrfanViewの.pngファイルを.bmpファイルに変換してサイズ変更しましたが、これらのアイコンは機能しませんでした。
Sk8erPeter

1

コメントを残すのに十分な担当者がいませんが、この情報はshell32.dllに含まれているようです。ファイルはコンパイルされているため、その中にある関数を確認するのは困難ですが、それが1つのように見えます。

対象(レジストリのエクスポート):

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
興味深い情報。ただし、回答ではなくコメントのようです。あなたは今、どこでもコメントするのに十分な担当者を持っています:)
ベンN
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.