EternalWindows
シェル拡張 / サムネイルイメージ ハンドラ
サンプルはこちら

サムネイルイメージ ハンドラは、特定の拡張子を持ったファイルにサムネイルイメージを表示するために使用されます。 次に示す図は、エクスプローラーからsample.bhyを選択した際のものですが、 左下にサムネイルイメージが表示されていることが分かります。

サムネイルイメージ ハンドラのオブジェクトは、IThumbnailProviderとIInitializeWithStreamを実装する必要があります。 IThumbnailProviderはビットマップをシェルに返すために使用し、 IInitializeWithStreamはファイルのデータを取得するために使用します。

class CThumbnailProvider : public IThumbnailProvider, public IInitializeWithStream
{
public:
	STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject);
	STDMETHODIMP_(ULONG) AddRef();
	STDMETHODIMP_(ULONG) Release();
	
	STDMETHODIMP GetThumbnail(UINT cx, HBITMAP *phbmp, WTS_ALPHATYPE *pdwAlpha);
	
	STDMETHODIMP Initialize(IStream *pstream, DWORD grfMode);

	CThumbnailProvider();
	~CThumbnailProvider();

private:
	LONG m_cRef;
};

GetThumbnailがIThumbnailProviderのメソッドであり、 InitializeがIInitializeWithStreamのメソッドになります。 IInitializeWithStreamの代わりに、IInitializeWithFileやIInitializeWithItemを実装することもできそうですが、 これらのIIDはQueryInterfaceに送られてきません。

Initializeは、サムネイルイメージを表示する段階になると呼ばれます。 このメソッドでS_OKを返すとGetThumbnailが呼ばれることになります。

STDMETHODIMP CThumbnailProvider::Initialize(IStream *pstream, DWORD grfMode)
{
	return S_OK;
}

今回は単純にS_OKを返しているだけですが、実際の開発ではファイル内のデータを読み取ることになると思われます。 そしてGetThumbnailでは、そのデータを基にビットイメージを初期化することになるでしょう。 次に、データを読み取る例を示します。

STDMETHODIMP CThumbnailProvider::Initialize(IStream *pstream, DWORD grfMode)
{
	BYTE  data[1024];
	ULONG uSize = sizeof(data);

	pstream->Read(data, 10, &uSize);

	return S_OK;
}

IStream::Readを呼び出せば、第1引数のバッファに読み取ったデータが返ります。 第2引数は読み取りたいサイズを指定し、第3引数はバッファのサイズを格納した変数のアドレスを指定します。

GetThumbnailは、サムネイルイメージを格納したビットマップのハンドルとビットマップのタイプを返します。

STDMETHODIMP CThumbnailProvider::GetThumbnail(UINT cx, HBITMAP *phbmp, WTS_ALPHATYPE *pdwAlpha)
{
	UINT             i;
	LPBYTE           lp;
	LPVOID           lpBits;
	BITMAPINFO       bmi;
	BITMAPINFOHEADER bmiHeader;

	ZeroMemory(&bmiHeader, sizeof(BITMAPINFOHEADER));
	bmiHeader.biSize      = sizeof(BITMAPINFOHEADER);
	bmiHeader.biWidth     = cx;
	bmiHeader.biHeight    = cx;
	bmiHeader.biPlanes    = 1;
	bmiHeader.biBitCount  = 32;

	bmi.bmiHeader = bmiHeader;

	*phbmp  = CreateDIBSection(NULL, (LPBITMAPINFO)&bmi, DIB_RGB_COLORS, &lpBits, NULL, 0);

	lp = (LPBYTE)lpBits;
	for (i = 0; i < cx * cx; i++) {
		lp[0] = 0;
		lp[1] = 0;
		lp[2] = 255;
		lp[3] = 128;
		lp += 4;
	}

	*pdwAlpha = WTSAT_ARGB;

	return S_OK;
}

返すべきビットマップのフォーマットは、幅と高さがcx以下であり、 ビット数が32ビットでなければならないとされています。 よって、BITMAPINFOHEADER構造体をそのように初期化しています。 また、ビットマップはDIBセクションでなければならないため、 CreateDIBSectionの戻り値をphbmpに格納しています。 ループ文におけるlp[0]からlp[3]は1ピクセルの色の成分を表しており、 lp[0]が青、lp[1]が緑、lp[2]が赤、lp[3]がアルファ値になります。 上記ではlp[0]とlp[1]が0で、lp[2]が最高値になっているため、 ビットイメージの各ピクセルの色は赤になるように思えます。 しかし、pdwAlphaにWTSAT_ARGBを指定した場合はアルファ値が考慮されるようになるため、 lp[3]が128になっていることから、ビットマップは半透明で表示されることになります。 アルファ値を考慮したくない場合は、lp[3]に不透明を示す255を指定するか、 pdwAlphaにWTSAT_RGBを指定します。

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

HKEY_CLASSES_ROOT
  <特定の拡張子>
    shellex
      {E357FCCD-A995-4576-B01F-234630154E96} (既定) = オブジェクトのCLSID

サムネイルイメージ ハンドラのDLLは、サムネイルイメージを表示する段階でシェルにロードされ、 表示が不要になった場合にアンロードされます。 この表示される段階というのがはっきりと分からないのですが、 対象のファイルを何らかのフォルダに貼り付けた場合はロードされるように思えます。


戻る