EternalWindows
シェル名前空間 / ShellBrowserサンプル(切り替え)
コードの説明はこちら

今回は、フォルダビュー内で任意のフォルダに切り替えられるようにします。 サンプルのコード量が多いため、コード説明については右のリンクから参照してください。 まず、CShellBrowserの定義を含んだsample.hを示します。

class CShellBrowser : public IShellBrowser, public IServiceProvider, public IDispatch
{
public:
	STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject);
	STDMETHODIMP_(ULONG) AddRef();
	STDMETHODIMP_(ULONG) Release();
	
	STDMETHODIMP GetWindow(HWND *phwnd);
	STDMETHODIMP ContextSensitiveHelp(BOOL fEnterMode);
	STDMETHODIMP InsertMenusSB(HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths);
	STDMETHODIMP SetMenuSB(HMENU hmenuShared, HOLEMENU holemenuRes, HWND hwndActiveObject);
	STDMETHODIMP RemoveMenusSB(HMENU hmenuShared);
	STDMETHODIMP SetStatusTextSB(LPCWSTR lpszStatusText);
	STDMETHODIMP EnableModelessSB(BOOL fEnable);
	STDMETHODIMP TranslateAcceleratorSB(LPMSG lpmsg, WORD wID);
	STDMETHODIMP BrowseObject(PCUIDLIST_RELATIVE pidl, UINT wFlags);
	STDMETHODIMP GetViewStateStream(DWORD grfMode, IStream **ppStrm);
	STDMETHODIMP GetControlWindow(UINT id, HWND *lphwnd);
	STDMETHODIMP SendControlMsg(UINT id, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *pret);
	STDMETHODIMP QueryActiveShellView(IShellView **ppshv);
	STDMETHODIMP OnViewWindowActive(IShellView *ppshv);
	STDMETHODIMP SetToolbarItems(LPTBBUTTONSB lpButtons, UINT nButtons, UINT uFlags);
	
	STDMETHODIMP QueryService(REFGUID guidService, REFIID riid, void **ppv);
	
	STDMETHODIMP GetTypeInfoCount(UINT *pctinfo);
	STDMETHODIMP GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo);
	STDMETHODIMP GetIDsOfNames(REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId);
	STDMETHODIMP Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr);

	CShellBrowser();
	~CShellBrowser();
	int Run(HINSTANCE hinst, int nCmdShow);
	LRESULT WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
	BOOL Create();
	void BindFolder(LPWSTR lpszPath, BOOL bFullPath);
	void UpdateToolbar();
	void InitializeMenuItem(HMENU hmenu, LPTSTR lpszItemName, int nId, HMENU hmenuSub);

private:
	LONG          m_cRef;
	HWND          m_hwnd;
	HWND          m_hwndView;
	HWND          m_hwndStatus;
	HWND          m_hwndToolbar;
	IShellView    *m_pShellView;
	IShellFolder  *m_pShellFolder;
	ITravelLogStg *m_pTravelLogStg;
};

次に、CTravelLogStgなどの定義を含んだtravel.hを示します。

class CTravelLogEntry;

class CTravelLogStg : public ITravelLogStg
{
public:
	STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject);
	STDMETHODIMP_(ULONG) AddRef();
	STDMETHODIMP_(ULONG) Release();
	
	STDMETHODIMP CreateEntry(LPCOLESTR pszUrl, LPCOLESTR pszTitle, ITravelLogEntry *ptleRelativeTo, BOOL fPrepend, ITravelLogEntry **pptle);
	STDMETHODIMP TravelTo(ITravelLogEntry *ptle);
	STDMETHODIMP EnumEntries(TLENUMF flags, IEnumTravelLogEntry **ppenum);
	STDMETHODIMP FindEntries(TLENUMF flags, LPCWSTR pszUrl, IEnumTravelLogEntry **ppenum);
	STDMETHODIMP GetCount(TLENUMF flags, DWORD *pcEntries);
	STDMETHODIMP RemoveEntry(ITravelLogEntry *ptle);
	STDMETHODIMP GetRelativeEntry(int iOffset, ITravelLogEntry **ptle);
	
	CTravelLogStg(CShellBrowser *pShellBrowser);
	~CTravelLogStg();
	void DeleteChain(BOOL bPrepend);

private:
	LONG            m_cRef;
	CShellBrowser   *m_pShellBrowser;
	CTravelLogEntry *m_pCurrent;
};

class CTravelLogEntry : public ITravelLogEntry
{
public:
	STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject);
	STDMETHODIMP_(ULONG) AddRef();
	STDMETHODIMP_(ULONG) Release();
	
	STDMETHODIMP GetTitle(LPWSTR *ppszTitle);
	STDMETHODIMP GetURL(LPWSTR *ppszURL);

	CTravelLogEntry(LPOLESTR lpszUrl, LPOLESTR lpszTitle);
	~CTravelLogEntry();
	
	CTravelLogEntry *m_pPrev;
	CTravelLogEntry *m_pNext;
	BOOL m_bFullPath;

private:
	LONG m_cRef;
	LPOLESTR m_lpszUrl;
	LPOLESTR m_lpszTitle;
};

class CEnumTravelLogEntry : public IEnumTravelLogEntry
{
public:
	STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject);
	STDMETHODIMP_(ULONG) AddRef();
	STDMETHODIMP_(ULONG) Release();

	STDMETHODIMP Next(ULONG cElt, ITravelLogEntry **rgElt, ULONG *pcEltFetched);
	STDMETHODIMP Skip(ULONG cElt);
	STDMETHODIMP Reset(VOID);
	STDMETHODIMP Clone(IEnumTravelLogEntry **ppEnum);
	
	CEnumTravelLogEntry(TLENUMF flags, CTravelLogEntry *pCurrent);
	~CEnumTravelLogEntry();

private:
	LONG            m_cRef;
	TLENUMF         m_flags;
	CTravelLogEntry *m_pCurrent;
};

続いて、CShellBrowserの実装を含んだsample.cppを示します。

#include <windows.h>
#include <shlobj.h>
#include <shlwapi.h>
#include <commctrl.h>
#include <tlogstg.h>
#include "sample.h"
#include "travel.h"

#define ID_TOOLBAR 100
#define ID_BACK 200
#define ID_FORWARD 300

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

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

CShellBrowser *g_pShellBrowser = NULL;

int WINAPI WinMain(HINSTANCE hinst, HINSTANCE hinstPrev, LPSTR lpszCmdLine, int nCmdShow)
{
	int nResult = 0;

	OleInitialize(NULL);
	
	g_pShellBrowser = new CShellBrowser;
	if (g_pShellBrowser != NULL) {
		nResult = g_pShellBrowser->Run(hinst, nCmdShow);
		g_pShellBrowser->Release();
	}
	
	OleUninitialize();

	return nResult;
}

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	return g_pShellBrowser->WindowProc(hwnd, uMsg, wParam, lParam);
}


// CShellBrowser


CShellBrowser::CShellBrowser()
{
	m_cRef = 1;
	m_hwnd = NULL;
	m_hwndView = NULL;
	m_pShellView = NULL;
	m_hwndStatus = NULL;
	m_hwndToolbar = NULL;
	m_pShellView = NULL;
	m_pShellFolder = NULL;
	m_pTravelLogStg = NULL;
}

CShellBrowser::~CShellBrowser()
{
}

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

	if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IOleWindow) || IsEqualIID(riid, IID_IShellBrowser))
		*ppvObject = static_cast<IShellBrowser *>(this);
	else if (IsEqualIID(riid, IID_IServiceProvider))
		*ppvObject = static_cast<IServiceProvider *>(this);
	else if (IsEqualIID(riid, IID_IDispatch))
		*ppvObject = static_cast<IDispatch *>(this);
	else
		return E_NOINTERFACE;

	AddRef();
	
	return S_OK;
}

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

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

	return m_cRef;
}

STDMETHODIMP CShellBrowser::GetWindow(HWND *phwnd)
{
	*phwnd = m_hwnd;

	return S_OK;
}

STDMETHODIMP CShellBrowser::ContextSensitiveHelp(BOOL fEnterMode)
{
	return E_NOTIMPL;
}

STDMETHODIMP CShellBrowser::InsertMenusSB(HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths)
{
	HMENU hmenuPopupFile;
	HMENU hmenuPopupEdit;
	HMENU hmenuPopupView;
	HMENU hmenuPopupTool;
	HMENU hmenuPopupHelp;
	
	hmenuPopupFile = CreatePopupMenu();
	hmenuPopupEdit = CreatePopupMenu();
	hmenuPopupView = CreatePopupMenu();
	hmenuPopupTool = CreatePopupMenu();
	hmenuPopupHelp = CreatePopupMenu();
	
	InitializeMenuItem(hmenuShared, TEXT("ファイル(&F)"), FCIDM_MENU_FILE, hmenuPopupFile);
	InitializeMenuItem(hmenuShared, TEXT("編集(&E)"), FCIDM_MENU_EDIT, hmenuPopupEdit);
	InitializeMenuItem(hmenuShared, TEXT("表示(&V)"), FCIDM_MENU_VIEW, hmenuPopupView);
	InitializeMenuItem(hmenuShared, TEXT("ツール(&T)"), FCIDM_MENU_TOOLS, hmenuPopupTool);
	InitializeMenuItem(hmenuShared, TEXT("ヘルプ(&H)"), FCIDM_MENU_HELP, hmenuPopupHelp);

	lpMenuWidths->width[0] = 0;
	lpMenuWidths->width[1] = 0;
	lpMenuWidths->width[2] = 0;
	lpMenuWidths->width[3] = 0;
	lpMenuWidths->width[4] = 0;
	lpMenuWidths->width[5] = 0;

	return S_OK;
}

STDMETHODIMP CShellBrowser::SetMenuSB(HMENU hmenuShared, HOLEMENU holemenuRes, HWND hwndActiveObject)
{
	if (hwndActiveObject == NULL)
		return E_FAIL;

	SetMenu(m_hwnd, hmenuShared);
	
	return S_OK;
}

STDMETHODIMP CShellBrowser::RemoveMenusSB(HMENU hmenuShared)
{
	int i, nCount;

	nCount = GetMenuItemCount(hmenuShared);

	for (i = 0; i < nCount; i++)
		RemoveMenu(hmenuShared, i, MF_BYPOSITION);

	return S_OK;
}

STDMETHODIMP CShellBrowser::SetStatusTextSB(LPCWSTR lpszStatusText)
{
	SendMessageW(m_hwndStatus, SB_SETTEXT, 0, (LPARAM)lpszStatusText);

	return S_OK;
}

STDMETHODIMP CShellBrowser::EnableModelessSB(BOOL fEnable)
{
	return E_NOTIMPL;
}

STDMETHODIMP CShellBrowser::TranslateAcceleratorSB(LPMSG lpmsg, WORD wID)
{
	return E_NOTIMPL;
}

STDMETHODIMP CShellBrowser::BrowseObject(PCUIDLIST_RELATIVE pidl, UINT wFlags)
{
	BOOL            bResult;
	WCHAR           szFullPath[256];
	ITravelLogEntry *pTravelLogEntry;

	if (wFlags & SBSP_SAMEBROWSER || wFlags & SBSP_OPENMODE) {
		bResult = SHGetPathFromIDList(pidl, szFullPath);
		if (bResult) {
			m_pTravelLogStg->CreateEntry(szFullPath, PathFindFileName(szFullPath), NULL, FALSE, &pTravelLogEntry);
		}
		else {
			WCHAR  szName[256];
			STRRET strret;
			m_pShellFolder->GetDisplayNameOf(ILFindLastID(pidl), SHGDN_NORMAL, &strret);
			StrRetToBuf(&strret, ILFindLastID(pidl), szName, sizeof(szName) / sizeof(TCHAR));
			m_pTravelLogStg->CreateEntry((LPWSTR)pidl, szName, NULL, FALSE, &pTravelLogEntry);
		}
		m_pTravelLogStg->TravelTo(pTravelLogEntry);
		return S_OK;
	}
	
	return E_NOTIMPL;
}

STDMETHODIMP CShellBrowser::GetViewStateStream(DWORD grfMode, IStream **ppStrm)
{
	return E_NOTIMPL;
}

STDMETHODIMP CShellBrowser::GetControlWindow(UINT id, HWND *lphwnd)
{
	if (lphwnd == NULL)
		return E_POINTER;

	if (id == FCW_STATUS)
		*lphwnd = m_hwndStatus;
	else
		return E_FAIL;

	return S_OK;
}

STDMETHODIMP CShellBrowser::SendControlMsg(UINT id, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *pret)
{
	LRESULT lr;

	if (id == FCW_STATUS) {
		lr = SendMessage(m_hwndStatus, uMsg, wParam, lParam);
		if (pret != NULL)
			*pret = lr;
	}
	else
		return E_FAIL;

	return S_OK;
}

STDMETHODIMP CShellBrowser::QueryActiveShellView(IShellView **ppshv)
{
	*ppshv = m_pShellView;
	
	m_pShellView->AddRef();

	return S_OK;
}

STDMETHODIMP CShellBrowser::OnViewWindowActive(IShellView *ppshv)
{
	return E_NOTIMPL;
}

STDMETHODIMP CShellBrowser::SetToolbarItems(LPTBBUTTONSB lpButtons, UINT nButtons, UINT uFlags)
{
	return E_NOTIMPL;
}

STDMETHODIMP CShellBrowser::QueryService(REFGUID guidService, REFIID riid, void **ppv)
{
	*ppv = NULL;

	if (IsEqualIID(riid, IID_IOleWindow) || IsEqualIID(riid, IID_IShellBrowser)) {
		*ppv = static_cast<IShellBrowser *>(this);
		AddRef();
	}
	else if (IsEqualIID(riid, IID_ITravelLogStg)) {
		*ppv = static_cast<ITravelLogStg *>(m_pTravelLogStg);
		m_pTravelLogStg->AddRef();
	}
	else
		return E_NOINTERFACE;

	return S_OK;
}

STDMETHODIMP CShellBrowser::GetTypeInfoCount(UINT *pctinfo)
{
	*pctinfo = 0;
	
	return S_OK;
}

STDMETHODIMP CShellBrowser::GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
{
	return E_NOTIMPL;
}

STDMETHODIMP CShellBrowser::GetIDsOfNames(REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
{
	return E_NOTIMPL;
}

STDMETHODIMP CShellBrowser::Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
{
	return E_NOTIMPL;
}

int CShellBrowser::Run(HINSTANCE hinst, int nCmdShow)
{
	TCHAR      szAppName[] = TEXT("MyShellBrowser");
	HWND       hwnd;
	MSG        msg;
	WNDCLASSEX wc;

	wc.cbSize        = sizeof(WNDCLASSEX);
	wc.style         = 0;
	wc.lpfnWndProc   = ::WindowProc;
	wc.cbClsExtra    = 0;
	wc.cbWndExtra    = 0;
	wc.hInstance     = hinst;
	wc.hIcon         = (HICON)LoadImage(NULL, IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_SHARED);
	wc.hCursor       = (HCURSOR)LoadImage(NULL, IDC_ARROW, IMAGE_CURSOR, 0, 0, LR_SHARED);
	wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	wc.lpszMenuName  = NULL;
	wc.lpszClassName = szAppName;
	wc.hIconSm       = (HICON)LoadImage(NULL, IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_SHARED);
	
	if (RegisterClassEx(&wc) == 0)
		return 0;

	hwnd = CreateWindowEx(0, szAppName, szAppName, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hinst, NULL);
	if (hwnd == NULL)
		return 0;

	ShowWindow(hwnd, nCmdShow);
	UpdateWindow(hwnd);
	
	while (GetMessage(&msg, NULL, 0, 0) > 0) {
		if (m_pShellView->TranslateAcceleratorW(&msg) != S_OK) {
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
	}

	return (int)msg.wParam;
}


LRESULT CShellBrowser::WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	static IShellWindows *pShellWindows = NULL;
	static LONG          lCookie = 0;

	switch (uMsg) {

	case WM_CREATE: {
		TBBUTTON tbButton[] = {
			{HIST_BACK, ID_BACK, 0, BTNS_BUTTON, {0}, 0, 0},
			{HIST_FORWARD, ID_FORWARD, 0, BTNS_BUTTON, {0}, 0, 0}
		};
		int                  nCount = sizeof(tbButton) / sizeof(tbButton[0]);
		HRESULT              hr;
		PIDLIST_ABSOLUTE     pidl;
		INITCOMMONCONTROLSEX ic;

		ic.dwSize = sizeof(INITCOMMONCONTROLSEX);
		ic.dwICC  = ICC_BAR_CLASSES;
		InitCommonControlsEx(&ic);
		
		m_hwndStatus = CreateWindowEx(0, STATUSCLASSNAME, TEXT(""), WS_CHILD | WS_VISIBLE, 0, 0, 0, 0, hwnd, (HMENU)FCIDM_STATUS, ((LPCREATESTRUCT)lParam)->hInstance, NULL);	
		m_hwndToolbar = CreateToolbarEx(hwnd, WS_CHILD | WS_VISIBLE, ID_TOOLBAR, 0, HINST_COMMCTRL, IDB_HIST_LARGE_COLOR, tbButton, nCount, 0, 0, 0, 0, sizeof(TBBUTTON));

		SHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl);
		m_pTravelLogStg = new CTravelLogStg(this);
		m_pTravelLogStg->CreateEntry((LPWSTR)pidl, L"デスクトップ", NULL, FALSE, NULL);
		CoTaskMemFree(pidl);
		
		m_hwnd = hwnd;
		if (!Create())
			return -1;

		hr = CoCreateInstance(CLSID_ShellWindows, NULL, CLSCTX_ALL, IID_PPV_ARGS(&pShellWindows));
		if (SUCCEEDED(hr))
			pShellWindows->Register(this, (LONG)m_hwnd, SWC_3RDPARTY, &lCookie);

		return 0;
	}

	case WM_COMMAND:
		if (LOWORD(wParam) == ID_BACK || LOWORD(wParam) == ID_FORWARD) {
			TLENUMF             flags;
			ITravelLogEntry     *pTravelLogEntry;
			IEnumTravelLogEntry *pEnumTravelLogEntry;

			flags = LOWORD(wParam) == ID_BACK ? TLEF_RELATIVE_BACK : TLEF_RELATIVE_FORE;
			m_pTravelLogStg->EnumEntries(flags, &pEnumTravelLogEntry);
			pEnumTravelLogEntry->Next(1, &pTravelLogEntry, NULL);
			m_pTravelLogStg->TravelTo(pTravelLogEntry);
			pTravelLogEntry->Release();
			pEnumTravelLogEntry->Release();
		}
		else
			SendMessage(m_hwndView, uMsg, wParam, lParam);
		return 0;

	case WM_SIZE: {
		int  nHeightToolbar, nHeightStatus;
		RECT rc;
		
		MoveWindow(m_hwndToolbar, 0, 0, LOWORD(lParam), HIWORD(wParam), TRUE);
		SendMessage(m_hwndStatus, WM_SIZE, wParam, lParam);
		
		GetWindowRect(m_hwndToolbar, &rc);
		nHeightToolbar = rc.bottom - rc.top;
		GetWindowRect(m_hwndStatus, &rc);
		nHeightStatus = rc.bottom - rc.top;
		MoveWindow(m_hwndView, 0, nHeightToolbar, LOWORD(lParam), HIWORD(lParam) - nHeightStatus - nHeightToolbar, TRUE);
		
		return 0;
	}

	case WM_DESTROY:
		if (m_pShellView != NULL) {
			m_pShellView->DestroyViewWindow();
			m_pShellView->Release();
		}
		if (m_pShellFolder != NULL)
			m_pShellFolder->Release();
		if (m_pTravelLogStg != NULL)
			m_pTravelLogStg->Release();
		if (pShellWindows != NULL) {
			pShellWindows->Revoke(lCookie);
			pShellWindows->Release();
		}
		PostQuitMessage(0);
		return 0;

	default:
		break;

	}

	return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

BOOL CShellBrowser::Create()
{
	HRESULT         hr;
	RECT            rc;
	FOLDERSETTINGS  fs;
	IObjectWithSite *pObjectWithSite;
	
	if (m_pShellFolder == NULL)
		SHGetDesktopFolder(&m_pShellFolder);

	if (m_pShellView != NULL) {
		m_pShellView->DestroyViewWindow();
		m_pShellView->Release();
	}

	if (m_pShellFolder->CreateViewObject(m_hwnd, IID_PPV_ARGS(&m_pShellView)) != S_OK) {
		m_pShellFolder->Release();
		return FALSE;
	}

	hr = m_pShellView->QueryInterface(IID_PPV_ARGS(&pObjectWithSite));
	if (SUCCEEDED(hr)) {
		pObjectWithSite->SetSite(static_cast<IServiceProvider *>(this));
		pObjectWithSite->Release();
	}

	fs.ViewMode = FVM_DETAILS;
	fs.fFlags   = 0;
	SetRectEmpty(&rc);
	if (m_pShellView->CreateViewWindow(NULL, &fs, static_cast<IShellBrowser *>(this), &rc, &m_hwndView) != S_OK) {
		m_pShellView->Release();
		m_pShellFolder->Release();
		return FALSE;
	}

	GetClientRect(m_hwnd, &rc);
	SendMessage(m_hwnd, WM_SIZE, 0, MAKELONG(rc.right - rc.left, rc.bottom - rc.top));

	m_pShellView->UIActivate(SVUIA_ACTIVATE_NOFOCUS);

	return TRUE;
}

void CShellBrowser::BindFolder(LPWSTR lpszPath, BOOL bFullPath)
{
	IShellFolder     *pDesktopFolder;
	PIDLIST_ABSOLUTE pidl;

	if (bFullPath)
		pidl = ILCreateFromPath(lpszPath);
	else
		pidl = (PIDLIST_ABSOLUTE)lpszPath;

	m_pShellFolder->Release();
	SHGetDesktopFolder(&pDesktopFolder);
	pDesktopFolder->BindToObject(pidl, NULL, IID_PPV_ARGS(&m_pShellFolder));
	pDesktopFolder->Release();
	if (bFullPath)
		CoTaskMemFree(pidl);
	
	Create();
	UpdateToolbar();
}

void CShellBrowser::UpdateToolbar()
{
	int                 i;
	int                 nId[] = {ID_BACK, ID_FORWARD};
	TLENUMF             flags[] = {TLEF_RELATIVE_BACK, TLEF_RELATIVE_FORE};
	BOOL                bEnable;
	HRESULT             hr;
	ITravelLogEntry     *pTravelLogEntry;
	IEnumTravelLogEntry *pEnumTravelLogEntry;

	for (i = 0; i < 2; i++) {
		m_pTravelLogStg->EnumEntries(flags[i], &pEnumTravelLogEntry);
		hr = pEnumTravelLogEntry->Next(1, &pTravelLogEntry, NULL);
		if (hr == S_OK) {
			bEnable = TRUE;
			pTravelLogEntry->Release();
		}
		else
			bEnable = FALSE;
		SendMessage(m_hwndToolbar, TB_ENABLEBUTTON, nId[i], MAKELONG(bEnable, 0));
		pEnumTravelLogEntry->Release();
	}
}

void CShellBrowser::InitializeMenuItem(HMENU hmenu, LPTSTR lpszItemName, int nId, HMENU hmenuSub)
{
	MENUITEMINFO mii;
	
	mii.cbSize = sizeof(MENUITEMINFO);
	mii.fMask  = MIIM_ID | MIIM_TYPE;
	mii.wID    = nId;

	if (lpszItemName != NULL) {
		mii.fType      = MFT_STRING;
		mii.dwTypeData = lpszItemName;
	}
	else
		mii.fType = MFT_SEPARATOR;

	if (hmenuSub != NULL) {
		mii.fMask   |= MIIM_SUBMENU;
		mii.hSubMenu = hmenuSub;
	}

	InsertMenuItem(hmenu, nId, FALSE, &mii);
}

最後に、CTravelLogStgなどの実装を含んだtravel.cppを示します。

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

CTravelLogStg::CTravelLogStg(CShellBrowser *pShellBrowser)
{
	m_cRef = 1;
	m_pCurrent = NULL;
	m_pShellBrowser = pShellBrowser;
}

CTravelLogStg::~CTravelLogStg()
{
	if (m_pCurrent != NULL) {
		DeleteChain(TRUE);
		DeleteChain(FALSE);
		delete m_pCurrent;
	}
}

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

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

	AddRef();
	
	return S_OK;
}

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

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

	return m_cRef;
}

STDMETHODIMP CTravelLogStg::CreateEntry(LPCOLESTR pszUrl, LPCOLESTR pszTitle, ITravelLogEntry *ptleRelativeTo, BOOL fPrepend, ITravelLogEntry **pptle)
{
	CTravelLogEntry *pNew;

	if (pszUrl == NULL)
		return E_INVALIDARG;

	pNew = new CTravelLogEntry((LPOLESTR)pszUrl, (LPOLESTR)pszTitle);

	if (m_pCurrent != NULL) {
		DeleteChain(fPrepend);
		if (fPrepend) {	
			m_pCurrent->m_pPrev = pNew;
			pNew->m_pNext = m_pCurrent;
		}
		else {
			m_pCurrent->m_pNext = pNew;
			pNew->m_pPrev = m_pCurrent;
		}
	}
	else
		m_pCurrent = pNew;

	if (pptle != NULL)
		*pptle = pNew;

	m_pShellBrowser->UpdateToolbar();

	return S_OK;
}

STDMETHODIMP CTravelLogStg::TravelTo(ITravelLogEntry *ptle)
{
	LPWSTR lpszUrl;

	m_pCurrent = (CTravelLogEntry *)ptle;

	ptle->GetURL(&lpszUrl);
	m_pShellBrowser->BindFolder(lpszUrl, m_pCurrent->m_bFullPath);

	return S_OK;
}

STDMETHODIMP CTravelLogStg::EnumEntries(TLENUMF flags, IEnumTravelLogEntry **ppenum)
{
	CTravelLogEntry *p = m_pCurrent;

	if (p == NULL)
		return E_FAIL;

	if (flags == TLEF_RELATIVE_BACK)
		p = p->m_pPrev;
	else if (flags == TLEF_RELATIVE_FORE)
		p = p->m_pNext;
	else if (flags == TLEF_ABSOLUTE) {
		while(p->m_pPrev != NULL)
			p = p->m_pPrev;
	}
	else if (flags & TLEF_INCLUDE_UNINVOKEABLE)
		return E_NOTIMPL;
	else
		;

	*ppenum = new CEnumTravelLogEntry(flags, p);

	return S_OK;
}

STDMETHODIMP CTravelLogStg::FindEntries(TLENUMF flags, LPCWSTR pszUrl, IEnumTravelLogEntry **ppenum)
{
	return E_NOTIMPL;
}

STDMETHODIMP CTravelLogStg::GetCount(TLENUMF flags, DWORD *pcEntries)
{
	return E_NOTIMPL;
}

STDMETHODIMP CTravelLogStg::RemoveEntry(ITravelLogEntry *ptle)
{
	return E_NOTIMPL;
}

STDMETHODIMP CTravelLogStg::GetRelativeEntry(int iOffset, ITravelLogEntry **ptle)
{
	return E_NOTIMPL;
}

void CTravelLogStg::DeleteChain(BOOL bPrepend)
{
	CTravelLogEntry *p, *p2;

	if (bPrepend) {
		if (m_pCurrent->m_pPrev != NULL) {
			for (p = m_pCurrent->m_pPrev; p != NULL;) {
				p2 = p->m_pPrev;
				delete p;
				p = p2;
			}
		}
	}
	else {
		if (m_pCurrent->m_pNext != NULL) {
			for (p = m_pCurrent->m_pNext; p != NULL;) {
				p2 = p->m_pNext;
				delete p;
				p = p2;
			}
		}
	}
}


// CEnumTravelLogEntry


CEnumTravelLogEntry::CEnumTravelLogEntry(TLENUMF flags, CTravelLogEntry *pCurrent)
{
	m_cRef = 1;
	m_flags = flags;
	m_pCurrent = pCurrent;
}

CEnumTravelLogEntry::~CEnumTravelLogEntry()
{
}

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

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

	AddRef();
	
	return S_OK;
}

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

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

	return m_cRef;
}

STDMETHODIMP CEnumTravelLogEntry::Next(ULONG cElt, ITravelLogEntry **rgElt, ULONG *pcEltFetched)
{
	if (m_pCurrent == NULL)
		return E_FAIL;
	
	*rgElt = m_pCurrent;

	if (m_flags & TLEF_RELATIVE_INCLUDE_CURRENT && m_flags != TLEF_ABSOLUTE) 
		m_flags &= ~TLEF_RELATIVE_INCLUDE_CURRENT;

	if (m_flags == TLEF_RELATIVE_BACK || m_flags == 0)
		m_pCurrent = m_pCurrent->m_pPrev;
	else if (m_flags == TLEF_RELATIVE_FORE || m_flags == TLEF_ABSOLUTE)
		m_pCurrent = m_pCurrent->m_pNext;
	else
		;

	if (pcEltFetched != NULL)
		*pcEltFetched = 1;

	return S_OK;
}

STDMETHODIMP CEnumTravelLogEntry::Skip(ULONG cElt)
{
	return E_NOTIMPL;
}

STDMETHODIMP CEnumTravelLogEntry::Reset(VOID)
{
	return E_NOTIMPL;
}

STDMETHODIMP CEnumTravelLogEntry::Clone(IEnumTravelLogEntry **ppEnum)
{
	return E_NOTIMPL;
}


// CTravelLogEntry


CTravelLogEntry::CTravelLogEntry(LPOLESTR lpszUrl, LPOLESTR lpszTitle)
{
	m_cRef = 1;
	m_pPrev = NULL;
	m_pNext = NULL;

	m_bFullPath = PathIsDirectory(lpszUrl);
	if (m_bFullPath)
		SHStrDup(lpszUrl, &m_lpszUrl);
	else
		m_lpszUrl = (LPWSTR)ILClone((PIDLIST_ABSOLUTE)lpszUrl);

	if (lpszTitle != NULL)
		SHStrDup(lpszTitle, &m_lpszTitle);
	else
		m_lpszTitle = NULL;
}

CTravelLogEntry::~CTravelLogEntry()
{
	if (m_lpszUrl != NULL)
		CoTaskMemFree(m_lpszUrl);
	
	if (m_lpszTitle != NULL)
		CoTaskMemFree(m_lpszTitle);
}

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

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

	AddRef();
	
	return S_OK;
}

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

STDMETHODIMP_(ULONG) CTravelLogEntry::Release()
{
	return InterlockedDecrement(&m_cRef);
}

STDMETHODIMP CTravelLogEntry::GetTitle(LPWSTR *ppszTitle)
{
	if (m_lpszTitle != NULL)
		SHStrDup(m_lpszTitle, ppszTitle);
	else
		*ppszTitle = NULL;

	return S_OK;
}

STDMETHODIMP CTravelLogEntry::GetURL(LPWSTR *ppszURL)
{
	*ppszURL = m_lpszUrl;

	return S_OK;
}

戻る