mirror of https://github.com/lianthony/NT4.0
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.
2761 lines
87 KiB
2761 lines
87 KiB
//---------------------------------------------------------------------------
|
|
//
|
|
// Copyright (c) Microsoft Corporation 1991-1993
|
|
//
|
|
// File: netfind.c
|
|
//
|
|
// Description: This file contains the net specific search code that is
|
|
// needed for the find computer code.
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
#include "shellprv.h"
|
|
#pragma hdrstop
|
|
|
|
// #define FIND_TRACE
|
|
#define NET_TIMINGS
|
|
|
|
#ifdef NET_TIMINGS
|
|
int NTF_cNoPEnum = 0;
|
|
int NTF_dtNoPEnum = 0;
|
|
int NTF_cNextItem = 0;
|
|
int NTF_dtNextItem = 0;
|
|
int NTF_dtTime = 0;
|
|
#endif
|
|
|
|
|
|
#define DFM_DEFERINIT (WM_USER+42)
|
|
//
|
|
// REVIEW:: The recursive code in this module has been totally neutered to
|
|
// make the ITG group happy. IE we mad this functional mostly usless and
|
|
// wasted a lot of time doing so... The ifdefs are under #ifdef CASTRATED
|
|
//
|
|
|
|
|
|
//===========================================================================
|
|
// Define the Default data filter data structures
|
|
//===========================================================================
|
|
|
|
// Use the code from property sheet to create the dialogs
|
|
HWND WINAPI CreatePage(PROPSHEETPAGE *hpage, HWND hwndParent);
|
|
|
|
//
|
|
// Define the internal structure of our default filter
|
|
typedef struct _CNETFilter // fff
|
|
{
|
|
IDocFindFileFilter dfff;
|
|
UINT cRef;
|
|
|
|
HWND hwndTabs;
|
|
|
|
HANDLE hMRUSpecs;
|
|
|
|
LPITEMIDLIST pidlStart; // Where to start the search from.
|
|
|
|
// Data associated with the file name.
|
|
LPTSTR pszCompName; // the one we do compares with
|
|
TCHAR szUserInputCompName[MAX_PATH]; // User input
|
|
|
|
} CNETFilter, FAR* LPNETFILTER;
|
|
|
|
|
|
// Define common page data for each of our pages
|
|
// WARNING the fields in this must align the same as the definition
|
|
// in docfind2.c
|
|
|
|
typedef struct { // dfpsp
|
|
PSP hpsp;
|
|
HANDLE hThreadInit;
|
|
HWND hwndDlg;
|
|
LPNETFILTER pdff;
|
|
DWORD dwState;
|
|
} DOCFINDPROPSHEETPAGE, * LPDOCFINDPROPSHEETPAGE;
|
|
|
|
|
|
#define DFPAGE_INIT 0x0001 /* This page has been initialized */
|
|
#define DFPAGE_CHANGE 0x0002 /* The user has modified the page */
|
|
|
|
//===========================================================================
|
|
// Prototypes of some of the internal functions.
|
|
//===========================================================================
|
|
|
|
BOOL CALLBACK DocFind_CCOMPFNameLocDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
|
|
|
|
|
|
|
|
//===========================================================================
|
|
// Define some other module global data
|
|
//===========================================================================
|
|
|
|
#pragma data_seg(DATASEG_READONLY)
|
|
DFPAGELIST s_CCOMPFplComp[] =
|
|
{
|
|
{DLG_NFNAMELOC, DocFind_CCOMPFNameLocDlgProc},
|
|
};
|
|
#pragma data_seg()
|
|
|
|
// Some global strings...
|
|
const TCHAR s_szCompSpecMRU[] = REGSTR_PATH_EXPLORER TEXT("\\FindComputerMRU");
|
|
|
|
|
|
|
|
|
|
//==========================================================================
|
|
//
|
|
// Create the default filter for our find code... They should be completly
|
|
// self contained...
|
|
//
|
|
|
|
//===========================================================================
|
|
// CNETFilter : member prototype
|
|
//===========================================================================
|
|
HRESULT STDMETHODCALLTYPE CNETFilter_QueryInterface(LPDOCFINDFILEFILTER pnetf, REFIID riid, LPVOID FAR* ppvObj);
|
|
ULONG STDMETHODCALLTYPE CNETFilter_AddRef(LPDOCFINDFILEFILTER pnetf);
|
|
ULONG STDMETHODCALLTYPE CNETFilter_Release(LPDOCFINDFILEFILTER pnetf);
|
|
STDMETHODIMP CNETFilter_GetIconsAndMenu (LPDOCFINDFILEFILTER pdfff,
|
|
HWND hwndDlg, HICON *phiconSmall, HICON *phiconLarge, HMENU *phmenu);
|
|
STDMETHODIMP CNETFilter_GetStatusMessageIndex (LPDOCFINDFILEFILTER pdfff,
|
|
UINT uContext, UINT *puMsgIndex);
|
|
STDMETHODIMP CNETFilter_GetFolderMergeMenuIndex (LPDOCFINDFILEFILTER pdfff,
|
|
UINT *puMergeMenu);
|
|
STDMETHODIMP CNETFilter_AddPages(LPDOCFINDFILEFILTER pnetf, HWND hwndTabs,
|
|
LPITEMIDLIST pidlStart);
|
|
STDMETHODIMP CNetFilter_FFilterChanged(LPDOCFINDFILEFILTER pdfff);
|
|
STDMETHODIMP CNETFilter_GenerateTitle(LPDOCFINDFILEFILTER pnetf,
|
|
LPTSTR *ppszTitle, BOOL fFileName);
|
|
STDMETHODIMP CNETFilter_ClearSearchCriteria(LPDOCFINDFILEFILTER pnetf);
|
|
STDMETHODIMP CNETFilter_PrepareToEnumObjects(LPDOCFINDFILEFILTER pnetf, DWORD *pdwFlags);
|
|
STDMETHODIMP CNETFilter_EnableChanges(LPDOCFINDFILEFILTER pnetf, BOOL fEnable);
|
|
STDMETHODIMP CNETFilter_CreateDetails(LPDOCFINDFILEFILTER pnetf,
|
|
HWND hwndDlg, HDPA hdpaPidf, LPVOID FAR* ppvOut);
|
|
STDMETHODIMP CNETFilter_EnumObjects (LPDOCFINDFILEFILTER pnetf, LPSHELLFOLDER psf,
|
|
DWORD grfFlags, LPTSTR pszProgressText, IDFEnum **ppdfenum) PURE;
|
|
STDMETHODIMP CNETFilter_FDoesItemMatchFilter(LPDOCFINDFILEFILTER pnetf,
|
|
LPTSTR pszFolder, WIN32_FIND_DATA * pfinddata,
|
|
LPSHELLFOLDER psf, LPITEMIDLIST pidl);
|
|
STDMETHODIMP CNETFilter_SaveCriteria(LPDOCFINDFILEFILTER pnetf, IStream *pstm, WORD fCharType);
|
|
STDMETHODIMP CNETFilter_RestoreCriteria(LPDOCFINDFILEFILTER pnetf,
|
|
IStream * pstm, int cCriteria, WORD fCharType);
|
|
STDMETHODIMP CNETFilter_DeclareFSNotifyInterest(LPDOCFINDFILEFILTER pnetf, HWND hwndDlg, UINT uMsg);
|
|
|
|
#pragma data_seg(DATASEG_READONLY)
|
|
IDocFindFileFilterVtbl c_CCOMPFFilterVtbl =
|
|
{
|
|
CNETFilter_QueryInterface,
|
|
CNETFilter_AddRef,
|
|
CNETFilter_Release,
|
|
CNETFilter_GetIconsAndMenu,
|
|
CNETFilter_GetStatusMessageIndex,
|
|
CNETFilter_GetFolderMergeMenuIndex,
|
|
CNETFilter_AddPages,
|
|
CNetFilter_FFilterChanged,
|
|
CNETFilter_GenerateTitle,
|
|
CNETFilter_PrepareToEnumObjects,
|
|
CNETFilter_ClearSearchCriteria,
|
|
CNETFilter_EnableChanges,
|
|
CNETFilter_CreateDetails,
|
|
CNETFilter_EnumObjects,
|
|
CNETFilter_FDoesItemMatchFilter,
|
|
CNETFilter_SaveCriteria,
|
|
CNETFilter_RestoreCriteria,
|
|
CNETFilter_DeclareFSNotifyInterest
|
|
};
|
|
|
|
#pragma data_seg()
|
|
|
|
|
|
//==========================================================================
|
|
// Creation function to create default find filter...
|
|
//==========================================================================
|
|
IDocFindFileFilter * CreateDefaultComputerFindFilter()
|
|
{
|
|
LPNETFILTER pfff = (void*)LocalAlloc(LPTR, SIZEOF(CNETFilter));
|
|
if (pfff == NULL)
|
|
return(NULL);
|
|
|
|
pfff->dfff.lpVtbl = &c_CCOMPFFilterVtbl;
|
|
pfff->cRef = 1;
|
|
|
|
// We should now simply return the filter
|
|
return &pfff->dfff;
|
|
|
|
}
|
|
|
|
//==========================================================================
|
|
// Query interface for the docfind filter interface...
|
|
//==========================================================================
|
|
|
|
HRESULT STDMETHODCALLTYPE CNETFilter_QueryInterface(LPDOCFINDFILEFILTER pnetf, REFIID riid, LPVOID FAR* ppvObj)
|
|
{
|
|
return ResultFromScode(E_NOTIMPL);
|
|
}
|
|
|
|
//==========================================================================
|
|
// IDocFindFileFilter::AddRef
|
|
//==========================================================================
|
|
ULONG STDMETHODCALLTYPE CNETFilter_AddRef(LPDOCFINDFILEFILTER pnetf)
|
|
{
|
|
LPNETFILTER this = IToClass(CNETFilter, dfff, pnetf);
|
|
this->cRef++;
|
|
return(this->cRef);
|
|
}
|
|
|
|
//==========================================================================
|
|
// IDocFindFileFilter::Release
|
|
//==========================================================================
|
|
ULONG STDMETHODCALLTYPE CNETFilter_Release(LPDOCFINDFILEFILTER pnetf)
|
|
{
|
|
LPNETFILTER this = IToClass(CNETFilter, dfff, pnetf);
|
|
this->cRef--;
|
|
if (this->cRef>0)
|
|
{
|
|
return(this->cRef);
|
|
}
|
|
|
|
// Destroy the MRU Lists...
|
|
|
|
if (this->hMRUSpecs)
|
|
FreeMRUList(this->hMRUSpecs);
|
|
|
|
// unless we do not have a combobox
|
|
if (this->pidlStart)
|
|
ILFree(this->pidlStart);
|
|
|
|
if (this->pszCompName)
|
|
LocalFree( this->pszCompName );
|
|
|
|
LocalFree((HLOCAL)this);
|
|
return(0);
|
|
}
|
|
|
|
//==========================================================================
|
|
// IDocFindFileFilter::GetIconsAndMenu
|
|
//==========================================================================
|
|
STDMETHODIMP CNETFilter_GetIconsAndMenu (LPDOCFINDFILEFILTER pdfff,
|
|
HWND hwndDlg, HICON *phiconSmall, HICON *phiconLarge, HMENU *phmenu)
|
|
{
|
|
*phiconSmall = LoadImage(HINST_THISDLL, MAKEINTRESOURCE(IDI_COMPFIND),
|
|
IMAGE_ICON, g_cxSmIcon, g_cySmIcon, LR_DEFAULTCOLOR);
|
|
*phiconLarge = LoadIcon(HINST_THISDLL, MAKEINTRESOURCE(IDI_COMPFIND));
|
|
|
|
// Now for the menu
|
|
*phmenu = LoadMenu(HINST_THISDLL, MAKEINTRESOURCE(MENU_FINDCOMPDLG));
|
|
|
|
// BUGBUG:: Still menu to process!
|
|
|
|
return ResultFromScode(S_OK);
|
|
}
|
|
|
|
//==========================================================================
|
|
// Function to get the string resource index number that is proper for the
|
|
// current type of search.
|
|
//==========================================================================
|
|
STDMETHODIMP CNETFilter_GetStatusMessageIndex (LPDOCFINDFILEFILTER pdfff,
|
|
UINT uContext, UINT *puMsgIndex)
|
|
{
|
|
// Currently context is not used
|
|
*puMsgIndex = IDS_COMPUTERSFOUND;
|
|
|
|
return ResultFromScode(S_OK);
|
|
}
|
|
|
|
//==========================================================================
|
|
// Function to let find know which menu to load to merge for the folder
|
|
//==========================================================================
|
|
STDMETHODIMP CNETFilter_GetFolderMergeMenuIndex (LPDOCFINDFILEFILTER pdfff,
|
|
UINT *puMergeMenu)
|
|
{
|
|
*puMergeMenu = POPUP_NETFIND_POPUPMERGE;
|
|
return ResultFromScode(S_OK);
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
// IDocFindFileFilter::AddPages
|
|
//==========================================================================
|
|
STDMETHODIMP CNETFilter_AddPages(LPDOCFINDFILEFILTER pnetf, HWND hwndTabs,
|
|
LPITEMIDLIST pidlStart)
|
|
{
|
|
HWND hwndMainDlg;
|
|
TCHAR szTemp[20];
|
|
|
|
LPNETFILTER this = IToClass(CNETFilter, dfff, pnetf);
|
|
hwndMainDlg = GetParent(hwndTabs);
|
|
|
|
// save away a pointer to the filter
|
|
this->hwndTabs = hwndTabs;
|
|
|
|
// We want to update the animation to show the Find computer one instead
|
|
// of the find files, so wack it here
|
|
wsprintf(szTemp, TEXT("#%d"),IDA_FINDCOMP);
|
|
SetDlgItemText(hwndMainDlg, IDD_ANIMATE, szTemp);
|
|
|
|
// since we removed the browse and drop down list we need to prefill this
|
|
this->pidlStart = SHCloneSpecialIDList(HWND_DESKTOP, CSIDL_NETWORK, FALSE);
|
|
|
|
return DocFind_AddPages(pnetf, hwndTabs, s_CCOMPFplComp, ARRAYSIZE(s_CCOMPFplComp));
|
|
}
|
|
|
|
//==========================================================================
|
|
// IDocFindFileFilter::FFilterChanged - Returns S_OK if nothing changed.
|
|
//==========================================================================
|
|
STDMETHODIMP CNetFilter_FFilterChanged(LPDOCFINDFILEFILTER pdfff)
|
|
{
|
|
// Currently not saving so who cares?
|
|
return(ResultFromScode(S_FALSE));
|
|
}
|
|
|
|
|
|
//==========================================================================
|
|
// IDocFindFileFilter::GenerateTitle - Generates the title given the current
|
|
// search criteria.
|
|
//==========================================================================
|
|
STDMETHODIMP CNETFilter_GenerateTitle(LPDOCFINDFILEFILTER pnetf,
|
|
LPTSTR *ppszTitle, BOOL fFileName)
|
|
{
|
|
LPNETFILTER this = IToClass(CNETFilter, dfff, pnetf);
|
|
LPTSTR pszMsg;
|
|
int iRes;
|
|
|
|
// For now lets use the default find...
|
|
iRes = IDS_FIND_TITLE_COMPUTER;
|
|
|
|
// Now lets construct the message from the resource
|
|
pszMsg = ShellConstructMessageString(HINST_THISDLL,
|
|
MAKEINTRESOURCE(iRes), fFileName? TEXT(" #") : TEXT(":"));
|
|
|
|
|
|
*ppszTitle = pszMsg; // Return the pointer to the caller
|
|
|
|
return ResultFromScode(S_OK);
|
|
}
|
|
|
|
//==========================================================================
|
|
// IDocFindFileFilter::ClearSearchCriteria
|
|
//==========================================================================
|
|
STDMETHODIMP CNETFilter_ClearSearchCriteria(LPDOCFINDFILEFILTER pnetf)
|
|
{
|
|
int cPages;
|
|
HWND hwndMainDlg;
|
|
TC_DFITEMEXTRA tie;
|
|
LPNETFILTER this = IToClass(CNETFilter, dfff, pnetf);
|
|
|
|
hwndMainDlg = GetParent(this->hwndTabs);
|
|
for (cPages = TabCtrl_GetItemCount(this->hwndTabs) -1; cPages >= 0; cPages--)
|
|
{
|
|
tie.tci.mask = TCIF_PARAM;
|
|
TabCtrl_GetItem(this->hwndTabs, cPages, &tie.tci);
|
|
SendNotify(tie.hwndPage, hwndMainDlg, PSN_RESET, NULL);
|
|
}
|
|
|
|
return ResultFromScode(S_OK);
|
|
}
|
|
|
|
//==========================================================================
|
|
// IDocFindFileFilter::PrepareToEnumObjects
|
|
//==========================================================================
|
|
STDMETHODIMP CNETFilter_PrepareToEnumObjects(LPDOCFINDFILEFILTER pnetf, DWORD *pdwFlags)
|
|
{
|
|
int cPages;
|
|
HWND hwndMainDlg;
|
|
TC_DFITEMEXTRA tie;
|
|
LPNETFILTER this = IToClass(CNETFilter, dfff, pnetf);
|
|
|
|
hwndMainDlg = GetParent(this->hwndTabs);
|
|
for (cPages = TabCtrl_GetItemCount(this->hwndTabs) -1; cPages >= 0; cPages--)
|
|
{
|
|
tie.tci.mask = TCIF_PARAM;
|
|
TabCtrl_GetItem(this->hwndTabs, cPages, &tie.tci);
|
|
SendNotify(tie.hwndPage, hwndMainDlg, PSN_APPLY, NULL);
|
|
}
|
|
|
|
// Update the flags and buffer strings
|
|
|
|
*pdwFlags &= ~FFLT_INCLUDESUBDIRS;
|
|
// Also lets convert the Computer name pattern into the strings
|
|
// will do the compares against.
|
|
if ((this->szUserInputCompName[0] == TEXT('\\')) &&
|
|
(this->szUserInputCompName[1] == TEXT('\\')))
|
|
{
|
|
// (DavePl)
|
|
//
|
|
// This code used to reuse the pszCompName buffer if it was non-null, but
|
|
// if you do a find with _no_ criteria, and then a find with a \\foo criteria,
|
|
// the buffer will be reused, but its too short (allocated by DocFind_SetupWildCardingOnFileSpec)
|
|
// and memory trashing occurs
|
|
|
|
|
|
if (this->pszCompName)
|
|
{
|
|
LocalFree(this->pszCompName);
|
|
}
|
|
|
|
this->pszCompName = LocalAlloc( LPTR, (lstrlen(this->szUserInputCompName)+1)*SIZEOF(TCHAR) );
|
|
|
|
if (this->pszCompName)
|
|
// We are doing special unc matching
|
|
lstrcpy(this->pszCompName, this->szUserInputCompName);
|
|
}
|
|
else
|
|
{
|
|
if (this->pszCompName)
|
|
{
|
|
LocalFree( this->pszCompName );
|
|
this->pszCompName = NULL;
|
|
}
|
|
DocFind_SetupWildCardingOnFileSpec(this->szUserInputCompName,
|
|
&this->pszCompName);
|
|
}
|
|
|
|
return ResultFromScode(S_OK);
|
|
}
|
|
|
|
|
|
//==========================================================================
|
|
// IDocFindFileFilter::EnableChanges
|
|
//==========================================================================
|
|
STDMETHODIMP CNETFilter_EnableChanges(LPDOCFINDFILEFILTER pnetf, BOOL fEnable)
|
|
{
|
|
int cPages;
|
|
HWND hwndMainDlg;
|
|
TC_DFITEMEXTRA tie;
|
|
LPNETFILTER this = IToClass(CNETFilter, dfff, pnetf);
|
|
|
|
hwndMainDlg = GetParent(this->hwndTabs);
|
|
for (cPages = TabCtrl_GetItemCount(this->hwndTabs) -1; cPages >= 0; cPages--)
|
|
{
|
|
tie.tci.mask = TCIF_PARAM;
|
|
TabCtrl_GetItem(this->hwndTabs, cPages, &tie.tci);
|
|
SendMessage(tie.hwndPage, DFM_ENABLECHANGES, (WPARAM)fEnable, 0);
|
|
}
|
|
|
|
return ResultFromScode(S_OK);
|
|
}
|
|
|
|
|
|
//==========================================================================
|
|
// IDocFindFileFilter::FDoesItemMatchFilter
|
|
//==========================================================================
|
|
STDMETHODIMP CNETFilter_FDoesItemMatchFilter(LPDOCFINDFILEFILTER pnetf,
|
|
LPTSTR pszFolder, WIN32_FIND_DATA * pfinddata,
|
|
LPSHELLFOLDER psf, LPITEMIDLIST pidl)
|
|
{
|
|
LPNETFILTER this = IToClass(CNETFilter, dfff, pnetf);
|
|
SCODE sc = MAKE_SCODE(0, 0, 1);
|
|
|
|
// Make sure that we only return computers...
|
|
BYTE bType;
|
|
|
|
bType = SIL_GetType(pidl);
|
|
|
|
// First pass dont push anything that is below a computer...
|
|
if ((bType & (SHID_NET | SHID_INGROUPMASK)) != SHID_NET_SERVER)
|
|
return ResultFromScode(0); // does not match
|
|
|
|
// Here is where I start getting in bed with the network enumerator
|
|
// format of IDLists.
|
|
if (this->pszCompName && this->pszCompName[0])
|
|
{
|
|
// Although for now not much...
|
|
STRRET str;
|
|
|
|
psf->lpVtbl->GetDisplayNameOf(psf, pidl, SHGDN_NORMAL, &str);
|
|
|
|
#ifdef UNICODE
|
|
{
|
|
TCHAR szPath[MAX_PATH];
|
|
if (StrRetToStrN(szPath, MAX_PATH, &str, pidl))
|
|
{
|
|
if (!PathMatchSpec(szPath, this->pszCompName))
|
|
return ResultFromScode(0); // does not match
|
|
}
|
|
else
|
|
{
|
|
return ResultFromScode(0); // strret conv fails => no match
|
|
}
|
|
}
|
|
#else
|
|
Assert (str.uType == STRRET_OFFSET)
|
|
if (str.uType != STRRET_OFFSET)
|
|
return ResultFromScode(0); // does not match
|
|
|
|
if (!PathMatchSpec((LPTSTR)((LPBYTE)pidl + str.uOffset), this->pszCompName))
|
|
return ResultFromScode(0); // does not match
|
|
#endif
|
|
|
|
}
|
|
|
|
return ResultFromScode(sc); // return TRUE to imply yes!
|
|
}
|
|
|
|
//==========================================================================
|
|
// IDocFindFileFilter::SaveCriteria
|
|
//==========================================================================
|
|
STDMETHODIMP CNETFilter_SaveCriteria(LPDOCFINDFILEFILTER pnetf, IStream *pstm, WORD fCharType)
|
|
{
|
|
//
|
|
#ifdef NOT_DONE_YET
|
|
#endif
|
|
|
|
LPNETFILTER this = IToClass(CNETFilter, dfff, pnetf);
|
|
int cCriteria = 0;
|
|
|
|
return ResultFromScode(MAKE_SCODE(0, 0, cCriteria));
|
|
}
|
|
|
|
//==========================================================================
|
|
// IDocFindFileFilter::RestoreCriteria
|
|
//==========================================================================
|
|
STDMETHODIMP CNETFilter_RestoreCriteria(LPDOCFINDFILEFILTER pnetf,
|
|
IStream *pstm, int cCriteria, WORD fCharType)
|
|
{
|
|
LPNETFILTER this = IToClass(CNETFilter, dfff, pnetf);
|
|
|
|
#ifdef NOT_DONE_YET
|
|
#endif
|
|
return ResultFromScode(S_OK);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////
|
|
// Now starting the code for the name and location page
|
|
////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
//==========================================================================
|
|
//
|
|
// Process the WM_SIZE of the details page
|
|
//
|
|
void DocFind_CCOMPFNameLocOnSize(HWND hwndDlg, UINT state, int cx, int cy)
|
|
{
|
|
RECT rc;
|
|
int cxMargin;
|
|
if (state == SIZE_MINIMIZED)
|
|
return; // don't bother when we are minimized...
|
|
|
|
// Get the location of first static to calculate margin
|
|
GetWindowRect(GetDlgItem(hwndDlg, IDD_STATIC), &rc);
|
|
MapWindowPoints(HWND_DESKTOP, hwndDlg, (POINT *)&rc, 2);
|
|
cxMargin = rc.left;
|
|
cx -= cxMargin;
|
|
|
|
DocFind_SizeControl(hwndDlg, IDD_FILESPEC, cx, TRUE);
|
|
|
|
}
|
|
|
|
|
|
//==========================================================================
|
|
// Helper to helper to add an item to the combobox.
|
|
//==========================================================================
|
|
|
|
HRESULT _GetDisplayName(LPSHELLFOLDER psfGP, LPCITEMIDLIST pidl, LPTSTR pszRet, UINT cchMax)
|
|
{
|
|
LPITEMIDLIST pidlParent = ILClone(pidl);
|
|
HRESULT hres;
|
|
VDATEINPUTBUF(pszRet, TCHAR, cchMax);
|
|
|
|
if (pidlParent)
|
|
{
|
|
LPSHELLFOLDER psfParent = NULL;
|
|
ILRemoveLastID(pidlParent);
|
|
if (ILIsEmpty(pidlParent))
|
|
{
|
|
psfParent = psfGP;
|
|
psfParent->lpVtbl->AddRef(psfParent);
|
|
hres = S_OK;
|
|
}
|
|
else
|
|
{
|
|
hres = psfGP->lpVtbl->BindToObject(psfGP, pidlParent, NULL, &IID_IShellFolder, &psfParent);
|
|
}
|
|
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
STRRET str;
|
|
pidl = ILFindLastID(pidl);
|
|
hres = psfParent->lpVtbl->GetDisplayNameOf(psfParent, pidl, SHGDN_NORMAL, &str);
|
|
StrRetToStrN(pszRet, cchMax, &str, pidl);
|
|
|
|
psfParent->lpVtbl->Release(psfParent);
|
|
}
|
|
|
|
ILFree(pidlParent);
|
|
}
|
|
else
|
|
{
|
|
hres = E_OUTOFMEMORY;
|
|
}
|
|
return hres;
|
|
}
|
|
|
|
int DocFind_LocCBAddPidl(HWND hwndCtl, LPSHELLFOLDER psf,
|
|
LPITEMIDLIST pidlParent, LPITEMIDLIST pidl, LPITEMIDLIST *ppidlAbs,
|
|
BOOL fFullName)
|
|
{
|
|
LPDFCBITEM pdfcbi;
|
|
TCHAR szPath[MAX_PATH];
|
|
int iItem = -1;
|
|
LPITEMIDLIST pidlAbs;
|
|
|
|
pidlAbs = ILCombine(pidlParent, pidl);
|
|
if (!pidlAbs)
|
|
return(-1);
|
|
|
|
if (fFullName)
|
|
{
|
|
if (!SHGetPathFromIDList(pidlAbs, szPath))
|
|
{
|
|
ILFree(pidlAbs);
|
|
return(-1);
|
|
}
|
|
}
|
|
else if (FAILED(_GetDisplayName(psf, pidl, szPath, ARRAYSIZE(szPath))))
|
|
{
|
|
ILFree(pidlAbs);
|
|
return(-1);
|
|
}
|
|
|
|
pdfcbi = (LPDFCBITEM)LocalAlloc(LPTR, SIZEOF(DFCBITEM));
|
|
if (pdfcbi != NULL)
|
|
{
|
|
|
|
pdfcbi->pidl = pidlAbs;
|
|
if (ppidlAbs)
|
|
*ppidlAbs = pdfcbi->pidl;
|
|
|
|
pdfcbi->iImage = SHMapPIDLToSystemImageListIndex(
|
|
psf, pidl, NULL);
|
|
|
|
pdfcbi->uFixedDrives = 0; // no fixed drives being referenced
|
|
|
|
if ((iItem = SendMessage(hwndCtl, CB_ADDSTRING, 0,
|
|
(LPARAM)szPath)) != CB_ERRSPACE)
|
|
{
|
|
// Set the data for this item now...
|
|
SendMessage(hwndCtl, CB_SETITEMDATA, iItem, (LPARAM)pdfcbi);
|
|
}
|
|
else
|
|
{
|
|
Assert(FALSE);
|
|
LocalFree((HLOCAL)pdfcbi);
|
|
}
|
|
}
|
|
return(iItem);
|
|
}
|
|
|
|
//==========================================================================
|
|
// Helper function to see if an Pidl is aready in the list...
|
|
//==========================================================================
|
|
int DocFind_LocCBFindPidl(HWND hwnd, LPITEMIDLIST pidl)
|
|
{
|
|
LPDFCBITEM pdfcbi;
|
|
int i;
|
|
|
|
for (i = SendMessage(hwnd, CB_GETCOUNT, 0, 0); i >= 0; i--)
|
|
{
|
|
pdfcbi = (LPDFCBITEM)SendMessage(hwnd, CB_GETITEMDATA, i, 0);
|
|
|
|
if ((pdfcbi != NULL) && (pdfcbi != (LPDFCBITEM)CB_ERR) &&
|
|
ILIsEqual(pidl, pdfcbi->pidl))
|
|
break;
|
|
}
|
|
return(i);
|
|
|
|
}
|
|
|
|
|
|
//==========================================================================
|
|
// Initialize the Name and loacation page
|
|
//==========================================================================
|
|
void DocFind_CCOMPFNameLocInit(LPDOCFINDPROPSHEETPAGE pdfpsp)
|
|
{
|
|
LPNETFILTER pdff = pdfpsp->pdff;
|
|
TCHAR szPath[MAX_PATH];
|
|
LPITEMIDLIST pidlWindows;
|
|
|
|
// We want to set the default search drive to the windows drive.
|
|
// I am going to be a bit slimmy, but...
|
|
//
|
|
GetWindowsDirectory(szPath, ARRAYSIZE(szPath));
|
|
if (szPath[1] == TEXT(':'))
|
|
szPath[3] = TEXT('\0');
|
|
|
|
pidlWindows = ILCreateFromPath(szPath);
|
|
|
|
if ((pdfpsp->dwState & DFPAGE_INIT) == 0)
|
|
{
|
|
pdff->hMRUSpecs = DocFind_UpdateMRUItem(NULL, pdfpsp->hwndDlg, IDD_FILESPEC,
|
|
s_szCompSpecMRU, pdff->szUserInputCompName, szNULL);
|
|
|
|
// Update our state to let us know that we have already initialized...
|
|
pdfpsp->dwState |= DFPAGE_INIT;
|
|
}
|
|
|
|
|
|
ILFree(pidlWindows);
|
|
|
|
}
|
|
|
|
|
|
//==========================================================================
|
|
// Validate the page to make sure that the data is valid. If it is not
|
|
// we need to display a message to the user and also set the focus to
|
|
// the invalid field.
|
|
//==========================================================================
|
|
void DocFind_CCOMPFNameLocValidatePage(LPDOCFINDPROPSHEETPAGE pdfpsp)
|
|
{
|
|
|
|
// No validation is needed here (At least not now).
|
|
|
|
}
|
|
|
|
|
|
//==========================================================================
|
|
//
|
|
// Apply any changes that happened in the name loc page to the filter
|
|
//
|
|
void DocFind_CCOMPFNameLocApply(LPDOCFINDPROPSHEETPAGE pdfpsp)
|
|
{
|
|
LPNETFILTER pdff = pdfpsp->pdff;
|
|
|
|
GetDlgItemText(pdfpsp->hwndDlg, IDD_FILESPEC, pdff->szUserInputCompName,
|
|
ARRAYSIZE(pdff->szUserInputCompName));
|
|
|
|
DocFind_UpdateMRUItem(pdff->hMRUSpecs, pdfpsp->hwndDlg, IDD_FILESPEC,
|
|
s_szCompSpecMRU, pdff->szUserInputCompName, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
//
|
|
// DocFind_OnCommand - Process the WM_COMMAND messages
|
|
//
|
|
void DocFind_CCOMPFNameLocOnCommand(HWND hwndDlg, UINT id, HWND hwndCtl, UINT code)
|
|
{
|
|
}
|
|
//==========================================================================
|
|
// Handle the Measure item for the ComboBox
|
|
//==========================================================================
|
|
|
|
BOOL DocFind_LocCBMeasureItem(HWND hwnd,
|
|
MEASUREITEMSTRUCT FAR* lpMeasureItem)
|
|
{
|
|
HWND hwndItem;
|
|
HDC hdc;
|
|
TEXTMETRIC tm;
|
|
// Now lets setup the size of the structure ...
|
|
// I assume that this is the combobox as this is the only item
|
|
// we have that is owner drawn.
|
|
lpMeasureItem->itemHeight = g_cySmIcon;
|
|
|
|
// Lets check the off case that the text metrics are larger then
|
|
// this.
|
|
hwndItem = GetDlgItem(hwnd, lpMeasureItem->CtlID);
|
|
hdc = GetDC(hwndItem);
|
|
GetTextMetrics(hdc, &tm);
|
|
if ((UINT)tm.tmHeight > lpMeasureItem->itemHeight)
|
|
lpMeasureItem->itemHeight = (UINT)tm.tmHeight;
|
|
|
|
lpMeasureItem->itemHeight += 2 * GetSystemMetrics(SM_CYBORDER);
|
|
|
|
ReleaseDC(hwndItem, hdc);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//==========================================================================
|
|
// Handle the DrawItem for the combobox.
|
|
//==========================================================================
|
|
BOOL DocFind_LocCBDrawItem(HWND hwnd,
|
|
const DRAWITEMSTRUCT FAR* lpdi)
|
|
{
|
|
LPDFCBITEM pdfcbi = (LPDFCBITEM)lpdi->itemData;
|
|
HIMAGELIST himl;
|
|
TCHAR szDisplayName[MAX_PATH];
|
|
RECT rc;
|
|
int cch;
|
|
int iBack, iText;
|
|
SIZE sz;
|
|
|
|
// If not drawing entire or selection bail out
|
|
if (!((lpdi->itemAction & ODA_SELECT) ||
|
|
(lpdi->itemAction & ODA_DRAWENTIRE)))
|
|
return FALSE;
|
|
|
|
// Also bail if no information...
|
|
if (lpdi->itemID==(UINT)-1)
|
|
return FALSE;
|
|
|
|
// First draw the imagelist
|
|
Shell_GetImageLists(NULL, &himl);
|
|
rc = lpdi->rcItem;
|
|
|
|
ImageList_Draw(himl, pdfcbi->iImage, lpdi->hDC,
|
|
rc.left + GetSystemMetrics(SM_CXBORDER),
|
|
(rc.bottom + rc.top - g_cySmIcon) / 2, 0);
|
|
if (lpdi->itemState & (ODS_SELECTED | ODS_FOCUS))
|
|
{
|
|
iText = SetTextColor(lpdi->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
|
|
iBack = SetBkColor(lpdi->hDC, GetSysColor(COLOR_HIGHLIGHT));
|
|
}
|
|
|
|
// Now lets output the text
|
|
rc.left += 2 * GetSystemMetrics(SM_CYBORDER) + g_cxSmIcon;
|
|
|
|
SendMessage(lpdi->hwndItem, CB_GETLBTEXT, lpdi->itemID, (LPARAM)szDisplayName);
|
|
GetTextExtentPoint(lpdi->hDC, szDisplayName,
|
|
cch = lstrlen(szDisplayName), &sz);
|
|
|
|
ExtTextOut(lpdi->hDC, rc.left, (rc.bottom + rc.top - sz.cy) / 2,
|
|
ETO_OPAQUE, &rc, szDisplayName, cch, NULL);
|
|
|
|
// Restore colors
|
|
if (lpdi->itemState & (ODS_SELECTED | ODS_FOCUS))
|
|
{
|
|
SetTextColor(lpdi->hDC, iText);
|
|
SetBkColor(lpdi->hDC, iBack);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// This function is the dialog (or property sheet page) for the name and
|
|
// location page.
|
|
//
|
|
|
|
const static TCHAR szHelpFile[] = TEXT("network.hlp");
|
|
#pragma data_seg(DATASEG_READONLY)
|
|
const static DWORD aGeneralHelpIds[] = { // Context Help IDs
|
|
IDD_STATIC, IDH_FINDCOMP_NAME,
|
|
IDD_FILESPEC, IDH_FINDCOMP_NAME,
|
|
|
|
0, 0
|
|
};
|
|
#pragma data_seg()
|
|
|
|
BOOL CALLBACK DocFind_CCOMPFNameLocDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
LPDOCFINDPROPSHEETPAGE pdfpsp = (LPDOCFINDPROPSHEETPAGE)GetWindowLong(hwndDlg, DWL_USER);
|
|
|
|
switch (msg) {
|
|
HANDLE_MSG(hwndDlg, WM_COMMAND, DocFind_CCOMPFNameLocOnCommand);
|
|
HANDLE_MSG(hwndDlg, WM_SIZE, DocFind_CCOMPFNameLocOnSize);
|
|
|
|
case WM_INITDIALOG:
|
|
SetWindowLong(hwndDlg, DWL_USER, lParam);
|
|
pdfpsp = (LPDOCFINDPROPSHEETPAGE)lParam;
|
|
pdfpsp->hwndDlg = hwndDlg;
|
|
break;
|
|
|
|
|
|
case WM_NCDESTROY:
|
|
Free(pdfpsp);
|
|
SetWindowLong(hwndDlg, DWL_USER, 0);
|
|
return FALSE; // We MUST return FALSE to avoid mem-leak
|
|
|
|
case DFM_ENABLECHANGES:
|
|
EnableWindow(GetDlgItem(hwndDlg, IDD_FILESPEC), (BOOL)wParam);
|
|
break;
|
|
|
|
case WM_HELP:
|
|
WinHelp((HWND) ((LPHELPINFO) lParam)->hItemHandle, szHelpFile, HELP_WM_HELP,
|
|
(DWORD) (LPTSTR) aGeneralHelpIds);
|
|
break;
|
|
|
|
case WM_CONTEXTMENU: // right mouse click
|
|
WinHelp((HWND) wParam, szHelpFile, HELP_CONTEXTMENU,
|
|
(DWORD) (LPTSTR) aGeneralHelpIds);
|
|
break;
|
|
|
|
|
|
case WM_NOTIFY:
|
|
switch (((NMHDR *)lParam)->code) {
|
|
case PSN_KILLACTIVE:
|
|
DocFind_CCOMPFNameLocValidatePage(pdfpsp);
|
|
break;
|
|
case PSN_SETACTIVE:
|
|
DocFind_CCOMPFNameLocInit(pdfpsp);
|
|
|
|
break;
|
|
|
|
case PSN_APPLY:
|
|
if ((pdfpsp->dwState & DFPAGE_INIT) != 0)
|
|
DocFind_CCOMPFNameLocApply(pdfpsp);
|
|
|
|
break;
|
|
case PSN_RESET:
|
|
if ((pdfpsp->dwState & DFPAGE_INIT) != 0)
|
|
{
|
|
// Null the filespec
|
|
SetDlgItemText(hwndDlg, IDD_FILESPEC, c_szNULL);
|
|
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////
|
|
// Define the Details interface used for this search. This includes
|
|
// The column header definitions.
|
|
////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
//===========================================================================
|
|
// CCOMPFDetails : member prototype - Docfind Folder implementation
|
|
//===========================================================================
|
|
ULONG STDMETHODCALLTYPE CCOMPFDetails_Release(IShellDetails * psd);
|
|
STDMETHODIMP CCOMPFDetails_GetDetailsOf(IShellDetails * psd,
|
|
LPCITEMIDLIST pidl, UINT iCol, LPSHELLDETAILS lpDetails);
|
|
|
|
// Functions that we call out of the file systems verison of this
|
|
extern STDMETHODIMP CNETDetails_GetDetailsOf(IShellDetails * psd,
|
|
LPCITEMIDLIST pidl, UINT iCol, LPSHELLDETAILS lpDetails);
|
|
STDMETHODIMP CCOMPFDetails_ColumnClick(IShellDetails * psd, UINT iColumn);
|
|
|
|
//===========================================================================
|
|
// CCOMPFDetails : Vtable
|
|
//===========================================================================
|
|
#pragma warning(error: 4090 4028 4047)
|
|
#pragma data_seg(DATASEG_READONLY)
|
|
|
|
extern const UINT s_auMapDFColToFSCol[];
|
|
enum
|
|
{
|
|
IDFCOL_NAME = 0,
|
|
IDFCOL_PATH,
|
|
IDFCOL_COMMENT,
|
|
IDFCOL_MAX, // Make sure this is the last enum item
|
|
} ;
|
|
|
|
|
|
|
|
#pragma data_seg(DATASEG_READONLY)
|
|
const COL_DATA s_CCOMPF_cols[] = {
|
|
{IDFCOL_NAME, IDS_NAME_COL, 20, LVCFMT_LEFT},
|
|
{IDFCOL_PATH, IDS_WORKGROUP_COL, 20, LVCFMT_LEFT},
|
|
{IDFCOL_COMMENT, IDS_COMMENT_COL, 20, LVCFMT_LEFT},
|
|
};
|
|
|
|
|
|
IShellDetailsVtbl c_CCOMPFDetailVtbl =
|
|
{
|
|
SH32Unknown_QueryInterface,
|
|
SH32Unknown_AddRef,
|
|
SH32Unknown_Release,
|
|
CCOMPFDetails_GetDetailsOf,
|
|
CCOMPFDetails_ColumnClick,
|
|
};
|
|
|
|
#pragma data_seg()
|
|
#pragma warning(default: 4090 4028 4047)
|
|
|
|
|
|
typedef struct _CCOMPFDetails
|
|
{
|
|
SH32Unknown SH32Unk;
|
|
|
|
// Pointer to docfind folder
|
|
HWND hwndDlg;
|
|
HDPA hdpaPidf;
|
|
} CCOMPFDetails;
|
|
|
|
|
|
STDMETHODIMP CNETFilter_CreateDetails(LPDOCFINDFILEFILTER pnetf,
|
|
HWND hwndDlg, HDPA hdpaPidf, LPVOID FAR* ppvOut)
|
|
{
|
|
HRESULT hres = ResultFromScode(E_OUTOFMEMORY);
|
|
CCOMPFDetails *psd;
|
|
|
|
psd = (void*)LocalAlloc(LPTR, SIZEOF(CCOMPFDetails));
|
|
if (!psd)
|
|
{
|
|
goto Error1;
|
|
}
|
|
|
|
psd->SH32Unk.unk.lpVtbl = (IUnknownVtbl *)&c_CCOMPFDetailVtbl;
|
|
psd->SH32Unk.cRef = 1;
|
|
psd->SH32Unk.riid = &IID_IShellDetails;
|
|
|
|
psd->hwndDlg = hwndDlg;
|
|
psd->hdpaPidf = hdpaPidf;
|
|
|
|
*ppvOut = psd;
|
|
|
|
return(NOERROR);
|
|
|
|
Error1:;
|
|
return(hres);
|
|
}
|
|
|
|
|
|
STDMETHODIMP CCOMPFDetails_GetDetailsOf(IShellDetails * psd, LPCITEMIDLIST pidl,
|
|
UINT iColumn, LPSHELLDETAILS lpDetails)
|
|
{
|
|
CCOMPFDetails * this = IToClass(CCOMPFDetails, SH32Unk.unk, psd);
|
|
|
|
if (iColumn >= IDFCOL_MAX)
|
|
{
|
|
return(ResultFromScode(E_NOTIMPL));
|
|
}
|
|
|
|
lpDetails->str.uType = STRRET_CSTR;
|
|
lpDetails->str.cStr[0] = '\0';
|
|
|
|
if (!pidl)
|
|
{
|
|
LoadStringA(HINST_THISDLL, s_CCOMPF_cols[iColumn].ids,
|
|
lpDetails->str.cStr, ARRAYSIZE(lpDetails->str.cStr));
|
|
lpDetails->fmt = s_CCOMPF_cols[iColumn].iFmt;
|
|
lpDetails->cxChar = s_CCOMPF_cols[iColumn].cchCol;
|
|
return(NOERROR);
|
|
}
|
|
|
|
if (iColumn == IDFCOL_PATH)
|
|
{
|
|
// We need to now get to the idlist of the items folder.
|
|
LPDFFOLDERLISTITEM pdffli = DPA_FastGetPtr(this->hdpaPidf,
|
|
*DF_IFLDRPTR(pidl));
|
|
|
|
if (pdffli != NULL)
|
|
{
|
|
LPCITEMIDLIST pidlLast;
|
|
// This one is not part of the standard file system view...
|
|
// This is rather gross, but I will assume that the parent
|
|
// Of our item will get the same input as we do..., except
|
|
// for the root!
|
|
|
|
Assert (pdffli->psf);
|
|
if (pdffli->psf != NULL)
|
|
{
|
|
pidlLast = ILFindLastID(pdffli->pidl);
|
|
if (pidlLast == pdffli->pidl)
|
|
{
|
|
LPSHELLFOLDER psfDesktop = Desktop_GetShellFolder(TRUE);
|
|
return psfDesktop->lpVtbl->GetDisplayNameOf(psfDesktop,
|
|
pidlLast, SHGDN_NORMAL, &lpDetails->str);
|
|
}
|
|
else
|
|
{
|
|
HRESULT hres;
|
|
hres = pdffli->psf->lpVtbl->GetDisplayNameOf(pdffli->psf,
|
|
pidlLast, SHGDN_NORMAL, &lpDetails->str);
|
|
if (SUCCEEDED(hres) && (lpDetails->str.uType == STRRET_OFFSET))
|
|
{
|
|
// Can't deal with it being an offset as the offset
|
|
// is from our internal PIDL
|
|
//
|
|
lstrcpyA(lpDetails->str.cStr,
|
|
(LPSTR)((LPBYTE)pidlLast + lpDetails->str.uOffset));
|
|
lpDetails->str.uType = STRRET_CSTR;
|
|
}
|
|
}
|
|
}
|
|
return(NOERROR);
|
|
}
|
|
|
|
return(ResultFromScode(E_INVALIDARG));
|
|
}
|
|
|
|
else
|
|
{
|
|
// Let the file system function do it for us...
|
|
// BUGBUG:: This uses the hard coded network one which
|
|
// is probably not very good, but it beats having to create
|
|
//
|
|
return CNETDetails_GetDetailsOf(NULL, pidl,
|
|
s_auMapDFColToFSCol[iColumn], lpDetails);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP CCOMPFDetails_ColumnClick(IShellDetails * psd, UINT iColumn)
|
|
{
|
|
CCOMPFDetails * this = IToClass(CCOMPFDetails, SH32Unk.unk, psd);
|
|
|
|
ShellFolderView_ReArrange(this->hwndDlg, iColumn);
|
|
return(NOERROR);
|
|
}
|
|
|
|
//===========================================================================
|
|
// CNETFEnum: class definition
|
|
//===========================================================================
|
|
|
|
|
|
typedef struct _CNETFEnum // DFENUM (Doc find Container)
|
|
{
|
|
IDFEnum dfenum;
|
|
UINT cRef;
|
|
IShellFolder *psf; // Pointer to shell folder
|
|
|
|
// Stuff to use in the search
|
|
DWORD grfFlags; // Flags that control things like recursion
|
|
|
|
// filter info...
|
|
LPTSTR pszDisplayText; // Place to write feadback text into
|
|
LPNETFILTER pnetf; // Pointer to the net filter...
|
|
|
|
// enumeration state
|
|
|
|
LPSHELLFOLDER psfEnum; // Pointer to shell folder for the object.
|
|
LPENUMIDLIST penum; // Enumerator in use.
|
|
LPITEMIDLIST pidl; // The idlist of the currently processing
|
|
LPITEMIDLIST pidlStart; // Pointer to the starting point.
|
|
int iFolder; // Which folder are we adding items for?
|
|
BOOL fAddedSubDirs;
|
|
BOOL fObjReturnedInDir; // Has an object been returned in this dir?
|
|
BOOL fFindUNC; // Find UNC.
|
|
int iPassCnt; // Used to control when to reiterat...
|
|
|
|
} CNETFEnum, FAR* LPDFENUM;
|
|
|
|
//===========================================================================
|
|
// CNETFEnum : member prototype - Docfind Folder implementation
|
|
//===========================================================================
|
|
HRESULT STDMETHODCALLTYPE CNETFEnum_QueryInterface(
|
|
IDFEnum * pdfenum, REFIID riid, LPVOID FAR* ppvObj);
|
|
ULONG STDMETHODCALLTYPE CNETFEnum_AddRef(IDFEnum * pdfenum);
|
|
ULONG STDMETHODCALLTYPE CNETFEnum_Release(IDFEnum * pdfenum);
|
|
|
|
STDMETHODIMP CNETFEnum_Next(IDFEnum * pdfenum, LPITEMIDLIST *ppidl,
|
|
int *pcObjectSearched, int *pcFoldersSearched, volatile BOOL *pfContinue, int *pState, HWND hwnd);
|
|
|
|
|
|
STDMETHODIMP CDefDFEnum_Skip(IDFEnum * pdfenum, int celt);
|
|
STDMETHODIMP CDefDFEnum_Reset(IDFEnum * pdfenum);
|
|
|
|
|
|
//===========================================================================
|
|
// CNETFEnum : Vtable
|
|
//===========================================================================
|
|
#pragma warning(error: 4090 4028 4047)
|
|
#pragma data_seg(DATASEG_READONLY)
|
|
|
|
IDFEnumVtbl c_CCOMPFFIterVtbl =
|
|
{
|
|
CNETFEnum_QueryInterface,
|
|
CNETFEnum_AddRef,
|
|
CNETFEnum_Release,
|
|
CNETFEnum_Next,
|
|
CDefDFEnum_Skip,
|
|
CDefDFEnum_Reset,
|
|
};
|
|
|
|
|
|
//==========================================================================
|
|
// CNETFEnum::QueryInterface
|
|
//==========================================================================
|
|
|
|
HRESULT STDMETHODCALLTYPE CNETFEnum_QueryInterface(IDFEnum * pdfenum, REFIID riid, LPVOID FAR* ppvObj)
|
|
{
|
|
return ResultFromScode(E_NOTIMPL);
|
|
}
|
|
|
|
//==========================================================================
|
|
// IDFEnum::AddRef
|
|
//==========================================================================
|
|
ULONG STDMETHODCALLTYPE CNETFEnum_AddRef(IDFEnum * pdfenum)
|
|
{
|
|
LPDFENUM this = IToClass(CNETFEnum, dfenum, pdfenum);
|
|
this->cRef++;
|
|
return(this->cRef);
|
|
}
|
|
//==========================================================================
|
|
// CNETFilter_EnumObjects - Get The real recursive filtered enumerator...
|
|
//==========================================================================
|
|
HRESULT CNETFilter_EnumObjects( IDocFindFileFilter * pdfff,
|
|
LPSHELLFOLDER psf, DWORD grfFlags, LPTSTR pszDisplayText, IDFEnum **ppdfenum)
|
|
{
|
|
// We need to construct the iterator
|
|
LPNETFILTER pnetf = (LPNETFILTER)pdfff;
|
|
LPDFENUM pdfenum = LocalAlloc(LPTR, SIZEOF(CNETFEnum));
|
|
if (pdfenum == NULL)
|
|
return ResultFromScode(E_OUTOFMEMORY);
|
|
|
|
// Now initialize the data structures.
|
|
pdfenum->dfenum.lpVtbl = &c_CCOMPFFIterVtbl;
|
|
pdfenum->cRef = 1;
|
|
pdfenum->psf = psf;
|
|
pdfenum->pszDisplayText = pszDisplayText;
|
|
pdfenum->grfFlags = grfFlags;
|
|
pdfenum->pnetf = pnetf;
|
|
|
|
pdfenum->pidlStart = ILClone(pnetf->pidlStart);
|
|
pdfenum->iPassCnt = 0;
|
|
|
|
// See if this is a UNC Search
|
|
if (pnetf->pszCompName && (pnetf->pszCompName[0] == TEXT('\\')))
|
|
pdfenum->fFindUNC = TRUE;
|
|
|
|
|
|
// Save away the filter pointer
|
|
pnetf->dfff.lpVtbl->AddRef(pdfff);
|
|
|
|
// The rest of the fields should be zero/NULL
|
|
*ppdfenum = &pdfenum->dfenum; // Return the appropriate value;
|
|
|
|
#ifdef FIND_TRACE
|
|
DebugMsg(DM_TRACE, TEXT("CNETFilter::EnumObjects"));
|
|
#endif
|
|
|
|
#ifdef NET_TIMINGS
|
|
// Reset Counters
|
|
NTF_cNoPEnum = NTF_dtNoPEnum = 0;
|
|
NTF_cNextItem = NTF_dtNextItem = 0;
|
|
#endif
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
//==========================================================================
|
|
// CNETFEnum::Release
|
|
//==========================================================================
|
|
ULONG STDMETHODCALLTYPE CNETFEnum_Release(IDFEnum * pdfenum)
|
|
{
|
|
LPDFENUM this = IToClass(CNETFEnum, dfenum, pdfenum);
|
|
|
|
this->cRef--;
|
|
if (this->cRef>0)
|
|
{
|
|
return(this->cRef);
|
|
}
|
|
|
|
// Release any open enumerator and open IShell folder we may have.
|
|
if (this->psfEnum != NULL)
|
|
this->psfEnum->lpVtbl->Release(this->psfEnum);
|
|
if (this->penum != NULL)
|
|
this->penum->lpVtbl->Release(this->penum);
|
|
|
|
|
|
// Release our use of the filter
|
|
if (this->pnetf)
|
|
this->pnetf->dfff.lpVtbl->Release(&this->pnetf->dfff);
|
|
|
|
if (this->pidlStart)
|
|
ILFree(this->pidlStart);
|
|
if (this->pidl)
|
|
ILFree(this->pidl);
|
|
|
|
LocalFree((HLOCAL)this);
|
|
|
|
#ifdef NET_TIMINGS
|
|
// Output some timings.
|
|
if (!this->fFindUNC)
|
|
{
|
|
DebugMsg(DM_TRACE, TEXT("CNETFEnum:: Start Enums(%d), Time(%d), Per item(%d)"),
|
|
NTF_cNoPEnum, NTF_dtNoPEnum, NTF_dtNoPEnum/NTF_cNoPEnum);
|
|
|
|
DebugMsg(DM_TRACE, TEXT("CNETFEnum:: Count Next(%d), Time(%d), Per item(%d)"),
|
|
NTF_cNextItem, NTF_dtNextItem, NTF_dtNextItem/NTF_cNextItem);
|
|
}
|
|
#endif
|
|
return(0);
|
|
}
|
|
|
|
|
|
//===========================================================================
|
|
// Helper function that does the find next and stuff to return an IDLISt...
|
|
//===========================================================================
|
|
LPITEMIDLIST DocFind_NextIDL(LPSHELLFOLDER psf, LPENUMIDLIST penum)
|
|
{
|
|
UINT celt;
|
|
LPITEMIDLIST pidl = NULL;
|
|
|
|
if (penum->lpVtbl->Next(penum, 1, &pidl, &celt)==NOERROR && celt==1)
|
|
{
|
|
return pidl;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
//===========================================================================
|
|
// Helper function that possibly pushes a directory onto the list of this
|
|
// to be searched.
|
|
//===========================================================================
|
|
|
|
|
|
//===========================================================================
|
|
// _FindCompByUNCName -
|
|
// Helper function to the next function to help process find computer
|
|
// on returning computers by UNC names...
|
|
//
|
|
//
|
|
//===========================================================================
|
|
STDMETHODIMP _FindCompByUNCName(CNETFEnum * this, LPITEMIDLIST *ppidl,
|
|
int *piState)
|
|
{
|
|
LPTSTR pszT;
|
|
LPITEMIDLIST pidl;
|
|
|
|
//
|
|
// Two cases, There is a UNC name entered. If so we need to process
|
|
// this by extracting everythign off after the server name...
|
|
//
|
|
pszT = this->pnetf->pszCompName;
|
|
|
|
if ((pszT==NULL) || (*pszT == TEXT('\0')))
|
|
{
|
|
*piState = GNF_DONE;
|
|
return NOERROR;
|
|
}
|
|
|
|
if (*pszT == TEXT('\\'))
|
|
{
|
|
for (pszT += 2; *pszT; pszT = CharNext(pszT))
|
|
{
|
|
if (*pszT == TEXT('\\'))
|
|
{
|
|
// found something after server name, so get rid of it
|
|
*pszT = TEXT('\0');
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// They did not enter a unc name, but lets try to convert to
|
|
// unc name
|
|
pszT = LocalReAlloc(pszT,(3 + lstrlen(pszT))*SIZEOF(TCHAR),
|
|
LMEM_MOVEABLE );
|
|
if (pszT)
|
|
{
|
|
this->pnetf->pszCompName = pszT;
|
|
*pszT++ = TEXT('\\');
|
|
*pszT++ = TEXT('\\');
|
|
lstrcpy(pszT, this->pnetf->szUserInputCompName);
|
|
}
|
|
else
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
// Now parse the displayname - Argh we convert to Unicode, such
|
|
// that we can uncovert at the other side.
|
|
//
|
|
pidl = ILCreateFromPath(this->pnetf->pszCompName);
|
|
if (pidl != NULL)
|
|
{
|
|
LPITEMIDLIST pidlToAdd;
|
|
//
|
|
// We have a pidl so lets extract off the last part and clone
|
|
// it to return and use the part before the end to add to the
|
|
// folder list.
|
|
pidlToAdd = ILCombine(ILFindLastID(pidl), (LPITEMIDLIST)&s_mkidBlank);
|
|
ILRemoveLastID(pidl); // Remove the last id (computer)
|
|
CDFFolder_AddFolderToFolderList(
|
|
this->psf, pidl, NULL, &this->iFolder);
|
|
// Now add the right signature on...
|
|
pidlToAdd->mkid.cb += DF_APPENDSIZE;
|
|
*(DF_SIGPTR(pidlToAdd)) = DF_TAGSIG;
|
|
*(DF_IFLDRPTR(pidlToAdd)) = this->iFolder;
|
|
// Now add this to the view
|
|
*ppidl = pidlToAdd;
|
|
*piState = GNF_MATCH;
|
|
}
|
|
else
|
|
*piState = GNF_DONE;
|
|
|
|
// And Return;
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
//===========================================================================
|
|
// CNETFEnum::Next Recursive Iterator that is very special to the docfind.
|
|
// It will walk each directory, breath first, it will call the
|
|
// defined callback function to determine if it is an
|
|
// interesting file to us. It will also return additional
|
|
// information, such as: The number of folders and files
|
|
// searched, so we can give results back to the user. It
|
|
// will return control to the caller whenever:
|
|
// a) Finds a match.
|
|
// b) runs out of things to search.
|
|
// c) Starts searching in another directory
|
|
// d) when the callback says to...
|
|
//
|
|
//
|
|
//===========================================================================
|
|
STDMETHODIMP CNETFEnum_Next(IDFEnum * pdfenum, LPITEMIDLIST *ppidl,
|
|
int *pcObjectSearched, int *pcFoldersSearched,
|
|
volatile BOOL *pfContinue, int *piState, HWND hwnd)
|
|
{
|
|
// If we aren't enumerating a directory, then get the next directory
|
|
// name from the dir list, and begin enumerating its contents...
|
|
//
|
|
CNETFEnum * this = IToClass(CNETFEnum, dfenum, pdfenum);
|
|
BOOL fContinue = TRUE;
|
|
STRRET strret;
|
|
LPSHELLFOLDER psfDesktop = Desktop_GetShellFolder(TRUE);
|
|
|
|
//
|
|
// Special case to find UNC Names quickly. It will ignore all other
|
|
// things.
|
|
if (this->fFindUNC)
|
|
{
|
|
// If not the first time through return that we are done!
|
|
if (this->iPassCnt)
|
|
{
|
|
*piState = GNF_DONE;
|
|
return NOERROR;
|
|
}
|
|
|
|
this->iPassCnt = 1;
|
|
|
|
return _FindCompByUNCName(this, ppidl, piState);
|
|
}
|
|
|
|
do
|
|
{
|
|
if (this->penum)
|
|
{
|
|
LPITEMIDLIST pidl;
|
|
#ifdef NET_TIMINGS
|
|
NTF_dtTime = GetTickCount();
|
|
#endif
|
|
pidl = DocFind_NextIDL(this->psfEnum, this->penum);
|
|
#ifdef NET_TIMINGS
|
|
NTF_cNextItem++;
|
|
NTF_dtNextItem += GetTickCount() - NTF_dtTime;
|
|
#endif
|
|
|
|
if (pidl)
|
|
{
|
|
#ifdef FIND_TRACE
|
|
TCHAR szTrace[MAX_PATH];
|
|
STRRET str;
|
|
this->psfEnum->lpVtbl->GetDisplayNameOf(this->psfEnum, pidl, SHGDN_NORMAL,
|
|
&str);
|
|
StrRetToStrN(szTrace, ARRAYSIZE(szTrace), &str, pidl);
|
|
DebugMsg(DM_TRACE, TEXT("CNETFEnum::Next: %s"), szTrace);
|
|
#endif
|
|
// Now see if this is someone we might want to return.
|
|
// Our Match function take esither find data or idlist...
|
|
// for networks we work off of the idlist,
|
|
fContinue = FALSE; // We can exit the loop;
|
|
(*pcObjectSearched)++;
|
|
if (this->pnetf->dfff.lpVtbl->FDoesItemMatchFilter(
|
|
&this->pnetf->dfff,
|
|
this->pszDisplayText, NULL, this->psfEnum, pidl) != 0)
|
|
{
|
|
LPITEMIDLIST pidlToAdd;
|
|
*piState = GNF_MATCH;
|
|
|
|
// Now see if we have to add this folder to our
|
|
// list.
|
|
if (!this->fObjReturnedInDir)
|
|
{
|
|
this->fObjReturnedInDir = TRUE;
|
|
CDFFolder_AddFolderToFolderList(
|
|
this->psf, ILClone(this->pidl), NULL,
|
|
&this->iFolder);
|
|
}
|
|
|
|
// Now lets muck up the IDList to put ur index number
|
|
// onto the end of the idlist.
|
|
pidlToAdd = ILCombine((LPITEMIDLIST)pidl,
|
|
(LPITEMIDLIST)&s_mkidBlank);
|
|
ILFree(pidl);
|
|
if (pidlToAdd)
|
|
{
|
|
pidlToAdd->mkid.cb += DF_APPENDSIZE;
|
|
*(DF_SIGPTR(pidlToAdd)) = DF_TAGSIG;
|
|
*(DF_IFLDRPTR(pidlToAdd)) = this->iFolder;
|
|
|
|
// Now add this to the view
|
|
*ppidl = pidlToAdd;
|
|
if ((this->iPassCnt == 1) && this->pnetf->pszCompName && *this->pnetf->pszCompName)
|
|
{
|
|
// See if this is an exact match of the name
|
|
// we are looking for. If it is we set pass=2
|
|
// as to not add the item twice.
|
|
STRRET str;
|
|
|
|
this->psf->lpVtbl->GetDisplayNameOf(this->psf,
|
|
pidlToAdd, SHGDN_NORMAL, &str);
|
|
|
|
#ifdef UNICODE
|
|
{
|
|
TCHAR szName[MAX_PATH];
|
|
if (StrRetToStrN(szName, MAX_PATH, &str, pidlToAdd))
|
|
{
|
|
if (0 == lstrcmpi(szName, this->pnetf->szUserInputCompName))
|
|
{
|
|
this->iPassCnt = 2;
|
|
}
|
|
}
|
|
}
|
|
|
|
#else
|
|
Assert (str.uType == STRRET_OFFSET)
|
|
|
|
// Note in this test we ignore the two slashes...
|
|
if ((str.uType == STRRET_OFFSET) &&
|
|
(ualstrcmpi((LPTSTR)((LPBYTE)pidlToAdd + str.uOffset),
|
|
this->pnetf->szUserInputCompName) == 0))
|
|
this->iPassCnt = 2;
|
|
#endif
|
|
}
|
|
break;
|
|
}
|
|
|
|
}
|
|
else
|
|
|
|
{
|
|
// Release the IDList that did not match
|
|
ILFree(pidl);
|
|
*piState = GNF_NOMATCH;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Close out the shell folder and the enumeration function.
|
|
this->penum->lpVtbl->Release(this->penum);
|
|
this->penum = NULL;
|
|
|
|
this->psfEnum->lpVtbl->Release(this->psfEnum);
|
|
this->psfEnum = NULL;
|
|
}
|
|
}
|
|
if (!this->penum)
|
|
{
|
|
switch (this->iPassCnt)
|
|
{
|
|
case 1:
|
|
// We went through all of the items see if there is
|
|
// an exact match...
|
|
this->iPassCnt = 2;
|
|
|
|
return _FindCompByUNCName(this, ppidl, piState);
|
|
|
|
case 2:
|
|
// We looped through everything so return done!
|
|
*piState = GNF_DONE;
|
|
return NOERROR;
|
|
|
|
case 0:
|
|
// This is the main pass through here...
|
|
// Need to clone the idlist
|
|
this->pidl = ILClone(this->pidlStart);
|
|
if (this->pidl == NULL)
|
|
{
|
|
*piState = GNF_ERROR;
|
|
return ResultFromScode(E_OUTOFMEMORY);
|
|
}
|
|
this->iPassCnt = 1;
|
|
|
|
// We will do the first on in our own thread.
|
|
if (SUCCEEDED(psfDesktop->lpVtbl->BindToObject(psfDesktop,
|
|
this->pidl, NULL, &IID_IShellFolder,
|
|
&this->psfEnum)))
|
|
{
|
|
|
|
// BUGBUG:: Need more flags to control this!
|
|
if (FAILED(this->psfEnum->lpVtbl->EnumObjects(this->psfEnum,
|
|
(HWND)NULL, // BUGBUG: hwndOwner
|
|
SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &this->penum)))
|
|
{
|
|
// Failed to get iterator so release folder.
|
|
this->psfEnum->lpVtbl->Release(this->psfEnum);
|
|
this->psfEnum = NULL;
|
|
this->penum = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
// We are now read to get the IShellfolder for this guy!
|
|
(*pcFoldersSearched)++;
|
|
|
|
// Need to put something here to show what is being searched!
|
|
strret.uType = STRRET_OFFSET;
|
|
if (SUCCEEDED(psfDesktop->lpVtbl->GetDisplayNameOf(psfDesktop,
|
|
this->pidl, SHGDN_NORMAL, &strret)))
|
|
{
|
|
StrRetToStrN(this->pszDisplayText, MAX_PATH, &strret,
|
|
this->pidl);
|
|
}
|
|
|
|
#ifdef NET_TIMINGS
|
|
NTF_cNoPEnum++;
|
|
#endif
|
|
}
|
|
} while (fContinue && *pfContinue);
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
//===========================================================================
|
|
// CNETFEnum::Skip Recursive Iterator that is very special to the docfind.
|
|
//===========================================================================
|
|
STDMETHODIMP CDefDFEnum_Skip(IDFEnum * pdfenum, int celt)
|
|
{
|
|
return (E_NOTIMPL);
|
|
}
|
|
|
|
//===========================================================================
|
|
// CNETFEnum::Reset
|
|
//===========================================================================
|
|
STDMETHODIMP CDefDFEnum_Reset(IDFEnum * pdfenum)
|
|
{
|
|
return (E_NOTIMPL);
|
|
}
|
|
|
|
|
|
|
|
|
|
//###########################################################################
|
|
// 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
|
|
LPTSTR pszDisplayName;// Return display name of item selected.
|
|
int *piImage; // where to return the Image index.
|
|
LPCTSTR 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
|
|
LPSHELLFOLDER 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 DocFind_BFSFDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
|
|
LPITEMIDLIST _BFSFUpdateISHCache(PBFSF pbfsf, HTREEITEM hti, LPITEMIDLIST pidlItem);
|
|
|
|
//===========================================================================
|
|
// DocFind_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;
|
|
// NB: The ANSI Thunk (see below) does not call through this routine,
|
|
// but rather called DialogBoxParam on its own. If you change this
|
|
// routine, change the A version as well!!
|
|
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, DocFind_BFSFDlgProc, (LPARAM)&bfsf))
|
|
lpRet = bfsf.pidlCurrent;
|
|
else
|
|
lpRet = NULL;
|
|
|
|
if (hcOld)
|
|
SetCursor(hcOld);
|
|
|
|
return lpRet;
|
|
}
|
|
|
|
#ifdef UNICODE
|
|
|
|
LPITEMIDLIST WINAPI SHBrowseForFolderA(LPBROWSEINFOA lpbi)
|
|
{
|
|
LPITEMIDLIST lpRet;
|
|
WCHAR wszReturn[MAX_PATH];
|
|
|
|
ThunkText * pThunkText = ConvertStrings(1,
|
|
lpbi->lpszTitle);
|
|
|
|
if (pThunkText)
|
|
{
|
|
BFSF bfsf =
|
|
{
|
|
lpbi->hwndOwner,
|
|
lpbi->pidlRoot,
|
|
wszReturn,
|
|
&lpbi->iImage,
|
|
pThunkText->m_pStr[0], // UNICODE copy of lpbi->lpszTitle
|
|
lpbi->ulFlags,
|
|
lpbi->lpfn,
|
|
lpbi->lParam,
|
|
};
|
|
HCURSOR hcOld = SetCursor(LoadCursor(NULL,IDC_WAIT));
|
|
SHELLSTATE ss;
|
|
BOOL fDialogResult;
|
|
|
|
SHGetSetSettings(&ss, SSF_SHOWALLOBJECTS, FALSE);
|
|
bfsf.fShowAllObjects = ss.fShowAllObjects;
|
|
|
|
// Now Create the dialog that will be doing the browsing.
|
|
|
|
fDialogResult = DialogBoxParam(HINST_THISDLL,
|
|
MAKEINTRESOURCE(DLG_BROWSEFORFOLDER),
|
|
lpbi->hwndOwner, DocFind_BFSFDlgProc,
|
|
(LPARAM)&bfsf);
|
|
LocalFree(pThunkText);
|
|
if (hcOld)
|
|
SetCursor(hcOld);
|
|
|
|
if (fDialogResult)
|
|
{
|
|
BOOL fDefUsed;
|
|
if (NULL != lpbi->pszDisplayName)
|
|
{
|
|
WideCharToMultiByte(CP_ACP,
|
|
WC_COMPOSITECHECK | WC_DEFAULTCHAR,
|
|
wszReturn,
|
|
-1,
|
|
lpbi->pszDisplayName,
|
|
MAX_PATH,
|
|
"_",
|
|
&fDefUsed);
|
|
}
|
|
lpRet = bfsf.pidlCurrent;
|
|
}
|
|
else
|
|
{
|
|
lpRet = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lpRet = NULL;
|
|
}
|
|
|
|
return lpRet;
|
|
}
|
|
#else
|
|
LPITEMIDLIST WINAPI SHBrowseForFolderW(LPBROWSEINFOW lpbi)
|
|
{
|
|
return NULL; // BUGBUG - BobDay - We should move this into SHUNIMP.C
|
|
}
|
|
#endif
|
|
|
|
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 _BFSFAddItemToTree(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 _BFSFGetIDListFromTreeItem(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 ((NULL != (tvi.hItem = TreeView_GetParent(hwndTree, tvi.hItem))) && pidl)
|
|
{
|
|
if (!TreeView_GetItem(hwndTree, &tvi))
|
|
return(pidl); // will assume I screwed 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;
|
|
|
|
hres = psfParent->lpVtbl->CompareIDs(psfParent,
|
|
0, (LPITEMIDLIST)lParam1, (LPITEMIDLIST)lParam2);
|
|
if (!SUCCEEDED(hres))
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
return((short)SCODE_CODE(GetScode(hres)));
|
|
}
|
|
|
|
void _BFSFSort(PBFSF pbfsf, HTREEITEM hti, LPSHELLFOLDER 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 lpnmtv)
|
|
{
|
|
LPITEMIDLIST pidlToExpand;
|
|
LPITEMIDLIST pidl;
|
|
LPSHELLFOLDER psf;
|
|
LPSHELLFOLDER psfDesktop = Desktop_GetShellFolder(TRUE);
|
|
BYTE bType;
|
|
DWORD grfFlags;
|
|
BOOL fPrinterTest = FALSE;
|
|
int cAdded = 0;
|
|
TV_ITEM tvi;
|
|
|
|
LPENUMIDLIST penum; // Enumerator in use.
|
|
|
|
if (lpnmtv->action != TVE_EXPAND)
|
|
return FALSE;
|
|
|
|
if ((lpnmtv->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 = lpnmtv->itemNew.hItem;
|
|
tvi.state = TVIS_EXPANDEDONCE;
|
|
tvi.stateMask = TVIS_EXPANDEDONCE;
|
|
TreeView_SetItem(pbfsf->hwndTree, &tvi);
|
|
|
|
|
|
if (lpnmtv->itemNew.hItem == NULL)
|
|
{
|
|
lpnmtv->itemNew.hItem = TreeView_GetSelection(pbfsf->hwndTree);
|
|
if (lpnmtv->itemNew.hItem == NULL)
|
|
return FALSE;
|
|
}
|
|
|
|
pidlToExpand = _BFSFGetIDListFromTreeItem(pbfsf->hwndTree, lpnmtv->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 (NULL != (pidl = DocFind_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
|
|
}
|
|
}
|
|
|
|
_BFSFAddItemToTree(pbfsf->hwndTree, lpnmtv->itemNew.hItem,
|
|
pidl, cChildren);
|
|
cAdded++;
|
|
}
|
|
|
|
// Now Cleanup after ourself
|
|
penum->lpVtbl->Release(penum);
|
|
|
|
_BFSFSort(pbfsf, lpnmtv->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 = lpnmtv->itemNew.hItem;
|
|
tvi.cChildren = 0;
|
|
|
|
TreeView_SetItem(pbfsf->hwndTree, &tvi);
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//===========================================================================
|
|
void _BFSFHandleDeleteItem(PBFSF pbfsf, LPNM_TREEVIEW lpnmtv)
|
|
{
|
|
// We need to free the IDLists that we allocated previously
|
|
if (lpnmtv->itemOld.lParam != 0)
|
|
ILFree((LPITEMIDLIST)lpnmtv->itemOld.lParam);
|
|
}
|
|
|
|
//===========================================================================
|
|
LPITEMIDLIST _BFSFUpdateISHCache(PBFSF pbfsf, HTREEITEM hti,
|
|
LPITEMIDLIST pidlItem)
|
|
{
|
|
HTREEITEM htiParent;
|
|
LPSHELLFOLDER 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 = _BFSFGetIDListFromTreeItem(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 *lpnm)
|
|
{
|
|
TV_ITEM ti;
|
|
LPITEMIDLIST pidlItem = (LPITEMIDLIST)lpnm->item.lParam;
|
|
|
|
if ((lpnm->item.mask & (TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_TEXT | TVIF_CHILDREN)) == 0)
|
|
return; // nothing for us to do here.
|
|
|
|
pidlItem = _BFSFUpdateISHCache(pbfsf, lpnm->item.hItem, pidlItem);
|
|
|
|
ti.mask = 0;
|
|
ti.hItem = (HTREEITEM)lpnm->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 (lpnm->item.mask & (TVIF_IMAGE | TVIF_SELECTEDIMAGE))
|
|
{
|
|
// We now need to map the item into the right image index.
|
|
ti.iImage = lpnm->item.iImage = SHMapPIDLToSystemImageListIndex(
|
|
pbfsf->psfParent, pidlItem, &ti.iSelectedImage);
|
|
// we should save it back away to
|
|
lpnm->item.iSelectedImage = ti.iSelectedImage;
|
|
ti.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE;
|
|
}
|
|
// Also see if this guy has any child folders
|
|
if (lpnm->item.mask & TVIF_CHILDREN)
|
|
{
|
|
ULONG ulAttrs;
|
|
|
|
ulAttrs = SFGAO_HASSUBFOLDER;
|
|
pbfsf->psfParent->lpVtbl->GetAttributesOf(pbfsf->psfParent,
|
|
1, &pidlItem, &ulAttrs);
|
|
|
|
ti.cChildren = lpnm->item.cChildren =
|
|
(ulAttrs & SFGAO_HASSUBFOLDER)? 1 : 0;
|
|
|
|
ti.mask |= TVIF_CHILDREN;
|
|
|
|
}
|
|
|
|
if (lpnm->item.mask & TVIF_TEXT)
|
|
{
|
|
STRRET str;
|
|
pbfsf->psfParent->lpVtbl->GetDisplayNameOf(pbfsf->psfParent,
|
|
pidlItem, SHGDN_INFOLDER, &str);
|
|
|
|
StrRetToStrN(lpnm->item.pszText, lpnm->item.cchTextMax, &str, pidlItem);
|
|
ti.mask |= TVIF_TEXT;
|
|
ti.pszText = lpnm->item.pszText;
|
|
}
|
|
|
|
// Update the item now
|
|
TreeView_SetItem(pbfsf->hwndTree, &ti);
|
|
}
|
|
|
|
//===========================================================================
|
|
void _BFSFHandleSelChanged(PBFSF pbfsf, LPNM_TREEVIEW lpnmtv)
|
|
{
|
|
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, lpnmtv->itemNew.hItem,
|
|
(LPITEMIDLIST)lpnmtv->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 = _BFSFGetIDListFromTreeItem(pbfsf->hwndTree, lpnmtv->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 = _BFSFGetIDListFromTreeItem(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 = _BFSFGetIDListFromTreeItem(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;
|
|
}
|
|
|
|
//===========================================================================
|
|
// DocFind_OnBFSFInitDlg - Process the init dialog
|
|
//===========================================================================
|
|
BOOL DocFind_OnBFSFInitDlg(HWND hwnd, HWND hwndFocus, LPARAM lParam)
|
|
{
|
|
HTREEITEM hti;
|
|
PBFSF pbfsf = (PBFSF)lParam;
|
|
HIMAGELIST himl;
|
|
LPTSTR lpsz;
|
|
TCHAR 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 = _BFSFAddItemToTree(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;
|
|
|
|
htiRoot = _BFSFAddItemToTree(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 = _BFSFGetIDListFromTreeItem(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, ARRAYSIZE(szTitle));
|
|
SetWindowText(hwnd, szTitle);
|
|
}
|
|
else if ((pbfsf->ulFlags & BIF_BROWSEFORPRINTER) != 0)
|
|
{
|
|
LoadString(HINST_THISDLL, IDS_FINDSEARCH_PRINTER, szTitle, ARRAYSIZE(szTitle));
|
|
SetWindowText(hwnd, szTitle);
|
|
}
|
|
|
|
BFSFCallback(pbfsf, BFFM_INITIALIZED, 0);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//
|
|
// Called when a ANSI app sends BFFM_SETSTATUSTEXT message.
|
|
//
|
|
void _BFSFSetStatusTextA(PBFSF pbfsf, LPCSTR lpszText)
|
|
{
|
|
CHAR szText[100];
|
|
if (!HIWORD(lpszText)) {
|
|
LoadStringA(HINST_THISDLL, LOWORD((DWORD)lpszText), szText, ARRAYSIZE(szText));
|
|
lpszText = szText;
|
|
}
|
|
|
|
SetDlgItemTextA(pbfsf->hwndDlg, IDD_BROWSESTATUS, lpszText);
|
|
}
|
|
|
|
|
|
//
|
|
// Called when a UNICODE app sends BFFM_SETSTATUSTEXT message.
|
|
//
|
|
void _BFSFSetStatusTextW(PBFSF pbfsf, LPCWSTR lpszText)
|
|
{
|
|
WCHAR szText[100];
|
|
if (!HIWORD(lpszText)) {
|
|
LoadStringW(HINST_THISDLL, LOWORD((DWORD)lpszText), szText, ARRAYSIZE(szText));
|
|
lpszText = szText;
|
|
}
|
|
|
|
SetDlgItemTextW(pbfsf->hwndDlg, IDD_BROWSESTATUS, lpszText);
|
|
}
|
|
|
|
|
|
//
|
|
// Called when an ANSI app sends BFFM_SETSELECTION message.
|
|
//
|
|
BOOL _BFSFSetSelectionA(PBFSF pbfsf, BOOL blParamIsPath, LPARAM lParam)
|
|
{
|
|
BOOL fRet = FALSE;
|
|
|
|
if (blParamIsPath)
|
|
{
|
|
#ifdef UNICODE
|
|
//
|
|
// UNICODE build. Convert path from ansi to wide-char.
|
|
//
|
|
LPWSTR lpszPathW = NULL;
|
|
INT cchPathW = 0;
|
|
|
|
cchPathW = MultiByteToWideChar(CP_ACP,
|
|
0,
|
|
(LPCSTR)lParam,
|
|
-1,
|
|
NULL,
|
|
0);
|
|
if (0 < cchPathW)
|
|
{
|
|
lpszPathW = LocalAlloc(LPTR, cchPathW * sizeof(TCHAR));
|
|
if (NULL != lpszPathW)
|
|
{
|
|
MultiByteToWideChar(CP_ACP,
|
|
0,
|
|
(LPCSTR)lParam,
|
|
-1,
|
|
lpszPathW,
|
|
cchPathW);
|
|
|
|
lParam = (LPARAM)SHSimpleIDListFromPath(lpszPathW);
|
|
LocalFree(lpszPathW);
|
|
}
|
|
else
|
|
return FALSE; // Failed buffer allocation.
|
|
}
|
|
#else
|
|
//
|
|
// ANSI build. Just use ANSI path "as is".
|
|
//
|
|
lParam = (LPARAM)SHSimpleIDListFromPath((LPCTSTR)lParam);
|
|
#endif
|
|
|
|
if (!lParam)
|
|
return FALSE; // Failed pidl creation.
|
|
}
|
|
|
|
fRet = BrowseSelectPidl(pbfsf, (LPITEMIDLIST)lParam);
|
|
|
|
if (blParamIsPath)
|
|
ILFree((LPITEMIDLIST)lParam);
|
|
|
|
return fRet;
|
|
}
|
|
|
|
|
|
//
|
|
// Called when a UNICODE app sends BFFM_SETSELECTION message.
|
|
//
|
|
BOOL _BFSFSetSelectionW(PBFSF pbfsf, BOOL blParamIsPath, LPARAM lParam)
|
|
{
|
|
BOOL fRet = FALSE;
|
|
|
|
if (blParamIsPath)
|
|
{
|
|
|
|
#ifndef UNICODE
|
|
//
|
|
// ANSI build. Convert path from wide-char to ansi.
|
|
//
|
|
LPSTR lpszPathA = NULL;
|
|
INT cchPathA = 0;
|
|
|
|
cchPathA = WideCharToMultiByte(CP_ACP,
|
|
0,
|
|
(LPWSTR)lParam,
|
|
-1,
|
|
NULL,
|
|
0,
|
|
0,
|
|
0);
|
|
if (0 < cchPathA)
|
|
{
|
|
lpszPathA = LocalAlloc(LPTR, cchPathA * sizeof(TCHAR));
|
|
if (NULL != lpszPathA)
|
|
{
|
|
WideCharToMultiByte(CP_ACP,
|
|
0,
|
|
(LPWSTR)lParam,
|
|
-1,
|
|
lpszPathA,
|
|
cchPathA,
|
|
0,
|
|
0);
|
|
|
|
lParam = (LPARAM)SHSimpleIDListFromPath(lpszPathA);
|
|
LocalFree(lpszPathA);
|
|
}
|
|
else
|
|
return FALSE; // Failed buffer allocation.
|
|
}
|
|
#else
|
|
//
|
|
// UNICODE build. Just use wide char path "as is".
|
|
//
|
|
lParam = (LPARAM)SHSimpleIDListFromPath((LPCTSTR)lParam);
|
|
#endif
|
|
if (!lParam)
|
|
return FALSE; // Failed pidl creation.
|
|
}
|
|
|
|
fRet = BrowseSelectPidl(pbfsf, (LPITEMIDLIST)lParam);
|
|
|
|
if (blParamIsPath)
|
|
{
|
|
//
|
|
// Free the pidl we created from path.
|
|
//
|
|
ILFree((LPITEMIDLIST)lParam);
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
|
|
//===========================================================================
|
|
// DocFind_OnBFSFCommand - Process the WM_COMMAND message
|
|
//===========================================================================
|
|
void DocFind_OnBFSFCommand(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 = _BFSFGetIDListFromTreeItem(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;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
//===========================================================================
|
|
// DocFind_BSFSDlgProc - The dialog procedure for processing the browse
|
|
// for starting folder dialog.
|
|
//===========================================================================
|
|
#pragma data_seg(DATASEG_READONLY)
|
|
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 DocFind_BFSFDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam,
|
|
LPARAM lParam)
|
|
{
|
|
PBFSF pbfsf = (PBFSF)GetWindowLong(hwndDlg, DWL_USER);
|
|
|
|
switch (msg) {
|
|
HANDLE_MSG(pbfsf, WM_COMMAND, DocFind_OnBFSFCommand);
|
|
HANDLE_MSG(hwndDlg, WM_INITDIALOG, DocFind_OnBFSFInitDlg);
|
|
|
|
case WM_DESTROY:
|
|
if (pbfsf->psfParent && (pbfsf->psfParent != Desktop_GetShellFolder(TRUE)))
|
|
{
|
|
pbfsf->psfParent->lpVtbl->Release(pbfsf->psfParent);
|
|
pbfsf->psfParent = NULL;
|
|
}
|
|
break;
|
|
|
|
case BFFM_SETSTATUSTEXTA:
|
|
_BFSFSetStatusTextA(pbfsf, (LPCSTR)lParam);
|
|
break;
|
|
|
|
case BFFM_SETSTATUSTEXTW:
|
|
_BFSFSetStatusTextW(pbfsf, (LPCWSTR)lParam);
|
|
break;
|
|
|
|
case BFFM_SETSELECTIONW:
|
|
return _BFSFSetSelectionW(pbfsf, (BOOL)wParam, lParam);
|
|
|
|
case BFFM_SETSELECTIONA:
|
|
return _BFSFSetSelectionA(pbfsf, (BOOL)wParam, lParam);
|
|
|
|
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)(LPTSTR) aBrowseHelpIDs);
|
|
break;
|
|
|
|
case WM_CONTEXTMENU:
|
|
WinHelp((HWND) wParam, NULL, HELP_CONTEXTMENU,
|
|
(DWORD)(LPVOID) aBrowseHelpIDs);
|
|
break;
|
|
|
|
default:
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
/*----------------------------------------------------------------------------
|
|
/ CNETFilter_DeclareFSNotifyInterest implementation
|
|
/ ----------------------------------
|
|
/ Purpose:
|
|
/ Register our interest in changes to the network so that the find results
|
|
/ can be correctly refreshed.
|
|
/
|
|
/ Notes:
|
|
/ -
|
|
/
|
|
/ In:
|
|
/ pdfff -> description of the find filter
|
|
/ hwndDlg = window handle of the find dialog
|
|
/ uMsg = message to be sent to window when informing of notify
|
|
/
|
|
/ Out:
|
|
/ -
|
|
/----------------------------------------------------------------------------*/
|
|
STDMETHODIMP CNETFilter_DeclareFSNotifyInterest(LPDOCFINDFILEFILTER pnetf, HWND hwndDlg, UINT uMsg)
|
|
{
|
|
LPNETFILTER this = IToClass(CNETFilter, dfff, pnetf);
|
|
SHChangeNotifyEntry fsne;
|
|
|
|
fsne.fRecursive = TRUE;
|
|
fsne.pidl = this ->pidlStart;
|
|
|
|
if (fsne.pidl)
|
|
{
|
|
SHChangeNotifyRegister(hwndDlg, SHCNRF_NewDelivery | SHCNRF_ShellLevel, SHCNE_DISKEVENTS, uMsg, 1, &fsne);
|
|
}
|
|
|
|
return NOERROR;
|
|
}
|