EternalWindows
シェル拡張 / 仮想フォルダサンプル
コードの説明はこちら

仮想フォルダのサンプルコードを確認します。 ファイルとしてダウンロードする場合は、こちらをクリックしてください。 まず、sample.defを示します。

LIBRARY	"ShellFolder"

EXPORTS
	DllCanUnloadNow PRIVATE
	DllGetClassObject PRIVATE
	DllRegisterServer PRIVATE
	DllUnregisterServer PRIVATE

次に、sample.hを示します。

class CShellFolder : public IShellFolder2, public IPersistFolder2
{
public:
	STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject);
	STDMETHODIMP_(ULONG) AddRef();
	STDMETHODIMP_(ULONG) Release();

	STDMETHODIMP ParseDisplayName(HWND hwnd, IBindCtx *pbc, LPWSTR pszDisplayName, ULONG *pchEaten, PIDLIST_RELATIVE *ppidl, ULONG *pdwAttributes);
	STDMETHODIMP EnumObjects(HWND hwndOwner, SHCONTF grfFlags, IEnumIDList **ppenumIDList);
	STDMETHODIMP BindToObject(PCUIDLIST_RELATIVE pidl, IBindCtx *pbc, REFIID riid, void **ppvOut);
	STDMETHODIMP BindToStorage(PCUIDLIST_RELATIVE pidl, IBindCtx *pbc, REFIID riid, void **ppvOut);
	STDMETHODIMP CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2);
	STDMETHODIMP CreateViewObject(HWND hwndOwner, REFIID riid, void **ppv);
	STDMETHODIMP GetAttributesOf(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, SFGAOF *rgfInOut);
	STDMETHODIMP GetUIObjectOf(HWND hwndOwner, UINT cidl, PCUITEMID_CHILD_ARRAY apidl, REFIID riid, UINT *rgfReserved, void **ppv);
	STDMETHODIMP GetDisplayNameOf(PCUITEMID_CHILD pidl, SHGDNF uFlags, STRRET *pName);
	STDMETHODIMP SetNameOf(HWND hwndOwner, PCUITEMID_CHILD pidl, LPCWSTR pszName, SHGDNF uFlags, PITEMID_CHILD *ppidlOut);

	STDMETHODIMP GetDefaultSearchGUID(GUID *pguid);
	STDMETHODIMP EnumSearches(IEnumExtraSearch **ppEnum);
	STDMETHODIMP GetDefaultColumn(DWORD dwReserved, ULONG *pSort, ULONG *pDisplay);
	STDMETHODIMP GetDefaultColumnState(UINT iColumn, SHCOLSTATEF *pcsFlags);
	STDMETHODIMP GetDetailsEx(PCUITEMID_CHILD pidl, const SHCOLUMNID *pscid, VARIANT *pv);
	STDMETHODIMP GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, SHELLDETAILS *psd);
	STDMETHODIMP MapColumnToSCID(UINT iColumn, SHCOLUMNID *pscid);

	STDMETHODIMP GetClassID(CLSID *pClassID);
	STDMETHODIMP Initialize(LPCITEMIDLIST pidl);
	STDMETHODIMP GetCurFolder(LPITEMIDLIST *ppidl);

	CShellFolder();
	~CShellFolder();
	void SetLevel(BYTE level);

private:
	LONG              m_cRef;
	BYTE              m_level;
	PIDLIST_ABSOLUTE  m_pidl;
};

class CEnumIDList : public IEnumIDList
{
public:
	STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject);
	STDMETHODIMP_(ULONG) AddRef();
	STDMETHODIMP_(ULONG) Release();
	
	STDMETHODIMP Next(ULONG celt, LPITEMIDLIST *rgelt, ULONG *pceltFetched);
	STDMETHODIMP Skip(ULONG celt);
	STDMETHODIMP Reset(VOID);
	STDMETHODIMP Clone(IEnumIDList **ppenum);

	CEnumIDList(BYTE level, SHCONTF flags);
	~CEnumIDList();
	
private:
	LONG    m_cRef;
	BYTE    m_level;
	SHCONTF m_flags;
	ULONG   m_uCount;
};

class CUIObject : public IContextMenu, public IExtractIcon, public IObjectWithSite
{
public:
	STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject);
	STDMETHODIMP_(ULONG) AddRef();
	STDMETHODIMP_(ULONG) Release();

	STDMETHODIMP QueryContextMenu(HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags);
	STDMETHODIMP InvokeCommand(LPCMINVOKECOMMANDINFO pici);
	STDMETHODIMP GetCommandString(UINT_PTR idCmd, UINT uFlags, UINT *pwReserved, LPSTR pszName, UINT cchMax);
	
	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 SetSite(IUnknown *pUnkSite);
	STDMETHODIMP GetSite(REFIID riid, void **ppvSite);

	CUIObject(PITEMID_CHILD pidl);
	~CUIObject();

private:
	LONG          m_cRef;
	PITEMID_CHILD m_pidl;
	IUnknown      *m_pUnkSite;
};

class CClassFactory : public IClassFactory
{
public:
	STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject);
	STDMETHODIMP_(ULONG) AddRef();
	STDMETHODIMP_(ULONG) Release();
	
	STDMETHODIMP CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppvObject);
	STDMETHODIMP LockServer(BOOL fLock);
};

struct ITEMDATA {
	USHORT ub;
	BYTE   level;
	BYTE   iconIndex;
	SFGAOF attribute;
	WCHAR  szName[10];
};
typedef struct ITEMDATA ITEMDATA;
typedef struct ITEMDATA *LPITEMDATA;

次に、sample.cppを示します。

#include <windows.h>
#include <shlwapi.h>
#include <shlobj.h>
#include "sample.h"

#pragma comment (lib, "shlwapi.lib")

const CLSID CLSID_ShellFolderSample = {0x112143a6, 0x62c1, 0x4478, {0x9e, 0x8f, 0x87, 0x26, 0x99, 0x25, 0x5e, 0x2e}};
const TCHAR g_szClsid[] = TEXT("{112143A6-62C1-4478-9E8F-872699255E2E}");
const TCHAR g_szFolderName[] = TEXT("MyFolder");

LONG      g_lLocks = 0;
HINSTANCE g_hinstDll = NULL;

void LockModule(BOOL bLock);
BOOL CreateRegistryKey(HKEY hKeyRoot, LPTSTR lpszKey, LPTSTR lpszValue, LPTSTR lpszData);
BOOL CreateRegistryKeyDword(HKEY hKeyRoot, LPTSTR lpszKey, LPTSTR lpszValue, LPDWORD lpdw);


// CShellFolder


CShellFolder::CShellFolder()
{
	m_cRef = 1;
	m_pidl = NULL;
	m_level = 0;
	
	LockModule(TRUE);
}

CShellFolder::~CShellFolder()
{
	if (m_pidl != NULL)
		CoTaskMemFree(m_pidl);
	
	LockModule(FALSE);
}

STDMETHODIMP CShellFolder::QueryInterface(REFIID riid, void **ppvObject)
{
	*ppvObject = NULL;
	
	if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IShellFolder) || IsEqualIID(riid, IID_IShellFolder2))
		*ppvObject = static_cast<IShellFolder2 *>(this);
	else if (IsEqualIID(riid, IID_IPersist) || IsEqualIID(riid, IID_IPersistFolder) || IsEqualIID(riid, IID_IPersistFolder2))
		*ppvObject = static_cast<IPersistFolder2 *>(this);
	else
		return E_NOINTERFACE;

	AddRef();

	return S_OK;
}

STDMETHODIMP_(ULONG) CShellFolder::AddRef()
{
	return InterlockedIncrement(&m_cRef);
}

STDMETHODIMP_(ULONG) CShellFolder::Release()
{
	if (InterlockedDecrement(&m_cRef) == 0) {
		delete this;
		return 0;
	}

	return m_cRef;
}

STDMETHODIMP CShellFolder::ParseDisplayName(HWND hwnd, IBindCtx *pbc, LPWSTR pszDisplayName, ULONG *pchEaten, PIDLIST_RELATIVE *ppidl, ULONG *pdwAttributes)
{
	return E_NOTIMPL;
}

STDMETHODIMP CShellFolder::EnumObjects(HWND hwndOwner, SHCONTF grfFlags, IEnumIDList **ppenumIDList)
{
	*ppenumIDList = new CEnumIDList(m_level, grfFlags);

	return S_OK;
}

STDMETHODIMP CShellFolder::BindToObject(PCUIDLIST_RELATIVE pidl, IBindCtx *pbc, REFIID riid, void **ppvOut)
{
	CShellFolder *p;
	HRESULT      hr;

	p = new CShellFolder();
	
	hr = p->QueryInterface(riid, ppvOut);
	if (SUCCEEDED(hr)) {
		PIDLIST_ABSOLUTE pidlNew = ILCombine(m_pidl, pidl);
		p->Initialize(pidlNew);
		p->SetLevel(m_level + 1);
	}

	p->Release();

	return hr;
}

STDMETHODIMP CShellFolder::BindToStorage(PCUIDLIST_RELATIVE pidl, IBindCtx *pbc, REFIID riid, void **ppvOut)
{
	return BindToObject(pidl, pbc, riid, ppvOut);
}

STDMETHODIMP CShellFolder::CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2)
{
	LPITEMDATA lpData1 = (LPITEMDATA)pidl1;
	LPITEMDATA lpData2 = (LPITEMDATA)pidl2;
	USHORT     nCode;

	nCode = StrCmpW(lpData1->szName, lpData2->szName);

	return MAKE_HRESULT(0, 0, nCode);
}

STDMETHODIMP CShellFolder::CreateViewObject(HWND hwndOwner, REFIID riid, void **ppv)
{
	HRESULT hr = E_NOINTERFACE;
	
	if (IsEqualIID(riid, IID_IShellView)) {
		SFV_CREATE sfvCreate;

		sfvCreate.cbSize   = sizeof(SFV_CREATE);
		sfvCreate.pshf     = static_cast<IShellFolder *>(this);
		sfvCreate.psvOuter = NULL;
		sfvCreate.psfvcb   = NULL;
		
		hr = SHCreateShellFolderView(&sfvCreate, (IShellView **)ppv);
	}

	return hr;
}

STDMETHODIMP CShellFolder::GetAttributesOf(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, SFGAOF *rgfInOut)
{
	LPITEMDATA lpData = (LPITEMDATA)apidl[0];
	
	*rgfInOut &= lpData->attribute;

	return S_OK;
}

STDMETHODIMP CShellFolder::GetUIObjectOf(HWND hwndOwner, UINT cidl, PCUITEMID_CHILD_ARRAY apidl, REFIID riid, UINT *rgfReserved, void **ppv)
{
	HRESULT hr E_NOINTERFACE;

	if (IsEqualIID(riid, IID_IContextMenu)) {
		CUIObject *p;

		p = new CUIObject((LPITEMIDLIST)apidl[0]);
		hr = p->QueryInterface(riid, ppv);
		p->Release();
	}
	else if (IsEqualIID(riid, IID_IExtractIcon)) {
		CUIObject *p;

		p = new CUIObject((LPITEMIDLIST)apidl[0]);
		hr = p->QueryInterface(riid, ppv);
		p->Release();
	}
	else
		;

	return hr;
}

STDMETHODIMP CShellFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl, SHGDNF uFlags, STRRET *pName)
{
	LPITEMDATA lpData = (LPITEMDATA)pidl;

	pName->uType = STRRET_WSTR;
	SHStrDupW(lpData->szName, &pName->pOleStr);

	return S_OK;
}

STDMETHODIMP CShellFolder::SetNameOf(HWND hwndOwner, PCUITEMID_CHILD pidl, LPCWSTR pszName, SHGDNF uFlags, PITEMID_CHILD *ppidlOut)
{
	return E_NOTIMPL;
}

STDMETHODIMP CShellFolder::GetDefaultSearchGUID(GUID *pguid)
{
	return E_NOTIMPL;
}

STDMETHODIMP CShellFolder::EnumSearches(IEnumExtraSearch **ppEnum)
{
	return E_NOINTERFACE;
}

STDMETHODIMP CShellFolder::GetDefaultColumn(DWORD dwReserved, ULONG *pSort, ULONG *pDisplay)
{
	*pSort = 0;
	*pDisplay = 0;

	return S_OK;
}

STDMETHODIMP CShellFolder::GetDefaultColumnState(UINT iColumn, SHCOLSTATEF *pcsFlags)
{
	if (iColumn == 0) {
		*pcsFlags = SHCOLSTATE_ONBYDEFAULT | SHCOLSTATE_TYPE_STR;
		return S_OK;
	}

	return E_INVALIDARG;
}

STDMETHODIMP CShellFolder::GetDetailsEx(PCUITEMID_CHILD pidl, const SHCOLUMNID *pscid, VARIANT *pv)
{
	return E_NOTIMPL;
}

STDMETHODIMP CShellFolder::GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, SHELLDETAILS *psd)
{
	WCHAR   szBuf[256];
	HRESULT hr = E_FAIL;

	if (pidl == NULL) {
		if (iColumn == 0) {
			psd->fmt = LVCFMT_LEFT;
			StrCpyW(szBuf, L"名前");
			hr = S_OK;
		}
	}
	else {
		if (iColumn == 0) {
			psd->fmt = LVCFMT_LEFT;
			StrCpyW(szBuf, ((LPITEMDATA)pidl)->szName);
			hr = S_OK;
		}
	}

	if (hr == S_OK) {
		psd->str.uType = STRRET_WSTR;
		hr = SHStrDupW(szBuf, &psd->str.pOleStr);
	}

	return hr;
}

STDMETHODIMP CShellFolder::MapColumnToSCID(UINT iColumn, SHCOLUMNID *pscid)
{
	return E_NOTIMPL;
}

STDMETHODIMP CShellFolder::GetClassID(CLSID *pClassID)
{
	*pClassID = CLSID_ShellFolderSample;

	return S_OK;
}

STDMETHODIMP CShellFolder::Initialize(LPCITEMIDLIST pidl)
{
	if (pidl == NULL)
		return E_FAIL;

	m_pidl = ILClone(pidl);

	return S_OK;
}

STDMETHODIMP CShellFolder::GetCurFolder(LPITEMIDLIST *ppidl)
{
	if (m_pidl == NULL || ppidl == NULL)
		return E_FAIL;

	*ppidl = ILClone(m_pidl);

	return S_OK;
}

void CShellFolder::SetLevel(BYTE level)
{
	m_level = level;
}


// CClassFactory


STDMETHODIMP CClassFactory::QueryInterface(REFIID riid, void **ppvObject)
{
	*ppvObject = NULL;
	
	if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IClassFactory))
		*ppvObject = static_cast<IClassFactory *>(this);
	else
		return E_NOINTERFACE;

	AddRef();
	
	return S_OK;
}

STDMETHODIMP_(ULONG) CClassFactory::AddRef()
{
	LockModule(TRUE);

	return 2;
}

STDMETHODIMP_(ULONG) CClassFactory::Release()
{
	LockModule(FALSE);

	return 1;
}

STDMETHODIMP CClassFactory::CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppvObject)
{
	CShellFolder *p;
	HRESULT      hr;

	*ppvObject = NULL;

	if (pUnkOuter != NULL)
		return CLASS_E_NOAGGREGATION;

	p = new CShellFolder();
	if (p == NULL)
		return E_OUTOFMEMORY;

	hr = p->QueryInterface(riid, ppvObject);
	p->Release();

	return hr;
}

STDMETHODIMP CClassFactory::LockServer(BOOL fLock)
{
	LockModule(fLock);

	return S_OK;
}


// DLL Export


STDAPI DllCanUnloadNow()
{
	return g_lLocks == 0 ? S_OK : S_FALSE;
}

STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
{
	static CClassFactory serverFactory;
	HRESULT hr;

	*ppv = NULL;
	
	if (IsEqualCLSID(rclsid, CLSID_ShellFolderSample))
		hr = serverFactory.QueryInterface(riid, ppv);
	else
		hr = CLASS_E_CLASSNOTAVAILABLE;

	return hr;
}

STDAPI DllRegisterServer(void)
{
	TCHAR szModulePath[MAX_PATH];
	TCHAR szKey[256];
	DWORD dwData = SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_CANDELETE;

	wsprintf(szKey, TEXT("CLSID\\%s"), g_szClsid);
	if (!CreateRegistryKey(HKEY_CLASSES_ROOT, szKey, NULL, (LPTSTR)g_szFolderName))
		return E_FAIL;

	GetModuleFileName(g_hinstDll, szModulePath, sizeof(szModulePath) / sizeof(TCHAR));
	wsprintf(szKey, TEXT("CLSID\\%s\\InprocServer32"), g_szClsid);
	if (!CreateRegistryKey(HKEY_CLASSES_ROOT, szKey, NULL, szModulePath))
		return E_FAIL;

	wsprintf(szKey, TEXT("CLSID\\%s\\InprocServer32"), g_szClsid);
	if (!CreateRegistryKey(HKEY_CLASSES_ROOT, szKey, TEXT("ThreadingModel"), TEXT("Apartment")))
		return E_FAIL;

	wsprintf(szKey, TEXT("CLSID\\%s\\DefaultIcon"), g_szClsid);
	if (!CreateRegistryKey(HKEY_CLASSES_ROOT, szKey, NULL, szModulePath))
		return E_FAIL;
	
	wsprintf(szKey, TEXT("CLSID\\%s\\ShellFolder"), g_szClsid);
	if (!CreateRegistryKeyDword(HKEY_CLASSES_ROOT, szKey, TEXT("Attributes"), &dwData))
		return E_FAIL;

	wsprintf(szKey, TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Desktop\\NameSpace\\%s"), g_szClsid);
	if (!CreateRegistryKey(HKEY_LOCAL_MACHINE, szKey, NULL, TEXT("ShellFolder Sample")))
		return E_FAIL;

	return S_OK;
}

STDAPI DllUnregisterServer(void)
{
	TCHAR szKey[256];

	wsprintf(szKey, TEXT("CLSID\\%s"), g_szClsid);
	SHDeleteKey(HKEY_CLASSES_ROOT, szKey);

	wsprintf(szKey, TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Desktop\\NameSpace\\%s"), g_szClsid);
	SHDeleteKey(HKEY_LOCAL_MACHINE, szKey);

	return S_OK;
}

BOOL WINAPI DllMain(HINSTANCE hinstDll, DWORD dwReason, LPVOID lpReserved)
{
	switch (dwReason) {

	case DLL_PROCESS_ATTACH:
		g_hinstDll = hinstDll;
		DisableThreadLibraryCalls(hinstDll);
		return TRUE;

	}

	return TRUE;
}


// Function


void LockModule(BOOL bLock)
{
	if (bLock)
		InterlockedIncrement(&g_lLocks);
	else
		InterlockedDecrement(&g_lLocks);
}

BOOL CreateRegistryKey(HKEY hKeyRoot, LPTSTR lpszKey, LPTSTR lpszValue, LPTSTR lpszData)
{
	HKEY  hKey;
	LONG  lResult;
	DWORD dwSize;

	lResult = RegCreateKeyEx(hKeyRoot, lpszKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, NULL);
	if (lResult != ERROR_SUCCESS)
		return FALSE;

	if (lpszData != NULL)
		dwSize = (lstrlen(lpszData) + 1) * sizeof(TCHAR);
	else
		dwSize = 0;

	RegSetValueEx(hKey, lpszValue, 0, REG_SZ, (LPBYTE)lpszData, dwSize);
	RegCloseKey(hKey);
	
	return TRUE;
}

BOOL CreateRegistryKeyDword(HKEY hKeyRoot, LPTSTR lpszKey, LPTSTR lpszValue, LPDWORD lpdw)
{
	HKEY hKey;
	LONG lResult;

	lResult = RegCreateKeyEx(hKeyRoot, lpszKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, NULL);
	if (lResult != ERROR_SUCCESS)
		return FALSE;

	RegSetValueEx(hKey, lpszValue, 0, REG_DWORD, (LPBYTE)lpdw, sizeof(DWORD));
	RegCloseKey(hKey);
	
	return TRUE;
}

次に、enumid.cppを示します。

#include <windows.h>
#include <shlobj.h>
#include "sample.h"

const ITEMDATA g_itemData[] = {
	{sizeof(ITEMDATA), 0, 0, 0, L"アイテムA"},
	{sizeof(ITEMDATA), 0, 1, SFGAO_FOLDER, L"アイテムB"},
	{sizeof(ITEMDATA), 1, 2, 0, L"アイテムC"}
};
const int g_nItemCount = sizeof(g_itemData) / sizeof(g_itemData[0]);

CEnumIDList::CEnumIDList(BYTE level, SHCONTF flags)
{
	m_cRef = 1;
	m_level = level;
	m_flags = flags;
	m_uCount = 0;
}

CEnumIDList::~CEnumIDList()
{
}

STDMETHODIMP CEnumIDList::QueryInterface(REFIID riid, void **ppvObject)
{
	*ppvObject = NULL;

	if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IEnumIDList))
		*ppvObject = static_cast<IEnumIDList *>(this);
	else
		return E_NOINTERFACE;

	AddRef();

	return S_OK;
}

STDMETHODIMP_(ULONG) CEnumIDList::AddRef()
{
	return InterlockedIncrement(&m_cRef);
}

STDMETHODIMP_(ULONG) CEnumIDList::Release()
{
	if (InterlockedDecrement(&m_cRef) == 0) {	
		delete this;
		return 0;
	}

	return m_cRef;
}

STDMETHODIMP CEnumIDList::Next(ULONG celt, LPITEMIDLIST *rgelt, ULONG *pceltFetched)
{
	USHORT        uSize = sizeof(ITEMDATA);
	PITEMID_CHILD pidl;
	
	if (m_uCount >= g_nItemCount)
		return E_FAIL;

	for (; m_uCount < g_nItemCount; m_uCount++) {
		if (g_itemData[m_uCount].level != m_level)
			continue;
		
		if (g_itemData[m_uCount].attribute & SFGAO_FOLDER) {
			if (!(m_flags & SHCONTF_FOLDERS))
				continue;
		}
		else {
			if (!(m_flags & SHCONTF_NONFOLDERS))
				continue;
		}

		pidl = (PITEMID_CHILD)CoTaskMemAlloc(uSize + sizeof(USHORT));
		ZeroMemory(pidl, uSize + sizeof(USHORT));
		CopyMemory(pidl, &g_itemData[m_uCount], uSize);
		
		*rgelt = pidl;
		if (pceltFetched != NULL)
			*pceltFetched = 1;
		m_uCount++;

		return S_OK;
	}

	return E_FAIL;
}

STDMETHODIMP CEnumIDList::Skip(ULONG celt)
{
	m_uCount += celt;

	return S_OK;
}

STDMETHODIMP CEnumIDList::Reset(VOID)
{
	m_uCount = 0;
	
	return S_OK;
}

STDMETHODIMP CEnumIDList::Clone(IEnumIDList **ppenum)
{
	*ppenum = new CEnumIDList(m_level, m_flags);
	(*ppenum)->Skip(m_uCount);

	return S_OK;
}

次に、uiobject.cppを示します。

#include <windows.h>
#include <shlobj.h>
#include "sample.h"

CUIObject::CUIObject(PITEMID_CHILD pidl)
{
	m_cRef = 1;
	m_pidl = pidl;
	m_pUnkSite = NULL;
}

CUIObject::~CUIObject()
{
}

STDMETHODIMP CUIObject::QueryInterface(REFIID riid, void **ppvObject)
{
	*ppvObject = NULL;

	if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IContextMenu))
		*ppvObject = static_cast<IContextMenu *>(this);
	else if (IsEqualIID(riid, IID_IExtractIcon))
		*ppvObject = static_cast<IExtractIcon *>(this);
	else if (IsEqualIID(riid, IID_IObjectWithSite))
		*ppvObject = static_cast<IObjectWithSite *>(this);
	else
		return E_NOINTERFACE;

	AddRef();

	return S_OK;
}

STDMETHODIMP_(ULONG) CUIObject::AddRef()
{
	return InterlockedIncrement(&m_cRef);
}

STDMETHODIMP_(ULONG) CUIObject::Release()
{
	if (InterlockedDecrement(&m_cRef) == 0) {
		delete this;
		return 0;
	}

	return m_cRef;
}

STDMETHODIMP CUIObject::QueryContextMenu(HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags)
{
	MENUITEMINFO mii;
	
	mii.cbSize     = sizeof(MENUITEMINFO);
	mii.fMask      = MIIM_ID | MIIM_TYPE | MIIM_STATE;
	mii.fType      = MFT_STRING;
	mii.fState     = MFS_DEFAULT;
	mii.wID        = idCmdFirst;
	mii.dwTypeData = TEXT("開く");
	
	InsertMenuItem(hmenu, idCmdFirst, FALSE, &mii);

	return MAKE_SCODE(SEVERITY_SUCCESS, FACILITY_NULL, 1);
}

STDMETHODIMP CUIObject::InvokeCommand(LPCMINVOKECOMMANDINFO pici)
{
	UINT idCmd = LOWORD(pici->lpVerb);

	if (HIWORD(pici->lpVerb) != 0)
		return E_INVALIDARG;

	if (idCmd == 0) {
		LPITEMDATA lpData = (LPITEMDATA)m_pidl;
		
		if (lpData->attribute & SFGAO_FOLDER) {
			IServiceProvider *pServiceProvider;
			IShellBrowser    *pShellBrowser;
			HRESULT          hr;

			hr = m_pUnkSite->QueryInterface(IID_PPV_ARGS(&pServiceProvider));
			if (SUCCEEDED(hr)) {
				hr = pServiceProvider->QueryService(SID_STopLevelBrowser, IID_PPV_ARGS(&pShellBrowser));
				if (SUCCEEDED(hr)) {
					pShellBrowser->BrowseObject(m_pidl, SBSP_SAMEBROWSER | SBSP_RELATIVE);
					pShellBrowser->Release();
				}
				pServiceProvider->Release();
			}
		}
		else
			MessageBox(NULL, lpData->szName, TEXT("OK"), MB_OK);
	}
	else
		;

	return S_OK;
}

STDMETHODIMP CUIObject::GetCommandString(UINT_PTR idCmd, UINT uFlags, UINT *pwReserved, LPSTR pszName, UINT cchMax)
{
	return NOERROR;
}

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

	return S_OK;
}

STDMETHODIMP CUIObject::Extract(LPCTSTR pszFile, UINT nIconIndex, HICON *phiconLarge, HICON *phiconSmall, UINT nIconSize)
{
	LPTSTR     nId[] = {IDI_EXCLAMATION, IDI_QUESTION, IDI_ERROR};
	LPITEMDATA lpData = (LPITEMDATA)m_pidl;

	if (phiconLarge != NULL)
		*phiconLarge = (HICON)LoadImage(NULL, nId[lpData->iconIndex], IMAGE_ICON, 0, 0, LR_SHARED);
	
	if (phiconSmall != NULL)
		*phiconSmall = (HICON)LoadImage(NULL, nId[lpData->iconIndex], IMAGE_ICON, 0, 0, LR_SHARED);

	return S_OK;
}

STDMETHODIMP CUIObject::SetSite(IUnknown *pUnkSite)
{
	m_pUnkSite = pUnkSite;

	return S_OK;
}

STDMETHODIMP CUIObject::GetSite(REFIID riid, void **ppvSite)
{
	if (m_pUnkSite == NULL)
		return E_NOINTERFACE;

	return m_pUnkSite->QueryInterface(riid, ppvSite);
}

戻る