このアーカイブは同期化されません。 mixi の日記が更新されても、このアーカイブには反映されません。
アイコンは 3 種類用意しているが、
まだ 1 つしかクラスを作っていなかった。
今日はマウントポイント用のクラスを作ることにする。
クラス名は「MountPointIconID」とする。
基本的な部分は HardLinkIconID と変わらないので、
HardLinkIconID をコピーして作ると速い。
まずは、クラスの定義を作成する。
========== MountPointIconID.hpp ==========
#ifndef mountpointiconid_hpp_included
#define mountpointiconid_hpp_included
#include <shlobj.h>
#include "Object.hpp"
class MountPointIconID : public Object, public IShellIconOverlayIdentifier {
// インタフェース
public:
// IUnknown の実装
virtual HRESULT STDMETHODCALLTYPE QueryInterface(
/* [in] */ REFIID riid,
/* [out] */ void** ppvObject);
virtual ULONG STDMETHODCALLTYPE AddRef();
virtual ULONG STDMETHODCALLTYPE Release();
// IShellIconOverlayIdentifier
virtual HRESULT STDMETHODCALLTYPE IsMemberOf(
/* [in] */ LPCWSTR pwszPath,
/* [in] */ DWORD dwAttrib);
virtual HRESULT STDMETHODCALLTYPE GetOverlayInfo(
/* [out] */ LPWSTR pwszIconFile,
/* [in] */ int cchMax,
/* [out] */ int* pIndex,
/* [out] */ DWORD* pdwFlags);
virtual HRESULT STDMETHODCALLTYPE GetPriority(
/* [out] */ int* pPriority);
};
#endif // !mountpointiconid_hpp_included
========== end of MountPointIconID.hpp ==========
多重継承のところで書いたように、
IUnknown のメソッドは全てオーバライドが必要だ。
では、実体の定義をしよう。
========== MountPointIconID.cpp ==========
// ビルド環境用のヘッダ
#include "global.hpp"
// クラスを定義したヘッダ
#include "MountPointIconID.hpp"
// リソース ID のヘッダ
#include "resource.h"
// MountPointIconID の実装
// IUnknown
HRESULT MountPointIconID::QueryInterface(
/* [in] */ REFIID riid,
/* [out] */ void** ppvObject) {
// ppvObject が NULL なら例外
if (ppvObject == NULL) return E_POINTER;
// ppvObject は out なので、
// ポインタが指す元の値は無視できる
*ppvObject = NULL;
if (IsEqualIID(riid, IID_IShellIconOverlayIdentifier)) {
*ppvObject = static_cast<IShellIconOverlayIdentifier*>(this);
} else if (IsEqualIID(riid, IID_IUnknown)) {
*ppvObject = static_cast<IShellIconOverlayIdentifier*>(this);
} else {
return E_NOINTERFACE;
}
// ポインタを作成した場合カウンタを増加
static_cast<IUnknown*>(*ppvObject)->AddRef();
return S_OK;
}
ULONG STDMETHODCALLTYPE MountPointIconID::AddRef() {
return Object::AddRef();
}
ULONG STDMETHODCALLTYPE MountPointIconID::Release() {
return Object::Release();
}
========== (MountPointIconID.cpp) ==========
対応インタフェースは HardLinkIconID と変わらないので、
IUnknown の実装も全く同じとなる。
========== (MountPointIconID.cpp) ==========
// IShellIconOverlayIdentifier
HRESULT STDMETHODCALLTYPE MountPointIconID::GetOverlayInfo(
/* [out] */ LPWSTR pwszIconFile,
/* [in] */ int cchMax,
/* [out] */ int* pIndex,
/* [out] */ DWORD* pdwFlags) {
// 引数のチェック
if (pwszIconFile == NULL || pIndex == NULL || pdwFlags == NULL) {
return E_POINTER;
}
if (IsBadWritePtr(pwszIconFile, sizeof (WCHAR) * cchMax)) {
return E_INVALIDARG;
}
if (IsBadWritePtr(pIndex, sizeof (int))) return E_INVALIDARG;
if (IsBadWritePtr(pdwFlags, sizeof (DWORD))) return E_INVALIDARG;
// 自分自身のファイル名とアイコンインデックスを返す
if (!GetModuleFileName(g_moduleHandle, pwszIconFile, cchMax)) {
return HRESULT_FROM_WIN32(GetLastError());
}
*pIndex = -IDI_MOUNTPOINT;
*pdwFlags = ISIOI_ICONFILE | ISIOI_ICONINDEX;
return S_OK;
}
HRESULT STDMETHODCALLTYPE MountPointIconID::GetPriority(
/* [out] */ int* pPriority) {
// 引数のチェック
if (pPriority == NULL) return E_POINTER;
if (IsBadWritePtr(pPriority, sizeof (int))) return E_INVALIDARG;
// 優先順位は最高(デフォルトに任せる)
*pPriority = 0;
return S_OK;
}
HRESULT STDMETHODCALLTYPE MountPointIconID::IsMemberOf(
/* [in] */ LPCWSTR pwszPath,
/* [in] */ DWORD dwAttrib) {
// 引数のチェック
if (pwszPath == NULL) return E_FAIL;
if (IsBadStringPtrW(pwszPath, MAX_PATH)) return E_FAIL;
// ファイル情報を得る
WIN32_FIND_DATA stat;
HANDLE handle = FindFirstFile(pwszPath, &stat);
if (handle == INVALID_HANDLE_VALUE) return E_FAIL;
FindClose(handle);
// リパースポイントかどうか
if (!(stat.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT))
return S_FALSE;
// dwReserved0 にはリパースタグが入っているので調べる
if (stat.dwReserved0 != IO_REPARSE_TAG_MOUNT_POINT)
return S_FALSE;
return S_OK;
}
========== end of MountPointIconID.cpp ==========
GetOverlayInfo と GetPriority もほとんど変わらないが、
IsMemberOf はマウントポイント固有の実装となる。
マウントポイントはリパースポイントの一部なので、
ファイル属性に FILE_ATTRIBUTE_REPARSE_POINT が含まれ、
ファイルに関連付けられているリパースデータバッファに
IO_REPARSE_TAG_MOUNT_POINT リパースタグが含まれる。
これを調べるためには、GetFileAttribute で属性を調べ、
CreateFile でファイルを開き、DeviceIOControl で
リパースデータバッファを取得するのが手順だが、
ファイル属性とリパースタグを調べるだけなら、
FindFirstFile API を使うと手っ取り早い。
FindFirstFile が返す WIN32_FIND_DATA 構造体には、
ファイル属性とリパースタグの両方が含まれている。
属性は dwFileAttributes に、
リパースタグは dwReserved0 に格納されているため、
これを使うと IsMemberOf を簡単に実装する事ができる。