Cドライブの全内容をメニューで表示

解説


 多階層のメニューを表示する。メニューの表示内容は指定したフォルダー内のファイルや フォルダーとした。使用例ではC:\を指定しているので、Cドライブに存在する全てのファイル やフォルダー名をメニューで一覧できる。
 メニューは一度に全てを作らず、動的に生成するためCドライブの全ファイルを表示する 場合でもCPUパワーをあまり必要とせず、ストレスなく表示できる。



使用例


	void	Test()
	{
		CFolderMenu	cMenu;

		POINT		pt;
		CAtlString	strPath;
		CAtlString	strName;


		::GetCursorPos(&pt);
		cMenu.ShowMenu(m_hWnd,_T("c:\\"),pt,TPM_LEFTALIGN,strPath,strName);

		::MessageBox(NULL,strName,NULL,NULL);
	}



ソースコード



#include "atlcoll.h"


	//
	//	フォルダーメニュークラス
	//
	//指定したフォルダー内のファイルとフォルダーをサブフォルダーにまでさかのぼって
	//全てメニューとして表示する。
	//
	//■使用例
	//
	//		CFolderMenu	cMenu;
	//
	//		POINT		pt;
	//		CAtlString	strPath;
	//		CAtlString	strName;
	//
	//
	//		::GetCursorPos(&pt);
	//		cMenu.ShowMenu(m_hWnd,_T("c:\\"),pt,TPM_LEFTALIGN,strPath,strName);
	//
	//		::MessageBox(NULL,strName,NULL,NULL);
	class	CFolderMenu
	{
	protected:

		//
		//	メニュー処理関数
		//
		//	メニューメッセージの処理とメニュー生成、フォルダ内列挙関数など内部処理をほぼ全て含む関数
		//
		class CMenuMessageWnd : public CWindowImpl
		{
		protected:

			BEGIN_MSG_MAP(CMenuMessageWnd)
				MESSAGE_HANDLER(WM_MENUSELECT, OnMenuSelect)			//フォルダを示すメニューが選択されたときの処理
			END_MSG_MAP()


			//メニューハンドル(HMENU)とフォルダパスを関連付けるmap
			//サブメニューを選択したときにそれがどこのフォルダなのかを識別するために利用
			CAtlMap	_mapFolderPath;



			//
			//	メニュー選択時処理
			//
			//	フォルダを示すメニューが選択されたとき、その子フォルダ内を調べてフォルダとファイル名を追加する。
			//
			LRESULT OnMenuSelect(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
			{
				bHandled = FALSE;

				if(HIWORD(wParam) & MF_POPUP)		//ポップアップメニューが選択されたときのみ処理する
				{
					HMENU	hMenu;
					CAtlMap::CPair*	pPair;

					hMenu = ::GetSubMenu((HMENU)lParam,LOWORD(wParam));		//選択されたサブメニューを取得
					if(hMenu && ::GetMenuItemCount(hMenu) == 0)
					{
						pPair = _mapFolderPath.Lookup(hMenu);				//メニューハンドルから関連するフォルダー名を取得
						if(pPair)
							AddPathToMenu(hMenu,pPair->m_value);			//フォルダ内のファイルやフォルダをメニューに追加
					}
				}

				return	0;
			}


			//
			//	ファイル/フォルダーパス情報
			//
			//	配列_acFileListに格納するために定義
			//	格納されているファイル(フォルダー)のフルパスは「_strPath + _strFile」になる。
			//	つまり_strPathにはフルパスは格納されないことに注意!
			//
			class	CFileData
			{
			public:
				CFileData()
				{
					_bFolder = false;
				}
				CFileData(LPCTSTR pszPath,LPCTSTR pszFile,bool bFolder)
				{
					_strPath = pszPath;
					_strFile = pszFile;
					_bFolder = bFolder;
				}

				CAtlString	_strPath;		//パス名(ex.「c:\\windows\\」なら「c:\\」が格納される)
				CAtlString	_strFile;		//ファイル名(ex.「c:\\windows\\」なら「windows」が格納される)
				bool		_bFolder;		//フォルダーならtrue、ファイルならfalse
			};

			//ファイル・フォルダ情報格納配列
			//メニューに表示しているフォルダやファイルの全情報を格納する
			//メニュー登録時のIDはこの配列への「インデックス+1」とする。
			CDnpArrayEx	_acFileList;



			////
			////	SortFileListArray()用の比較関数
			////
			//static	int __cdecl SortFileListArray(const void * lpData1, const void * lpData2,void* lpParam)
			//{
			//	DWORD		nData1;
			//	DWORD		nData2;

			//	nData1 = *(DWORD*)lpData1;
			//	nData2 = *(DWORD*)lpData2;

			//	CDnpArrayEx*	lpastrFile;

			//	lpastrFile = (CDnpArrayEx*) lpParam;

			//	return	strcmp(lpastrFile->GetAt((int)nData1)._strFile,lpastrFile->GetAt((int)nData2)._strFile);
			//}

			////
			////	文字列の並べ替え関数
			////
			////		CDnpStringArrayを昇順に並べ替える
			////
			//bool	SortFileListArray(CDnpArrayEx* pacFileList)
			//{
			//	int				i;
			//	int				nCount;
			//	DWORD*			lpnIndex;
			//	CDnpArrayEx	acTmp;

			//	if(pacFileList == NULL)
			//		return	false;

			//	nCount = pacFileList->GetSize();

			//	lpnIndex = new DWORD[nCount + 1];
			//	if(lpnIndex == NULL)
			//		return	false;

			//	for(i = 0; i < nCount; i++)
			//		lpnIndex[i] = i;

			//	QuickSort(lpnIndex,nCount,sizeof(DWORD),SortFileListArray,pacFileList);

			//	for(i = 0; i < nCount; i++)
			//		acTmp.Add((*pacFileList)[lpnIndex[i]]);

			//	delete	lpnIndex;

			//	pacFileList->RemoveAll();
			//	for(i = 0; i < nCount; i++)
			//		pacFileList->Add(acTmp[i]);

			//	return	true;
			//}


			//
			//	ファイル/フォルダの列挙
			//
			//指定したフォルダ内のファイルなどを列挙します。
			//列挙結果はpacFileListに追加します。
			//	pszFolder内のフォルダとファイルを列挙してpacFileList配列へ追加する
			//
			bool	GetFileList(LPCTSTR pszFolder,CDnpArrayEx* pacFileList)
			{
				BOOL			bFind;
				HANDLE			hFind;
				WIN32_FIND_DATA	FindFileData;
				CAtlString		strFolder;

				if(pacFileList == NULL || pszFolder == NULL || _tcslen(pszFolder) == 0)
					return	false;

				//pacFileList->RemoveAll();				//削除したらダメ!

				strFolder = pszFolder;
				if(strFolder.Right(1) != _T('\\'))
					strFolder += _T("\\");

				hFind = ::FindFirstFile(strFolder + _T("*.*"),&FindFileData);
				if(hFind == INVALID_HANDLE_VALUE)
					return	false;

				bFind = TRUE;
				while(bFind)
				{
					if(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
					{
						if(_tcsncmp(FindFileData.cFileName,_T("."),1) != 0 && _tcsncmp(FindFileData.cFileName,_T(".."),2) != 0 )
							pacFileList->Add(CFileData(strFolder,FindFileData.cFileName,true));
					}
					else
						pacFileList->Add(CFileData(strFolder,FindFileData.cFileName,false));

					bFind = ::FindNextFile(hFind,&FindFileData);
				}
				::FindClose(hFind);

				//SortFileListArray(pacFileList);			//ソートしたい場合でもコメントを削除するのみではダメ!今回の関数で追加された数だけソートするように変更の必要あり

				return	true;
			}


			//
			//	メニュー情報の作成
			//
			//	HMENUにpszPathに存在するファイルやフォルダを追加する
			//
			bool	AddPathToMenu(HMENU hMenu,LPCTSTR pszPath)
			{
				INT_PTR	i;
				INT_PTR	nIndex;

				nIndex = _acFileList.GetSize();
				GetFileList(pszPath,&_acFileList);			//ファイルの列挙:_acFileListに追加する形で列挙

				for(i = nIndex; i < _acFileList.GetSize(); i++)
				{
					if(_acFileList[i]._bFolder)
					{
						HMENU	hMenuSub;

						hMenuSub = ::CreatePopupMenu();
						if(hMenuSub)
						{
							_mapFolderPath.SetAt(hMenuSub,_acFileList[i]._strPath + _acFileList[i]._strFile + _T("\\"));
							::AppendMenu(hMenu, MF_ENABLED | MF_POPUP,(UINT)hMenuSub,_acFileList[i]._strFile);
						}
						ATLASSERT(hMenuSub);
					}
					else
					{
						//IDをi +iとしてメニューに登録
						::AppendMenu(hMenu, MF_ENABLED | MF_STRING ,i + 1, _acFileList[i]._strFile);
					}
				}

				return	true;
			}





			//
			//	TrackPopupMenuの返値を示すIDから選択されたフォルダ・ファイルを取得する
			//
			//	失敗時はfalseが返る。かならず処理すること!
			//
			bool	GetPath(UINT_PTR nID,CAtlString& strPath,CAtlString& strName,bool& bFolder)
			{
				strPath = _T("");
				strName = _T("");
				bFolder = false;

				if(nID > (UINT_PTR)_acFileList.GetSize() || nID == 0)
					return	false;

				nID--;
				bFolder = _acFileList[nID]._bFolder;
				strPath = _acFileList[nID]._strPath;
				strName = _acFileList[nID]._strFile;

				return	true;
			}

		public:





			//
			//	メニューの表示
			//
			//	pszFolder内の全サブフォルダおよびファイルを表示する。
			//	選択結果はstrPathとstrNameに返る。
			//
			//	ptはメニュー表示位置、uFlagsはTrackPopupMenuに与えるフラグを示す。
			//
			bool	ShowMenu(HWND hParentWnd,LPCTSTR pszFolder,POINT pt,UINT uFlags,CAtlString& strPath,CAtlString& strName)
			{
				bool		ret;
				bool		bFolder;
				UINT_PTR	nID;
				HMENU		hMenu;

				Create(hParentWnd);				//メッセージ処理用ウインドウ作成
				if(IsWindow() == FALSE)
					return	false;

				ret = true;
				hMenu = ::CreatePopupMenu();	//メニュー作成
				if(hMenu == NULL)
					ret = false;

				if(ret)
					ret = AddPathToMenu(hMenu,pszFolder);		//メニューに一番上の階層のフォルダ内容を追加する
				if(ret)
					nID = (UINT_PTR)::TrackPopupMenu(hMenu,uFlags | TPM_RETURNCMD,pt.x,pt.y,NULL,m_hWnd,NULL);		//メニューの表示
				if(ret)
					ret = GetPath(nID,strPath,strName,bFolder);		//選択されたフォルダ・メニューの取得

				_mapFolderPath.RemoveAll();						//マップ情報の削除

				::DestroyMenu(hMenu);							//メニューハンドルの開放
				DestroyWindow();								//メッセージ処理用ウインドウの破壊

				return	ret;
			}

		};





		CMenuMessageWnd	_wndMenuMessage;		//	メニュー処理用ウインドウ



	public:


		//
		//	メニューの表示
		//
		//	pszFolder内の全サブフォルダおよびファイルを表示する。
		//	選択結果はstrPathとstrNameに返る。
		//
		//	ptはメニュー表示位置、uFlagsはTrackPopupMenuに与えるフラグを示す。
		//
		bool	ShowMenu(HWND hParentWnd,LPCTSTR pszFolder,POINT pt,UINT uFlags,CAtlString& strPath,CAtlString& strName)
		{
			return	_wndMenuMessage.ShowMenu(hParentWnd,pszFolder,pt,uFlags,strPath,strName);
		}
	};


カテゴリー「VC++ TIPS」 のエントリー