Shell Extension を使って Explorer にコンテキストメニューを追加する

ShellExtension の定義方法の覚書き,その2(^^;
今度はExplorerのコンテキストメニューを追加します。

ここで扱う「コンテキストメニュー」は,ExplorerでファイルをDrag&Dropしたときに表示される,「ここにコピー」などが入っているものです。

次のようなCOM実装を行うと,Drag&Dropされたファイル名を取得して処理を行うことができるようになります。

1. Wizard を使って,IDL に実装クラスを定義する。

import "oaidl.idl";
import "ocidl.idl";

[
    object,
    uuid(70C82BD2-E659-41A4-AAE8-27DC030F82BA),
    helpstring("IMyCtxExt インターフェイス"),
    pointer_default(unique)
]
interface IMyCtxExt : IUnknown{
};
...................................................
[
    uuid(7A7CEC4E-FD39-4983-9A3F-C791214721BC),
    version(1.0),
    helpstring("CtxExtTest 1.0 タイプ ライブラリ")
]
library HardLinkColumnLib
{
    importlib("stdole2.tlb");
    [
        uuid(D2E45164-9547-4356-8513-937EAF39421D),
        helpstring("MyCtxExt Class")
    ]
    coclass MyCtxExt
    {
        [default] interface IMyCtxExt;
    };
    ....................................................
};


2. IShellExtInit, IContextMenu を継承(実装)する COM クラスを定義する。

class ATL_NO_VTABLE CMyCtxExt :
    public CComObjectRootEx,
    public CComCoClass,
    public IShellExtInit,
    public IContextMenu
{
    std::vector selectedFiles;    // 選択されたファイルを保存
    ................................................

    // IShellExtInit
    STDMETHODIMP Initialize(LPCITEMIDLIST, LPDATAOBJECT, HKEY);

    // IContextMenu
    STDMETHODIMP GetCommandString(UINT, UINT, UINT*, LPSTR, UINT) {
        return E_NOTIMPL; }    // 今回は使用していない
    STDMETHODIMP InvokeCommand(LPCMINVOKECOMMANDINFO);
    STDMETHODIMP QueryContextMenu(HMENU, UINT, UINT, UINT, UINT);
};


3. Initialize メソッドでは,処理対象として選択されたファイル一覧を取得。

//    Initialize
//        選択されたファイルのリストを取得する

HRESULT
CMyCtxExt::Initialize(LPCITEMIDLIST pidlFolder, LPDATAOBJECT pDataObj, HKEY hProgID)
{
    // パラメータとして与えられたDataObjectから,Dropファイル情報を取得する
    FORMATETC fmt = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
    STGMEDIUM stg = { TYMED_HGLOBAL };
    if(FAILED(pDataObj->GetData(&fmt, &stg)))
        return E_INVALIDARG;
    HDROP hdrop = (HDROP)::GlobalLock(stg.hGlobal);
    if(hdrop == NULL)
        return E_INVALIDARG;

    // 選択されたファイル一覧を取得し,インスタンスに保存する
    selectedFiles.clear();
    UINT uNumFiles = ::DragQueryFile(hdrop, 0xFFFFFFFF, NULL, 0);
    for(UINT uFile = 0; uFile < uNumFiles; ++uFile) {
        TCHAR szFile[MAX_PATH];
        if(!DragQueryFile(hdrop, uFile, szFile, MAX_PATH))
            continue;
        selectedFiles.push_back(tstring(szFile));
    }レジストリへの登録は,次のスクリプトで。

    // パラメータ情報を開放し,処理結果を返す
    // 対象ファイルが1つ以上あれば OK
    ::GlobalUnlock(stg.hGlobal);
    return selectedFiles.size() > 0 ? S_OK : E_FAIL;
}


4. QueryContextMenu では,表示するメニューの追加を行う

//    QueryContextMenu
//        コンテキストメニューを設定する

HRESULT
CLinkCtxExt::QueryContextMenu(HMENU hmenu, UINT uMenuIndex, UINT uidFirstCmd, 
                              UINT uidLastCmd, UINT uFlags)
{
    // デフォルトメニュー表示が指示されている場合は何もしない
    if(uFlags & CMF_DEFAULTONLY)
        return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, 0);

    // コンテキストメニューに自身のメニューを追加する
    ::InsertMenu(hmenu, uMenuIndex, MF_STRING|MF_BYPOSITION, uidFirstCmd, "My Context Menu");
    return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, 1);
}


5. InvokeCommand に実施に行う処理を記述する。対象となるファイルリストは,Initialize で取得しておいたもの。

6. レジストリへの登録は,次のスクリプトで。

HKCR
{
    NoRemove CLSID
    {
        ForceRemove {D2E45164-9547-4356-8513-937EAF39421D} = s 'MyCtx Extension Class'
        {
            InprocServer32 = s '%MODULE%'
            {
                val ThreadingModel = s 'Apartment'
            }
        }
    }
    NoRemove *
    {
        NoRemove shellex
        {
            NoRemove ContextMenuHandlers
            {
                ForceRemove MyCtxExt = s '{D2E45164-9547-4356-8513-937EAF39421D}'
            }
        }
    }
    NoRemove Directory
    {
        NoRemove shellex
        {
            NoRemove ContextMenuHandlers
            {
                ForceRemove MyCtxExt = s '{D2E45164-9547-4356-8513-937EAF39421D}'
            }

        }
    }
    NoRemove Folder
    {
        NoRemove shellex
        {
            NoRemove ContextMenuHandlers
            {
                ForceRemove MyCtxExt = s '{D2E45164-9547-4356-8513-937EAF39421D}'
            }
        }
    }
}



タグ:Windows
この記事へのコメント
コメントを書く
お名前: [必須入力]

メールアドレス: [必須入力]

ホームページアドレス:

コメント:

認証コード: [必須入力]


※画像の中の文字を半角で入力してください。
※ブログオーナーが承認したコメントのみ表示されます。

この記事へのトラックバック
rank← ランキングはこちらをクリック!

×

この広告は180日以上新しい記事の投稿がないブログに表示されております。