878 lines
26 KiB
C
878 lines
26 KiB
C
//###########################################################################
|
|
// Code for the Browse For Starting Folder
|
|
//###########################################################################
|
|
// Structure to pass information to browse for folder dialog
|
|
typedef struct _bfsf
|
|
{
|
|
HWND hwndOwner;
|
|
LPCITEMIDLIST pidlRoot; // Root of search. Typically desktop or my net
|
|
LPSTR pszDisplayName;// Return display name of item selected.
|
|
int *piImage; // where to return the Image index.
|
|
LPCSTR lpszTitle; // resource (or text to go in the banner over the tree.
|
|
UINT ulFlags; // Flags that control the return stuff
|
|
BFFCALLBACK lpfn;
|
|
LPARAM lParam;
|
|
HWND hwndDlg; // The window handle to the dialog
|
|
HWND hwndTree; // The tree control.
|
|
HTREEITEM htiCurParent; // tree item associated with Current shell folder
|
|
IShellFolder * psfParent; // Cache of the last IShell folder I needed...
|
|
LPITEMIDLIST pidlCurrent; // IDlist of current folder to select
|
|
BOOL fShowAllObjects; // Should we Show all ?
|
|
} BFSF, *PBFSF;
|
|
|
|
|
|
BOOL CALLBACK _BFSFDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
|
|
LPITEMIDLIST _BFSFUpdateISHCache(PBFSF pbfsf, HTREEITEM hti, LPITEMIDLIST pidlItem);
|
|
|
|
|
|
// _BrowseForStartingFolder - Browse for a folder to start the
|
|
// search from.
|
|
|
|
|
|
|
|
// BUGBUG, give them a way to turn off the ok button.
|
|
|
|
LPITEMIDLIST WINAPI SHBrowseForFolder(LPBROWSEINFO lpbi)
|
|
{
|
|
LPITEMIDLIST lpRet;
|
|
BFSF bfsf =
|
|
{
|
|
lpbi->hwndOwner,
|
|
lpbi->pidlRoot,
|
|
lpbi->pszDisplayName,
|
|
&lpbi->iImage,
|
|
lpbi->lpszTitle,
|
|
lpbi->ulFlags,
|
|
lpbi->lpfn,
|
|
lpbi->lParam,
|
|
};
|
|
HCURSOR hcOld = SetCursor(LoadCursor(NULL,IDC_WAIT));
|
|
SHELLSTATE ss;
|
|
|
|
SHGetSetSettings(&ss, SSF_SHOWALLOBJECTS, FALSE);
|
|
bfsf.fShowAllObjects = ss.fShowAllObjects;
|
|
|
|
// Now Create the dialog that will be doing the browsing.
|
|
if (DialogBoxParam(HINST_THISDLL, MAKEINTRESOURCE(DLG_BROWSEFORFOLDER),
|
|
lpbi->hwndOwner, _BFSFDlgProc, (LPARAM)&bfsf))
|
|
lpRet = bfsf.pidlCurrent;
|
|
else
|
|
lpRet = NULL;
|
|
|
|
if (hcOld)
|
|
SetCursor(hcOld);
|
|
|
|
return lpRet;
|
|
}
|
|
|
|
void BFSFCallback(PBFSF pbfsf, UINT uMsg, LPARAM lParam)
|
|
{
|
|
if (pbfsf->lpfn) {
|
|
pbfsf->lpfn(pbfsf->hwndDlg, uMsg, lParam, pbfsf->lParam);
|
|
}
|
|
}
|
|
|
|
|
|
// Some helper functions for processing the dialog
|
|
|
|
HTREEITEM _AddItemToTree(HWND hwndTree, HTREEITEM htiParent, LPITEMIDLIST pidl, int cChildren)
|
|
{
|
|
TV_INSERTSTRUCT tii;
|
|
|
|
// Initialize item to add with callback for everything
|
|
tii.item.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE |
|
|
TVIF_PARAM | TVIF_CHILDREN;
|
|
tii.hParent = htiParent;
|
|
tii.hInsertAfter = TVI_FIRST;
|
|
tii.item.iImage = I_IMAGECALLBACK;
|
|
tii.item.iSelectedImage = I_IMAGECALLBACK;
|
|
tii.item.pszText = LPSTR_TEXTCALLBACK; //
|
|
tii.item.cChildren = cChildren; // Assume it has children
|
|
tii.item.lParam = (LPARAM)pidl;
|
|
|
|
return TreeView_InsertItem(hwndTree, &tii);
|
|
}
|
|
|
|
|
|
LPITEMIDLIST _GetIDListFromTreeItem(HWND hwndTree, HTREEITEM hti)
|
|
{
|
|
LPITEMIDLIST pidl;
|
|
LPITEMIDLIST pidlT;
|
|
TV_ITEM tvi;
|
|
|
|
// If no hti passed in, get the selected on.
|
|
if (hti == NULL)
|
|
{
|
|
hti = TreeView_GetSelection(hwndTree);
|
|
if (hti == NULL)
|
|
return(NULL);
|
|
}
|
|
|
|
// now lets get the information about the item
|
|
tvi.mask = TVIF_PARAM | TVIF_HANDLE;
|
|
tvi.hItem = hti;
|
|
if (!TreeView_GetItem(hwndTree, &tvi))
|
|
return NULL; // Failed again
|
|
|
|
pidl = ILClone((LPITEMIDLIST)tvi.lParam);
|
|
|
|
// Now walk up parents.
|
|
while ((tvi.hItem = TreeView_GetParent(hwndTree, tvi.hItem)) && pidl)
|
|
{
|
|
if (!TreeView_GetItem(hwndTree, &tvi))
|
|
return(pidl); // will assume I messed up...
|
|
pidlT = ILCombine((LPITEMIDLIST)tvi.lParam, pidl);
|
|
|
|
ILFree(pidl);
|
|
|
|
pidl = pidlT;
|
|
|
|
}
|
|
return(pidl);
|
|
}
|
|
|
|
|
|
int CALLBACK _BFSFTreeCompare(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
|
|
{
|
|
IShellFolder *psfParent = (IShellFolder *)lParamSort;
|
|
HRESULT hres = psfParent->lpVtbl->CompareIDs(psfParent, 0, (LPITEMIDLIST)lParam1, (LPITEMIDLIST)lParam2);
|
|
|
|
Assert(SUCCEEDED(hres));
|
|
|
|
return (short)SCODE_CODE(GetScode(hres));
|
|
}
|
|
|
|
void _BFSFSort(PBFSF pbfsf, HTREEITEM hti, IShellFolder * psf)
|
|
{
|
|
TV_SORTCB sSortCB;
|
|
|
|
sSortCB.hParent = hti;
|
|
sSortCB.lpfnCompare = _BFSFTreeCompare;
|
|
|
|
psf->lpVtbl->AddRef(psf);
|
|
sSortCB.lParam = (LPARAM)psf;
|
|
TreeView_SortChildrenCB(pbfsf->hwndTree, &sSortCB, FALSE);
|
|
psf->lpVtbl->Release(psf);
|
|
}
|
|
|
|
|
|
BOOL _BFSFHandleItemExpanding(PBFSF pbfsf, LPNM_TREEVIEW pnmtv)
|
|
{
|
|
LPITEMIDLIST pidlToExpand;
|
|
LPITEMIDLIST pidl;
|
|
IShellFolder * psf;
|
|
IShellFolder * psfDesktop = Desktop_GetShellFolder(TRUE);
|
|
BYTE bType;
|
|
DWORD grfFlags;
|
|
BOOL fPrinterTest = FALSE;
|
|
int cAdded = 0;
|
|
TV_ITEM tvi;
|
|
|
|
IEnumIDList * penum; // Enumerator in use.
|
|
|
|
if (pnmtv->action != TVE_EXPAND)
|
|
return FALSE;
|
|
|
|
if ((pnmtv->itemNew.state & TVIS_EXPANDEDONCE))
|
|
return FALSE;
|
|
|
|
// set this bit now because we might be reentered via the wnet apis
|
|
tvi.mask = TVIF_STATE;
|
|
tvi.hItem = pnmtv->itemNew.hItem;
|
|
tvi.state = TVIS_EXPANDEDONCE;
|
|
tvi.stateMask = TVIS_EXPANDEDONCE;
|
|
TreeView_SetItem(pbfsf->hwndTree, &tvi);
|
|
|
|
|
|
if (pnmtv->itemNew.hItem == NULL)
|
|
{
|
|
pnmtv->itemNew.hItem = TreeView_GetSelection(pbfsf->hwndTree);
|
|
if (pnmtv->itemNew.hItem == NULL)
|
|
return FALSE;
|
|
}
|
|
|
|
pidlToExpand = _GetIDListFromTreeItem(pbfsf->hwndTree, pnmtv->itemNew.hItem);
|
|
|
|
if (pidlToExpand == NULL)
|
|
return FALSE;
|
|
|
|
// Now lets get the IShellFolder and iterator for this object
|
|
// special case to handle if the Pidl is the desktop
|
|
// This is rather gross, but the desktop appears to be simply a pidl
|
|
// of length 0 and ILIsEqual will not work...
|
|
if (pidlToExpand->mkid.cb == 0)
|
|
{
|
|
psf = psfDesktop;
|
|
psfDesktop->lpVtbl->AddRef(psf);
|
|
}
|
|
else
|
|
{
|
|
if (FAILED(psfDesktop->lpVtbl->BindToObject(psfDesktop,
|
|
pidlToExpand, NULL, &IID_IShellFolder, &psf)))
|
|
{
|
|
ILFree(pidlToExpand);
|
|
return FALSE; // Could not get IShellFolder.
|
|
}
|
|
}
|
|
|
|
// Need to do a couple of special cases here to allow us to
|
|
// browse for a network printer. In this case if we are at server
|
|
// level we then need to change what we search for non folders when
|
|
// we are the level of a server.
|
|
if (pbfsf->ulFlags & BIF_BROWSEFORPRINTER)
|
|
{
|
|
grfFlags = SHCONTF_FOLDERS | SHCONTF_NETPRINTERSRCH;
|
|
pidl = ILFindLastID(pidlToExpand);
|
|
bType = SIL_GetType(pidl);
|
|
fPrinterTest = ((bType & (SHID_NET|SHID_INGROUPMASK))==SHID_NET_SERVER);
|
|
if (fPrinterTest)
|
|
grfFlags |= SHCONTF_NONFOLDERS;
|
|
}
|
|
else
|
|
grfFlags = SHCONTF_FOLDERS;
|
|
|
|
if (pbfsf->fShowAllObjects)
|
|
grfFlags |= SHCONTF_INCLUDEHIDDEN;
|
|
|
|
|
|
|
|
if (FAILED(psf->lpVtbl->EnumObjects(psf, pbfsf->hwndDlg, grfFlags, &penum)))
|
|
{
|
|
psf->lpVtbl->Release(psf);
|
|
ILFree(pidlToExpand);
|
|
return FALSE;
|
|
}
|
|
// psf->lpVtbl->AddRef(psf);
|
|
|
|
while (pidl = _NextIDL(psf, penum))
|
|
{
|
|
int cChildren = I_CHILDRENCALLBACK; // Do call back for children
|
|
//
|
|
// We need to special case here in the netcase where we onlyu
|
|
// browse down to workgroups...
|
|
//
|
|
//
|
|
// Here is where I also need to special case to not go below
|
|
// workgroups when the appropriate option is set.
|
|
//
|
|
bType = SIL_GetType(pidl);
|
|
if ((pbfsf->ulFlags & BIF_DONTGOBELOWDOMAIN) && (bType & SHID_NET))
|
|
{
|
|
switch (bType & (SHID_NET | SHID_INGROUPMASK))
|
|
{
|
|
case SHID_NET_SERVER:
|
|
ILFree(pidl); // Dont want to add this one
|
|
continue; // Try the next one
|
|
case SHID_NET_DOMAIN:
|
|
cChildren = 0; // Force to not have children;
|
|
}
|
|
}
|
|
|
|
else if ((pbfsf->ulFlags & BIF_BROWSEFORCOMPUTER) && (bType & SHID_NET))
|
|
{
|
|
if ((bType & (SHID_NET | SHID_INGROUPMASK)) == SHID_NET_SERVER)
|
|
cChildren = 0; // Don't expand below it...
|
|
}
|
|
else if (fPrinterTest)
|
|
{
|
|
// Special case when we are only allowing printers.
|
|
// for now I will simply key on the fact that it is non-FS.
|
|
ULONG ulAttr = SFGAO_FILESYSTEM;
|
|
|
|
psf->lpVtbl->GetAttributesOf(psf, 1, &pidl, &ulAttr);
|
|
|
|
if ((ulAttr & SFGAO_FILESYSTEM)== 0)
|
|
{
|
|
cChildren = 0; // Force to not have children;
|
|
}
|
|
else
|
|
{
|
|
ILFree(pidl); // Dont want to add this one
|
|
continue; // Try the next one
|
|
}
|
|
}
|
|
|
|
_AddItemToTree(pbfsf->hwndTree, pnmtv->itemNew.hItem,
|
|
pidl, cChildren);
|
|
cAdded++;
|
|
}
|
|
|
|
// Now Cleanup after ourself
|
|
penum->lpVtbl->Release(penum);
|
|
|
|
_BFSFSort(pbfsf, pnmtv->itemNew.hItem, psf);
|
|
psf->lpVtbl->Release(psf);
|
|
ILFree(pidlToExpand);
|
|
|
|
// If we did not add anything we should update this item to let
|
|
// the user know something happened.
|
|
//
|
|
if (cAdded == 0)
|
|
{
|
|
TV_ITEM tvi;
|
|
tvi.mask = TVIF_CHILDREN | TVIF_HANDLE; // only change the number of children
|
|
tvi.hItem = pnmtv->itemNew.hItem;
|
|
tvi.cChildren = 0;
|
|
|
|
TreeView_SetItem(pbfsf->hwndTree, &tvi);
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
void _BFSFHandleDeleteItem(PBFSF pbfsf, LPNM_TREEVIEW pnmtv)
|
|
{
|
|
// We need to free the IDLists that we allocated previously
|
|
if (pnmtv->itemOld.lParam != 0)
|
|
ILFree((LPITEMIDLIST)pnmtv->itemOld.lParam);
|
|
}
|
|
|
|
|
|
LPITEMIDLIST _BFSFUpdateISHCache(PBFSF pbfsf, HTREEITEM hti,
|
|
LPITEMIDLIST pidlItem)
|
|
{
|
|
HTREEITEM htiParent;
|
|
IShellFolder * psfDesktop = Desktop_GetShellFolder(TRUE);
|
|
|
|
if (pidlItem == NULL)
|
|
return(NULL);
|
|
|
|
// Need to handle the root case here!
|
|
htiParent = TreeView_GetParent(pbfsf->hwndTree, hti);
|
|
if ((htiParent != pbfsf->htiCurParent) || (pbfsf->psfParent == NULL))
|
|
{
|
|
LPITEMIDLIST pidl;
|
|
|
|
if (pbfsf->psfParent)
|
|
{
|
|
|
|
if (pbfsf->psfParent != psfDesktop)
|
|
pbfsf->psfParent->lpVtbl->Release(pbfsf->psfParent);
|
|
pbfsf->psfParent = NULL;
|
|
}
|
|
|
|
if (htiParent)
|
|
{
|
|
pidl = _GetIDListFromTreeItem(pbfsf->hwndTree, htiParent);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// If No Parent then the item here is one of our roots which
|
|
// should be fully qualified. So try to get the parent by
|
|
// decomposing the ID.
|
|
//
|
|
LPITEMIDLIST pidlT = (LPITEMIDLIST)ILFindLastID(pidlItem);
|
|
if (pidlT != pidlItem)
|
|
{
|
|
pidl = ILClone(pidlItem);
|
|
ILRemoveLastID(pidl);
|
|
pidlItem = pidlT;
|
|
}
|
|
else
|
|
pidl = NULL;
|
|
}
|
|
|
|
pbfsf->htiCurParent = htiParent;
|
|
|
|
// If still NULL then we use root of evil...
|
|
if (pidl == NULL || (pidl->mkid.cb == 0))
|
|
{
|
|
// Still one m
|
|
pbfsf->psfParent = psfDesktop;
|
|
|
|
if (pidl)
|
|
ILFree(pidl);
|
|
}
|
|
|
|
else
|
|
{
|
|
psfDesktop->lpVtbl->BindToObject(psfDesktop,
|
|
pidl, NULL, &IID_IShellFolder, &pbfsf->psfParent);
|
|
ILFree(pidl);
|
|
|
|
if (pbfsf->psfParent == NULL)
|
|
return NULL;
|
|
}
|
|
}
|
|
return(ILFindLastID(pidlItem));
|
|
}
|
|
|
|
|
|
|
|
void _BFSFGetDisplayInfo(PBFSF pbfsf, TV_DISPINFO *pnm)
|
|
{
|
|
TV_ITEM ti;
|
|
LPITEMIDLIST pidlItem = (LPITEMIDLIST)pnm->item.lParam;
|
|
|
|
if ((pnm->item.mask & (TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_TEXT | TVIF_CHILDREN)) == 0)
|
|
return; // nothing for us to do here.
|
|
|
|
pidlItem = _BFSFUpdateISHCache(pbfsf, pnm->item.hItem, pidlItem);
|
|
|
|
ti.mask = 0;
|
|
ti.hItem = (HTREEITEM)pnm->item.hItem;
|
|
|
|
// They are asking for IconIndex. See if we can find it now.
|
|
// Once found update their list, such that they wont call us back for
|
|
// it again.
|
|
if (pnm->item.mask & (TVIF_IMAGE | TVIF_SELECTEDIMAGE))
|
|
{
|
|
// We now need to map the item into the right image index.
|
|
ti.iImage = pnm->item.iImage = SHMapPIDLToSystemImageListIndex(
|
|
pbfsf->psfParent, pidlItem, &ti.iSelectedImage);
|
|
// we should save it back away to
|
|
pnm->item.iSelectedImage = ti.iSelectedImage;
|
|
ti.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE;
|
|
}
|
|
// Also see if this guy has any child folders
|
|
if (pnm->item.mask & TVIF_CHILDREN)
|
|
{
|
|
ULONG ulAttrs;
|
|
|
|
ulAttrs = SFGAO_HASSUBFOLDER;
|
|
pbfsf->psfParent->lpVtbl->GetAttributesOf(pbfsf->psfParent,
|
|
1, &pidlItem, &ulAttrs);
|
|
|
|
ti.cChildren = pnm->item.cChildren =
|
|
(ulAttrs & SFGAO_HASSUBFOLDER)? 1 : 0;
|
|
|
|
ti.mask |= TVIF_CHILDREN;
|
|
|
|
}
|
|
|
|
if (pnm->item.mask & TVIF_TEXT)
|
|
{
|
|
STRRET str;
|
|
pbfsf->psfParent->lpVtbl->GetDisplayNameOf(pbfsf->psfParent,
|
|
pidlItem, SHGDN_INFOLDER, &str);
|
|
|
|
StrRetToStrN(pnm->item.pszText, pnm->item.cchTextMax, &str, pidlItem);
|
|
ti.mask |= TVIF_TEXT;
|
|
ti.pszText = pnm->item.pszText;
|
|
}
|
|
|
|
// Update the item now
|
|
TreeView_SetItem(pbfsf->hwndTree, &ti);
|
|
}
|
|
|
|
|
|
void _BFSFHandleSelChanged(PBFSF pbfsf, LPNM_TREEVIEW pnmtv)
|
|
{
|
|
LPITEMIDLIST pidl;
|
|
ULONG ulAttrs = SFGAO_FILESYSTEM;
|
|
BYTE bType;
|
|
|
|
// We only need to do anything if we only want to return File system
|
|
// level objects.
|
|
if ((pbfsf->ulFlags & (BIF_RETURNONLYFSDIRS|BIF_RETURNFSANCESTORS|BIF_BROWSEFORPRINTER|BIF_BROWSEFORCOMPUTER)) == 0)
|
|
goto NotifySelChange;
|
|
|
|
// We need to get the attributes of this object...
|
|
pidl = _BFSFUpdateISHCache(pbfsf, pnmtv->itemNew.hItem,
|
|
(LPITEMIDLIST)pnmtv->itemNew.lParam);
|
|
|
|
if (pidl)
|
|
{
|
|
BOOL fEnable;
|
|
|
|
bType = SIL_GetType(pidl);
|
|
if ((pbfsf->ulFlags & (BIF_RETURNFSANCESTORS|BIF_RETURNONLYFSDIRS)) != 0)
|
|
{
|
|
int i;
|
|
// if this is the root pidl, then do a get attribs on 0
|
|
// so that we'll get the attributes on the root, rather than
|
|
// random returned values returned by FSFolder
|
|
if (ILIsEmpty(pidl)) {
|
|
i = 0;
|
|
} else
|
|
i = 1;
|
|
|
|
pbfsf->psfParent->lpVtbl->GetAttributesOf(pbfsf->psfParent,
|
|
i, &pidl, &ulAttrs);
|
|
|
|
fEnable = (((ulAttrs & SFGAO_FILESYSTEM) && (pbfsf->ulFlags & BIF_RETURNONLYFSDIRS)) ||
|
|
((ulAttrs & SFGAO_FILESYSANCESTOR) && (pbfsf->ulFlags & BIF_RETURNFSANCESTORS))) ||
|
|
((bType & (SHID_NET | SHID_INGROUPMASK)) == SHID_NET_SERVER);
|
|
}
|
|
else if ((pbfsf->ulFlags & BIF_BROWSEFORCOMPUTER) != 0)
|
|
fEnable = ((bType & (SHID_NET | SHID_INGROUPMASK)) == SHID_NET_SERVER);
|
|
else if ((pbfsf->ulFlags & BIF_BROWSEFORPRINTER) != 0)
|
|
{
|
|
// Printers are of type Share and usage Print...
|
|
fEnable = ((bType & (SHID_NET | SHID_INGROUPMASK)) == SHID_NET_SHARE);
|
|
}
|
|
|
|
EnableWindow(GetDlgItem(pbfsf->hwndDlg, IDOK),fEnable);
|
|
|
|
}
|
|
|
|
NotifySelChange:
|
|
if (pbfsf->lpfn) {
|
|
pidl = _GetIDListFromTreeItem(pbfsf->hwndTree, pnmtv->itemNew.hItem);
|
|
BFSFCallback(pbfsf, BFFM_SELCHANGED, (LPARAM)pidl);
|
|
ILFree(pidl);
|
|
}
|
|
}
|
|
|
|
BOOL BrowseSelectPidl(PBFSF pbfsf, LPCITEMIDLIST pidl)
|
|
{
|
|
HTREEITEM htiParent;
|
|
LPITEMIDLIST pidlTemp;
|
|
LPITEMIDLIST pidlNext = NULL;
|
|
LPITEMIDLIST pidlParent = NULL;
|
|
BOOL fRet = FALSE;
|
|
|
|
htiParent = TreeView_GetChild(pbfsf->hwndTree, NULL);
|
|
if (htiParent) {
|
|
|
|
// step through each item of the pidl
|
|
for (;;) {
|
|
TreeView_Expand(pbfsf->hwndTree, htiParent, TVE_EXPAND);
|
|
pidlParent = _GetIDListFromTreeItem(pbfsf->hwndTree, htiParent);
|
|
if (!pidlParent)
|
|
break;
|
|
|
|
pidlNext = ILClone(pidl);
|
|
if (!pidlNext)
|
|
break;
|
|
|
|
pidlTemp = ILFindChild(pidlParent, pidlNext);
|
|
if (!pidlTemp)
|
|
break;
|
|
|
|
if (ILIsEmpty(pidlTemp)) {
|
|
// found it!
|
|
//
|
|
TreeView_SelectItem(pbfsf->hwndTree, htiParent);
|
|
fRet = TRUE;
|
|
break;
|
|
} else {
|
|
// loop to find the next item
|
|
HTREEITEM htiChild;
|
|
|
|
pidlTemp = ILGetNext(pidlTemp);
|
|
if (!pidlTemp)
|
|
break;
|
|
else
|
|
pidlTemp->mkid.cb = 0;
|
|
|
|
|
|
htiChild = TreeView_GetChild(pbfsf->hwndTree, htiParent);
|
|
while (htiChild) {
|
|
BOOL fEqual;
|
|
pidlTemp = _GetIDListFromTreeItem(pbfsf->hwndTree, htiChild);
|
|
if (!pidlTemp) {
|
|
htiChild = NULL;
|
|
break;
|
|
}
|
|
fEqual = ILIsEqual(pidlTemp, pidlNext);
|
|
|
|
ILFree(pidlTemp);
|
|
if (fEqual) {
|
|
break;
|
|
} else {
|
|
htiChild = TreeView_GetNextSibling(pbfsf->hwndTree, htiChild);
|
|
}
|
|
}
|
|
|
|
if (!htiChild) {
|
|
// we didn't find the next one... bail
|
|
break;
|
|
} else {
|
|
// the found child becomes the next parent
|
|
htiParent = htiChild;
|
|
ILFree(pidlParent);
|
|
ILFree(pidlNext);
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
if (pidlParent) ILFree(pidlParent);
|
|
if (pidlNext) ILFree(pidlNext);
|
|
return fRet;
|
|
}
|
|
|
|
|
|
// _BFSFOnInitDlg - Process the init dialog
|
|
|
|
BOOL _BFSFOnInitDlg(HWND hwnd, HWND hwndFocus, LPARAM lParam)
|
|
{
|
|
HTREEITEM hti;
|
|
PBFSF pbfsf = (PBFSF)lParam;
|
|
HIMAGELIST himl;
|
|
LPSTR lpsz;
|
|
char szTitle[80]; // no title should be bigger than this!
|
|
HWND hwndTree;
|
|
|
|
lpsz = ResourceCStrToStr(HINST_THISDLL, pbfsf->lpszTitle);
|
|
SetDlgItemText(hwnd, IDD_BROWSETITLE, lpsz);
|
|
if (lpsz != pbfsf->lpszTitle)
|
|
{
|
|
LocalFree(lpsz);
|
|
lpsz = NULL;
|
|
}
|
|
|
|
|
|
SetWindowLong(hwnd, DWL_USER, (LONG)lParam);
|
|
pbfsf->hwndDlg = hwnd;
|
|
hwndTree = pbfsf->hwndTree = GetDlgItem(hwnd, IDD_FOLDERLIST);
|
|
|
|
if (hwndTree)
|
|
{
|
|
UINT swpFlags = SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER
|
|
| SWP_NOACTIVATE;
|
|
RECT rc;
|
|
POINT pt = {0,0};
|
|
|
|
if (!(pbfsf->ulFlags & BIF_STATUSTEXT)) {
|
|
HWND hwndStatus = GetDlgItem(hwnd, IDD_BROWSESTATUS);
|
|
// nuke the status window
|
|
ShowWindow(hwndStatus, SW_HIDE);
|
|
MapWindowPoints(hwndStatus, hwnd, &pt, 1);
|
|
GetClientRect(hwndTree, &rc);
|
|
MapWindowPoints(hwndTree, hwnd, (POINT*)&rc, 2);
|
|
rc.top = pt.y;
|
|
swpFlags = SWP_FRAMECHANGED | SWP_NOZORDER | SWP_NOACTIVATE;
|
|
}
|
|
|
|
Shell_GetImageLists(NULL, &himl);
|
|
TreeView_SetImageList(hwndTree, himl, TVSIL_NORMAL);
|
|
|
|
SetWindowLong(hwndTree, GWL_EXSTYLE,
|
|
GetWindowLong(hwndTree, GWL_EXSTYLE) | WS_EX_CLIENTEDGE);
|
|
|
|
// Now try to get this window to know to recalc
|
|
SetWindowPos(hwndTree, NULL, rc.left, rc.top,
|
|
rc.right - rc.left, rc.bottom - rc.top, swpFlags);
|
|
|
|
}
|
|
|
|
// If they passed in a root, add it, else add the contents of the
|
|
// Root of evil... to the list as ROOT objects.
|
|
if (pbfsf->pidlRoot)
|
|
{
|
|
LPITEMIDLIST pidl;
|
|
if (!HIWORD(pbfsf->pidlRoot)) {
|
|
pidl = SHCloneSpecialIDList(NULL, (UINT)pbfsf->pidlRoot, TRUE);
|
|
} else {
|
|
pidl = ILClone(pbfsf->pidlRoot);
|
|
}
|
|
// Now lets insert the Root object
|
|
hti = _AddItemToTree(hwndTree, TVI_ROOT, pidl, 1);
|
|
// Still need to expand below this point. to the starting location
|
|
// That was passed in. But for now expand the first level.
|
|
TreeView_Expand(hwndTree, hti, TVE_EXPAND);
|
|
}
|
|
else
|
|
{
|
|
LPCITEMIDLIST pidlDrives = GetSpecialFolderIDList(NULL, CSIDL_DRIVES, FALSE);
|
|
LPITEMIDLIST pidlDesktop = SHCloneSpecialIDList(NULL, CSIDL_DESKTOP, FALSE);
|
|
HTREEITEM htiRoot = _AddItemToTree(hwndTree, TVI_ROOT, pidlDesktop, 1);
|
|
|
|
// Expand the first level under the desktop
|
|
TreeView_Expand(hwndTree, htiRoot, TVE_EXPAND);
|
|
|
|
// Lets Preexpand the Drives portion....
|
|
hti = TreeView_GetChild(hwndTree, htiRoot);
|
|
while (hti)
|
|
{
|
|
LPITEMIDLIST pidl = _GetIDListFromTreeItem(hwndTree, hti);
|
|
if (ILIsEqual(pidl, pidlDrives))
|
|
{
|
|
|
|
TreeView_Expand(hwndTree, hti, TVE_EXPAND);
|
|
|
|
TreeView_SelectItem(hwndTree, hti);
|
|
ILFree(pidl);
|
|
break;
|
|
}
|
|
ILFree(pidl);
|
|
hti = TreeView_GetNextSibling(hwndTree, hti);
|
|
}
|
|
}
|
|
|
|
// go to our internal selection changed code to do any window enabling needed
|
|
{
|
|
NM_TREEVIEW nmtv;
|
|
hti = TreeView_GetSelection(hwndTree);
|
|
if (hti) {
|
|
TV_ITEM ti;
|
|
ti.mask = TVIF_PARAM;
|
|
ti.hItem = hti;
|
|
TreeView_GetItem(hwndTree, &ti);
|
|
nmtv.itemNew.hItem = hti;
|
|
nmtv.itemNew.lParam = ti.lParam;
|
|
|
|
_BFSFHandleSelChanged(pbfsf, &nmtv);
|
|
}
|
|
}
|
|
|
|
if ((pbfsf->ulFlags & BIF_BROWSEFORCOMPUTER) != 0)
|
|
{
|
|
LoadString(HINST_THISDLL, IDS_FINDSEARCH_COMPUTER, szTitle, sizeof(szTitle));
|
|
SetWindowText(hwnd, szTitle);
|
|
}
|
|
else if ((pbfsf->ulFlags & BIF_BROWSEFORPRINTER) != 0)
|
|
{
|
|
LoadString(HINST_THISDLL, IDS_FINDSEARCH_PRINTER, szTitle, sizeof(szTitle));
|
|
SetWindowText(hwnd, szTitle);
|
|
}
|
|
|
|
BFSFCallback(pbfsf, BFFM_INITIALIZED, 0);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void _BFSFSetStatusText(PBFSF pbfsf, LPCSTR lpszText)
|
|
{
|
|
char szText[100];
|
|
if (!HIWORD(lpszText)) {
|
|
LoadString(HINST_THISDLL, LOWORD(lpszText), szText, sizeof(szText));
|
|
lpszText = szText;
|
|
}
|
|
SetDlgItemText(pbfsf->hwndDlg, IDD_BROWSESTATUS, lpszText);
|
|
}
|
|
|
|
|
|
|
|
// _BFSFOnCommand - Process the WM_COMMAND message
|
|
|
|
void _BFSFOnCommand(PBFSF pbfsf, int id, HWND hwndCtl, UINT codeNotify)
|
|
{
|
|
HTREEITEM hti;
|
|
switch (id)
|
|
{
|
|
case IDOK:
|
|
// We can now update the structure with the idlist of the item selected
|
|
hti = TreeView_GetSelection(pbfsf->hwndTree);
|
|
pbfsf->pidlCurrent = _GetIDListFromTreeItem(pbfsf->hwndTree,
|
|
hti);
|
|
if (pbfsf->pszDisplayName || pbfsf->piImage)
|
|
{
|
|
TV_ITEM tvi;
|
|
tvi.mask = (pbfsf->pszDisplayName)? (TVIF_TEXT | TVIF_IMAGE) :
|
|
TVIF_IMAGE;
|
|
tvi.hItem = hti;
|
|
tvi.pszText = pbfsf->pszDisplayName;
|
|
tvi.cchTextMax = MAX_PATH;
|
|
TreeView_GetItem(pbfsf->hwndTree, &tvi);
|
|
|
|
if (pbfsf->piImage)
|
|
*pbfsf->piImage = tvi.iImage;
|
|
}
|
|
EndDialog(pbfsf->hwndDlg, 1); // To return TRUE.
|
|
break;
|
|
case IDCANCEL:
|
|
EndDialog(pbfsf->hwndDlg, 0); // to return FALSE from this.
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
// _BSFSDlgProc - The dialog procedure for processing the browse
|
|
// for starting folder dialog.
|
|
|
|
#pragma data_seg(".text", "CODE")
|
|
const static DWORD aBrowseHelpIDs[] = { // Context Help IDs
|
|
IDD_BROWSETITLE, NO_HELP,
|
|
IDD_BROWSESTATUS, NO_HELP,
|
|
IDD_FOLDERLIST, IDH_BROWSELIST,
|
|
|
|
0, 0
|
|
};
|
|
#pragma data_seg()
|
|
|
|
BOOL CALLBACK _BFSFDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
PBFSF pbfsf = (PBFSF)GetWindowLong(hwndDlg, DWL_USER);
|
|
|
|
switch (msg) {
|
|
HANDLE_MSG(pbfsf, WM_COMMAND, _BFSFOnCommand);
|
|
HANDLE_MSG(hwndDlg, WM_INITDIALOG, _BFSFOnInitDlg);
|
|
|
|
case WM_DESTROY:
|
|
if (pbfsf->psfParent && (pbfsf->psfParent != Desktop_GetShellFolder(TRUE)))
|
|
{
|
|
pbfsf->psfParent->lpVtbl->Release(pbfsf->psfParent);
|
|
pbfsf->psfParent = NULL;
|
|
}
|
|
break;
|
|
|
|
case BFFM_SETSTATUSTEXT:
|
|
_BFSFSetStatusText(pbfsf, (LPCSTR)lParam);
|
|
break;
|
|
|
|
case BFFM_SETSELECTION:
|
|
{
|
|
BOOL fRet;
|
|
|
|
// wParam TRUE means path, not pidl
|
|
if (wParam) {
|
|
lParam = (LPARAM)SHSimpleIDListFromPath((LPSTR)lParam);
|
|
if (!lParam)
|
|
return FALSE;
|
|
}
|
|
fRet = BrowseSelectPidl(pbfsf, (LPITEMIDLIST)lParam);
|
|
|
|
if (wParam)
|
|
ILFree((LPITEMIDLIST)lParam);
|
|
return fRet;
|
|
}
|
|
|
|
case BFFM_ENABLEOK:
|
|
EnableWindow(GetDlgItem(hwndDlg, IDOK), lParam);
|
|
break;
|
|
|
|
|
|
case WM_NOTIFY:
|
|
switch (((NMHDR *)lParam)->code)
|
|
{
|
|
case TVN_GETDISPINFO:
|
|
_BFSFGetDisplayInfo(pbfsf, (TV_DISPINFO *)lParam);
|
|
break;
|
|
|
|
case TVN_ITEMEXPANDING:
|
|
SetCursor(LoadCursor(NULL, IDC_WAIT));
|
|
_BFSFHandleItemExpanding(pbfsf, (LPNM_TREEVIEW)lParam);
|
|
break;
|
|
|
|
case TVN_ITEMEXPANDED:
|
|
SetCursor(LoadCursor(NULL, IDC_ARROW));
|
|
break;
|
|
|
|
case TVN_DELETEITEM:
|
|
_BFSFHandleDeleteItem(pbfsf, (LPNM_TREEVIEW)lParam);
|
|
break;
|
|
|
|
case TVN_SELCHANGED:
|
|
_BFSFHandleSelChanged(pbfsf, (LPNM_TREEVIEW)lParam);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case WM_HELP:
|
|
WinHelp((HWND)((LPHELPINFO) lParam)->hItemHandle, NULL,
|
|
HELP_WM_HELP, (DWORD)(LPSTR) aBrowseHelpIDs);
|
|
break;
|
|
|
|
case WM_CONTEXTMENU:
|
|
WinHelp((HWND) wParam, NULL, HELP_CONTEXTMENU,
|
|
(DWORD)(LPVOID) aBrowseHelpIDs);
|
|
break;
|
|
|
|
default:
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|