EternalWindows
シェル拡張 / アイコン ハンドラ
サンプルはこちら

アイコン ハンドラは、特定の拡張子のファイルにアイコンを表示するために使用します。 たとえば、次に示すファイルは.bhyという独自の拡張子になっていますが、 アイコン ハンドラを設定していればこのようなファイルにもアイコンが表示されるようになります。

アイコン ハンドラのオブジェクトは、IExtractIconとIPersistFileを実装する必要があります。 IExtractIconはアイコンのハンドルを取得するために使用し、 IPersistFileはアイコンの表示対象となるファイルを伝えるために使用します。

class CExtractIcon : public IExtractIcon, public IPersistFile
{
public:
	STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject);
	STDMETHODIMP_(ULONG) AddRef();
	STDMETHODIMP_(ULONG) Release();
	
	STDMETHODIMP GetIconLocation(UINT uFlags, LPTSTR szIconFile, UINT cchMax, int *piIndex, UINT *pwFlags);
	STDMETHODIMP Extract(LPCTSTR pszFile, UINT nIconIndex, HICON *phiconLarge, HICON *phiconSmall, UINT nIconSize);
	
	STDMETHODIMP GetClassID(CLSID *pClassID);
	STDMETHODIMP IsDirty();
	STDMETHODIMP Load(LPCOLESTR pszFileName, DWORD dwMode);
	STDMETHODIMP Save(LPCOLESTR pszFileName, BOOL fRemember);
	STDMETHODIMP SaveCompleted(LPCOLESTR pszFileName);
	STDMETHODIMP GetCurFile(LPOLESTR *ppszFileName);

	CExtractIcon();
	~CExtractIcon();

private:
	LONG m_cRef;
};

GetIconLocationとExtractがIExtractIconのメソッドであり、 GetClassIDからGetCurFileまでがIPersistFileのメソッドになります。 Windows Vista以降では、IPersistFileではなくIInitializeWithFileなどを実装するべきですが、 下位互換性の事を考えてIPersistFileを実装するようにしています。

IPersistFileの中で呼ばれるメソッドはLoadだけです。 このメソッドでS_OKを返すとGetIconLocationが呼ばれることになります。

STDMETHODIMP CExtractIcon::Load(LPCOLESTR pszFileName, DWORD dwMode)
{
	return S_OK;
}

第1引数にはアイコンの表示対象となるファイルのパスが格納されていますが、 特に参照することもないと思われます。 単純にS_OKを返すだけで問題ありません。

GetIconLocationでは、アイコンを格納しているファイルのパスとアイコンのインデックスを返すことになります。

STDMETHODIMP CExtractIcon::GetIconLocation(UINT uFlags, LPTSTR szIconFile, UINT cchMax, int *piIndex, UINT *pwFlags)
{
	*piIndex = GIL_NOTFILENAME;

	return S_OK;
}

GetIconLocationの目的はファイルパスやインデックスを返すことですが、 pwFlagsにGIL_NOTFILENAMEを指定した場合はこれを省略することができます。 今回のサンプルでは、ファイルからアイコンを取得しないことになっているため、 これでも特に問題はないことになります。 ただし、実際の開発では第2引数にアイコンを格納するファイルパスを格納し、 第4引数にアイコンのインデックスを格納することになるでしょう。 多くの場合、アイコンを格納するのはDLLであると思われるため、 GetModuleFileNameを呼び出すことが予想されます。

GetIconLocationでパスとインデックスを取得したシェルは、 Extractを呼び出してアイコンのハンドルを取得することになります。

STDMETHODIMP CExtractIcon::Extract(LPCTSTR pszFile, UINT nIconIndex, HICON *phiconLarge, HICON *phiconSmall, UINT nIconSize)
{
	if (phiconLarge != NULL)
		*phiconLarge = (HICON)LoadImage(NULL, IDI_QUESTION, IMAGE_ICON, 0, 0, LR_SHARED);
	if (phiconSmall != NULL)
		*phiconSmall = (HICON)LoadImage(NULL, IDI_QUESTION, IMAGE_ICON, 0, 0, LR_SHARED);

	return S_OK;
}

本来、Extractでは第1引数のファイルから第2引数のインデックスで識別されるアイコンを取得しますが、 今回はLoadImageで取得した既定のアイコンハンドルを返しています。

アイコン ハンドラを登録するには、次に示すレジストリキーを作成することになります。

HKEY_CLASSES_ROOT
 <特定の拡張子> (既定) = オブジェクトのProgID

HKEY_CLASSES_ROOT
  <オブジェクトのProgID>
    shellex
      IconHandler (既定) = オブジェクトのCLSID

アイコン ハンドラのDLLは、ファイルにアイコンを表示する段階でシェルにロードされ、 アイコンの表示が終了するとアンロードされます。 実際にアイコンが反映されるためには、シェルを再起動する必要があります。


戻る