« 2009年3月 | トップページ | 2009年6月 »

2009年4月27日 (月)

シェル拡張-エクスプローラのコンテキストメニューを拡張 [5]

[4](ソース例)でアップしたソース(CShellMenuExt.cpp)のCShellMenuExt::GetCommandString()は不完全だった。
エクスプローラのステータスバーを表示しているときに、フォーカスがあるコンテキストメニューの項目の説明文を設定することがこの関数の役割の一つでした。

STDMETHODIMP CShellMenuExt::GetCommandString(UINT idCmd,
                                         UINT uFlags,
                                         UINT FAR *reserved,
                                         LPSTR pszName,
                                         UINT cchMax)
{
    ODS("CShellMenuExt::GetCommandString()\r\n");

    switch (idCmd)
    {
        case 0:
          if (uFlags == GCS_HELPTEXTA){
             lstrcpyA(pszName, "GAK メニュー 1 を起動します");
          } else if (uFlags == GCS_HELPTEXTW){
            // ここではテキストをハードコーディングしているが、
             // 変数に保持した値を使うならば MultiByteToWideChar()でユニコード文字列化するなどする。
             lstrcpyW((LPWSTR)pszName, L"GAK メニュー 1 を起動します");
          } else if (uFlags == GCS_VERBA){
             lstrcpyA(pszName, "GAKmenu1");
          } else if (uFlags == GCS_VERBW){
             lstrcpyW((LPWSTR)pszName, L"GAKmenu1");
          }
            break;

    }

    return NOERROR;
}

GCS_VERBA/GCS_VERBWの役割は依然としてよくわかりません。

2009年4月13日 (月)

シェル拡張-エクスプローラのコンテキストメニューを拡張 [4]

拡張子.GAKファイルに対するコンテキストメニュー拡張DLLの例。
ソースはこちら(VC++6のプロジェクトファイル含む)。元々のサンプルの名残は相当残ってますが。


・[1][3]の手順によってDLLを作成したあと、ファクトリクラスとコンテキストメニュークラスの名前を変更した。
その後ソースファイルを整理した(両クラスの実装を一つのソースファイルにまとめた)。

・[2]の「拡張子.GAKにコンテキストメニュー」のregファイル例に示したレジストリ登録をDllRegisterServer()関数に組み込んだ。
 REGSVR32.EXE ShellMenuExt.dll
 で登録できる。

・追加メニューは一つだけで、実行すると選択したファイル名を表示する。(09/04/14加筆)

2009年4月10日 (金)

シェル拡張-エクスプローラのコンテキストメニューを拡張 [3]

[1]で作成したDLLにDllRegisterServer()/DllUnregisterServer()を追加する。

別のPlatform SKDサンプル ShellIconOverlay で定義されているDllRegisterServer()/DllUnregisterServer() が大きく流用可能である。
HKEY_CLASSES_ROOT\CLSID の下に登録する部分と、HKEY_LOCAL_MACHINE\....\Approved の下に登録する部分はできているので、これ以外のレジストリ登録コードを追加すればよい。

これによってREGファイルを使わなくても REGSVR32.EXE で登録が可能になる。


SDKサンプルShellIconOverlay のDllUnregisterServer()には間違いがある。
Approvedの値を削除するところで
      lResult = RegDeleteValue(hKey, STR_EXT_TITLE);

      lResult = RegDeleteValue(hKey, szCLSID);
でなければならない。

SDKサンプルと言えど完全ではないようだ。


このようにして作成したDLLのソースを公開したらよいのでしょうが、ほとんど元々のサンプルプログラムのままなので...

2009年4月 9日 (木)

シェル拡張-エクスプローラのコンテキストメニューを拡張 [2]

[1]に続いて、レジストリの設定方法。

SDKサンプル ShellExt はDllRegisterServer()を実装していないので、同サンプルのレジストリファイル ShellExt.reg を修正する。
 (1) GUID をDLLで使っている値に置き換える
 
 (2) InProcServer32 に作成したDLLのフルパスを記述する。
  ディレクトリの区切りは \\ である。
 
 (3) アプリケーション名 "Shell Extension Sample" を適当に置き換える。


拡張子 .GAK にコンテキストメニュー
 元々のサンプル ShellExt は拡張子 .GAK のコンテキストメニューを拡張している。
 その仕様のままの regファイル作成例は、
 
REGEDIT4

[HKEY_CLASSES_ROOT\CLSID\{16FCCEF9-27E1-451c-ADBF-4E4AA4FAC14B}]
   @="Test Shell Ext2"
[HKEY_CLASSES_ROOT\CLSID\{16FCCEF9-27E1-451c-ADBF-4E4AA4FAC14B}\InProcServer32]
   @="D:\\*******\\TestShellExt2.dll"
     "ThreadingModel"="Apartment"

[HKEY_CLASSES_ROOT\.gak]
   @="GAKFile"
[HKEY_CLASSES_ROOT\GAKFile]
   @="Shell Extension file"
[HKEY_CLASSES_ROOT\GAKFile\shellex\ContextMenuHandlers]
   @="GAKMenu"
[HKEY_CLASSES_ROOT\GAKFile\shellex\ContextMenuHandlers\GAKMenu]
   @="{16FCCEF9-27E1-451c-ADBF-4E4AA4FAC14B}"

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved]
   "{16FCCEF9-27E1-451c-ADBF-4E4AA4FAC14B}"="Test Shell Ext2"


すべてのファイルにコンテキストメニュー

REGEDIT4

[HKEY_CLASSES_ROOT\CLSID\{16FCCEF9-27E1-451c-ADBF-4E4AA4FAC14B}]
   @="Test Shell Ext2"
[HKEY_CLASSES_ROOT\CLSID\{16FCCEF9-27E1-451c-ADBF-4E4AA4FAC14B}\InProcServer32]
   @="D:\\*****\\TestShellExt2.dll"
     "ThreadingModel"="Apartment"

[HKEY_CLASSES_ROOT\*\shellex\ContextMenuHandlers\Test Shell Ext2]
   @="{16FCCEF9-27E1-451c-ADBF-4E4AA4FAC14B}"

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved]
   "{16FCCEF9-27E1-451c-ADBF-4E4AA4FAC14B}"="Test Shell Ext2"


regファイルを実行するとレジストリに登録され、すぐにコンテキストメニューが有効になる。

Contextmenu_sample_2_3 

ファイルタイプごとのコンテキストメニューも出ていることが分かる。

後は CtxMenu.cpp のカスタマイズということになる。

シェル拡張-エクスプローラのコンテキストメニューを拡張 [1]

Platform SDKのサンプルプログラム ShellExt のソースを流用することによりエクスプローラのコンテキストメニューを拡張する方法を調べてみた。
サンプルプログラムはプロパティシートやアイコンハンドラの拡張もしているが、ここではコンテキストメニューの拡張に対象を限る。

利用したPlatform SDK は "Microsoft Platform SDK September 1999 Edition"
開発環境は Windows2000Pro + Visual C++ 6.0


1.VC++にてプロジェクトの新規作成
"Win32 Dynamic-Link Library" - 空のDLLプロジェクト

2.SDKサンプル ShellExt から以下のファイルをコピーし、新プロジェクトに追加
 Priv.h
 ShellExt.h
 ShellExt.cpp
 CtxMenu.cpp
 ShExInit.cpp
 ShellExt.def

3.ShellExt.h の修正
 (1) GUIDを再生成して、CLSID_ShellExtension の定義を書き換える。
  GUIDの生成にはたとえばVC++6付属の GUIDGEN.EXE を利用。
 
 (2) クラスCShellExt の定義の修正
  ・IContextMenuIShellExtInit だけを継承する。
  ・IExtraction/IPersistFile/IShellPropSheetExt/ICopyHookのメソッド定義を削除
  ・GetCommandStringメソッドの第一引数の型を UINT_PTR から UINT に変更
   (これをしないとコンパイルエラー「GetCommandStringの宣言を確認してください」)

4.ShellExt.cpp の修正
 (1) CShellExt::QueryInterface メソッドの修正
  ・IDD_IExtraction/IID_IPersistFile/IID_IShellPropSheetExt/IID_IShellCopyHook に対する処理の部分(else if の羅列)を削除
 
5.CtxMenu.cpp の修正
 (1) CShellExt::GetCommandString メソッドの修正
  ・第一引数の型を UINT_PTR から UINT に変更

6.ShellExt.def の修正
 (1) LIBRARY をDLL名に


コンテキストメニューは元々のサンプルのままだが以上でコンパイルはOK

ページを改めてレジストリの設定について...

« 2009年3月 | トップページ | 2009年6月 »