OSに関係なく特殊フォルダのパスを取得する

デスクトップやお気に入り、マイドキュメントなどの特殊フォルダにアクセスするとき、例えば「c:\windows\」や「c:\Program Files\」のようにソースコードに書いてはいけない。必ず専用のAPIを利用してパスを取得する必要がある。取得にはSHGetFolderPath、SHGetSpecialFolderPath、SHGetFolderLocationなどを利用する。

現在のプラットフォームでは何も考えずにSHGetFolderPathを利用すればいい。しかし古いプラットフォームもサポートしたプログラムにしようと考えるとやっかいなことになる可能性がある。SHGetFolderPathをshfolder.libに実装したりshell32.dllに変えたり...と過去に何回かの変更があるからだ。
ここで紹介する関数は現在のプラットフォームではSHGetFolderPathを、古いものではSHGetSpecialFolderPathを利用して特殊フォルダのパスを取得している。

取得できるフォルダには...
CSIDL_ADMINTOOLS
CSIDL_COMMON_ADMINTOOLS
CSIDL_APPDATA
CSIDL_COMMON_APPDATA
CSIDL_COMMON_DOCUMENTS
CSIDL_COOKIES
CSIDL_HISTORY
CSIDL_INTERNET_CACHE
CSIDL_LOCAL_APPDATA
CSIDL_MYPICTURES
CSIDL_PERSONAL
CSIDL_PROGRAM_FILES
CSIDL_PROGRAM_FILES_COMMON
CSIDL_SYSTEM
CSIDL_WINDOWS
などなどがある。これらはshlobj.hに定義されているのでそちらを参考にするといいだろう。

#include "shlobj.h"


//
//	SHGetSpecialFolderPathの全プラットフォーム対応バージョン
//
BOOL	SafeSHGetSpecialFolderPath(HWND hwndOwner,LPTSTR lpszPath,int nFolder,BOOL fCreate)
{
	BOOL	(CALLBACK* g_pfnSHGetSpecialFolderPath)(HWND,LPTSTR,int,BOOL);
	HRESULT	(CALLBACK* g_pfnSHGetFolderPath)(HWND,int,HANDLE,DWORD,LPTSTR);

	int			i;
	BOOL		ret;
	HRESULT		hr;
	HMODULE		hDLL;
	TCHAR		pszDllFile[][15] = {_T("shfolder.dll"),_T("shell32.dll")};

	if(lpszPath == NULL)
		return	FALSE;
	*lpszPath = NULL;

	ret = FALSE;
	for(i = 0; i < 2; i++)
	{
		hDLL = ::LoadLibrary(pszDllFile[i]);
		if(hDLL == NULL)
			continue;

		#ifdef UNICODE
			(*(FARPROC*)&g_pfnSHGetSpecialFolderPath = ::GetProcAddress(hDLL,"SHGetSpecialFolderPathW"));
			(*(FARPROC*)&g_pfnSHGetFolderPath = ::GetProcAddress(hDLL,"SHGetFolderPathW"));
		#else
			(*(FARPROC*)&g_pfnSHGetSpecialFolderPath = ::GetProcAddress(hDLL,"SHGetSpecialFolderPathA"));
			(*(FARPROC*)&g_pfnSHGetFolderPath = ::GetProcAddress(hDLL,"SHGetFolderPathA"));
		#endif

		if(g_pfnSHGetSpecialFolderPath)
			ret = g_pfnSHGetSpecialFolderPath(hwndOwner,lpszPath,nFolder,fCreate);
		if(ret == FALSE && g_pfnSHGetFolderPath)
		{
			hr = g_pfnSHGetFolderPath(hwndOwner,nFolder | (fCreate ? CSIDL_FLAG_CREATE : 0),NULL,SHGFP_TYPE_DEFAULT,lpszPath);
			ret = (SUCCEEDED(hr)) ? TRUE : FALSE;
		}

		::FreeLibrary(hDLL);

		if(ret)
			return	TRUE;
	}

	return	FALSE;
}



void	Test(void)
{
	BOOL	ret;
	TCHAR	pszPath[MAX_PATH*2];

	ret = SafeSHGetSpecialFolderPath(NULL,pszPath,CSIDL_DESKTOPDIRECTORY,FALSE);

	if(ret)
		::MessageBox(NULL,pszPath,_T(""),MB_OK);
	else
		::MessageBox(NULL,_T("取得に失敗しました"),_T(""),MB_OK);
}

プロジェクトファイルをダウンロード


カテゴリー「ファイル・フォルダ」 のエントリー