2011-12-26 9 views

答えて

4

すべてのシェル拡張ハンドラは、インプロセスのコンポーネントオブジェクトモデル(COM)オブジェクトです。 「シェル拡張ハンドラの登録」の説明に従ってGUIDを割り当てて登録する必要があります。これらはDLLとして実装されており、次の標準関数をエクスポートする必要があります。 DllMain。 DLLの標準エントリポイント。 DllGetClassObject。オブジェクトのクラスファクトリを公開します。 DllCanUnloadNow。 COMがこの関数を呼び出して、オブジェクトがクライアントにサービスを提供しているかどうかを判断します。そうでない場合、システムはDLLをアンロードして関連するメモリを解放することができます。 すべてのCOMオブジェクトと同様に、シェル拡張ハンドラはIUnknownインターフェイスとクラスファクトリを実装する必要があります。ほとんどの場合、Windows XP以前のバージョンではIPersistFileまたはIShellExtInitインターフェイスを実装する必要があります。これらは、Windows VistaのIInitializeWithStream、IInitializeWithItem、およびIInitializeWithFileに置き換えられました。シェルは、これらのインターフェイスを使用してハンドラを初期化します。 IPersistFileインターフェイスは、次のようで実装する必要があります。

  • アイコンハンドラ
  • データ・ハンドラー
  • ドロップハンドラ

がIShellExtInitインタフェースは、以下で実装する必要があります。

  • ショートカットメニューハンドラ
  • ドラッグアンドドロップハンドラ
  • プロパティシートハンドラ

実装IPersistFile IPersistFileインターフェースは、オブジェクトからロードまたはディスクファイルに保存することができるように設計されています。 IUnknownに加えて、独自の5つのメソッドと、IPersistから継承するGetClassIDメソッドの6つのメソッドがあります。シェル拡張では、IPersistはシェル拡張ハンドラオブジェクトを初期化するためにのみ使用されます。通常、ディスクの読み書きは不要なため、GetClassIDメソッドとLoadメソッドだけがトークンなしの実装を必要とします。 シェルはGetClassIDを最初に呼び出し、この関数は拡張ハンドラオブジェクトのクラス識別子(CLSID)を返します。シェルはLoadを呼び出し、2つの値を渡します。最初のpszFileは、Shellが操作しようとしているファイルまたはフォルダの名前をUnicode文字列で表したものです。 2番目はdwModeで、ファイルアクセスモードを示します。通常、ファイルにアクセスする必要はないため、dwModeは通常ゼロです。このメソッドは、後で参照するために必要に応じてこれらの値を保存します。 次のコードは、一般的なシェル拡張ハンドラがGetClassIDメソッドとLoadメソッドをどのように実装するかを示しています。 ANSIまたはUnicodeのいずれかを処理するように設計されています。 CLSID_SampleExtHandlerは拡張ハンドラオブジェクトのGUIDで、CSampleShellExtensionはインターフェイスを実装するために使用されるクラスの名前です。 m_szFileName変数とm_dwMode変数は、ファイルの名前とアクセスフラグを格納するために使用されるプライベート変数です。

class CSampleShellExtension : public IPersistFile 
{ 
    // Method declarations not included 

    private: 
    WCHAR m_szFileName[MAX_PATH]; // The file name 
    DWORD m_dwMode;     // The file access mode 
} 

IFACEMETHODIMP CSampleShellExtension::GetClassID(__out CLSID *pCLSID) 
{ 
    *pCLSID = CLSID_SampleExtHandler; 
} 

IFACEMETHODIMP CSampleShellExtension::Load(PCWSTR pszFile, DWORD dwMode) 
{ 
    m_dwMode = dwMode; 
    return StringCchCopy(m_szFileName, ARRAYSIZE(m_szFileName), pszFile); 
} 

//実装サンプルは次のセクションに続きます。

実装IShellExtInit IShellExtInitインタフェースは、IUnknownのに加えて、唯一の方法、IShellExtInit ::初期化を有しています。このメソッドには、シェルがさまざまな種類の情報を渡すために使用できる3つのパラメータがあります。渡される値はハンドラの型に依存し、一部はNULLに設定できます。 pidlFolderは、アイテム識別子リスト(PIDL)へのフォルダのポインタを保持します。これは絶対PIDLです。プロパティシート拡張の場合、この値はNULLです。ショートカットメニュー拡張の場合は、ショートカットメニューが表示されている項目を含むフォルダのPIDLです。デフォルト以外のドラッグ&ドロップハンドラの場合は、ターゲットフォルダのPIDLです。 pDataObjectは、データオブジェクトのIDataObjectインターフェイスへのポインタを保持します。データオブジェクトは、CF_HDROP形式の1つ以上のファイル名を保持します。 hRegKeyは、ファイルオブジェクトまたはフォルダタイプのレジストリキーを保持します。 IShellExtInit :: Initializeメソッドは、後で使用するために必要に応じて、ファイル名、IDataObjectポインター、およびレジストリキーを格納します。次のコードは、IShellExtInit :: Initializeの実装を示しています。簡単にするために、この例では、データオブジェクトには1つのファイルしか含まれていないものとしています。一般的に、データオブジェクトには複数のファイルが含まれており、それぞれのファイルを抽出する必要があります。

// This code continues the CSampleShellExtension sample shown in the 
// "Implementing IPersistFile" section above. 

class CSampleShellExtension : public IShellExtInit { 
    // Method declarations not included 

    private: 
    // IDList of the folder for extensions invoked on the folder, such as 
    // background context menu handlers or nondefault drag-and-drop handlers. 
    PIDLIST_ABSOLUTE m_pidlFolder; 

    // The data object contains an expression of the items that the handler is 
    // being initialized for. Use SHCreateShellItemArrayFromDataObject to 
    // convert this object to an array of items. Use SHGetItemFromObject if you 
    // are only interested in a single Shell item. If you need a file system 
    // path, use IShellItem::GetDisplayName(SIGDN_FILESYSPATH, ...). 
    IDataObject *m_pdtobj; 

    // For context menu handlers, the registry key provides access to verb 
    // instance data that might be stored there. This is a rare feature to use 
    // so most extensions do not need this variable. 
    HKEY m_hRegKey;    } 
     // This method must be very efficient. Do not do any unnecessary work here. 
    // Use Initialize to acquire resources that will be used later. 
    IFACEMETHODIMP CSampleShellExtension::Initialize(__in_opt PCIDLIST_ABSOLUTEpidlFolder,__in_opt IDataObject *pDataObject, __in_opt HKEY hRegKey) 
    { 
    // In some cases,handlers are initialized multiple times. Therefore, 
    // clear any previous state here. 
    CoTaskMemFree(m_pidlFolder); 
    m_pidlFolder = NULL; 

    if (m_pdtobj) 
    { 
     m_pdtobj->Release(); 
    } 

    if (m_hRegKey) 
    { 
     RegCloseKey(m_hRegKey); 
     m_hRegKey = NULL; 
    } 

    // Capture the inputs for use later. 
    HRESULT hr = S_OK; 

    if (pidlFolder) 
    { 
     m_pidlFolder = ILClone(pidlFolder); // Make a copy to use later. 
     hr = m_pidlFolder ? S_OK : E_OUTOFMEMORY; 
    } 

    if (SUCCEEDED(hr)) 
    { 
     // If a data object pointer was passed into the method, save it and 
     // extract the file name. 
     if (pDataObject) 
     { 
      m_pdtobj = pDataObject; 
      m_pdtobj->AddRef(); 
     } 

     // It is uncommon to use the registry handle, but if you need it, 
     // duplicate it now. 
     if (hRegKey) 
     { 
      LSTATUS const result = RegOpenKeyEx(hRegKey, NULL, 0, KEY_READ, &m_hRegKey); 
      hr = HRESULT_FROM_WIN32(result); 
     } 
    } 

    return hr; } 

シェル拡張ハンドラを作成または変更するときは、変更を加えたことをシステムに通知することが重要です。 SHCNE_ASSOCCHANGEDイベントを指定してSHChangeNotifyを呼び出すことにより、そのようにします。 SHChangeNotifyを呼び出さないと、システムが再起動されるまで変更が認識されないことがあります。 Windows 2000システムに適用されるいくつかの追加要因があります。詳細については、「Windows 2000システムでのシェル拡張ハンドラの登録」セクションを参照してください。 すべてのコンポーネントオブジェクトモデル(COM)オブジェクトと同様に、Windowsソフトウェア開発キット(SDK)と共に提供されるGuidgen.exeなどのツールを使用して、ハンドラのGUIDを作成する必要があります。そのGUIDの文字列形式の名前を持つHKEY_CLASSES_ROOT \ CLSIDの下にサブキーを作成します。シェル拡張ハンドラはインプロセスサーバーであるため、(デフォルト)値をハンドラのDLLのパスに設定して、そのGUIDサブキーの下にInprocServer32サブキーも作成する必要があります。アパートスレッドモデルを使用します。例を次に示します

HKEY_CLASSES_ROOT CLSID 
     {00021500-0000-0000-C000-000000000046} 
      InprocServer32 
      (Default) = %windir%\System32\Example.dll 
      ThreadingModel = Apartment 

シェルは、シェル拡張ハンドラを含むことができる措置をとるときはいつでも、それが適切なレジストリサブキーをチェックします。拡張ハンドラが登録されているサブキーは、呼び出されるタイミングを制御します。たとえば、シェルがファイルタイプのメンバのショートカットメニューを表示するときに呼び出されるショートカットメニューハンドラを持つのが一般的な方法です。この場合、ハンドラはファイルタイプのProgIDサブキーの下に登録する必要があります。

+1

これは私が[もっと基本的な質問](http://stackoverflow.com/questions/8438066)でそのような概要を望んでいた本当に素晴らしい答えです。私はあなたが恩恵を得ると思う。しかし、カテゴリはどこで変更できますか?スクリーンショットの赤いボックス。 – rekire

+1

素晴らしい分析....本当に役立ちます。 –

関連する問題