Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1054 lines
28 KiB

//
// 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;
int cchPath = lstrlen(pszPath) + 1;
LPFILEITEMDATA lpfid = (LPFILEITEMDATA)LocalAlloc(LMEM_FIXED,
sizeof(FILEITEMDATA) + (cchPath*sizeof(TCHAR)) );
if (lpfid)
{
TV_INSERTSTRUCT tvis;
lpfid->dwFlags = dwFlags;
StringCchCopy(lpfid->szPath, cchPath, 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, UINT cchCurDir, 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)
StringCchCat(lpszCurDir, cchCurDir, 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, cchCurDir, 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, ARRAYSIZE(szPathPrgs), NULL, htiPrgs,
FFF_AddDirs | (bAddFiles ? FFF_AddFiles : 0));
//
// Now fill in the rest of the start menu, excluding programs
//
FillFolder(hwndTree, szPathStart, ARRAYSIZE(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,
};
StringCchCopy(szFileDblNull, ARRAYSIZE(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)
{
int cchPath = MAX_PATH;
LPFILEITEMDATA lpfidNew = (LPFILEITEMDATA)LocalAlloc(LMEM_FIXED,
sizeof(LPFILEITEMDATA)+ (cchPath*sizeof(TCHAR)) );
if (lpfidNew)
{
lpfidNew->dwFlags = lpfidOld->dwFlags;
StringCchCopy(lpfidNew->szPath, cchPath, lpfidOld->szPath);
PathRemoveFileSpec(lpfidNew->szPath);
PathCleanupSpec(lpfidNew->szPath, lpszNewName);
if ( PathCombine(lpfidNew->szPath, lpfidNew->szPath, lpszNewName) &&
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)
{
StringCchCopy(ptvdi->item.pszText, ptvdi->item.cchTextMax, fi.szDisplayName);
}
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;
}