1053 lines
27 KiB
C
1053 lines
27 KiB
C
//
|
|
// Folder.C
|
|
//
|
|
// Copyright (C) Microsoft, 1994,1995 All Rights Reserved.
|
|
//
|
|
// History:
|
|
// ral 6/23/94 - First pass
|
|
// 3/20/95 [stevecat] - NT port & real clean up, unicode, etc.
|
|
//
|
|
//
|
|
|
|
#include "priv.h"
|
|
#include "appwiz.h"
|
|
#include "help.h" // Help context IDs
|
|
|
|
typedef struct _FILEITEMDATA {
|
|
DWORD dwFlags;
|
|
TCHAR szPath[1];
|
|
} FILEITEMDATA, * LPFILEITEMDATA;
|
|
|
|
#define FIDFLAG_CANADDNEW 0x00000001
|
|
#define FIDFLAG_CANDEL 0x00000002
|
|
#define FIDFLAG_ISFOLDER 0x00000004
|
|
#define FIDFLAG_ISPROGS 0x00000008
|
|
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
int CALLBACK CompareFolderCB(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
|
|
{
|
|
#define lpfid1 ((LPFILEITEMDATA)lParam1)
|
|
#define lpfid2 ((LPFILEITEMDATA)lParam2)
|
|
#define b1IsDir (lpfid1->dwFlags & FIDFLAG_ISFOLDER)
|
|
#define b2IsDir (lpfid2->dwFlags & FIDFLAG_ISFOLDER)
|
|
|
|
//
|
|
// Programs folder always goes to top
|
|
//
|
|
|
|
if (lpfid1->dwFlags & FIDFLAG_ISPROGS)
|
|
{
|
|
return(-1);
|
|
}
|
|
|
|
if (lpfid2->dwFlags & FIDFLAG_ISPROGS)
|
|
{
|
|
return(1);
|
|
}
|
|
|
|
if (b1IsDir == b2IsDir)
|
|
{
|
|
return(lstrcmpi(lpfid1->szPath, lpfid2->szPath));
|
|
}
|
|
else
|
|
{
|
|
if (b1IsDir)
|
|
{
|
|
return(-1);
|
|
}
|
|
else
|
|
{
|
|
return(1);
|
|
}
|
|
}
|
|
|
|
#undef b1IsDir
|
|
#undef b2IsDir
|
|
#undef lpfid1
|
|
#undef lpfid2
|
|
}
|
|
|
|
|
|
//
|
|
// Sorts the specified folder so that folders appear at the top and all
|
|
// files appear in alphabetical order below.
|
|
//
|
|
|
|
void SortFolder(HWND hwndTree, HTREEITEM hParent)
|
|
{
|
|
TV_SORTCB sSortCB;
|
|
|
|
sSortCB.hParent = hParent;
|
|
sSortCB.lpfnCompare = CompareFolderCB;
|
|
sSortCB.lParam = 0;
|
|
|
|
TreeView_SortChildrenCB(hwndTree, &sSortCB, FALSE);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Adds a new folder for the specifed path and returns its HTREEITEM. If
|
|
// it is unable to add the item then NULL is returned.
|
|
// NOTE: If dwFileAttributes == AI_NOATTRIB (-1) then no attributes specified.
|
|
// If pidl is NULL then no pidl specified.
|
|
//
|
|
|
|
HTREEITEM AddItem(HWND hwndTree, LPCTSTR pszPath,
|
|
HTREEITEM hParent, LPITEMIDLIST pidl,
|
|
DWORD dwFlags)
|
|
{
|
|
HTREEITEM newhti = NULL;
|
|
LPFILEITEMDATA lpfid = (LPFILEITEMDATA)LocalAlloc(LMEM_FIXED,
|
|
sizeof(FILEITEMDATA) + (lstrlen(pszPath) + 1)*sizeof(TCHAR));
|
|
if (lpfid)
|
|
{
|
|
TV_INSERTSTRUCT tvis;
|
|
lpfid->dwFlags = dwFlags;
|
|
lstrcpy(lpfid->szPath, pszPath);
|
|
|
|
tvis.item.pszText = LPSTR_TEXTCALLBACK;
|
|
tvis.item.iImage = tvis.item.iSelectedImage = I_IMAGECALLBACK;
|
|
tvis.item.mask = TVIF_TEXT | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
|
|
tvis.item.lParam = (LPARAM)lpfid;
|
|
|
|
tvis.hParent = hParent;
|
|
tvis.hInsertAfter = TVI_LAST;
|
|
|
|
newhti = TreeView_InsertItem(hwndTree, &tvis);
|
|
if (!newhti)
|
|
LocalFree((LPVOID)lpfid);
|
|
}
|
|
return newhti;
|
|
}
|
|
|
|
//
|
|
// Flags for FillFolder
|
|
//
|
|
|
|
#define FFF_AddFiles 1
|
|
#define FFF_AddDirs 2
|
|
|
|
//
|
|
// Recursively add all folders below CurDir to the tree below hParent
|
|
//
|
|
|
|
BOOL IsFolderShortcut(LPCTSTR pszName)
|
|
{
|
|
SHFOLDERCUSTOMSETTINGS fcs = {0};
|
|
CLSID clsid = {0};
|
|
fcs.dwSize = sizeof(fcs);
|
|
fcs.dwMask = FCSM_CLSID;
|
|
fcs.pclsid = &clsid;
|
|
|
|
if (SUCCEEDED(SHGetSetFolderCustomSettings(&fcs, pszName, FCS_READ)))
|
|
{
|
|
return IsEqualGUID(&clsid, &CLSID_FolderShortcut);
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
void FillFolder(HWND hwndTree, LPTSTR lpszCurDir, LPTSTR lpszExclude,
|
|
HTREEITEM hParent, DWORD dwFlags)
|
|
{
|
|
int iStrTerm = lstrlen(lpszCurDir);
|
|
WIN32_FIND_DATA fd;
|
|
HANDLE hfind;
|
|
HTREEITEM hNewItem = NULL;
|
|
#define bAddFiles (dwFlags & FFF_AddFiles)
|
|
#define bAddDirs (dwFlags & FFF_AddDirs)
|
|
|
|
lstrcat(lpszCurDir, TEXT("\\*.*"));
|
|
|
|
hfind = FindFirstFile(lpszCurDir, &fd);
|
|
|
|
if (hfind != INVALID_HANDLE_VALUE)
|
|
{
|
|
do
|
|
{
|
|
BOOL bIsDir = (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
|
|
|
|
if (((bAddFiles && !bIsDir) ||
|
|
// skip "." and ".." and hidden files
|
|
(bAddDirs && bIsDir && (fd.cFileName[0] != TEXT('.')))) &&
|
|
!(fd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN))
|
|
{
|
|
lpszCurDir[iStrTerm] = TEXT('\\');
|
|
lstrcpy(lpszCurDir + iStrTerm + 1, fd.cFileName);
|
|
|
|
// let's fudge it -- if it's a folder shortcut, don't treat it
|
|
// like a real folder, since we can't navigate into it anyway
|
|
// and it's not worth the trouble to try.
|
|
if (bIsDir && IsFolderShortcut(lpszCurDir))
|
|
{
|
|
bIsDir = FALSE;
|
|
}
|
|
|
|
//
|
|
// Don't add this if it's supposed to be excluded
|
|
//
|
|
|
|
if (!lpszExclude || !bIsDir ||
|
|
lstrcmpi(lpszExclude, lpszCurDir) != 0)
|
|
{
|
|
hNewItem = AddItem(hwndTree, lpszCurDir, hParent, NULL,
|
|
FIDFLAG_CANADDNEW | FIDFLAG_CANDEL |
|
|
(bIsDir ? FIDFLAG_ISFOLDER : 0));
|
|
if (bIsDir)
|
|
{
|
|
FillFolder(hwndTree, lpszCurDir, NULL,
|
|
hNewItem, dwFlags);
|
|
}
|
|
}
|
|
}
|
|
} while (FindNextFile(hfind, &fd));
|
|
|
|
FindClose(hfind);
|
|
}
|
|
|
|
lpszCurDir[iStrTerm] = 0;
|
|
|
|
//
|
|
// Non-null if any items added to folder.
|
|
//
|
|
|
|
if (hNewItem)
|
|
{
|
|
SortFolder(hwndTree, hParent);
|
|
if (!bAddFiles)
|
|
{
|
|
TreeView_Expand(hwndTree, hParent, TVE_EXPAND);
|
|
}
|
|
}
|
|
#undef bAddFiles
|
|
#undef bRecurse
|
|
}
|
|
|
|
|
|
//
|
|
// Returns a pointer to the directory string for the currently selected
|
|
// item.
|
|
//
|
|
|
|
LPFILEITEMDATA GetCurSel(HWND hwndTree, HTREEITEM * lphtiSel)
|
|
{
|
|
TV_ITEM tvi;
|
|
|
|
tvi.hItem = TreeView_GetSelection(hwndTree);
|
|
|
|
if (lphtiSel)
|
|
{
|
|
*lphtiSel = tvi.hItem;
|
|
}
|
|
|
|
if (tvi.hItem == NULL)
|
|
{
|
|
return(NULL);
|
|
}
|
|
|
|
tvi.mask = TVIF_PARAM;
|
|
TreeView_GetItem(hwndTree, &tvi);
|
|
|
|
return((LPFILEITEMDATA)tvi.lParam);
|
|
}
|
|
|
|
|
|
//
|
|
// Add the specified special folder..
|
|
//
|
|
|
|
HTREEITEM AddSpecialFolder(HWND hwndTree, HTREEITEM htiParent, int nFolder,
|
|
LPTSTR pszPath, DWORD dwFlags)
|
|
{
|
|
LPITEMIDLIST pidl = NULL;
|
|
HTREEITEM hti = NULL;
|
|
|
|
if (SUCCEEDED(SHGetSpecialFolderLocation(hwndTree, nFolder, &pidl)))
|
|
{
|
|
if (SHGetPathFromIDList(pidl, pszPath))
|
|
{
|
|
//
|
|
// For the desktop, we want the desktop directory, but the icon
|
|
// for the magic desktop PIDL.
|
|
//
|
|
if (nFolder == CSIDL_DESKTOPDIRECTORY)
|
|
{
|
|
SHFree(pidl);
|
|
if (FAILED(SHGetSpecialFolderLocation(hwndTree, CSIDL_DESKTOP, &pidl)))
|
|
{
|
|
pidl = NULL;
|
|
}
|
|
}
|
|
|
|
if (NULL != pidl)
|
|
{
|
|
hti = AddItem(hwndTree, pszPath, htiParent, pidl,
|
|
FIDFLAG_ISFOLDER | dwFlags);
|
|
}
|
|
}
|
|
}
|
|
if (NULL != pidl)
|
|
{
|
|
SHFree(pidl);
|
|
}
|
|
return(hti);
|
|
}
|
|
|
|
|
|
BOOL _inline MakePrgIcon0Index(HWND hwndTree, HIMAGELIST himl)
|
|
{
|
|
LPITEMIDLIST pidl;
|
|
|
|
if (SUCCEEDED(SHGetSpecialFolderLocation(hwndTree, CSIDL_PROGRAMS, &pidl)))
|
|
{
|
|
SHFILEINFO fi;
|
|
BOOL_PTR fOk = SHGetFileInfo( (LPTSTR) pidl, 0, &fi, sizeof( fi ),
|
|
SHGFI_ICON | SHGFI_SMALLICON | SHGFI_PIDL );
|
|
|
|
SHFree( pidl );
|
|
|
|
if (fOk)
|
|
{
|
|
ImageList_AddIcon(himl, fi.hIcon);
|
|
DestroyIcon(fi.hIcon);
|
|
return(TRUE);
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//
|
|
// Initialize the tree
|
|
//
|
|
|
|
void InitFolderTree( HWND hwndTree, BOOL bAddFiles, HIMAGELIST *phiml )
|
|
{
|
|
HCURSOR hcurOld = SetCursor(LoadCursor(NULL, IDC_WAIT));
|
|
HTREEITEM htiStart = NULL;
|
|
HTREEITEM htiPrgs = NULL;
|
|
TCHAR szPathStart[MAX_PATH];
|
|
TCHAR szPathPrgs[MAX_PATH];
|
|
UINT flags = ILC_MASK | ILC_COLOR32;
|
|
HIMAGELIST himl;
|
|
|
|
if(IS_WINDOW_RTL_MIRRORED(hwndTree))
|
|
{
|
|
flags |= ILC_MIRROR;
|
|
}
|
|
himl = ImageList_Create(GetSystemMetrics(SM_CXSMICON),
|
|
GetSystemMetrics(SM_CYSMICON),
|
|
flags, 10, 1);
|
|
|
|
if (phiml)
|
|
*phiml = himl;
|
|
|
|
if (!himl)
|
|
{
|
|
return;
|
|
}
|
|
|
|
TreeView_SetImageList(hwndTree, himl, TVSIL_NORMAL);
|
|
|
|
//
|
|
// Add the programs folder as index 0. All sub-folders of programs
|
|
// will also have the same icon. This saves both memory and time.
|
|
//
|
|
|
|
if (!MakePrgIcon0Index(hwndTree, himl))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (!bAddFiles)
|
|
{
|
|
AddSpecialFolder(hwndTree, TVI_ROOT, CSIDL_DESKTOPDIRECTORY, szPathStart, 0);
|
|
}
|
|
|
|
htiStart = AddSpecialFolder(hwndTree, TVI_ROOT, CSIDL_STARTMENU, szPathStart, FIDFLAG_CANADDNEW);
|
|
|
|
if (htiStart)
|
|
{
|
|
htiPrgs = AddSpecialFolder(hwndTree, htiStart, CSIDL_PROGRAMS, szPathPrgs, FIDFLAG_CANADDNEW | FIDFLAG_ISPROGS);
|
|
if (htiPrgs)
|
|
{
|
|
FillFolder(hwndTree, szPathPrgs, NULL, htiPrgs,
|
|
FFF_AddDirs | (bAddFiles ? FFF_AddFiles : 0));
|
|
//
|
|
// Now fill in the rest of the start menu, excluding programs
|
|
//
|
|
|
|
FillFolder(hwndTree, szPathStart, szPathPrgs, htiStart,
|
|
FFF_AddDirs | (bAddFiles ? FFF_AddFiles : 0));
|
|
}
|
|
}
|
|
|
|
//
|
|
// Now select and expand the programs folder.
|
|
//
|
|
|
|
if (htiPrgs)
|
|
{
|
|
TreeView_SelectItem(hwndTree, htiPrgs);
|
|
if (bAddFiles)
|
|
{
|
|
TreeView_Expand(hwndTree, htiPrgs, TVE_EXPAND);
|
|
}
|
|
}
|
|
SetCursor(hcurOld);
|
|
}
|
|
|
|
|
|
//
|
|
// Delete Selected Item
|
|
//
|
|
|
|
VOID RemoveSelItem(HWND hDlg, HWND hwndTree)
|
|
{
|
|
HTREEITEM hCur;
|
|
LPFILEITEMDATA lpfid = GetCurSel(hwndTree, &hCur);
|
|
|
|
if (!lpfid)
|
|
{
|
|
ShellMessageBox(g_hinst, hDlg, MAKEINTRESOURCE(IDS_NONESEL),
|
|
0, MB_OK | MB_ICONEXCLAMATION);
|
|
}
|
|
else
|
|
{
|
|
if (lpfid->dwFlags & FIDFLAG_CANDEL)
|
|
{
|
|
TCHAR szFileDblNull[MAX_PATH+1];
|
|
|
|
SHFILEOPSTRUCT sFileOp =
|
|
{
|
|
hDlg,
|
|
FO_DELETE,
|
|
szFileDblNull,
|
|
NULL,
|
|
(lpfid->dwFlags & FIDFLAG_ISFOLDER) ?
|
|
FOF_ALLOWUNDO :
|
|
FOF_SILENT | FOF_ALLOWUNDO,
|
|
};
|
|
|
|
lstrcpy(szFileDblNull, lpfid->szPath);
|
|
|
|
szFileDblNull[lstrlen(szFileDblNull)+1] = 0;
|
|
|
|
if (!SHFileOperation(&sFileOp))
|
|
{
|
|
if (!(sFileOp.fAnyOperationsAborted))
|
|
{
|
|
TreeView_DeleteItem(hwndTree, hCur);
|
|
}
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
ShellMessageBox(g_hinst, hDlg, MAKEINTRESOURCE(IDS_CANTDELETE),
|
|
0, MB_OK | MB_ICONEXCLAMATION, PathFindFileName(lpfid->szPath));
|
|
}
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// END SHARED CODE. BEGIN WIZARD SPECIFIC CODE.
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
//
|
|
// Returns -1 if no item is selected, otherwise, sets lpwd->lpszFolder
|
|
// to point to the appropriate string, and returns 0.
|
|
//
|
|
|
|
LPARAM PickFolderNextHit(LPWIZDATA lpwd)
|
|
{
|
|
LPFILEITEMDATA lpfid = GetCurSel(GetDlgItem(lpwd->hwnd, IDC_FOLDERTREE), NULL);
|
|
|
|
if (lpfid)
|
|
{
|
|
lpwd->lpszFolder = (LPTSTR)&(lpfid->szPath);
|
|
lpwd->szProgDesc[0] = 0;
|
|
return(0);
|
|
}
|
|
else
|
|
{
|
|
return(-1);
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Creates a new, empty folder.
|
|
//
|
|
|
|
VOID CreateNewFolder(LPWIZDATA lpwd)
|
|
{
|
|
TCHAR szNewName[MAX_PATH];
|
|
HTREEITEM hParent;
|
|
LPFILEITEMDATA lpfidParent = GetCurSel(GetDlgItem(lpwd->hwnd, IDC_FOLDERTREE), &hParent);
|
|
|
|
if (lpfidParent && (lpfidParent->dwFlags & FIDFLAG_CANADDNEW))
|
|
{
|
|
int iDirLen = lstrlen(lpfidParent->szPath);
|
|
TCHAR szNewShort[10];
|
|
TCHAR szNewLong[80];
|
|
|
|
LoadString(g_hinst, IDS_NEWFOLDERSHORT, szNewShort, ARRAYSIZE(szNewShort));
|
|
LoadString(g_hinst, IDS_NEWFOLDERLONG, szNewLong, ARRAYSIZE(szNewLong));
|
|
|
|
PathMakeUniqueName(szNewName, ARRAYSIZE(szNewName),
|
|
szNewShort, szNewLong, lpfidParent->szPath);
|
|
if (CreateDirectory(szNewName, NULL))
|
|
{
|
|
HWND hwndTree = GetDlgItem(lpwd->hwnd, IDC_FOLDERTREE);
|
|
HTREEITEM hNewDude = AddItem(hwndTree, szNewName, hParent, NULL,
|
|
FIDFLAG_ISFOLDER | FIDFLAG_CANADDNEW | FIDFLAG_CANDEL);
|
|
|
|
if (hNewDude == NULL)
|
|
{
|
|
TraceMsg(TF_ERROR, "%s", "Unable to add new folder to tree.");
|
|
}
|
|
|
|
if (hNewDude)
|
|
{
|
|
SortFolder(hwndTree, hParent);
|
|
TreeView_SelectItem(hwndTree, hNewDude);
|
|
TreeView_EditLabel(hwndTree, hNewDude);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TraceMsg(TF_ERROR, "%s", "Unable to create new directory");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TraceMsg(TF_ERROR, "%s", "No group selected. Can't create directory.");
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Begin editing a tree label. This function returns FALSE for success, and
|
|
// TRUE for failure.
|
|
//
|
|
|
|
BOOL BeginEdit(LPWIZDATA lpwd, TV_DISPINFO * lptvdi)
|
|
{
|
|
if (TreeView_GetParent(lptvdi->hdr.hwndFrom, lptvdi->item.hItem))
|
|
{
|
|
lpwd->dwFlags |= WDFLAG_INEDITMODE;
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Return FALSE if rename can't happen. True if it worked.
|
|
//
|
|
|
|
BOOL EndEdit(LPWIZDATA lpwd, TV_DISPINFO * lptvdi)
|
|
{
|
|
BOOL bWorked = FALSE;
|
|
#define lpszNewName (LPTSTR)lptvdi->item.pszText
|
|
#define lpfidOld ((LPFILEITEMDATA)(lptvdi->item.lParam))
|
|
#define hCurItem lptvdi->item.hItem;
|
|
|
|
lpwd->dwFlags &= ~WDFLAG_INEDITMODE;
|
|
|
|
if (lpszNewName)
|
|
{
|
|
LPFILEITEMDATA lpfidNew = (LPFILEITEMDATA)LocalAlloc(LMEM_FIXED,
|
|
sizeof(LPFILEITEMDATA)+MAX_PATH*sizeof(TCHAR));
|
|
|
|
if (lpfidNew)
|
|
{
|
|
lpfidNew->dwFlags = lpfidOld->dwFlags;
|
|
|
|
lstrcpy(lpfidNew->szPath, lpfidOld->szPath);
|
|
|
|
PathRemoveFileSpec(lpfidNew->szPath);
|
|
|
|
PathCleanupSpec(lpfidNew->szPath, lpszNewName);
|
|
|
|
PathCombine(lpfidNew->szPath, lpfidNew->szPath, lpszNewName);
|
|
|
|
if (MoveFile(lpfidOld->szPath, lpfidNew->szPath))
|
|
{
|
|
TV_ITEM tvi;
|
|
tvi.hItem = hCurItem;
|
|
tvi.mask = TVIF_PARAM;
|
|
tvi.lParam = (LPARAM)lpfidNew;
|
|
TreeView_SetItem(lptvdi->hdr.hwndFrom, &tvi);
|
|
bWorked = TRUE;
|
|
}
|
|
else
|
|
{
|
|
TraceMsg(TF_ERROR, "%s", "Unable to rename directory");
|
|
}
|
|
LocalFree(bWorked ? lpfidOld : lpfidNew);
|
|
}
|
|
}
|
|
|
|
return(bWorked);
|
|
|
|
#undef lpszNewName
|
|
#undef lpfidOld
|
|
#undef hCurItem
|
|
}
|
|
|
|
|
|
//
|
|
// Called when Next or Back is hit to force the end of label editing.
|
|
//
|
|
|
|
void ForceEndEdit(LPWIZDATA lpwd)
|
|
{
|
|
if (lpwd->dwFlags & WDFLAG_INEDITMODE)
|
|
{
|
|
TreeView_EndEditLabelNow(GetDlgItem(lpwd->hwnd, IDC_FOLDERTREE), FALSE);
|
|
}
|
|
}
|
|
|
|
|
|
void FillInItem(TV_DISPINFO * ptvdi)
|
|
{
|
|
SHFILEINFO fi;
|
|
|
|
#define lpfid ((LPFILEITEMDATA)(ptvdi->item.lParam))
|
|
if (SHGetFileInfo(lpfid->szPath, 0, &fi, sizeof(fi),
|
|
SHGFI_ICON | SHGFI_DISPLAYNAME | SHGFI_SMALLICON))
|
|
{
|
|
if (ptvdi->item.mask & TVIF_IMAGE)
|
|
{
|
|
ptvdi->item.iImage = ptvdi->item.iSelectedImage =
|
|
ImageList_AddIcon(TreeView_GetImageList(ptvdi->hdr.hwndFrom, TVSIL_NORMAL),
|
|
fi.hIcon);
|
|
ptvdi->item.mask |= TVIF_SELECTEDIMAGE;
|
|
}
|
|
|
|
if (ptvdi->item.mask & TVIF_TEXT)
|
|
{
|
|
StrCpyN(ptvdi->item.pszText, fi.szDisplayName, ptvdi->item.cchTextMax);
|
|
}
|
|
|
|
DestroyIcon(fi.hIcon);
|
|
|
|
ptvdi->item.mask |= TVIF_DI_SETITEM;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Main dialog procedure for tree of folders
|
|
//
|
|
|
|
BOOL_PTR CALLBACK PickFolderDlgProc(HWND hDlg, UINT message , WPARAM wParam, LPARAM lParam)
|
|
{
|
|
NMHDR *lpnm = NULL;
|
|
LPPROPSHEETPAGE lpp = (LPPROPSHEETPAGE)(GetWindowLongPtr(hDlg, DWLP_USER));
|
|
LPWIZDATA lpwd = lpp ? (LPWIZDATA)lpp->lParam : NULL;
|
|
|
|
switch(message)
|
|
{
|
|
case WM_NOTIFY:
|
|
lpnm = (NMHDR *)lParam;
|
|
if(lpnm)
|
|
{
|
|
switch(lpnm->code)
|
|
{
|
|
case PSN_SETACTIVE:
|
|
if(lpwd)
|
|
{
|
|
if (lpwd->dwFlags & WDFLAG_LINKHEREWIZ)
|
|
{
|
|
SetDlgMsgResult(hDlg, WM_NOTIFY, -1);
|
|
}
|
|
else
|
|
{
|
|
lpwd->hwnd = hDlg;
|
|
PropSheet_SetWizButtons(GetParent(hDlg),
|
|
(lpwd->dwFlags & WDFLAG_NOBROWSEPAGE) ?
|
|
PSWIZB_NEXT : PSWIZB_BACK | PSWIZB_NEXT);
|
|
|
|
PostMessage(hDlg, WMPRIV_POKEFOCUS, 0, 0);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case PSN_WIZBACK:
|
|
if(lpwd)
|
|
{
|
|
ForceEndEdit(lpwd);
|
|
SetDlgMsgResult(hDlg, WM_NOTIFY, 0);
|
|
}
|
|
break;
|
|
|
|
case PSN_WIZNEXT:
|
|
if(lpwd)
|
|
{
|
|
ForceEndEdit(lpwd);
|
|
SetDlgMsgResult(hDlg, WM_NOTIFY, PickFolderNextHit(lpwd));
|
|
}
|
|
break;
|
|
|
|
case PSN_RESET:
|
|
if(lpwd)
|
|
{
|
|
CleanUpWizData(lpwd);
|
|
}
|
|
break;
|
|
|
|
case NM_DBLCLK:
|
|
PropSheet_PressButton(GetParent(hDlg), PSBTN_NEXT);
|
|
break;
|
|
|
|
#define lpfidNew ((LPFILEITEMDATA)(((LPNM_TREEVIEW)lParam)->itemNew.lParam))
|
|
|
|
case TVN_SELCHANGED:
|
|
Button_Enable(GetDlgItem(hDlg, IDC_NEWFOLDER),
|
|
(lpfidNew->dwFlags & FIDFLAG_CANADDNEW));
|
|
break;
|
|
#undef lpfidNew
|
|
|
|
#define lptvdi ((TV_DISPINFO *)lParam)
|
|
|
|
case TVN_BEGINLABELEDIT:
|
|
if(lpwd)
|
|
{
|
|
SetDlgMsgResult(hDlg, WM_NOTIFY, BeginEdit(lpwd, lptvdi));
|
|
}
|
|
break;
|
|
|
|
case TVN_ENDLABELEDIT:
|
|
if(lpwd)
|
|
{
|
|
SetDlgMsgResult(hDlg, WM_NOTIFY, EndEdit(lpwd, lptvdi));
|
|
}
|
|
break;
|
|
#undef lptvdi
|
|
|
|
#define lptvn ((LPNM_TREEVIEW)lParam)
|
|
|
|
case TVN_ITEMEXPANDING:
|
|
if (lptvn->action != TVE_EXPAND)
|
|
{
|
|
SetDlgMsgResult(hDlg, WM_NOTIFY, -1);
|
|
}
|
|
break;
|
|
|
|
case TVN_DELETEITEM:
|
|
if (lptvn->itemOld.lParam)
|
|
{
|
|
LocalFree((LPVOID)lptvn->itemOld.lParam);
|
|
}
|
|
break;
|
|
#undef lptvn
|
|
|
|
case TVN_GETDISPINFO:
|
|
FillInItem(((TV_DISPINFO *)lParam));
|
|
break;
|
|
|
|
default:
|
|
return FALSE;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case WM_INITDIALOG:
|
|
lpwd = InitWizSheet(hDlg, lParam, 0);
|
|
if(lpwd)
|
|
{
|
|
lpwd->himl = NULL;
|
|
|
|
if( !( lpwd->dwFlags & WDFLAG_LINKHEREWIZ ) )
|
|
{
|
|
InitFolderTree( GetDlgItem( hDlg, IDC_FOLDERTREE ),
|
|
FALSE, &lpwd->himl );
|
|
}
|
|
}
|
|
break;
|
|
|
|
|
|
case WM_NCDESTROY:
|
|
//
|
|
// See if we should destroy the himl...
|
|
//
|
|
|
|
if(lpwd)
|
|
{
|
|
if (lpwd->himl)
|
|
{
|
|
ImageList_Destroy(lpwd->himl);
|
|
lpwd->himl = NULL; // make sure not twice
|
|
}
|
|
}
|
|
return FALSE;
|
|
|
|
|
|
case WMPRIV_POKEFOCUS:
|
|
SetFocus(GetDlgItem(hDlg, IDC_FOLDERTREE));
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
switch (GET_WM_COMMAND_ID(wParam, lParam))
|
|
{
|
|
case IDC_NEWFOLDER:
|
|
if(lpwd)
|
|
{
|
|
CreateNewFolder(lpwd);
|
|
}
|
|
break;
|
|
|
|
/// case IDC_DELFOLDER:
|
|
/// {
|
|
/// HWND hTree = GetDlgItem(hDlg, IDC_FOLDERTREE);
|
|
/// RemoveSelItem(hDlg, hTree);
|
|
/// SetFocus(hTree);
|
|
/// break;
|
|
/// }
|
|
}
|
|
|
|
default:
|
|
return FALSE;
|
|
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// END WIZARD SPECIFIC CODE. BEGIN DELETE ITEM DIALOG CODE.
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
typedef struct _FOLDERTHREADINFO {
|
|
HANDLE hThread;
|
|
HWND hwndTree;
|
|
HIMAGELIST himl;
|
|
} FOLDERTHREADINFO, * PFOLDERTHREADINFO;
|
|
|
|
|
|
void CALLBACK FolderEnumItems(PFOLDERTHREADINFO pfti, HTREEITEM hParent)
|
|
{
|
|
HTREEITEM hitem;
|
|
|
|
hitem = hParent;
|
|
while (hitem && pfti->hThread)
|
|
{
|
|
TV_ITEM tvi;
|
|
tvi.mask = TVIF_IMAGE;
|
|
tvi.hItem = hitem;
|
|
TreeView_GetItem(pfti->hwndTree, &tvi);
|
|
hitem = TreeView_GetNextSibling(pfti->hwndTree, hitem);
|
|
}
|
|
|
|
hitem = TreeView_GetChild(pfti->hwndTree, hParent);
|
|
|
|
while (hitem && pfti->hThread)
|
|
{
|
|
FolderEnumItems(pfti, hitem);
|
|
hitem = TreeView_GetNextSibling(pfti->hwndTree, hitem);
|
|
}
|
|
}
|
|
|
|
|
|
DWORD CALLBACK FolderThread(PFOLDERTHREADINFO pfti)
|
|
{
|
|
HANDLE hThread = pfti->hThread;
|
|
|
|
FolderEnumItems(pfti, TreeView_GetRoot(pfti->hwndTree));
|
|
|
|
CloseHandle(hThread);
|
|
|
|
pfti->hThread = 0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
VOID CreateFolderThread(PFOLDERTHREADINFO pfti)
|
|
{
|
|
//
|
|
// Create background thread to force list view to draw items
|
|
//
|
|
|
|
DWORD idThread;
|
|
|
|
if (pfti->hThread)
|
|
{
|
|
return;
|
|
}
|
|
|
|
pfti->hThread = CreateThread(NULL, 0, FolderThread, pfti, 0, &idThread);
|
|
|
|
if(pfti->hThread)
|
|
{
|
|
SetThreadPriority(pfti->hThread, THREAD_PRIORITY_BELOW_NORMAL);
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Main dialog procedure for delete items dialog.
|
|
//
|
|
|
|
const static DWORD aDelItemHelpIDs[] = { // Context Help IDs
|
|
IDC_TEXT, NO_HELP,
|
|
IDC_FOLDERTREE, IDH_TRAY_REMOVEDLG_LIST,
|
|
IDC_DELETEITEM, IDH_TRAY_REMOVEDLG_DEL,
|
|
|
|
0, 0
|
|
};
|
|
|
|
void WaitForThreadToFinish(HWND hDlg, FOLDERTHREADINFO *pfti)
|
|
{
|
|
if (pfti->hThread)
|
|
{
|
|
SHProcessSentMessagesUntilEvent(hDlg, pfti->hThread, 10000);
|
|
CloseHandle(pfti->hThread);
|
|
pfti->hThread = NULL;
|
|
}
|
|
}
|
|
|
|
BOOL_PTR CALLBACK DelItemDlgProc(HWND hDlg, UINT message , WPARAM wParam, LPARAM lParam)
|
|
{
|
|
PFOLDERTHREADINFO pfti = (PFOLDERTHREADINFO)GetWindowLongPtr(hDlg, DWLP_USER);
|
|
|
|
switch(message)
|
|
{
|
|
case WM_NOTIFY:
|
|
#define lpnm ((NMHDR *)lParam)
|
|
|
|
switch(lpnm->code)
|
|
{
|
|
#define lpfidNew ((LPFILEITEMDATA)(((LPNM_TREEVIEW)lParam)->itemNew.lParam))
|
|
|
|
case TVN_SELCHANGED:
|
|
{
|
|
BOOL fCanDel = (lpfidNew->dwFlags & FIDFLAG_CANDEL);
|
|
HWND hwndDelItem = GetDlgItem(hDlg, IDC_DELETEITEM);
|
|
|
|
if ((!fCanDel) && (GetFocus() == hwndDelItem))
|
|
{
|
|
SetFocus(GetDlgItem(hDlg, IDOK));
|
|
SendMessage(hDlg, DM_SETDEFID, IDOK, 0);
|
|
}
|
|
Button_Enable(hwndDelItem, fCanDel);
|
|
break;
|
|
}
|
|
|
|
#undef lpfidNew
|
|
|
|
#define lptvn ((LPNM_TREEVIEW)lParam)
|
|
|
|
case TVN_DELETEITEM:
|
|
if (lptvn->itemOld.lParam)
|
|
{
|
|
LocalFree((LPVOID)lptvn->itemOld.lParam);
|
|
}
|
|
break;
|
|
|
|
#undef lptvn
|
|
|
|
#define lptkd ((TV_KEYDOWN *)lParam)
|
|
|
|
case TVN_KEYDOWN:
|
|
if (lptkd->wVKey == VK_DELETE)
|
|
{
|
|
WaitForThreadToFinish(hDlg, pfti);
|
|
RemoveSelItem(hDlg, GetDlgItem(hDlg, IDC_FOLDERTREE));
|
|
CreateFolderThread(pfti);
|
|
return TRUE;
|
|
}
|
|
break;
|
|
|
|
#undef lptkd
|
|
|
|
case TVN_GETDISPINFO:
|
|
FillInItem(((TV_DISPINFO *)lParam));
|
|
break;
|
|
|
|
default:
|
|
return FALSE;
|
|
|
|
#undef lpnm
|
|
}
|
|
break;
|
|
|
|
case WM_INITDIALOG:
|
|
|
|
SetWindowLongPtr(hDlg, DWLP_USER, lParam);
|
|
|
|
pfti = (PFOLDERTHREADINFO)lParam;
|
|
|
|
InitFolderTree(GetDlgItem(hDlg, IDC_FOLDERTREE), TRUE, &pfti->himl);
|
|
|
|
pfti->hwndTree = GetDlgItem(hDlg, IDC_FOLDERTREE);
|
|
pfti->hThread = 0;
|
|
|
|
CreateFolderThread(pfti);
|
|
break;
|
|
|
|
case WM_HELP:
|
|
WinHelp((HWND)((LPHELPINFO) lParam)->hItemHandle, NULL,
|
|
HELP_WM_HELP, (DWORD_PTR)(LPTSTR) aDelItemHelpIDs);
|
|
break;
|
|
|
|
case WM_CONTEXTMENU:
|
|
WinHelp((HWND) wParam, NULL, HELP_CONTEXTMENU,
|
|
(DWORD_PTR)(LPVOID) aDelItemHelpIDs);
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
switch (GET_WM_COMMAND_ID(wParam, lParam))
|
|
{
|
|
case IDOK:
|
|
case IDCANCEL:
|
|
WaitForThreadToFinish(hDlg, pfti);
|
|
EndDialog(hDlg, GET_WM_COMMAND_ID(wParam, lParam));
|
|
break;
|
|
|
|
case IDC_DELETEITEM:
|
|
WaitForThreadToFinish(hDlg, pfti);
|
|
|
|
RemoveSelItem(hDlg, GetDlgItem(hDlg, IDC_FOLDERTREE));
|
|
CreateFolderThread(pfti);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
return FALSE;
|
|
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL RemoveItemsDialog( HWND hParent )
|
|
{
|
|
BOOL fReturn;
|
|
|
|
FOLDERTHREADINFO fti;
|
|
|
|
fti.himl = NULL; // incase we can not create the window
|
|
|
|
fReturn = (int)DialogBoxParam( g_hinst, MAKEINTRESOURCE( DLG_DELITEM ),
|
|
hParent, DelItemDlgProc, (LPARAM) &fti );
|
|
|
|
if( fti.himl )
|
|
ImageList_Destroy( fti.himl );
|
|
|
|
return fReturn;
|
|
}
|