左にエクスプローラ風のフォルダツリービューのペインを有し、ファイルをクリックすると右ペインで表示編集などの処理をする、ごく一般的な2ペインアプリケーションをMSVC++6.0 Win32SDKで作成すべく、インターネットで検索しましたが、MFCやVBの例はあるもののWin32SDKのサンプルコードを見つけることが出来ませんでした。
コモンコントロールでエクスプローラ風のフォルダツリービューのコードを自作するとなると極端な労力を要します。
そこで"Win32SDKプログラム"のフォルダツリービューの適当なサンプルコードの所在をご存知でしたらよろしくお願いします。
No.3ベストアンサー
- 回答日時:
こんばんは。
取り敢えず以下をヒントに作成して見ました。http://www.sm.rim.or.jp/~shishido/subdir.html
どちらにしろ、ハードディスク内を全検索する訳には行きませんので、最初は検索対象ドライブと+2階層まで、その後はツリーがクリックされる度に+2階層までを調べながら、こっそりとツリーを付け加えていきます(でないと、動かなくなる)。
後は、ツリービューに+マーク等の表示をさせるようにして下さい。以下参考程度に。
#include<windows.h>
#include<commctrl.h>
#include<tchar.h>
#include<crtdbg.h>
#include"resource.h"
typedef struct
{
HTREEITEM hTreeItem;//ツリーアイテム
union
{
LPVOID pVoid;//キャスト防ぎ
LPTSTR sPath;//ツリーアイテムのパス文字列
};
} DATA, *LPDATA;
typedef struct
{
union
{
LPVOID pVoid;//キャスト防ぎ
LPDATA pData;//DATA型の配列
};
INTnCount;//割り当てられた配列の個数
} ITEMPATHTABLE, *LPITEMPATHTABLE;
static ITEMPATHTABLE _S_pathTable = {0};
//パステーブルのメモリ解放
static VOID TreeView_FreePathTable(LPITEMPATHTABLE tbl)
{
const ITEMPATHTABLE zero = {0};
for(INT i = 0; i < tbl->nCount; ++i)
::free(tbl->pData[i].sPath);
::free(tbl->pData);
*tbl = zero;
}
//パス文字列でパステーブルを検索して対応するツリーアイテムのハンドルを見つける
static HTREEITEM TreeView_FindItemFromPath(LPITEMPATHTABLE tbl, LPCTSTR sPath)
{
for(INT i = 0; i < tbl->nCount; ++i)
if(::_tcscmp(tbl->pData[i].sPath, sPath) == 0)
return tbl->pData[i].hTreeItem;
return NULL;
}
//上の逆
static LPCTSTR TreeView_FindPathFromItem(LPITEMPATHTABLE tbl, HTREEITEM hTreeItem)
{
for(INT i = 0; i < tbl->nCount; ++i)
if(tbl->pData[i].hTreeItem == hTreeItem)
return tbl->pData[i].sPath;
return NULL;
}
//検索されたパスの文字列をテーブルに記録していく
static BOOL TreeView_SavePath(LPITEMPATHTABLE tbl, LPCTSTR sPath, HTREEITEM hTreeItem)
{
if(tbl->nCount == 0)
tbl->pVoid = ::malloc(sizeof(DATA) * (++tbl->nCount));
else
tbl->pVoid = ::realloc(tbl->pVoid, sizeof(DATA) * (++tbl->nCount));
LPDATA pData = &tbl->pData[tbl->nCount - 1];
pData->hTreeItem = hTreeItem;
pData->pVoid = ::malloc((::_tcslen(sPath) + 1) * sizeof(TCHAR));
::_tcscpy(pData->sPath, sPath);
return TRUE;
}
//ツリーアイテムの作成
static HTREEITEM AddTreeItem(HWND hTreeView, LPCTSTR sItemName, HTREEITEM hItemParent = NULL)
{
//親ツリーがNULLの場合はルートになる
TVINSERTSTRUCT tvis= {hItemParent == NULL ? TVI_ROOT : hItemParent, TVI_LAST};
tvis.item.mask= TVIF_TEXT | TVIF_PARAM;
tvis.item.pszText= (LPTSTR)sItemName;
tvis.item.cchTextMax= ::_tcslen(sItemName);
tvis.item.lParam= TRUE;//何か適当に
return TreeView_InsertItem(hTreeView, &tvis);
}
//ディレクトリであるかどうかの確認
static BOOL IsDirectory(const WIN32_FIND_DATA& wfd)
{
//違う
if(::_tcscmp(wfd.cFileName, TEXT(".")) == 0)
return FALSE;
//違う
if(::_tcscmp(wfd.cFileName, TEXT("..")) == 0)
return FALSE;
//FILE_ATTRIBUTE_DIRECTORYフラグがあればディレクトリ
return (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
}
//ツリービューにディレクトリを追加する
static VOID AddDirectory(HWND hTreeView, LPTSTR sSearchDirectory, LPCTSTR sOption, HTREEITEM hItemParent = NULL, INT level = 0)
{
//再帰は2段階まで
if(level == 2)
return;
//末尾に\が無ければ付け加える
if(sSearchDirectory[::_tcslen(sSearchDirectory) - 1] != TCHAR('\\'))
::_tcscat(sSearchDirectory, TEXT("\\"));
//フルパスと検索コマンドを足した文字を作成する
TCHAR sCmdPath[MAX_PATH];
::_tcscpy(sCmdPath, sSearchDirectory);
::_tcscat(sCmdPath, sOption);
//win32に渡して検索ハンドルを開く
WIN32_FIND_DATA wfd;
HANDLE hSearch = ::FindFirstFile(sCmdPath, &wfd);
//しくじった
if(hSearch == INVALID_HANDLE_VALUE)
{
::FindClose(hSearch);
return;
}
do
{
//ディレクトリであるかどうか
if(::IsDirectory(wfd))
{
//検索パスと見つかったディレクトリ文字を足す
TCHAR sFullPath[MAX_PATH];
::_tcscpy(sFullPath, sSearchDirectory);
::_tcscat(sFullPath, wfd.cFileName);
//パステーブルからsFullPathと一致する項目を検索する
HTREEITEM hTreeItem = ::TreeView_FindItemFromPath(&_S_pathTable, sFullPath);
//まだ登録されていない
if(hTreeItem == NULL)
{
//ツリーアイテムを作成する
hTreeItem = ::AddTreeItem(hTreeView, wfd.cFileName, hItemParent);
//ツリーアイテムとsFullPathをパステーブルに登録する
::TreeView_SavePath(&_S_pathTable, sFullPath, hTreeItem);
}
//再帰する
::AddDirectory(hTreeView, sFullPath, sOption, hTreeItem, level + 1);
}
}while(::FindNextFile(hSearch, &wfd));
//検索ハンドルを閉じる
::FindClose(hSearch);
}
//プロシージャ
int CALLBACK DlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
case WM_INITDIALOG:
{
//ドライブ監査
LPCTSTR sDrives[] = {TEXT("C:\\"), TEXT("D:\\")};
for(INT i = 0; i < sizeof(sDrives) / sizeof(sDrives[0]); ++i)
{
HWND hTreeView = ::GetDlgItem(hDlg, IDC_TREE1);
//作業用バッファに入れる(再帰で利用されるから)
TCHAR sSearchPath[MAX_PATH] = {TCHAR('\0')};
::_tcscpy(sSearchPath, sDrives[i]);
//ドライブのルートツリーアイテム作成
HTREEITEM hTreeItemDrive = ::AddTreeItem(hTreeView, sDrives[i]);
//パスとツリーアイテムハンドルを登録
::TreeView_SavePath(&_S_pathTable, sDrives[i], hTreeItemDrive);
//ドライブ内を検索してディレクトリへ侵入する
::AddDirectory(hTreeView, sSearchPath, TEXT("*.*"), hTreeItemDrive);
}
}
break;
case WM_VSCROLL:
break;
case WM_CLOSE:
::DestroyWindow(hDlg);
break;
case WM_DESTROY:
::TreeView_FreePathTable(&_S_pathTable);
::PostQuitMessage(0);
break;
case WM_NOTIFY:
{
//ツリーアイテムの+ボタンがクリックされたら
LPNMTREEVIEW pnmtv = (LPNMTREEVIEW)lParam;
if(pnmtv->hdr.code == TVN_ITEMEXPANDING)
{
//アイテムに対応したパス文字列を取り出す
LPCTSTR sItemPath = ::TreeView_FindPathFromItem(&_S_pathTable, pnmtv->itemNew.hItem);
//作業用バッファに入れる(再帰で利用されるから)
TCHAR sSearchPath[MAX_PATH] = {TCHAR('\0')};
::_tcscpy(sSearchPath, sItemPath);
//取り出したパスを使用して検索する
::AddDirectory(pnmtv->hdr.hwndFrom, sSearchPath, TEXT("*.*"));
}
}
break;
default:
return FALSE;
}
return TRUE;
}
//見ての通り
int APIENTRY WinMain(HINSTANCE hInst, HINSTANCE hInstPrev, LPSTR lpCmdLine, int nCmdShow)
{
MSG msg;
HWND hWnd = ::CreateDialog(hInst, MAKEINTRESOURCE(IDD_DIALOG1), NULL, DlgProc);
::ShowWindow(hWnd, nCmdShow);
while(GetMessage(&msg, NULL, 0, 0))
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
const INT result = ::_CrtDumpMemoryLeaks();
return msg.wParam;
}
詳細なコードをお示し頂きありがとうございます。
ファイル数が多い場合やフォルダの階層が深い場合にやはり極端に起動が遅く動かなくなる問題があるのですね。
再帰によるフォルダーツリーのコードが無闇に公開されない理由の一端を垣間見た気がします。
当方も以下のスキームを準備していたのですが、ハードディスクを全検索した場合などに問題を生じました。
クリックされる度に動的にツリーを付加するのは実によいアイデアで、大いに参考にさせていただきたいと思います。
どうも有難うございました。
--------------------------------------------------------------
//★ グローバル変数の設定
TV_INSERTSTRUCT tv;
HTREEITEM hParent;
//★ 初期データを設定
void InitTree(HWND hTree, char *pszBasePath)
{
memset((char *)&tv,'\0',sizeof(tv));
tv.hInsertAfter= TVI_LAST;
tv.item.mask= TVIF_TEXT;
SetCurrentDirectory(pszBasePath);
Set_TVdata(hTree, TVI_ROOT);
return;
}
//★ 再起でフォルダを Tree View に展開
void Set_TVdata(HWND hTree, HTREEITEM hPar)
{
HTREEITEM hParent;
WIN32_FIND_DATA fd;
tv.hParent = hPar;
HANDLE hFind = FindFirstFile("*", &fd);
do {
if (lstrcmp(fd.cFileName, "..") != 0 &&
lstrcmpi(fd.cFileName, ".") != 0) {
// ディレクトリの場合
if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
tv.hParent = hPar;
tv.item.pszText= fd.cFileName;
hParent= TreeView_InsertItem(hTree,&tv);
SetCurrentDirectory(fd.cFileName);
// 再帰の起動
Set_TVdata(hTree,hParent);
SetCurrentDirectory("..");
tv.hParent= hPar;
}
// ファイルの場合
else {
tv.item.pszText= fd.cFileName;
TreeView_InsertItem(hTree,&tv);
}
}
} while(FindNextFile(hFind, &fd));
FindClose(hFind);
tv.hParent = hPar;
return;
}
--------------------------------------------------------------
No.2
- 回答日時:
「エクスプローラーを作る」その1~その4(未完成)
http://hp.vector.co.jp/authors/VA016117/winsdk.h …
ぐらいですかね。WC_TREEVIEWで探すと他にもあるかも知れませんが。
ありがとうございます。これも見ましたがシェルインターフェースを使っていて少し難しいです。
もう少しシンプルにFindFirstFile() ~ FindNextFile() を再帰的に呼び出す方法でディレクトリツリーが作成できないかと考えています。
コモンコントロールでツリービューを作る例は多数あるのですが、ディレクトリツリーを最後まで完成したサンプルはなかなか見当たりません。
外国物でもよいのでわかりやすい例があればよろしくお願いします。
No.1
- 回答日時:
C++で良いんでしたら、WTLでの実装例はあります。
http://homepage1.nifty.com/Roy_/Software/WTL/WTL …
それとも直にWin32APIを使っていないとダメですかね?
ありがとうございます。少しコードを眺めましたが難しいですね。
当方WTLは使ったことがないのでWTLの実装と勉強から始めなければならず、出来たら直WIN32APIのサンプルコードがあるとありがたいのですが・・・・
Visual C++ 2008 Express Editionでコンパイルできるサンプルコードを探しています。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- Access(アクセス) AccessVBAで降順にするテーブル作成クエリを使用して作成したテーブルを削除し同一のテーブル作成 1 2023/01/06 11:17
- その他(開発・運用・管理) VisualStudioSetup.exeの設定について(Rustのインストールの準備として) 2 2023/04/17 12:54
- その他(データベース) Accessフォームからパラメーターで表示したレコードを指定のExcelのセルへ転送する方法について 2 2022/08/22 18:04
- MySQL MySQL,JavaScript,PHPコードの結果を表示する方法を教えてください。 1 2023/02/13 17:49
- Word(ワード) PCで作ったwordをスマホで編集しようとすると「このファイルは読み取り専用です。」と表示される。 3 2023/05/30 14:51
- Windows 10 パスを通す 1 2022/09/10 20:01
- Outlook(アウトルック) PCで登録途中の画面から認証コードを確認する方法を教えてください。 3 2022/09/29 06:11
- Excel(エクセル) PHPプログラムをエクセルに張り付けると検索ボックスがでてくる! 3 2022/05/08 07:10
- その他(プログラミング・Web制作) pythonで、tkinterとpillowの組み合わせ 2 2022/08/16 17:42
- Excel(エクセル) Excelで、社外秘(閲覧のみ)と表示され、共有者が編集出来ないのですが 4 2023/06/20 17:54
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
フルパスから最後のディレクト...
-
GetPrivateProfileStringでini...
-
FTPでputすると空ファイルが出...
-
どんなプログラムを書いても指...
-
ExcelVBAでカレントディレクト...
-
ファイルやディレクトリの存在...
-
「UNCパスはサポートされません...
-
フォルダの物が増えたら、自動...
-
C言語からC++の関数をコールす...
-
複数のファイルへの一括処理(...
-
VB2008からDLLを呼出し使いたい。
-
エクセルVBAで相対パスでファイ...
-
VB.NETでWebアプリを作成後に、...
-
[VC]VCのデバッグ実行で落ちる...
-
C言語を用いたファイルの一括削...
-
テキストファイルからApp.Path...
-
マイクラでPythonのプログラミ...
-
windows.hがincludeされない
-
fopenで別ディレクトリにファイ...
-
ExcelVBA サーバーの(共有フォ...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
どんなプログラムを書いても指...
-
フルパスから最後のディレクト...
-
FTPでputすると空ファイルが出...
-
windows.hがincludeされない
-
ExcelVBAでカレントディレクト...
-
「UNCパスはサポートされません...
-
マイクラでPythonのプログラミ...
-
C言語を用いたファイルの一括削...
-
fopenで別ディレクトリにファイ...
-
GetPrivateProfileStringでini...
-
ファイルやディレクトリの存在...
-
ネットワーク上のコンピュータ...
-
ExcelVBA サーバーの(共有フォ...
-
エクセルVBAで相対パスでファイ...
-
pythonでの日本語操作
-
VBAで自身のファイル名を取得す...
-
webアプリケーションでの画像フ...
-
絶対パスの絶対て英語で何でし...
-
FTPでリモートのファイル一覧取得
-
ファイルダイアログのカレント...
おすすめ情報