解説
多階層のメニューを表示する。メニューの表示内容は指定したフォルダー内のファイルや フォルダーとした。使用例では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);
}
};







