所属通知:私はこの回答に記載されているソフトウェアの著者です。
最初に、この質問のために C ++とWin32を学んだことを知ってもらいます。
コンテキストメニューハンドラーとして登録される64ビットシェル拡張を開発しました。呼び出されると、既存のメニュー項目を調べ、興味深いエントリを探します。見つかった場合、アイコンを貼り付けます(以前に読み込まれている必要があります)。現時点では、Copy、Cut、Delete、Paste、Redo、Send to、Undoを探しています。コードを変更して独自のコードを追加できます。この手順を以下に説明します。(申し訳ありませんが、C ++を構成するのに十分ではありません。)
人に知られている最もgliいアイコンが付いた、動作中のスクリーンショット:
本当に必要な場合は、これらのアイコンをダウンロードできます。
設定する
(私のDropboxから)ダウンロードします。注意:このファイルは、ある種のマルウェアとしてVirusTotalスキャナーによって検出されます。これは、既存のエントリを強打するために行う必要があることを考えると理解できます。私はあなたのコンピュータに意図的な害を与えないという私の言葉を与えます。疑わしい場合、および/または変更および拡張したい場合は、GitHubのコードを参照してください!
Cドライブにフォルダーを作成しますC:\shellicon
。以下のタイトルでBMPファイルを作成します:copy
、cut
、delete
、paste
、redo
、sendto
、undo
。(願わくば、どちらがどのことをするのか明らかです。)これらの画像はおそらく16 x 16ピクセル(またはDPI設定が大きいとメニューのマージンが大きくなります)になるはずですが、より大きなものでも成功しました。アイコンを透明に見せたい場合は、背景をコンテキストメニューと同じ色にする必要があります。(このトリックはDropboxでも採用されています。)私はひどいアイコンをMSペイントで作りました。他のプログラムは、と互換性のある方法で保存する場合と保存しない場合がありますLoadImageA
。1インチあたり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
のがクリーンアップされることはありませんが、これは問題が多すぎるときExplorerをシャットダウンしてDLLのものは離れて行くことを考えることはありません。とにかくアイコンはほとんどメモリを消費しません。
32ビット用にコンパイルしている場合、最初のパラメーターGetCommandString
はのUINT
代わりに単なるUINT_PTR
です。
本当に透明なアイコンが必要な場合は、MSDN記事の下部に記載されているように、目的のアイコンでウィンドウを作成し、ウィンドウのハンドルを設定mii.hBmpItem
しHBMMENU_SYSTEM
て配置する必要があります。シェル拡張からウィンドウを作成する方法を理解できませんでした。はのフラグとして有望に見えますが、独自の落とし穴があります。具体的には、256色のビットマップを使用しない限り機能しません。mii.dwItemData
MENUITEMINFO
LR_LOADTRANSPARENT
LoadImageA
画像の読み込みで問題が発生した場合LR_DEFAULTSIZE
は、LoadImageA
呼び出しからフラグを削除してみてください。
C ++に十分熟練しHBITMAP
ている人は、おそらく他のDLLからリソースを取得してsに変換できますが、その人は私ではありません。
変更する
これをVisual Studioで作成しました。これはWindows C ++の最高のエディターだと思います。
C ++ツールをインストールした後、SLNファイルをVisual Studio 2015にロードします。ではIconInjector.cpp
、HBITMAP
上部にエントリを追加し、LoadImageA
呼び出してInitialize
新しいアイコンを追加できます。else if
セクションの下で、wcscmp
呼び出しを使用して完全一致wcsstr
を検索するか、呼び出しを使用して部分文字列の存在を検索します。どちらの場合も、&
Shift + F10を使用したときの下線/アクセラレータの位置を表します。モードをReleaseに、アーキテクチャをx64に設定し、Build → Build Solutionを実行します。出力の登録に失敗したというエラーが表示されますが、心配する必要はありません。とにかくこれを手動で行いたいでしょう。エクスプローラーを終了し、新しいDLL(\x64\Release\ContextIcons.dll
ソリューションフォルダー内)をその場所にコピーしてから、regsvr32
ダンスを行います。
帰属
MSDNライター、および「シェル拡張の作成に関する完全な白痴のガイド」の作成者に感謝します。
Eu辞
このシェル拡張の作成で殺された多くのExplorerインスタンスにとって、インターネット上の一部の人々は言葉の隣にアイコンを持っていることができるという大きな原因で亡くなりました。