docfind2.c
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 173k
Category:

Windows Kernel

Development Platform:

Visual C++

  1. //---------------------------------------------------------------------------
  2. //
  3. // Copyright (c) Microsoft Corporation 1991-1993
  4. //
  5. // File: docfind2.c
  6. //
  7. // Description: This file should contains most of the document find code
  8. // that is specific to the default search filters.
  9. //
  10. //
  11. // History:
  12. //  12-29-93 KurtE      Created.
  13. //
  14. //---------------------------------------------------------------------------
  15. #include "shellprv.h"
  16. #pragma  hdrstop
  17. #include "fstreex.h"
  18. #include "docfind.h"
  19. #include "prop.h"
  20. #ifndef MAXUSHORT
  21. #define MAXUSHORT 0xffff
  22. #endif
  23. //===========================================================================
  24. // Define the Default data filter data structures
  25. //===========================================================================
  26. //
  27. // Define the internal structure of our default filter
  28. typedef struct _CDFFilter   // fff
  29. {
  30.     IDocFindFileFilter  dfff;
  31.     LONG                cRef;
  32.     HWND                hwndTabs;
  33.     HANDLE              hMRUSpecs;
  34.     // Added support for Query results to be async...
  35.     IDFEnum             *pdfenumAsync;
  36.     // Here are the paths that we are to search on...
  37.     // Data associated with the Look in field
  38.     IShellFolder *      psfMyComputer;
  39.     int                 iMyComputer;
  40.     int                 iWindowsDrive;
  41.     int                 iDocumentFolders;
  42.     int                 iDesktopFolders;
  43.     int                 ipidlStart;
  44.     // Data associated with the file name.
  45.     BOOL                fNameChanged;       // The name changed earlier
  46.     LPTSTR              pszFileSpec;        // $$ the one we do compares with
  47.     LPTSTR              pszSpecs;           // same as pszFileSpec but with ''s for ';'s
  48.     LPTSTR *            apszFileSpecs;      // pointers into pszSpecs for each token
  49.     int                 cFileSpecs;         // count of specs
  50.     LPITEMIDLIST        pidlStart;          // Starting location ID list.
  51.     TCHAR               szPath[MAX_PATH];   // Location of where to start search from
  52.     TCHAR               szUserInputFileSpec[MAX_PATH];  // File pattern.
  53.     TCHAR               szText[MAXSTRLEN];  // Limit text to max editable size
  54.     DWORD               uFixedDrives;       // The list of fixed drives...
  55. #ifdef UNICODE
  56.     CHAR                szTextA[MAXSTRLEN];
  57. #endif
  58.     BOOL                fTopLevelOnly;      // Search on top level only?
  59.     BOOL                fShowAllObjects;    // $$ Should we show all files?
  60.     BOOL                fFilterChanged;     // Something in the filter changed.
  61.     BOOL                fWeRestoredSomeCriteria; // We need to initilize the pages...
  62.     // Fields associated with the file type
  63.     BOOL                fTypeChanged;       // Type changed;
  64.     int                 iType;              // Index of the type.
  65.     int                 iTypeLast;          // Save away last type...
  66.     PHASHITEM           phiType;            // Save away hash item
  67.     TCHAR               szTypeName[80];     // The display name for type
  68.     TCHAR               szTypeFilePatterns[MAX_PATH]; // $$ The file patterns associated with type
  69.     LPTSTR              pszIndexedSearch;   // what to search for... (Maybe larger than MAX_PATH because it's a list of paths.
  70.     ULONG               ulQueryDialect;    // ISQLANG_V1 or ISQLANG_V2
  71.     DWORD               dwWarningFlags;    // Warning bits (DFW_xxx).
  72.     LPGREPINFO          lpgi;               // $$ Grep information.
  73.     int                 iSizeType;          // $$ What type of size 0 - none, 1 > 2 <
  74.     DWORD               dwSize;             // $$ Size comparison
  75.     WORD                wDateType;          // $$ 0 - none, 1 days before, 2 months before...
  76.     WORD                wDateValue;         //  (Num of months or days)
  77.     WORD                dateModifiedBefore; // $$
  78.     WORD                dateModifiedAfter;  // $$
  79.     BITBOOL             fFoldersOnly:1;     // $$ Are we searching for folders?
  80.     BITBOOL             fTextCaseSen:1;     // $$ Case sensitive searching...
  81.     BITBOOL             fTextReg:1;         // $$ regular expressions.
  82.     BITBOOL             fSearchSlowFiles:1;  // && probably missleading as file over a 300baud modem is also slow
  83.     int                 iNextConstraint;    // which constraint to look at next...
  84. } CDFFilter;
  85. // Lets define some constants to use to define which types of date we are searching on
  86. #define DFF_DATE_ALL        (IDD_MDATE_ALL-IDD_MDATE_ALL)
  87. #define DFF_DATE_DAYS       (IDD_MDATE_DAYS-IDD_MDATE_ALL)
  88. #define DFF_DATE_MONTHS     (IDD_MDATE_MONTHS-IDD_MDATE_ALL)
  89. #define DFF_DATE_BETWEEN    (IDD_MDATE_BETWEEN-IDD_MDATE_ALL)
  90. #define DFF_DATE_RANGEMASK  0x00ff
  91. #define DFF_DATE_TYPEMASK   0xff00
  92. #define DFF_DATE_MODIFIED   0x0000
  93. #define DFF_DATE_CREATED    0x0100
  94. #define DFF_DATE_ACCESSED   0x0200
  95. // Define new criteria to be saved in file...
  96. #define DFSC_SEARCHFOR          0x5000
  97. // Define common page data for each of our pages
  98. typedef struct { // dfpsp
  99.     PROPSHEETPAGE   psp;
  100.     HANDLE          hThreadInit;
  101.     HWND            hwndDlg;
  102.     CDFFilter *     pdff;
  103.     DWORD           dwState;
  104. } DOCFINDPROPSHEETPAGE, * LPDOCFINDPROPSHEETPAGE;
  105. typedef struct {    // pdfsli
  106.     DWORD   dwVer;  // Version
  107.     DWORD   dwType; // Type of data (defined below)
  108. } DOCFINDSAVELOOKIN;
  109. // Used to enum top level paths
  110. //
  111. typedef struct {
  112.     // Stuff to use in the search
  113.     LPTSTR       pszPath;            // Passed in path from creater
  114.     // Handle cases where we search one level deep like at \compname and the like
  115.     //
  116.     LPCITEMIDLIST pidlStart;        // Passed in pidl to begin from
  117.     IShellFolder *psfTopLevel;      // Top level shellfolder
  118.     IEnumIDList *penumTopLevel;     // Top level enum function.
  119.     BOOL        fFirstPass;         // Is this the first pass?
  120.     LPTSTR      pszPathNext;        // filter path enumeration state
  121. } CDFEStartPaths;
  122. const COL_DATA c_df_cols[] = {
  123.     {IDFCOL_NAME,       IDS_NAME_COL,     20,   LVCFMT_LEFT,    &SCID_NAME},
  124.     {IDFCOL_PATH,       IDS_PATH_COL,     20,   (short int)(LVCFMT_LEFT | LVCFMT_COL_HAS_IMAGES), &SCID_DIRECTORY},
  125.     {IDFCOL_RANK,       IDS_RANK_COL,     10,   LVCFMT_RIGHT,   &SCID_RANK},
  126.     {IDFCOL_SIZE,       IDS_SIZE_COL,     10,   LVCFMT_RIGHT,   &SCID_SIZE},
  127.     {IDFCOL_TYPE,       IDS_TYPE_COL,     20,   LVCFMT_LEFT,    &SCID_TYPE},
  128.     {IDFCOL_MODIFIED,   IDS_MODIFIED_COL, 30,   LVCFMT_LEFT,    &SCID_WRITETIME}
  129. };
  130. // Functions used enumerate the top level find strings, handling this like MyComputer \AServer
  131. HRESULT DF_GetSearchPaths(CDFFilter *this, LPCITEMIDLIST pidlStart,  LPWSTR *papwszPaths[], UINT *pcPaths);
  132. BOOL DF_EnumNextTopPath(CDFEStartPaths * pdfesp, LPTSTR pszOut, int cch);
  133. BOOL IsSuperHidden(DWORD dwAttribs); // for now in docfind.cpp
  134. HRESULT _IsNTFSDrive(int iDrive);  // in docfind.cpp
  135. typedef struct {
  136.     IDFEnum     dfenum;
  137.     UINT        cRef;
  138.     IShellFolder *psf;              // Pointer to shell folder
  139.     // Stuff to use in the search
  140.     LPITEMIDLIST    pidlStart;      // PidlStart...
  141.     // List of start paths...
  142.     LPWSTR      *apwszPaths;        // array of paths
  143.     UINT        cPaths;             // how many in it...
  144.     UINT        iPathNext;          // which one to process next...
  145.     // We may have an Async Enum that does some of the paths...
  146.     IDFEnum     *pdfenumAsync;      
  147.     IShellFolder *psfStart;         // The starting folder for the search.
  148.     int         cchStart;           // How many characters are in the
  149.     DWORD       grfFlags;           // Flags that control things like recursion
  150.     WIN32_FIND_DATA finddata;       // Win32 file data to use
  151.     // filter info...
  152.     LPTSTR       pszProgressText;    // Path Buffer pointer
  153.     IDocFindFileFilter  * pdfff;// The file filter to use...
  154.     TCHAR       szTempInternetCachePath[MAX_PATH];   // temporary internet path...
  155.     // enumeration state
  156.     int         ichPathFirst;       // ich into path string of current path...
  157.     int         iFolder;            // Which folder are we adding items for?
  158.     BOOL        fAddedSubDirs : 1;
  159.     BOOL        fObjReturnedInDir : 1;  // Has an object been returned in this dir?
  160.     BOOL        fFindFirstSucceed : 1;  // Did a find first file succeed.
  161.     int         depth;              // directory level (relative to pszPath)
  162.     HANDLE      hfind;
  163.     DIRBUF * pdbStack;           // Linked list of DIRBUFs to enum
  164.     DIRBUF * pdbReuse;
  165. } CDFEnum;
  166. #define DFSLI_VER                   0
  167. #define DFSLI_TYPE_PIDL             0   // Pidl is streamed after this
  168. #define DFSLI_TYPE_STRING           1   // cb follows this for length then string...
  169. // Document folders and children - Warning we assume the order of items after Document Folders
  170. #define DFSLI_TYPE_DOCUMENTFOLDERS  0x10
  171. #define DFSLI_TYPE_DESKTOP          0x11
  172. #define DFSLI_TYPE_PERSONAL         0x12
  173. // My computer and children...
  174. #define DFSLI_TYPE_MYCOMPUTER       0x20
  175. #define DFSLI_TYPE_LOCALDRIVES      0x21
  176. // BUGBUG I don't get it... why the manual calculation of the structure size?
  177. #define DOCFINDPSHTSIZE (SIZEOF(PROPSHEETPAGE)+SIZEOF(HANDLE)+SIZEOF(HWND)+SIZEOF(CDFFilter *)+SIZEOF(DWORD))
  178. #define DFPAGE_INIT     0x0001          /* This page has been initialized */
  179. #define DFPAGE_CHANGE   0x0002          /*  The user has modified the page */
  180. //------------------------------------------------------------------------------
  181. // Use same enum and string table between updatefield and getting the constraints
  182. // back out...
  183. typedef enum 
  184. {
  185.     CDFFUFE_IndexedSearch = 0,
  186.     CDFFUFE_LookIn,
  187.     CDFFUFE_IncludeSubFolders,
  188.     CDFFUFE_Named,
  189.     CDFFUFE_ContainingText,
  190.     CDFFUFE_FileType,
  191.     CDFFUFE_WhichDate,
  192.     CDFFUFE_DateLE,
  193.     CDFFUFE_DateGE,
  194.     CDFFUFE_DateNDays,
  195.     CDFFUFE_DateNMonths,
  196.     CDFFUFE_SizeLE,
  197.     CDFFUFE_SizeGE,
  198.     CDFFUFE_TextCaseSen,
  199.     CDFFUFE_TextReg,
  200.     CDFFUFE_SearchSlowFiles,
  201.     CDFFUFE_QueryDialect,
  202.     CDFFUFE_WarningFlags,
  203. } CDFFUFE;
  204. static const CDFFUF s_cdffuf[] = // Warning: index of fields is used below in case...
  205. {
  206.     {L"IndexedSearch", VT_BSTR, CDFFUFE_IndexedSearch},        
  207.     {L"LookIn", VT_BSTR, CDFFUFE_LookIn},
  208.     {L"IncludeSubFolders", VT_BOOL, CDFFUFE_IncludeSubFolders},
  209.     {L"Named",VT_BSTR, CDFFUFE_Named},
  210.     {L"ContainingText", VT_BSTR, CDFFUFE_ContainingText},
  211.     {L"FileType", VT_BSTR, CDFFUFE_FileType},
  212.     {L"WhichDate", VT_I4, CDFFUFE_WhichDate},
  213.     {L"DateLE", VT_DATE, CDFFUFE_DateLE},
  214.     {L"DateGE", VT_DATE, CDFFUFE_DateGE},
  215.     {L"DateNDays", VT_I4, CDFFUFE_DateNDays},
  216.     {L"DateNMonths", VT_I4, CDFFUFE_DateNMonths},
  217.     {L"SizeLE", VT_UI4, CDFFUFE_SizeLE},
  218.     {L"SizeGE", VT_UI4, CDFFUFE_SizeGE},
  219.     {L"CaseSensitive", VT_BOOL, CDFFUFE_TextCaseSen},
  220.     {L"RegularExpressions", VT_BOOL, CDFFUFE_TextReg},
  221.     {L"SearchSlowFiles", VT_BOOL, CDFFUFE_SearchSlowFiles},
  222.     {L"QueryDialect", VT_UI4, CDFFUFE_QueryDialect},
  223.     {L"WarningFlags", VT_UI4 /*DFW_xxx bits*/, CDFFUFE_WarningFlags},
  224.     {NULL, VT_EMPTY, 0}
  225. };
  226. //===========================================================================
  227. // Copied from comctl32.  This is all a hack.  Docfind used this internal
  228. // prsht function because it was too lazy to call CreateDialogIndirect.
  229. // But comctl32's internal structure has changed, so we have to do it
  230. // ourselves.  Nevermind that the actual function is tiny.
  231. //===========================================================================
  232. #include <pshpack2.h>
  233. typedef struct                           
  234. {                                        
  235.     WORD    wDlgVer;                     
  236.     WORD    wSignature;                  
  237.     DWORD   dwHelpID;                    
  238.     DWORD   dwExStyle;                   
  239.     DWORD   dwStyle;                     
  240.     WORD    cDlgItems;
  241.     WORD    x;                           
  242.     WORD    y;                           
  243.     WORD    cx;                          
  244.     WORD    cy;                          
  245. }   DLGEXTEMPLATE, FAR *LPDLGEXTEMPLATE;
  246. #include <poppack.h> /* Resume normal packing */
  247. HWND DocFindCreatePageDialog(LPPROPSHEETPAGE hpage, HWND hwndParent, LPDLGTEMPLATE pDlgTemplate)
  248. {
  249.     DWORD lSaveStyle;
  250.     LPDLGEXTEMPLATE pDlgExTemplate = (LPDLGEXTEMPLATE) pDlgTemplate;
  251.     // Note:  Don't need to restore the style since we're going
  252.     //        to free the memory anyway.
  253.     if (pDlgExTemplate->wSignature == 0xFFFF)
  254.     {
  255.         lSaveStyle = pDlgExTemplate->dwStyle;
  256.         pDlgExTemplate->dwStyle = (lSaveStyle & (DS_SETFONT | DS_LOCALEDIT | WS_CLIPCHILDREN))
  257.                                 | WS_CHILD | WS_TABSTOP | DS_3DLOOK | DS_CONTROL;
  258.     }
  259.     else
  260.     {
  261.         lSaveStyle = pDlgTemplate->style;
  262.         pDlgTemplate->style = (lSaveStyle & (DS_SETFONT | DS_LOCALEDIT | WS_CLIPCHILDREN))
  263.                                 | WS_CHILD | WS_TABSTOP | DS_3DLOOK | DS_CONTROL;
  264.     }
  265.     return CreateDialogIndirectParam(
  266.                     hpage->hInstance,
  267.                     (LPCDLGTEMPLATE)pDlgTemplate,
  268.                     hwndParent,
  269.                     hpage->pfnDlgProc, (LPARAM)hpage);
  270. }
  271. HWND DocFindCreatePage(LPPROPSHEETPAGE ppsp, HWND hwndParent)
  272. {
  273.     HWND hwndPage = NULL; // NULL indicates an error
  274.     HRSRC hRes;
  275.     // Comctl32.CreatePage supported these flags but we don't use them
  276.     // so we won't support them either.
  277.     ASSERT(!(ppsp->dwFlags & (PSP_USECALLBACK | PSP_IS16 | PSP_DLGINDIRECT)));
  278.     hRes = FindResource(ppsp->hInstance, ppsp->pszTemplate, RT_DIALOG);
  279.     if (hRes)
  280.     {
  281.         const DLGTEMPLATE * pDlgTemplate = LoadResource(ppsp->hInstance, hRes);
  282.         if (pDlgTemplate)
  283.         {
  284.             ULONG cbTemplate=SizeofResource(ppsp->hInstance, hRes);
  285.             LPDLGTEMPLATE pdtCopy = (LPDLGTEMPLATE)Alloc(cbTemplate);
  286.             ASSERT(cbTemplate>=sizeof(DLGTEMPLATE));
  287.             if (pdtCopy)
  288.             {
  289.                 hmemcpy(pdtCopy, pDlgTemplate, cbTemplate);
  290.                 hwndPage=DocFindCreatePageDialog(ppsp, hwndParent, pdtCopy);
  291.                 Free(pdtCopy);
  292.             }
  293.         }
  294.     }
  295.     return hwndPage;
  296. }
  297. //===========================================================================
  298. // Define some other module global data
  299. //===========================================================================
  300. const DWORD aNameHelpIDs[] = {
  301.         IDD_STATIC,         IDH_FINDFILENAME_NAME,
  302.         IDD_FILESPEC,       IDH_FINDFILENAME_NAME,
  303.         IDD_PATH,           IDH_FINDFILENAME_LOOKIN,
  304.         IDD_BROWSE,         IDH_FINDFILENAME_BROWSE,
  305.         IDD_TOPLEVELONLY,   IDH_FINDFILENAME_TOPLEVEL,
  306.         IDD_CONTAINS,   IDH_FINDFILECRIT_CONTTEXT,
  307.         0, 0
  308. };
  309. const DWORD aCriteriaHelpIDs[] = {
  310.         IDD_STATIC,     IDH_FINDFILECRIT_OFTYPE,
  311.         IDD_TYPECOMBO,  IDH_FINDFILECRIT_OFTYPE,
  312.         IDD_SIZECOMP,   IDH_FINDFILECRIT_SIZEIS,
  313.         IDD_SIZEVALUE,  IDH_FINDFILECRIT_K,
  314.         IDD_SIZEUPDOWN, IDH_FINDFILECRIT_K,
  315.         IDD_SIZELBL,    IDH_FINDFILECRIT_K,
  316.         0, 0
  317. };
  318. const DWORD aDateHelpIDs[] = {
  319.         IDD_MDATE_FROM,         IDH_FINDFILEDATE_FROM,
  320.         IDD_MDATE_AND,          IDH_FINDFILEDATE_TO,
  321.         IDD_MDATE_TO,           IDH_FINDFILEDATE_TO,
  322.         IDD_MDATE_ALL,          IDH_FINDFILEDATE_ALLFILES,
  323.         IDD_MDATE_PARTIAL,      IDH_FINDFILEDATE_CREATEORMOD,
  324.         IDD_MDATE_DAYS,         IDH_FINDFILEDATE_DAYS,
  325.         IDD_MDATE_DAYLBL,       IDH_FINDFILEDATE_DAYS,
  326.         IDD_MDATE_MONTHS,       IDH_FINDFILEDATE_MONTHS,
  327.         IDD_MDATE_MONTHLBL,     IDH_FINDFILEDATE_MONTHS,
  328.         IDD_MDATE_BETWEEN,      IDH_FINDFILEDATE_RANGE,
  329.         IDD_MDATE_NUMDAYS,      IDH_FINDFILEDATE_DAYS,
  330.         IDD_MDATE_DAYSUPDOWN,   IDH_FINDFILEDATE_DAYS,
  331.         IDD_MDATE_NUMMONTHS,    IDH_FINDFILEDATE_MONTHS,
  332.         IDD_MDATE_MONTHSUPDOWN, IDH_FINDFILEDATE_MONTHS,
  333.         IDD_MDATE_FROM,         IDH_FINDFILEDATE_FROM,
  334.         IDD_MDATE_TO,           IDH_FINDFILEDATE_TO,
  335.         0, 0
  336. };
  337. //==========================================================================
  338. //
  339. // Create the default filter for our find code...  They should be completly
  340. // self contained...
  341. //
  342. extern IDocFindFileFilterVtbl c_DFFilterVtbl;   // forward
  343. IDocFindFileFilter * CreateDefaultDocFindFilter()
  344. {
  345.     CDFFilter *pfff = (void*)LocalAlloc(LPTR, SIZEOF(CDFFilter));
  346.     if (pfff == NULL)
  347.         return(NULL);
  348.     pfff->dfff.lpVtbl = &c_DFFilterVtbl;
  349.     pfff->cRef = 1;
  350.     pfff->wDateType = DFF_DATE_ALL | DFF_DATE_MODIFIED;
  351.     pfff->ulQueryDialect = ISQLANG_V2;
  352.     // We should now simply return the filter
  353.     return &pfff->dfff;
  354. }
  355. STDMETHODIMP_(ULONG) CDFFilter_AddRef(IDocFindFileFilter *pdfff);
  356. STDMETHODIMP CDFFilter_QueryInterface(IDocFindFileFilter *pdfff, REFIID riid, LPVOID * ppvObj)
  357. {
  358.     if (IsEqualIID(riid, &IID_IUnknown) || 
  359.         IsEqualIID(riid, &IID_IDocFindFileFilter))
  360.     {
  361.         *ppvObj = pdfff;
  362.     } 
  363.     else
  364.     {
  365.         *ppvObj = NULL;
  366.         return E_NOINTERFACE;
  367.     }
  368.     
  369.     CDFFilter_AddRef(pdfff);
  370.     return NOERROR;    
  371. }
  372. STDMETHODIMP_(ULONG) CDFFilter_AddRef(IDocFindFileFilter *pdfff)
  373. {
  374.     CDFFilter *this = IToClass(CDFFilter, dfff, pdfff);
  375.     TraceMsg(TF_DOCFIND, "CDFFilter.AddRef %d",this->cRef+1);
  376.     return InterlockedIncrement(&this->cRef);
  377. }
  378. STDMETHODIMP_(ULONG) CDFFilter_Release(IDocFindFileFilter *pdfff)
  379. {
  380.     CDFFilter *this = IToClass(CDFFilter, dfff, pdfff);
  381.     TraceMsg(TF_DOCFIND, "CDFFilter.Release %d",this->cRef-1);
  382.     if (InterlockedDecrement(&this->cRef))
  383.         return this->cRef;
  384.     // Destroy the MRU Lists...
  385.     if (this->hMRUSpecs)
  386.         FreeMRUList(this->hMRUSpecs);
  387.     if (this->lpgi)
  388.     {
  389.         FreeGrepBufs(this->lpgi);
  390.         this->lpgi = NULL;
  391.     }
  392.     // Release our usage of My computer
  393.     if (this->psfMyComputer)
  394.     {
  395.         this->psfMyComputer->lpVtbl->Release(this->psfMyComputer);
  396.     }
  397.     if (this->pidlStart)
  398.         ILFree(this->pidlStart);
  399.     Str_SetPtr(&(this->pszFileSpec), NULL);
  400.     Str_SetPtr(&(this->pszSpecs), NULL);
  401.     LocalFree(this->apszFileSpecs); // elements point to pszSpecs so no free for them
  402.     
  403.     Str_SetPtr(&(this->pszIndexedSearch), NULL);
  404.     LocalFree((HLOCAL)this);
  405.     return(0);
  406. }
  407. //==========================================================================
  408. // Function to let the find know which icons to display and the top level menu
  409. //==========================================================================
  410. STDMETHODIMP CDFFilter_GetIconsAndMenu (IDocFindFileFilter *pdfff,
  411.         HWND hwndDlg, HICON *phiconSmall, HICON *phiconLarge, HMENU *phmenu)
  412. {
  413.     *phiconSmall = LoadImage(HINST_THISDLL, MAKEINTRESOURCE(IDI_DOCFIND),
  414.             IMAGE_ICON, g_cxSmIcon, g_cySmIcon, LR_DEFAULTCOLOR);
  415.     *phiconLarge  = LoadIcon(HINST_THISDLL, MAKEINTRESOURCE(IDI_DOCFIND));
  416.     // BUGBUG:: Still menu to process!
  417.     *phmenu = LoadMenu(HINST_THISDLL, MAKEINTRESOURCE(MENU_FINDDLG));
  418.     return (S_OK);
  419. }
  420. //==========================================================================
  421. // Function to get the string resource index number that is proper for the
  422. // current type of search.
  423. //==========================================================================
  424. STDMETHODIMP CDFFilter_GetStatusMessageIndex (IDocFindFileFilter *pdfff,
  425.         UINT uContext, UINT *puMsgIndex)
  426. {
  427.     // Currently context is not used
  428.     *puMsgIndex = IDS_FILESFOUND;
  429.     return (S_OK);
  430. }
  431. //==========================================================================
  432. // Function to let find know which menu to load to merge for the folder
  433. //==========================================================================
  434. STDMETHODIMP CDFFilter_GetFolderMergeMenuIndex (IDocFindFileFilter *pdfff,
  435.         UINT *puBGMainMergeMenu, UINT *puBGPopupMergeMenu)
  436. {
  437.     *puBGMainMergeMenu = POPUP_DOCFIND_MERGE;
  438.     *puBGPopupMergeMenu = POPUP_DOCFIND_POPUPMERGE;
  439.     return (S_OK);
  440. }
  441. STDMETHODIMP CDFFilter_GetItemContextMenu (IDocFindFileFilter *pdfff, HWND hwndOwner, IDocFindFolder* pdfFolder, IContextMenu **ppcm)
  442. {
  443.     *ppcm = CDFFolderContextMenuItem_Create(hwndOwner, pdfFolder);
  444.     return (*ppcm) ? S_OK : E_OUTOFMEMORY;
  445. }
  446. STDMETHODIMP CDFFilter_GetDefaultSearchGUID(IDocFindFileFilter *pdfff, IShellFolder2 *psf2, LPGUID lpGuid)
  447. {
  448.     return FindFileOrFolders_GetDefaultSearchGUID(psf2, lpGuid);
  449. }
  450. STDMETHODIMP CDFFilter_EnumSearches(IDocFindFileFilter *pdfff, IShellFolder2 *psf2, LPENUMEXTRASEARCH *ppenum)
  451. {
  452.     return CFSFolder_EnumSearches(psf2, ppenum);
  453. }
  454. STDMETHODIMP CDFFilter_GetSearchFolderClassId(IDocFindFileFilter *pdfff, LPGUID lpGuid)
  455. {
  456.     *lpGuid = CLSID_DocFindFolder;
  457.     return S_OK;
  458. }
  459. //==========================================================================
  460. // Helper function for add page to the IDocFindFileFilter::AddPages
  461. //==========================================================================
  462. HRESULT DocFind_AddPages(IDocFindFileFilter *pdfff, HWND hwndTabs,
  463.         const DFPAGELIST *pdfpl, int cdfpl)
  464. {
  465.     int i;
  466.     TCHAR szTemp[128+50];
  467.     RECT rc;
  468.     int dxMax = 0;
  469.     int dyMax = 0;
  470.     TC_DFITEMEXTRA tie;
  471.     LPDOCFINDPROPSHEETPAGE pdfpsp;
  472.     HWND hwndDlg;
  473.     tie.tci.mask = TCIF_TEXT | TCIF_PARAM;
  474.     tie.hwndPage = NULL;
  475.     tie.tci.pszText = szTemp;
  476.     TabCtrl_SetItemExtra(hwndTabs, CB_DFITEMEXTRA);
  477.     hwndDlg = GetParent(hwndTabs);
  478.     // First go through and create all of the dialog pages.
  479.     //
  480.     for (i=0; i < cdfpl; i++)
  481.     {
  482.         pdfpsp = LocalAlloc(LPTR, SIZEOF(DOCFINDPROPSHEETPAGE));
  483.         if (pdfpsp == NULL)
  484.             break;
  485.         pdfpsp->psp.dwSize = DOCFINDPSHTSIZE;
  486.         pdfpsp->psp.dwFlags = PSP_DEFAULT;
  487.         pdfpsp->psp.hInstance = HINST_THISDLL;
  488.         pdfpsp->psp.lParam = 0;
  489.         pdfpsp->psp.pszTemplate = MAKEINTRESOURCE(pdfpl[i].id);
  490.         pdfpsp->psp.pfnDlgProc = pdfpl[i].pfn;
  491.         pdfpsp->pdff = (struct _CDFFilter *)pdfff;
  492.         pdfpsp->hThreadInit = NULL;
  493.         tie.hwndPage = DocFindCreatePage(&pdfpsp->psp, hwndDlg);
  494.         if (tie.hwndPage != NULL)
  495.         {
  496.             GetWindowText(tie.hwndPage, szTemp, ARRAYSIZE(szTemp));
  497.             GetWindowRect(tie.hwndPage, &rc);
  498.             if ((rc.bottom - rc.top) > dyMax)
  499.                 dyMax = rc.bottom - rc.top;
  500.             if ((rc.right - rc.left) > dxMax)
  501.                 dxMax = rc.right - rc.left;
  502.             TabCtrl_InsertItem(hwndTabs, 1000, &tie.tci);
  503.         }
  504.     }
  505.     // We now need to resize everything to fit with the dialog templates
  506.     rc.left = rc.top = 0;
  507.     rc.right = dxMax;
  508.     rc.bottom = dyMax;
  509.     TabCtrl_AdjustRect(hwndTabs, TRUE, &rc);
  510.     // Size the page now
  511.     SetWindowPos(hwndTabs, NULL, 0, 0, rc.right - rc.left, rc.bottom - rc.top,
  512.             SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
  513.     // Now set the first page as active.  We should be able to do this by
  514.     // simply posting a WM_COMMAND to the main dialog
  515.     SendNotify(hwndDlg, hwndTabs, TCN_SELCHANGE, NULL);
  516.     return (S_OK);
  517. }
  518. void WaitForPageInitToComplete(LPDOCFINDPROPSHEETPAGE pdfpsp)
  519. {
  520.     if (pdfpsp && pdfpsp->hThreadInit)
  521.     {
  522.         WaitForSendMessageThread(pdfpsp->hThreadInit, INFINITE);
  523.         CloseHandle(pdfpsp->hThreadInit);
  524.         pdfpsp->hThreadInit = NULL;
  525.     }
  526. }
  527. //==========================================================================
  528. // IDocFindFileFilter::FFilterChanged - Returns S_OK if nothing changed.
  529. //==========================================================================
  530. STDMETHODIMP CDFFilter_FFilterChanged(IDocFindFileFilter *pdfff)
  531. {
  532.     CDFFilter *this = IToClass(CDFFilter, dfff, pdfff);
  533.     BOOL fFilterChanged = this->fFilterChanged;
  534.     this->fFilterChanged = FALSE;
  535.     return fFilterChanged? S_FALSE : S_OK;
  536. }
  537. //==========================================================================
  538. // IDocFindFileFilter::GenerateTitle - Generates the title given the current
  539. // search criteria.
  540. //==========================================================================
  541. STDMETHODIMP CDFFilter_GenerateTitle(IDocFindFileFilter *pdfff,
  542.         LPTSTR *ppszTitle, BOOL fFileName)
  543. {
  544.     CDFFilter *this = IToClass(CDFFilter, dfff, pdfff);
  545.     BOOL  fFilePattern;
  546.     int iRes;
  547.     TCHAR szFindName[80];    // German should not exceed this find: ->???
  548.     LPTSTR pszFileSpec = this->szUserInputFileSpec;
  549.     LPTSTR pszText = this->szText;
  550.     //
  551.     // Lets generate a title for the search.  The title will depend on
  552.     // the file patern(s), the type field and the containing text field
  553.     // Complicate this a bit with the search for field...
  554.     //
  555.     fFilePattern = (pszFileSpec[0] != TEXT('')) &&
  556.                 (lstrcmp(pszFileSpec, c_szStarDotStar) != 0);
  557.     if (!fFilePattern && (this->pdfenumAsync == NULL) && this->pszIndexedSearch)
  558.     {
  559.         pszFileSpec = this->pszIndexedSearch;
  560.         fFilePattern = (pszFileSpec[0] != TEXT('')) &&
  561.                     (lstrcmp(pszFileSpec, c_szStarDotStar) != 0);
  562.     }
  563.     if ((pszText[0] == TEXT('')) && (this->pdfenumAsync != NULL) && this->pszIndexedSearch)
  564.         pszText = this->pszIndexedSearch;
  565.     // First see if there is a type field
  566.     if (this->iType > 0)
  567.     {
  568.         // We have a type field no check for content...
  569.         if (pszText[0] != TEXT(''))
  570.         {
  571.             // There is text!
  572.             // Should now use type but...
  573.             // else see if the name field is not NULL and not *.*
  574.             if (fFilePattern)
  575.                 iRes = IDS_FIND_TITLE_TYPE_NAME_TEXT;
  576.             else
  577.                 iRes = IDS_FIND_TITLE_TYPE_TEXT;
  578.         }
  579.         else
  580.         {
  581.             // No type or text, see if file pattern
  582.             // Containing not found, first search for type then named
  583.             if (fFilePattern)
  584.                 iRes = IDS_FIND_TITLE_TYPE_NAME;
  585.             else
  586.                 iRes = IDS_FIND_TITLE_TYPE;
  587.         }
  588.     }
  589.     else
  590.     {
  591.         // No Type field ...
  592.         // first see if there is text to be searched for!
  593.         if (pszText[0] != TEXT(''))
  594.         {
  595.             // There is text!
  596.             // Should now use type but...
  597.             // else see if the name field is not NULL and not *.*
  598.             if (fFilePattern)
  599.                 iRes = IDS_FIND_TITLE_NAME_TEXT;
  600.             else
  601.                 iRes = IDS_FIND_TITLE_TEXT;
  602.         }
  603.         else
  604.         {
  605.             // No type or text, see if file pattern
  606.             // Containing not found, first search for type then named
  607.             if (fFilePattern)
  608.                 iRes = IDS_FIND_TITLE_NAME;
  609.             else
  610.                 iRes = IDS_FIND_TITLE_ALL;
  611.         }
  612.     }
  613.     // We put : in for first spot for title bar.  For name creation
  614.     // we remove it which will put the number at the end...
  615.     if (!fFileName)
  616.         LoadString(HINST_THISDLL, IDS_FIND_TITLE_FIND,
  617.                 szFindName, ARRAYSIZE(szFindName));
  618.     *ppszTitle = ShellConstructMessageString(HINST_THISDLL,
  619.             MAKEINTRESOURCE(iRes),
  620.             fFileName? szNULL : szFindName,
  621.             this->szTypeName, pszFileSpec, pszText);
  622.     return *ppszTitle ? S_OK : E_OUTOFMEMORY;
  623. }
  624. //==========================================================================
  625. // IDocFindFileFilter::ClearSearchCriteria
  626. //==========================================================================
  627. STDMETHODIMP CDFFilter_ClearSearchCriteria(IDocFindFileFilter *pdfff)
  628. {
  629.     int cPages;
  630.     HWND    hwndMainDlg;
  631.     TC_DFITEMEXTRA tie;
  632.     CDFFilter *this = IToClass(CDFFilter, dfff, pdfff);
  633.     hwndMainDlg = GetParent(this->hwndTabs);
  634.     for (cPages = TabCtrl_GetItemCount(this->hwndTabs) -1; cPages >= 0; cPages--)
  635.     {
  636.         tie.tci.mask = TCIF_PARAM;
  637.         TabCtrl_GetItem(this->hwndTabs, cPages, &tie.tci);
  638.         SendNotify(tie.hwndPage, hwndMainDlg, PSN_RESET, NULL);
  639.     }
  640.     // Also clear out a few other fields...
  641.     this->szUserInputFileSpec[0] = TEXT('');
  642.     this->iType = 0;
  643.     this->szText[0] = TEXT('');
  644.     return (S_OK);
  645. }
  646. //==========================================================================
  647. // DocFind_SetupWildCardingOnFileSpec - returns TRUE if wildards are in
  648. //      extension. Both "*" and "?" are treated as wildcards.
  649. //==========================================================================
  650. BOOL DocFind_SetupWildCardingOnFileSpec(LPTSTR pszSpecIn, LPTSTR *ppszSpecOut)
  651. {
  652.     LPTSTR pszIn = pszSpecIn;
  653.     LPTSTR pszOut;
  654.     LPTSTR pszStar;
  655.     LPTSTR pszAnyC;
  656.     BOOL fQuote;
  657.     TCHAR szSpecOut[3*MAX_PATH];   // Rather large...
  658.     // allocate a buffer that should be able to hold the resultant
  659.     // string.  When all is said and done we'll re-allocate to the
  660.     // correct size.
  661.     pszOut = szSpecOut;
  662.     while (*pszIn != TEXT(''))
  663.     {
  664.         LPTSTR pszT;
  665.         int     ich;
  666.         TCHAR  c;
  667.         // Strip in leading spaces out of there
  668.         while (*pszIn == TEXT(' '))
  669.             pszIn++;
  670.         if (*pszIn == TEXT(''))
  671.             break;
  672.         if (pszOut != szSpecOut)
  673.             *pszOut++ = TEXT(';');
  674.         if (FALSE != (fQuote = (*pszIn == TEXT('"'))))
  675.         {
  676.             // The user asked for something litteral.
  677.            pszT = pszIn = CharNext(pszIn);
  678.            while (*pszT && (*pszT != TEXT('"')))
  679.                pszT = CharNext(pszT);
  680.         }
  681.         else
  682.         {
  683.             pszT = pszIn + (ich = StrCSpn(pszIn, TEXT(",; ")));
  684.         }
  685.         c = *pszT;       // Save away the seperator character that was found
  686.         *pszT = TEXT('');    //
  687.         // Put in a couple of tests for * and *.*
  688.         if ((lstrcmp(pszIn, c_szStar) == 0) ||
  689.                 (lstrcmp(pszIn, c_szStarDotStar) == 0))
  690.         {
  691.             // Complete wild card so set a null criteria
  692.             *pszT = c;  // Restore char;
  693.             pszOut = szSpecOut;   // Set to start of string
  694.             break;
  695.         }
  696.         if (fQuote)
  697.         {
  698.             lstrcpy(pszOut, pszIn);
  699.             pszOut += lstrlen(pszIn);
  700.         }
  701.         else
  702.         {
  703.             // both "*" and "?" are wildcards.  When checking for wildcards check
  704.             // for both before we conclude there are no wildcards.  If a search
  705.             // string contains both "*" and "?" then we need for pszStar to point
  706.             // to the last occorance of either one (this is assumed in the code
  707.             // below which will add a ".*" when pszStar is the last character).
  708.             // NOTE: I wish there was a StrRPBrk function to do this for me.
  709.             pszStar = StrRChr(pszIn, NULL, TEXT('*'));
  710.             pszAnyC = StrRChr(pszIn, NULL, TEXT('?'));
  711.             if (pszAnyC > pszStar)
  712.                 pszStar = pszAnyC;
  713.             if (pszStar == NULL)
  714.             {
  715.                 // No wildcards were used:
  716.                 *pszOut++ = TEXT('*');
  717.                 lstrcpy(pszOut, pszIn);
  718.                 pszOut += ich;
  719.                 *pszOut++ = TEXT('*');
  720.             }
  721.             else
  722.             {
  723.                 // Includes wild cards
  724.                 lstrcpy(pszOut, pszIn);
  725.                 pszOut += ich;
  726.                 // if no extension 
  727.                 pszAnyC = StrRChr(pszIn, NULL, TEXT('.'));
  728.                 if ( pszAnyC == NULL )
  729.                 {
  730.                     // No extension is given
  731.                     if ((*(pszStar+1) == TEXT('')) && (*pszStar == TEXT('*')))
  732.                     {
  733.                         // The last character is an "*" so this single string will
  734.                         // match everything you would expect.
  735.                     }
  736.                     else
  737.                     {
  738.                         // in order to get the expected behavior we need to search
  739.                         // for two things, the actual string entered and the string
  740.                         // with any extension.  I.E. given "a*a" we need to search
  741.                         // for "a*a" and "a*a.*".  Otherwise we won't find both the
  742.                         // file "abba" and "abba.wav".  As a bonus we also pick up
  743.                         // "abc.cba" this way when using "*".  This also helps for
  744.                         // "a?", allowing it to find "a1.txt" as well as "aa"
  745.                         *pszOut++ = TEXT(';');  // seperate the two strings
  746.                         lstrcpy(pszOut, pszIn); // add the second variant
  747.                         pszOut += ich;
  748.                         *pszOut++ = TEXT('.');
  749.                         *pszOut++ = TEXT('*');  // Add on .* to the name
  750.                     }
  751.                 }
  752.             }
  753.         }
  754.         *pszT = c;  // Restore char;
  755.         if (c == TEXT(''))
  756.             break;
  757.         // Skip beyond quotes
  758.         if (*pszT == TEXT('"'))
  759.             pszT++;
  760.         if (*pszT != TEXT(''))
  761.             pszT++;
  762.         pszIn = pszT;   // setup for the next item
  763.     }
  764.     *pszOut++ = TEXT('');
  765.     // re-alloc the buffer down to the actual size of the string...
  766.     Str_SetPtr(ppszSpecOut, szSpecOut);
  767.     return TRUE;
  768. }
  769. //==========================================================================
  770. // IDocFindFileFilter::PrepareToEnumObjects
  771. //==========================================================================
  772. STDMETHODIMP CDFFilter_PrepareToEnumObjects(IDocFindFileFilter *pdfff, DWORD *pdwFlags)
  773. {
  774.     int cPages;
  775.     TC_DFITEMEXTRA tie;
  776.     SHELLSTATE ss;
  777.     CDFFilter *this = IToClass(CDFFilter, dfff, pdfff);
  778.     if (this->hwndTabs)
  779.     {
  780.         HWND    hwndMainDlg;
  781.         hwndMainDlg = GetParent(this->hwndTabs);
  782.         for (cPages = TabCtrl_GetItemCount(this->hwndTabs) -1; cPages >= 0; cPages--)
  783.         {
  784.             tie.tci.mask = TCIF_PARAM;
  785.             TabCtrl_GetItem(this->hwndTabs, cPages, &tie.tci);
  786.             SendNotify(tie.hwndPage, hwndMainDlg, PSN_APPLY, NULL);
  787.         }
  788.     }
  789.     // Update the flags and buffer strings
  790.     if (this->fTopLevelOnly)
  791.         *pdwFlags &= ~DFOO_INCLUDESUBDIRS;
  792.     else
  793.         *pdwFlags |= DFOO_INCLUDESUBDIRS;
  794.     if (this->fTextCaseSen)
  795.         *pdwFlags |= FFLT_CASESEN;
  796.     if (this->fTextReg)
  797.         *pdwFlags |= FFLT_REGULAR;
  798.     // Also get the shell state variables to see if we should show extensions and the like
  799.     SHGetSetSettings(&ss, SSF_SHOWEXTENSIONS|SSF_SHOWALLOBJECTS, FALSE);
  800.     if (ss.fShowExtensions)
  801.         *pdwFlags |= DFOO_SHOWEXTENSIONS;
  802.     else
  803.         *pdwFlags &= ~DFOO_SHOWEXTENSIONS;
  804.     this->fShowAllObjects = ss.fShowAllObjects;
  805.     if (ss.fShowAllObjects)
  806.         *pdwFlags |= DFOO_SHOWALLOBJECTS;
  807.     else
  808.         *pdwFlags &= ~DFOO_SHOWALLOBJECTS;
  809.     // Now lets generate the file patern we will ask the system to look for
  810.     // for now we will simply copy the file spec in...
  811.     // Here is where we try to put some smarts into the file patterns stuff
  812.     // It will go something like:
  813.     // look between each; or , and see if there are any wild cards.  If not
  814.     // do something like *patern*.
  815.     // Also if there is no search pattern or if it is * or *.*, set the
  816.     // filter to NULL as to speed it up.
  817.     //
  818.     DocFind_SetupWildCardingOnFileSpec(this->szUserInputFileSpec, &this->pszFileSpec);
  819.     this->cFileSpecs = 0;
  820.     if (this->pszFileSpec && this->pszFileSpec[0])
  821.     {
  822.         Str_SetPtr(&(this->pszSpecs), this->pszFileSpec);
  823.         if (this->pszSpecs)
  824.         {
  825.             int cTokens = 0;
  826.             LPTSTR pszToken = this->pszSpecs;
  827.             while (pszToken)
  828.             {
  829.                 // let's walk pszFileSpec to see how many specs we have...
  830.                 pszToken = StrChr(pszToken, TEXT(';'));
  831.                 if (pszToken)
  832.                     pszToken++;
  833.                 cTokens++;
  834.             }
  835.             if (cTokens)
  836.             {
  837.                 int i;
  838.                 // cleanup the previous search
  839.                 if (this->apszFileSpecs)
  840.                     LocalFree(this->apszFileSpecs);
  841.                 this->apszFileSpecs = (LPTSTR *)LocalAlloc(LPTR, cTokens*SIZEOF(LPTSTR *));
  842.                 if (this->apszFileSpecs)
  843.                 {
  844.                     this->cFileSpecs = cTokens;
  845.                     pszToken = this->pszSpecs;
  846.                     for (i = 0; i < cTokens; i++)
  847.                     {
  848.                         this->apszFileSpecs[i] = pszToken;
  849.                         pszToken = StrChr(pszToken, TEXT(';'));
  850.                         if (pszToken)
  851.                             *pszToken++ = TEXT('');
  852.                     }
  853.                 }
  854.             }
  855.         }
  856.     }
  857.     //
  858.     // Also if there is a search string associated with this search
  859.     // criteria, we need to initialize the search to allow greping on
  860.     // it.
  861.     // First check to see if we have an old one to release...
  862.     if (this->lpgi)
  863.     {
  864.         FreeGrepBufs(this->lpgi);
  865.         this->lpgi = NULL;
  866.     }
  867.     if (this->szText[0] != TEXT(''))
  868.     {
  869. #ifdef UNICODE
  870.         LPSTR lpszText;
  871.         UINT cchLength;
  872.         cchLength = lstrlen(this->szText)+1;
  873.         lpszText = this->szTextA;
  874.         cchLength = WideCharToMultiByte(CP_ACP, 0,
  875.                                         this->szText, cchLength,
  876.                                         this->szTextA, ARRAYSIZE(this->szTextA),
  877.                                         NULL, NULL);
  878.         // Must double NULL terminate lpszText.  InitGrepInfo requires
  879.         // this format!
  880.         lpszText[cchLength] = ''; // Do not wrap with TEXT(); should be ANSI
  881. #ifdef DOCFIND_RESUPPORT
  882.         this->lpgi = InitGrepInfo(lpszText, (LPSTR)szNULL,
  883.                 *pdwFlags & (FFLT_REGULAR | FFLT_CASESEN));
  884. #else
  885.         this->lpgi = InitGrepInfo(lpszText, (LPSTR)szNULL,
  886.                 *pdwFlags & (FFLT_CASESEN));
  887. #endif
  888. #else
  889. #ifdef DOCFIND_RESUPPORT
  890.         this->lpgi = InitGrepInfo(this->szText, (LPTSTR)szNULL,
  891.                 *pdwFlags & (FFLT_REGULAR | FFLT_CASESEN));
  892. #else
  893.         this->lpgi = InitGrepInfo(this->szText, (LPTSTR)szNULL,
  894.                 *pdwFlags & (FFLT_CASESEN));
  895. #endif
  896. #endif
  897.     }
  898.     return S_OK;
  899. }
  900. //==========================================================================
  901. // IDocFindFileFilter::GetDetailsof
  902. //==========================================================================
  903. STDMETHODIMP CDFFilter_GetDetailsOf(IDocFindFileFilter *pdfff, HDPA hdpaPidf,
  904.         LPCITEMIDLIST pidl, UINT *piColumn, LPSHELLDETAILS pdi)
  905. {
  906.     CDFFilter *this = IToClass(CDFFilter, dfff, pdfff);
  907.     HRESULT hr = S_OK;
  908.     if (*piColumn >= ARRAYSIZE(c_df_cols))
  909.         return E_NOTIMPL;
  910.     pdi->str.uType = STRRET_CSTR;
  911.     pdi->str.cStr[0] = 0;
  912.     if (!pidl)
  913.     {
  914.         pdi->fmt = c_df_cols[*piColumn].iFmt;
  915.         pdi->cxChar = c_df_cols[*piColumn].cchCol;
  916.         hr = ResToStrRet(c_df_cols[*piColumn].ids, &pdi->str);
  917.     }
  918.     else
  919.     {
  920.         TCHAR szTemp[MAX_PATH];
  921.         if (*piColumn == IDFCOL_PATH)
  922.         {
  923.             // We need to now get to the idlist of the items folder.
  924.             DFFolderListItem *pdffli = (DFFolderListItem *)DPA_GetPtr(hdpaPidf, DF_IFOLDER(pidl));
  925.             if (pdffli)
  926.             {
  927.                 SHGetPathFromIDList(&pdffli->idl, szTemp);
  928.                 hr = StringToStrRet(szTemp, &pdi->str);
  929.                 if (pdffli->iImage == -1)
  930.                 {
  931.                     SHFILEINFO sfi;
  932.                     SHGetFileInfo((LPCTSTR)&pdffli->idl, 0, &sfi, sizeof(sfi), SHGFI_PIDL | SHGFI_SYSICONINDEX);
  933.                     pdffli->iImage = sfi.iIcon;
  934.                 }
  935.             }
  936.         } 
  937.         else if (*piColumn == IDFCOL_RANK)
  938.         {
  939.             // See if the pidl has extra data or not.  If so use it
  940.             PCHIDDENDOCFINDDATA phdfd = (PCHIDDENDOCFINDDATA) ILFindHiddenID(pidl, IDLHID_DOCFINDDATA);
  941.             if (phdfd && (phdfd->wFlags & DFDF_EXTRADATA))
  942.             {
  943.                 AddCommas(phdfd->ulRank, szTemp);
  944.                 hr = StringToStrRet(szTemp, &pdi->str);
  945.             }
  946.         }
  947. #ifdef IF_ADD_MORE_COLS
  948.         else if (*piColumn >= IDFCOL_FIRST_QUERY)
  949.         {
  950.             // OK simply return S_FALSE and if we have a query active the caller will handle it.
  951.             *piColumn -= IDFCOL_FIRST_QUERY;
  952.             hr = S_FALSE; // tell caller to do it
  953.         }
  954. #endif
  955.         else if (*piColumn < ARRAYSIZE(c_df_cols))
  956.         {
  957.             // We need to now get to the idlist of the items folder.
  958.             DFFolderListItem *pdffli = (DFFolderListItem *)DPA_GetPtr(hdpaPidf, DF_IFOLDER(pidl));
  959.             // Let the file system function do it for us...
  960.             if (pdffli)
  961.             {
  962.                 IShellFolder *psf = DocFind_GetObjectsIFolder(NULL, pdffli, NULL);
  963.                 
  964.                 hr = E_FAIL;
  965.                 if (psf)
  966.                 {
  967.                     IShellFolder2 *psf2;
  968.                     
  969.                     hr = psf->lpVtbl->QueryInterface(psf, &IID_IShellFolder2, (void **)&psf2);
  970.                     if (SUCCEEDED(hr))
  971.                     {
  972.                         hr = MapSCIDToDetailsOf(psf2, pidl, c_df_cols[*piColumn].pscid, pdi);
  973.                         psf2->lpVtbl->Release(psf2);
  974.                     }
  975.                     psf->lpVtbl->Release(psf);
  976.                 }
  977.             }
  978.         }
  979.     }
  980.     return hr;
  981. }
  982. //==========================================================================
  983. // IDocFindFileFilter::FDoesItemMatchFilter
  984. //==========================================================================
  985. STDMETHODIMP CDFFilter_FDoesItemMatchFilter(IDocFindFileFilter *pdfff,
  986.         LPTSTR pszFolder, WIN32_FIND_DATA * pfd,
  987.         IShellFolder *psf, LPITEMIDLIST pidl)
  988. {
  989.     CDFFilter *this = IToClass(CDFFilter, dfff, pdfff);
  990.     SCODE sc = MAKE_SCODE(0, 0, 1);
  991.     WORD   wFileDate, wFileTime;
  992.     FILETIME ftLocal;
  993.     TCHAR    szPath[MAX_PATH];
  994.     WIN32_FIND_DATA finddata;
  995.     if (psf)
  996.     {
  997.         STRRET strret;
  998.         HANDLE hfind;
  999.         LPITEMIDLIST pidlLast = ILFindLastID(pidl);
  1000.         // This came in through a notify.. We should get enough info to make it work
  1001.         // properly... For now this will be gross and we will hit file system...
  1002.         // Also we passed through the full pidl to make sure that we could
  1003.         // verify properly if this in the tree we are interested in...
  1004.         // BUGBUG:: Need to better handle multiple paths!
  1005.         if ((this->pidlStart && !ILIsParent(this->pidlStart, pidl, (BOOL)this->fTopLevelOnly))
  1006.         || (!this->pidlStart && (BOOL)this->fTopLevelOnly))
  1007.             return 0;
  1008.         pfd = &finddata;
  1009.         if (FAILED(psf->lpVtbl->GetDisplayNameOf(psf, pidlLast, SHGDN_FORPARSING, &strret)))
  1010.             return 0;
  1011.         if (FAILED(StrRetToBuf(&strret, pidlLast, szPath, ARRAYSIZE(szPath))))
  1012.             return 0;
  1013.         hfind = FindFirstFile(szPath, pfd);
  1014.         if (INVALID_HANDLE_VALUE == hfind)
  1015.             return 0;
  1016.         FindClose(hfind);
  1017.     }
  1018.     // Note: We do not use the IDList in this one...
  1019.     // This function does filtering of the file information for
  1020.     // things that are not part of the standard file filter
  1021.     // First things we dont show hidden files
  1022.     // If show all is set then we should include hidden files also...
  1023.     if (!this->fShowAllObjects &&
  1024.             (pfd->dwFileAttributes & FILE_ATTRIBUTE_HIDDEN))
  1025.         return (0);     // does not match
  1026.     if (IsSuperHidden(pfd->dwFileAttributes))
  1027.         return (0);     // does not match
  1028.     // Process the case where we are looking for folders only
  1029.     if (this->fFoldersOnly &&
  1030.             ((pfd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)==0))
  1031.         return (0);     // does not match
  1032.     switch (this->iSizeType)
  1033.     {
  1034.     case 1:   // >
  1035.         if (!(pfd->nFileSizeLow > this->dwSize))
  1036.             return (0);     // does not match
  1037.         break;
  1038.     case 2:   // <
  1039.         if (!(pfd->nFileSizeLow < this->dwSize))
  1040.             return (0);     // does not match
  1041.         break;
  1042.     }
  1043.     // See if we should compare dates...
  1044.     switch (this->wDateType & DFF_DATE_TYPEMASK)
  1045.     {
  1046.     case DFF_DATE_ACCESSED:
  1047.         FileTimeToLocalFileTime(&pfd->ftLastAccessTime, &ftLocal);
  1048.         break;
  1049.     case DFF_DATE_CREATED:
  1050.         FileTimeToLocalFileTime(&pfd->ftCreationTime, &ftLocal);
  1051.         break;
  1052.     case DFF_DATE_MODIFIED:
  1053.         FileTimeToLocalFileTime(&pfd->ftLastWriteTime, &ftLocal);
  1054.     }
  1055.     FileTimeToDosDateTime(&ftLocal, &wFileDate, &wFileTime);
  1056.     if (this->dateModifiedBefore != 0)
  1057.     {
  1058.         if (!(wFileDate <= this->dateModifiedBefore))
  1059.             return (0);     // does not match
  1060.     }
  1061.     if (this->dateModifiedAfter != 0)
  1062.     {
  1063.         if (!(wFileDate >= this->dateModifiedAfter))
  1064.             return (0);     // does not match
  1065.     }
  1066.     // Match file specificaitions.
  1067.     if (this->pszFileSpec && this->pszFileSpec[0])
  1068.     {
  1069.         // if we have split up version of the specs we'll use it because PathMatchSpec is pretty stupid 
  1070.         // and can take up to 5-6 hours for more than 10 wildcard specs
  1071.         if (this->cFileSpecs)
  1072.         {
  1073.             int i;
  1074.             BOOL bMatch = FALSE;
  1075.             
  1076.             for (i = 0; i < this->cFileSpecs; i++)
  1077.             {
  1078.                 bMatch = PathMatchSpec(pfd->cFileName, this->apszFileSpecs[i]);
  1079.                 if (bMatch)
  1080.                     break;
  1081.             }
  1082.             if (!bMatch)
  1083.                 return (0);
  1084.         }
  1085.         else if (!PathMatchSpec(pfd->cFileName, this->pszFileSpec))
  1086.         {
  1087.         //short file name is never displayed to the user so don't use it to find match
  1088.         //&& !PathMatchSpec(pfd->cAlternateFileName, this->pszFileSpec))
  1089.             return (0);     // does not match
  1090.         }
  1091.     }
  1092.     if (this->szTypeFilePatterns[0])
  1093.     {
  1094.         // if looking for folders only and file pattern is all folders then no need to check
  1095.         // if folder name matches the pattern -- we know it is the folder, otherwise we
  1096.         // would have bailed out earlier in the function
  1097.         if (!(this->fFoldersOnly && lstrcmp(this->szTypeFilePatterns, TEXT(".")) == 0))
  1098.         {
  1099.             if (!PathMatchSpec(pfd->cFileName, this->szTypeFilePatterns))
  1100.                 return (0);     // does not match
  1101.         }
  1102.     }
  1103.     //
  1104.     // See if we need to do a grep of the file
  1105.     if (this->lpgi)
  1106.     {
  1107.         HANDLE hfil;
  1108.         BOOL fMatch = FALSE;
  1109.         DWORD dwCFOpts = FILE_FLAG_SEQUENTIAL_SCAN;
  1110. #ifdef WINNT
  1111.         if (g_bRunOnNT5 && PathIsHighLatency(pfd->cFileName, pfd->dwFileAttributes))
  1112.         {
  1113.             if (this->fSearchSlowFiles)
  1114.                 dwCFOpts |= FILE_FLAG_OPEN_NO_RECALL;
  1115.             else 
  1116.                 return (0);  // No match returned if files are high latency and user hasn't selected to search high latency files
  1117.         }
  1118. #endif
  1119.         // Don't grep files with the system bit set.
  1120.         // This was added explicitly to not search things like the
  1121.         // swap file and the like.
  1122.         if (pfd->dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)
  1123.             return (0);     // does not match
  1124.         if (!psf)
  1125.         {
  1126.             lstrcpy(szPath, pszFolder);
  1127.             PathAppend(szPath, pfd->cFileName);
  1128.         }
  1129.         // Pass in File_write_attributes so we can change the file access time. Ya, wierd name
  1130.         // to pass in as a access type but this is what kernel looks for...
  1131.         // Also try to pass through the no recall flags... If we get access denied again then
  1132.         // dond't pass this flag, my guess is that some networks like netware probably don't have
  1133.         // support for this flag...
  1134.         hfil = CreateFile(szPath,
  1135.                 GENERIC_READ | FILE_WRITE_ATTRIBUTES,
  1136.                 FILE_SHARE_READ ,
  1137.                  0, OPEN_EXISTING, dwCFOpts, 0);
  1138.         if (hfil == INVALID_HANDLE_VALUE)
  1139.         {
  1140.             // Some readonly shares don't like the FILE_WRITE_ATTRIBUTE, try without
  1141.             if (GetLastError() ==  ERROR_ACCESS_DENIED)
  1142.                 hfil = CreateFile(szPath, GENERIC_READ, FILE_SHARE_READ , 0, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, 0);
  1143.         }
  1144.         if (hfil != INVALID_HANDLE_VALUE)
  1145.         {
  1146.             // Go get around wimpy APIS that set the access date...
  1147.             FILETIME ftLastAccess;
  1148.             if (GetFileTime(hfil, NULL, &ftLastAccess, NULL))
  1149.                 SetFileTime(hfil, NULL, &ftLastAccess, NULL);
  1150.             fMatch = FileFindGrep(this->lpgi, hfil, FIND_FILE, NULL) != 0;
  1151.             CloseHandle(hfil);
  1152.         }
  1153.         if (!fMatch)
  1154.             return (0);     // does not match
  1155.     }
  1156.     return (sc);    // return TRUE to imply yes!
  1157. }
  1158. //==========================================================================
  1159. // Helper function for save criteria that will output the string and
  1160. // and id to the specified file.  it will also test for NULL and the like
  1161. //==========================================================================
  1162. int Docfind_SaveCriteriaItem(IStream * pstm, WORD wNum,
  1163.         LPTSTR psz, WORD fCharType)
  1164. {
  1165.     if ((psz == NULL) || (*psz == TEXT('')))
  1166.         return 0;
  1167.     else
  1168.     {
  1169.         LPVOID pszText = (LPVOID)psz; // Ptr to output text. Defaults to source.
  1170. #ifdef WINNT
  1171.         //
  1172.         // These are required to support ANSI-unicode conversions.
  1173.         //
  1174.         LPSTR pszAnsi  = NULL; // For unicode-to-ansi conversion.
  1175.         LPWSTR pszWide = NULL; // For ansi-to-unicode conversion.
  1176. #endif
  1177.         DFCRITERIA dfc;
  1178.         dfc.wNum = wNum;
  1179.         dfc.cbText = (WORD) ((lstrlen(psz) + 1) * SIZEOF(TCHAR));
  1180. #ifdef WINNT
  1181. #ifdef UNICODE
  1182.         //
  1183.         // Source string is Unicode but caller wants to save as ANSI.
  1184.         //
  1185.         if (DFC_FMT_ANSI == fCharType)
  1186.         {
  1187.            // Convert to ansi and write ansi.
  1188.            dfc.cbText = (WORD) WideCharToMultiByte(CP_ACP, 0L, psz, -1, pszAnsi, 0, NULL, NULL);
  1189.            if ((pszAnsi = (LPSTR)LocalAlloc(LMEM_FIXED, dfc.cbText)) != NULL)
  1190.            {
  1191.               WideCharToMultiByte(CP_ACP, 0L, psz, -1, pszAnsi, dfc.cbText / sizeof(pszAnsi[0]), NULL, NULL);
  1192.               pszText = (LPVOID)pszAnsi;
  1193.            }
  1194.         }
  1195. #else
  1196.         //
  1197.         // Source string is ANSI but caller wants to save as Unicode.
  1198.         //
  1199.         if (DFC_FMT_UNICODE == fCharType)
  1200.         {
  1201.            // Convert to unicode and write unicode.
  1202.            dfc.cbText = MultiByteToWideChar(CP_ACP, 0L, psz, -1, pszWide, 0);
  1203.            if ((pszWide = (LPWSTR)LocalAlloc(LMEM_FIXED, dfc.cbText)) != NULL)
  1204.            {
  1205.               MultiByteToWideChar(CP_ACP, 0L, psz, -1, pszWide, dfc.cbText / sizeof(pszWide[0]));
  1206.               pszText = (LPVOID)pszWide;
  1207.            }
  1208.         }
  1209. #endif  // UNICODE
  1210. #endif  // WINNT
  1211.         pstm->lpVtbl->Write(pstm, (LPTSTR)&dfc, SIZEOF(dfc), NULL);   // Output index
  1212.         pstm->lpVtbl->Write(pstm, pszText, dfc.cbText, NULL);  // output string + NULL
  1213. #ifdef WINNT
  1214.         //
  1215.         // Free up conversion buffers if any were created.
  1216.         //
  1217.         if (NULL != pszAnsi)
  1218.            LocalFree(pszAnsi);
  1219.         if (NULL != pszWide)
  1220.            LocalFree(pszWide);
  1221. #endif
  1222.     }
  1223.     return(1);
  1224. }
  1225. //==========================================================================
  1226. // IDocFindFileFilter::SaveCriteria
  1227. //==========================================================================
  1228. STDMETHODIMP CDFFilter_SaveCriteria(IDocFindFileFilter *pdfff, IStream * pstm, WORD fCharType)
  1229. {
  1230.     const TCHAR c_szPercentD[] = TEXT("%d");
  1231.     //
  1232.     CDFFilter *this = IToClass(CDFFilter, dfff, pdfff);
  1233.     int cCriteria;
  1234.     TCHAR szTemp[40];    // some random size
  1235.     LPITEMIDLIST pidlMyComputer;
  1236.     // The caller should have already validated the stuff and updated
  1237.     // everything for the current filter information.
  1238.     // we need to walk through and check each of the items to see if we
  1239.     // have a criteria to save away. this includes:
  1240.     //      (Name, Path, Type, Contents, size, modification dates)
  1241.     cCriteria = Docfind_SaveCriteriaItem(pstm, IDD_FILESPEC, this->szUserInputFileSpec, fCharType);
  1242.     pidlMyComputer = SHCloneSpecialIDList(NULL, CSIDL_DRIVES, FALSE);
  1243.     if (this->pidlStart && ILIsEqual(this->pidlStart, pidlMyComputer))
  1244.     {
  1245.         cCriteria += Docfind_SaveCriteriaItem(pstm, IDD_PATH,
  1246.                 TEXT("::"), fCharType);
  1247.     }
  1248.     else
  1249.         cCriteria += Docfind_SaveCriteriaItem(pstm, IDD_PATH,
  1250.                 this->szPath, fCharType);
  1251.     ILFree(pidlMyComputer);
  1252.     cCriteria += Docfind_SaveCriteriaItem(pstm, DFSC_SEARCHFOR,
  1253.             this->pszIndexedSearch, fCharType);
  1254.     cCriteria += Docfind_SaveCriteriaItem(pstm, IDD_TYPECOMBO,
  1255.             this->szTypeFilePatterns, fCharType);
  1256.     cCriteria += Docfind_SaveCriteriaItem(pstm, IDD_CONTAINS,
  1257.             this->szText, fCharType);
  1258.     
  1259.     // Also save away the state of the top level only
  1260.     wsprintf(szTemp, c_szPercentD, this->fTopLevelOnly);
  1261.     cCriteria += Docfind_SaveCriteriaItem(pstm, IDD_TOPLEVELONLY, szTemp, fCharType);
  1262.     // The Size field is little more fun!
  1263.     if (this->iSizeType != 0)
  1264.     {
  1265.         wsprintf(szTemp, TEXT("%d %ld"), this->iSizeType, this->dwSize);
  1266.         cCriteria += Docfind_SaveCriteriaItem(pstm, IDD_SIZECOMP, szTemp, fCharType);
  1267.     }
  1268.     // Likewise for the dates, should be fun as we need to save it depending on
  1269.     // how the date was specified
  1270.     switch (this->wDateType & DFF_DATE_RANGEMASK)
  1271.     {
  1272.     case DFF_DATE_ALL:
  1273.         // nothing to store
  1274.         break;
  1275.     case DFF_DATE_DAYS:
  1276.         wsprintf(szTemp, c_szPercentD, this->wDateValue);
  1277.         cCriteria += Docfind_SaveCriteriaItem(pstm, IDD_MDATE_NUMDAYS, szTemp, fCharType);
  1278.         break;
  1279.     case DFF_DATE_MONTHS:
  1280.         wsprintf(szTemp, c_szPercentD, this->wDateValue);
  1281.         cCriteria += Docfind_SaveCriteriaItem(pstm, IDD_MDATE_NUMMONTHS, szTemp, fCharType);
  1282.         break;
  1283.     case DFF_DATE_BETWEEN:
  1284.         if (this->dateModifiedAfter != 0)
  1285.         {
  1286.             wsprintf(szTemp, c_szPercentD, this->dateModifiedAfter);
  1287.             cCriteria += Docfind_SaveCriteriaItem(pstm, IDD_MDATE_FROM, szTemp, fCharType);
  1288.         }
  1289.         if (this->dateModifiedBefore != 0)
  1290.         {
  1291.             wsprintf(szTemp, c_szPercentD, this->dateModifiedBefore);
  1292.             cCriteria += Docfind_SaveCriteriaItem(pstm, IDD_MDATE_TO, szTemp, fCharType);
  1293.         }
  1294.         break;
  1295.     }
  1296.     if (((this->wDateType & DFF_DATE_RANGEMASK) != DFF_DATE_ALL) &&
  1297.         (this->wDateType & DFF_DATE_TYPEMASK))
  1298.     {
  1299.         wsprintf(szTemp, c_szPercentD, this->wDateType & DFF_DATE_TYPEMASK);
  1300.         cCriteria += Docfind_SaveCriteriaItem(pstm, IDD_MDATE_TYPE, szTemp, fCharType);
  1301.     }
  1302.     if( this->fTextCaseSen )
  1303.     {
  1304.         wsprintf( szTemp, TEXT("%d"), this->fTextCaseSen );
  1305.         cCriteria += Docfind_SaveCriteriaItem(pstm, IDD_TEXTCASESEN, szTemp, fCharType);
  1306.     }
  1307.     if( this->fTextReg )
  1308.     {
  1309.         wsprintf( szTemp, TEXT("%d"), this->fTextReg );
  1310.         cCriteria += Docfind_SaveCriteriaItem(pstm, IDD_TEXTREG, szTemp, fCharType);
  1311.     }
  1312.     if( this->fSearchSlowFiles )
  1313.     {
  1314.         wsprintf( szTemp, TEXT("%d"), this->fSearchSlowFiles );
  1315.         cCriteria += Docfind_SaveCriteriaItem(pstm, IDD_SEARCHSLOWFILES, szTemp, fCharType);
  1316.     }
  1317.     return (MAKE_SCODE(0, 0, cCriteria));
  1318. }
  1319. //==========================================================================
  1320. // IDocFindFileFilter::RestoreCriteria
  1321. //==========================================================================
  1322. STDMETHODIMP CDFFilter_RestoreCriteria(IDocFindFileFilter *pdfff,
  1323.         IStream * pstm, int cCriteria, WORD fCharType)
  1324. {
  1325.     CDFFilter *this = IToClass(CDFFilter, dfff, pdfff);
  1326.     TCHAR szTemp[MAX_PATH];    // some random size
  1327.     if (cCriteria > 0)
  1328.         this->fWeRestoredSomeCriteria = TRUE;
  1329.     while (cCriteria--)
  1330.     {
  1331.         // BUGBUG(DavePl) I'm assuming that if UNICODE chars are written in this
  1332.                 // stream, the cb is written accordingly.  ie: what you put in the stream
  1333.                 // is your own business, but write the cb as a byte count, not char count
  1334.         DFCRITERIA dfc;
  1335.         int cb;
  1336.         if (FAILED(pstm->lpVtbl->Read(pstm, &dfc, SIZEOF(dfc), &cb))
  1337.                 || (cb != SIZEOF(dfc)) || (dfc.cbText > SIZEOF(szTemp)))
  1338.             break;
  1339. #ifdef WINNT
  1340. #ifdef UNICODE
  1341.         if (DFC_FMT_UNICODE == fCharType)
  1342.         {
  1343.            //
  1344.            // Destination is Unicode and we're reading Unicode data from stream.
  1345.            // No conversion required.
  1346.            //
  1347.            if (FAILED(pstm->lpVtbl->Read(pstm, szTemp, dfc.cbText, &cb))
  1348.                    || (cb != dfc.cbText))
  1349.                break;
  1350.         }
  1351.         else
  1352.         {
  1353.            char szAnsi[MAX_PATH];
  1354.            //
  1355.            // Destination is Unicode but we're reading ANSI data from stream.
  1356.            // Read ansi.  Convert to unicode.
  1357.            //
  1358.            if (FAILED(pstm->lpVtbl->Read(pstm, szAnsi, dfc.cbText, &cb))
  1359.                    || (cb != dfc.cbText))
  1360.                break;
  1361.            MultiByteToWideChar(CP_ACP, 0L, szAnsi, -1, szTemp, ARRAYSIZE(szTemp));
  1362.         }
  1363. #else
  1364.         if (DFC_FMT_ANSI == fCharType)
  1365.         {
  1366.            //
  1367.            // Destination is ANSI and we're reading ANSI data from stream.
  1368.            // No conversion required.
  1369.            //
  1370.            if (FAILED(pstm->lpVtbl->Read(pstm, szTemp, dfc.cbText, &cb))
  1371.                    || (cb != dfc.cbText))
  1372.                break;
  1373.         }
  1374.         else
  1375.         {
  1376.            //
  1377.            // Destination is ANSI but we're reading Unicode data from stream.
  1378.            // Read unicode.  Convert to ansi.
  1379.            //
  1380.            WCHAR szWide[MAX_PATH];
  1381.            if (FAILED(pstm->lpVtbl->Read(pstm, szWide, dfc.cbText, &cb))
  1382.                    || (cb != dfc.cbText))
  1383.                break;
  1384.            WideCharToMultiByte(CP_ACP, 0L, szWide, -1, szTemp, ARRAYSIZE(szTemp), NULL, NULL);
  1385.         }
  1386. #endif  // UNICODE
  1387. #else
  1388.         if (FAILED(pstm->lpVtbl->Read(pstm, &szTemp, dfc.cbText, &cb))
  1389.                 || (cb != dfc.cbText))
  1390.             break;
  1391. #endif  // WINNT
  1392.         switch (dfc.wNum)
  1393.         {
  1394.         case IDD_FILESPEC:
  1395.             lstrcpy(this->szUserInputFileSpec, szTemp);
  1396.             break;
  1397.         case DFSC_SEARCHFOR:
  1398.             Str_SetPtr(&(this->pszIndexedSearch), szTemp);
  1399.             break;
  1400.         case IDD_PATH:
  1401.             if (lstrcmp(szTemp, TEXT("::")) == 0)
  1402.             {
  1403.                 this->pidlStart = SHCloneSpecialIDList(NULL, CSIDL_DRIVES, FALSE);
  1404.                 szTemp[0] = TEXT('');
  1405.             }
  1406.             else if (StrChr(szTemp,TEXT(';')) == NULL)
  1407.             {
  1408.                 // Simple pidl...
  1409.                 this->pidlStart = ILCreateFromPath(szTemp);
  1410.             }
  1411.             lstrcpy(this->szPath, szTemp);
  1412.             break;
  1413.         case IDD_TOPLEVELONLY:
  1414.             this->fTopLevelOnly = StrToInt(szTemp);
  1415.             break;
  1416.         case IDD_TYPECOMBO:
  1417.             lstrcpy(this->szTypeFilePatterns, szTemp);
  1418.             break;
  1419.         case IDD_CONTAINS:
  1420.             lstrcpy(this->szText, szTemp);
  1421.             break;
  1422.         case IDD_SIZECOMP:
  1423.             // we need to extract off the two parts, the type and
  1424.             // the value
  1425.             this->iSizeType = szTemp[0] - TEXT('0');
  1426.             this->dwSize = StrToInt(&szTemp[2]);
  1427.             break;
  1428.         case IDD_MDATE_NUMDAYS:
  1429.             this->wDateType = DFF_DATE_DAYS;
  1430.             this->wDateValue = (WORD) StrToInt(szTemp);
  1431.             break;
  1432.         case IDD_MDATE_NUMMONTHS:
  1433.             this->wDateType = DFF_DATE_MONTHS;
  1434.             this->wDateValue = (WORD) StrToInt(szTemp);
  1435.             break;
  1436.         case IDD_MDATE_FROM:
  1437.             this->wDateType = DFF_DATE_BETWEEN;
  1438.             this->dateModifiedAfter = (WORD) StrToInt(szTemp);
  1439.             break;
  1440.         case IDD_MDATE_TO:
  1441.             this->wDateType = DFF_DATE_BETWEEN;
  1442.             this->dateModifiedBefore = (WORD) StrToInt(szTemp);
  1443.             break;
  1444.         case IDD_MDATE_TYPE:
  1445.             this->wDateType |= (WORD)StrToInt(szTemp);
  1446.             break;
  1447.         case IDD_TEXTCASESEN:
  1448.             this->fTextCaseSen = (BITBOOL)StrToInt(szTemp);
  1449.             break;
  1450.         case IDD_TEXTREG:
  1451.             this->fTextReg = (BITBOOL)StrToInt(szTemp);
  1452.             break;
  1453.         case IDD_SEARCHSLOWFILES:
  1454.             this->fSearchSlowFiles = (BITBOOL)StrToInt(szTemp);
  1455.             break;
  1456.         }
  1457.     }
  1458.     return (S_OK);
  1459. }
  1460. //==========================================================================
  1461. // IDocFindFileFilter::GetColSaveStream
  1462. //==========================================================================
  1463. STDMETHODIMP CDFFilter_GetColSaveStream(IDocFindFileFilter *pnetf, WPARAM wParam, IStream **ppstm)
  1464. {
  1465.     *ppstm = OpenRegStream(HKEY_CURRENT_USER, REGSTR_PATH_EXPLORER, TEXT("DocFindColsX"), (DWORD) wParam);
  1466.     return(*ppstm ? S_OK : E_FAIL);
  1467. }
  1468. DWORD AddToQuery(LPWSTR *ppszBuf, DWORD *pcchBuf, LPWSTR pszAdd)
  1469. {
  1470.     DWORD cchAdd = lstrlenW(pszAdd);
  1471.     if (*ppszBuf && *pcchBuf > cchAdd)
  1472.     {
  1473.         StrCpyNW(*ppszBuf, pszAdd, *pcchBuf);
  1474.         *pcchBuf -= cchAdd;
  1475.         *ppszBuf += cchAdd;
  1476.     }
  1477.     return cchAdd;
  1478. }
  1479. DWORD AddQuerySep(DWORD *pcchBuf, LPWSTR *ppszCurrent, WCHAR  bSep)
  1480. {
  1481.     LPWSTR pszCurrent = *ppszCurrent;
  1482.     // make sure we have room for us plus terminator...
  1483.     if (*ppszCurrent && *pcchBuf >= 4)
  1484.     {
  1485.         *pszCurrent++ = L' ';
  1486.         *pszCurrent++ = bSep;
  1487.         *pszCurrent++ = L' ';
  1488.         *ppszCurrent = pszCurrent;
  1489.         *pcchBuf -= 3;
  1490.     }
  1491.     return 3; // size necessary
  1492. }
  1493. DWORD PrepareQueryParam(BOOL *pbFirst, DWORD *pcchBuf, LPWSTR *ppszCurrent)
  1494. {
  1495.     if (*pbFirst)
  1496.     {
  1497.         *pbFirst = FALSE;
  1498.         return 0;  // no size necessary
  1499.     }
  1500.         
  1501.     // we're not the first property
  1502.     return AddQuerySep(pcchBuf, ppszCurrent, L'&');
  1503. }
  1504. // pick the longest date query so we can avoid checking the buffer size each time we
  1505. // add something to the string
  1506. #define LONGEST_DATE  50 //lstrlen(TEXT("{prop name=access} <= 2000/12/31 23:59:59{/prop}"))+2
  1507. DWORD QueryDosDate(BOOL *pbFirst, DWORD *pcchBuf, LPWSTR *ppszCurrent, WORD wDate, WORD wDateType, BOOL bBefore)
  1508. {
  1509.     FILETIME ftLocal, ftGMT;
  1510.     SYSTEMTIME st;
  1511.     LPWSTR pszCurrent = *ppszCurrent;
  1512.     DWORD  cchNeeded = PrepareQueryParam(pbFirst, pcchBuf, &pszCurrent);
  1513.     
  1514.     if (pszCurrent && *pcchBuf > LONGEST_DATE)
  1515.     {
  1516.         DosDateTimeToFileTime(wDate, 0, &ftLocal);
  1517.         LocalFileTimeToFileTime(&ftLocal, &ftGMT);
  1518.         FileTimeToSystemTime(&ftGMT, &st);
  1519.         
  1520.         switch (wDateType & DFF_DATE_TYPEMASK)
  1521.         {
  1522.         case DFF_DATE_ACCESSED:
  1523.             StrCpyNW(pszCurrent, L"{prop name=access} ", *pcchBuf);
  1524.             break;
  1525.         case DFF_DATE_CREATED:
  1526.             StrCpyNW(pszCurrent, L"{prop name=create} ", *pcchBuf);
  1527.             break;
  1528.         case DFF_DATE_MODIFIED:
  1529.             StrCpyNW(pszCurrent, L"{prop name=write} ", *pcchBuf);
  1530.             break;
  1531.         }
  1532.     
  1533.         pszCurrent += lstrlenW(pszCurrent);
  1534.         if (bBefore)
  1535.         {
  1536.             *pszCurrent++ = L'<';
  1537.             // BUGBUG:: if you ask for a range like: 2/20/98 - 2/20/98 then we get no time at all
  1538.             // So for before, convert H:m:ss to 23:59:59...
  1539.             st.wHour = 23;
  1540.             st.wMinute = 59; 
  1541.             st.wSecond = 59;
  1542.         }
  1543.         else
  1544.             *pszCurrent++ = L'>';
  1545.         
  1546.         *pszCurrent++ = L'=';
  1547.         wnsprintfW(pszCurrent, *pcchBuf, L" %d/%d/%d %d:%d:%d{/prop}", st.wYear, st.wMonth, st.wDay,
  1548.             st.wHour, st.wMinute, st.wSecond);
  1549.         pszCurrent += lstrlenW(pszCurrent);
  1550.         
  1551.         *ppszCurrent = pszCurrent;
  1552.         *pcchBuf -= LONGEST_DATE;
  1553.     }
  1554.     return cchNeeded + LONGEST_DATE;
  1555. }
  1556. DWORD CIQueryFilePatterns(BOOL *pbFirst, DWORD *pcchBuf, LPWSTR *ppszCurrent, LPWSTR pszFilePatterns)
  1557. {
  1558.     WCHAR szNextPattern[MAX_PATH];  // overkill in size
  1559.     BOOL fFirst = TRUE;
  1560.     LPCWSTR pszNextPattern = pszFilePatterns;
  1561.     DWORD cchNeeded = PrepareQueryParam(pbFirst, pcchBuf, ppszCurrent);
  1562.     // Currently will have to long hand the query, may try to find shorter format once bugs
  1563.     // are fixed...
  1564.     // 
  1565.     cchNeeded += AddToQuery(ppszCurrent, pcchBuf, L"(");
  1566.     while ((pszNextPattern = NextPathW(pszNextPattern, szNextPattern, ARRAYSIZE(szNextPattern))) != NULL)
  1567.     {
  1568.         if (!fFirst)
  1569.         {
  1570.             cchNeeded += AddToQuery(ppszCurrent, pcchBuf, L" | ");
  1571.         }
  1572.         fFirst = FALSE;
  1573.         cchNeeded += AddToQuery(ppszCurrent, pcchBuf, L"#filename ");
  1574.         cchNeeded += AddToQuery(ppszCurrent, pcchBuf, szNextPattern);
  1575.     }
  1576.     cchNeeded += AddToQuery(ppszCurrent, pcchBuf, L")");
  1577.     return cchNeeded;
  1578. }
  1579. DWORD CIQueryTextPatterns(BOOL *pbFirst, DWORD *pcchBuf, LPWSTR *ppszCurrent, LPWSTR pszText, BOOL bTextReg)
  1580. {
  1581.     DWORD cchNeeded = PrepareQueryParam(pbFirst, pcchBuf, ppszCurrent);
  1582.     cchNeeded += AddToQuery(ppszCurrent, pcchBuf, L"{prop name=all}");
  1583.     cchNeeded += AddToQuery(ppszCurrent, pcchBuf, bTextReg? L"{regex}" : L"{phrase}");
  1584.     cchNeeded += AddToQuery(ppszCurrent, pcchBuf, pszText);
  1585.     cchNeeded += AddToQuery(ppszCurrent, pcchBuf, bTextReg? L"{/regex}{/prop}" : L"{/phrase}{/prop}");
  1586.     return cchNeeded;
  1587. }
  1588. #define MAX_DWORD_LEN  18
  1589. DWORD CIQuerySize(BOOL *pbFirst, DWORD *pcchBuf, LPWSTR *ppszCurrent, DWORD dwSize, int iSizeType)
  1590. {
  1591.     WCHAR szSize[MAX_DWORD_LEN+8]; // +8 for " {/prop}"
  1592.     DWORD cchNeeded = PrepareQueryParam(pbFirst, pcchBuf, ppszCurrent);
  1593.     cchNeeded += AddToQuery(ppszCurrent, pcchBuf, L"{prop name=size} ");
  1594.     cchNeeded += AddToQuery(ppszCurrent, pcchBuf, iSizeType == 1? L">" : L"<");
  1595.             
  1596.     wnsprintfW(szSize, *pcchBuf, L" %d{/prop}", dwSize);
  1597.     cchNeeded += AddToQuery(ppszCurrent, pcchBuf, szSize);
  1598.     return cchNeeded;
  1599. }
  1600. DWORD CIQueryIndex(BOOL *pbFirst, DWORD *pcchBuf, LPWSTR *ppszCurrent, LPWSTR pszText)
  1601. {
  1602.     DWORD cchNeeded = PrepareQueryParam(pbFirst, pcchBuf, ppszCurrent);
  1603.     cchNeeded += AddToQuery(ppszCurrent, pcchBuf, pszText);
  1604.     return cchNeeded;
  1605. }
  1606. DWORD CIQueryShellSettings(BOOL *pbFirst, DWORD *pcchBuf, LPWSTR *ppszCurrent)
  1607. {
  1608.     DWORD cchNeeded = 0;
  1609.     
  1610.     if (!ShowSuperHidden())
  1611.     {
  1612.         cchNeeded += PrepareQueryParam(pbFirst, pcchBuf, ppszCurrent);
  1613.         cchNeeded += AddToQuery(ppszCurrent, pcchBuf, L"NOT @attrib ^a 0x6 ");// don't show files w/ hidden and system bit on
  1614.     }
  1615.     {
  1616.         SHELLSTATE ss;
  1617.         
  1618.         SHGetSetSettings(&ss, SSF_SHOWALLOBJECTS, FALSE);
  1619.         if (!ss.fShowAllObjects)
  1620.         {
  1621.             cchNeeded += PrepareQueryParam(pbFirst, pcchBuf, ppszCurrent);
  1622.             cchNeeded += AddToQuery(ppszCurrent, pcchBuf, L"NOT @attrib ^a 0x2 "); // don't show files w/ hidden bit on
  1623.         }
  1624.     }
  1625.     return cchNeeded;
  1626. }
  1627. void CDFFilter_GenerateQueryHelper(CDFFilter *this, LPWSTR pwszQuery, DWORD *pcchQuery)
  1628. {
  1629.     DWORD cchNeeded = 0, cchLeft = *pcchQuery;
  1630.     LPWSTR pszCurrent = pwszQuery;
  1631.     BOOL  bFirst = TRUE; // first property
  1632.     USES_CONVERSION;
  1633.     if (this->pszFileSpec && this->pszFileSpec[0])
  1634.     {
  1635.         cchNeeded += CIQueryFilePatterns(&bFirst, &cchLeft, &pszCurrent, T2W(this->pszFileSpec));
  1636.     }
  1637.     // fFoldersOnly = TRUE implies szTypeFilePatterns = "."
  1638.     // we cannot pass "." to CI because they won't understand it as give me the folder types
  1639.     // we could check for @attrib ^a FILE_ATTRIBUTE_DIRECTORY (0x10) but ci doesn't index the folder names by default
  1640.     // so we normally won't get any results...
  1641.     if (!this->fFoldersOnly && this->szTypeFilePatterns[0])
  1642.     {
  1643.         cchNeeded += CIQueryFilePatterns(&bFirst, &cchLeft, &pszCurrent, T2W(this->szTypeFilePatterns));
  1644.     }
  1645.     
  1646.     // Date:
  1647.     if (this->dateModifiedBefore != 0)
  1648.     {           
  1649.         cchNeeded += QueryDosDate(&bFirst, &cchLeft, &pszCurrent, this->dateModifiedBefore, this->wDateType, TRUE);
  1650.     }
  1651.     
  1652.     if (this->dateModifiedAfter != 0)
  1653.     {
  1654.         cchNeeded += QueryDosDate(&bFirst, &cchLeft, &pszCurrent, this->dateModifiedAfter, this->wDateType, FALSE);
  1655.     }
  1656.     // Size:
  1657.     if (this->iSizeType != 0)
  1658.     {
  1659.         cchNeeded += CIQuerySize(&bFirst, &cchLeft, &pszCurrent, this->dwSize, this->iSizeType);
  1660.     }
  1661.     // Indexed Search: raw query
  1662.     if (this->pszIndexedSearch && (this->pszIndexedSearch[0] != TEXT('')))
  1663.     {
  1664.         // HACK Alert if first Char is ! then we assume Raw and pass it through directly to CI...
  1665.         // Likewise if it starts with @ or # pass through, but remember the @...
  1666.         cchNeeded += CIQueryIndex(&bFirst, &cchLeft, &pszCurrent, T2W(this->pszIndexedSearch));
  1667.     }
  1668.     // Containing Text:
  1669.     if (this->szText[0] != TEXT(''))
  1670.     {
  1671.         // Try not to quote the strings unless we need to.  This allows more flexability to do the
  1672.         // searching for example: "cat near dog" is different than: cat near dog
  1673.         cchNeeded += CIQueryTextPatterns(&bFirst, &cchLeft, &pszCurrent, T2W(this->szText), this->fTextReg);
  1674.     }
  1675.     cchNeeded += CIQueryShellSettings(&bFirst, &cchLeft, &pszCurrent);
  1676. #ifdef WINNT
  1677.     // assume TCHAR = WCHAR bellow
  1678.     {
  1679.         HKEY  hkey;
  1680.         UINT  cPaths;
  1681.         LPWSTR *apwszPaths;
  1682.         TCHAR szPath[MAX_PATH];
  1683.         // don't search recycle bin folder.  we add both nt4's recycled and nt5's recycler
  1684.         // for every drive we search.
  1685.         if (SUCCEEDED(DF_GetSearchPaths(this, NULL, &apwszPaths, &cPaths)))
  1686.         {
  1687.             int i;
  1688.             
  1689.             for (i = cPaths-1; i >= 0; i--)
  1690.             {
  1691.                 if (PathStripToRootW(apwszPaths[i]))
  1692.                 {
  1693.                     int iBin=0, cBins=2;
  1694.                     HRESULT hr;
  1695.                     static LPCWSTR s_awszRecycleBins[] = { L"Recycled\*", L"Recycler\*", };
  1696. #define NTFS_RBIN  1  // recycle bin on an ntfs drive is called recycler
  1697. #define FAT_RBIN   0  //              ||                        recycled
  1698. #define CCH_EXTRA  lstrlen(TEXT(" & !#PATH "))
  1699.                     hr = _IsNTFSDrive(PathGetDriveNumber(apwszPaths[i]));
  1700.                     // in the failiure case we exclude both recycler and recycled
  1701.                     if (SUCCEEDED(hr))
  1702.                     {
  1703.                         iBin = hr == S_OK? NTFS_RBIN : FAT_RBIN;
  1704.                         cBins = 1;
  1705.                     }
  1706.                     for (; iBin < ARRAYSIZE(s_awszRecycleBins) && cBins > 0; iBin++, cBins--)
  1707.                     {
  1708.                         if (PathCombine(szPath, apwszPaths[i], s_awszRecycleBins[iBin]))
  1709.                         {
  1710.                             DWORD cchSize = lstrlen(szPath)+CCH_EXTRA;
  1711.                             // don't bail out early if we are asked for size of query
  1712.                             if (pwszQuery && cchSize > cchLeft)
  1713.                                 break;
  1714.                             cchNeeded += AddToQuery(&pszCurrent, &cchLeft, L" & !#PATH ");
  1715.                             cchNeeded += AddToQuery(&pszCurrent, &cchLeft, szPath);
  1716.                         }
  1717.                     }
  1718.                 }
  1719.             }
  1720.             // we must exclude the special folders from the results or ci will find items that 
  1721.             // we cannot get pidls for.
  1722.             if (RegOpenKeyEx(HKEY_CURRENT_USER, CI_SPECIAL_FOLDERS, 0, KEY_READ, &hkey) == ERROR_SUCCESS)
  1723.             {
  1724.                 DWORD cValues = 0; // init to zero in case query info bellow fails
  1725.                 TCHAR szName[10];
  1726.             
  1727.                 RegQueryInfoKey(hkey, NULL, NULL, NULL, NULL, NULL, NULL, &cValues, NULL, NULL, NULL, NULL);
  1728.                 if (cValues)
  1729.                 {
  1730.                     DWORD i;
  1731.                     
  1732.                     for (i=0; i < cValues; i++)
  1733.                     {
  1734.                         DWORD cb = ARRAYSIZE(szPath)*SIZEOF(TCHAR);;
  1735.                         wsprintf(szName, TEXT("%d"), i);
  1736.                         if (RegQueryValueEx(hkey, szName, NULL, NULL, (BYTE *)szPath, &cb) == ERROR_SUCCESS)
  1737.                         {
  1738.                             // no +1 since 0 is already in szQuery
  1739.                             DWORD cchSize;
  1740.                             UINT  iDrive;
  1741.                             BOOL  bInclude = FALSE;
  1742.                             for (iDrive=0; iDrive < cPaths; iDrive++)
  1743.                             {
  1744.                                 // szPath has " as the first char so skip it..
  1745.                                 if (PathGetDriveNumber(apwszPaths[iDrive]) == PathGetDriveNumber(szPath+1))
  1746.                                 {
  1747.                                     bInclude = TRUE;
  1748.                                     break;
  1749.                                 }
  1750.                             }
  1751.                             if (!bInclude)
  1752.                                 continue;
  1753.                             cchSize = lstrlen(szPath)+CCH_EXTRA;
  1754.                             // don't bail out early if we are asked for size of query
  1755.                             if (pwszQuery && cchSize > cchLeft)
  1756.                                 break;
  1757.                             cchNeeded += AddToQuery(&pszCurrent, &cchLeft, L" & !#PATH ");
  1758.                             cchNeeded += AddToQuery(&pszCurrent, &cchLeft, szPath);
  1759.                         }
  1760.                     }
  1761.                 }
  1762.                 RegCloseKey(hkey);
  1763.             }
  1764.             // clean up
  1765.             for (i = cPaths-1; i >= 0; i--)
  1766.             {
  1767.                 LocalFree((HLOCAL)apwszPaths[i]);
  1768.             }
  1769.             LocalFree((HLOCAL)apwszPaths);
  1770.         }
  1771.     }
  1772. #endif
  1773.     // If no constraints are set, CI errors out, so instead give it a dummy one of filename
  1774.     // *.*
  1775.     if (pwszQuery && pszCurrent == pwszQuery)
  1776.         CIQueryFilePatterns(&bFirst, &cchLeft, &pszCurrent, L"*.*");
  1777.     if (pszCurrent)
  1778.     {
  1779.         // Make sure we terminate the string at the end...
  1780.         *pszCurrent = TEXT('');
  1781.     }
  1782.     if (!pwszQuery)
  1783.     {
  1784.         *pcchQuery = cchNeeded;
  1785.     }
  1786.     else
  1787.     {
  1788.         ASSERT(*pcchQuery > cchNeeded);
  1789.     }
  1790. }
  1791. //==========================================================================
  1792. // Create a query command string out of the search criteria
  1793. //==========================================================================
  1794. STDMETHODIMP CDFFilter_GenerateQueryRestrictions(IDocFindFileFilter *pdfff, LPWSTR *ppwszQuery, 
  1795.          DWORD *pdwGQR_Flags)
  1796. {
  1797.     CDFFilter *this = IToClass(CDFFilter, dfff, pdfff);
  1798.     // we should be able to make use of ci no matter what (exceptions at the end of the function)
  1799.     DWORD dwGQR_Flags = GQR_MAKES_USE_OF_CI; 
  1800.     HRESULT hres = S_OK;
  1801.     // Named: or Of type:
  1802.     // Match file specificaitions.
  1803.     if (ppwszQuery)
  1804.     {
  1805.         DWORD cchNeeded = 0;
  1806.         
  1807.         CDFFilter_GenerateQueryHelper(this, NULL, &cchNeeded);
  1808.         cchNeeded++;  // for 
  1809.         
  1810.         *ppwszQuery = (LPWSTR)LocalAlloc(LMEM_FIXED, cchNeeded * sizeof(WCHAR));
  1811.         if (! *ppwszQuery)
  1812.             return E_OUTOFMEMORY;
  1813.         CDFFilter_GenerateQueryHelper(this, *ppwszQuery, &cchNeeded);
  1814.     }
  1815.     
  1816.     if (this->pszIndexedSearch && (this->pszIndexedSearch[0] != TEXT('')))
  1817.         dwGQR_Flags |= GQR_REQUIRES_CI;
  1818.     // ci is not case sensitive, so if user wanted case sensitive search we cannot use ci
  1819.     // also ci doesn't index folder names by default so to be safe we just default to our
  1820.     // disk traversal algorithm...
  1821.     if (this->fTextCaseSen || this->fFoldersOnly)
  1822.     {    
  1823.         if (dwGQR_Flags & GQR_REQUIRES_CI && this->fTextCaseSen)
  1824.             hres = MAKE_HRESULT(3, FACILITY_SEARCHCOMMAND, SCEE_CASESENINDEX);
  1825.         else if (dwGQR_Flags & GQR_MAKES_USE_OF_CI)
  1826.             dwGQR_Flags &= ~GQR_MAKES_USE_OF_CI;
  1827.     }
  1828.         
  1829.     *pdwGQR_Flags = dwGQR_Flags;  // return calculated Flags...
  1830.     return hres;
  1831. }
  1832. STDMETHODIMP CDFFilter_ReleaseQuery(IDocFindFileFilter *pdfff)
  1833. {
  1834. #ifdef WINNT
  1835.     CDFFilter *this = IToClass(CDFFilter, dfff, pdfff);
  1836.     if (this->pdfenumAsync)
  1837.     {
  1838.         this->pdfenumAsync->lpVtbl->Release(this->pdfenumAsync);
  1839.         this->pdfenumAsync = NULL;
  1840.     }
  1841. #endif
  1842.     return S_OK;
  1843. }
  1844.                        
  1845. STDMETHODIMP CDFFilter_GetQueryLanguageDialect(IDocFindFileFilter *pdfff, ULONG* pulDialect)
  1846. {
  1847.     CDFFilter *this = IToClass(CDFFilter, dfff, pdfff);
  1848.     
  1849.     if(NULL == this || NULL == pulDialect)
  1850.         return E_POINTER;
  1851.     *pulDialect = this->ulQueryDialect;
  1852.     return S_OK;
  1853. }
  1854. STDMETHODIMP CDFFilter_GetWarningFlags(IDocFindFileFilter *pdfff, DWORD* pdwWarningFlags)
  1855. {
  1856.     CDFFilter *this = IToClass(CDFFilter, dfff, pdfff);
  1857.     if(NULL == this || NULL == pdwWarningFlags)
  1858.         return E_POINTER;
  1859.     *pdwWarningFlags = this->dwWarningFlags;
  1860.     return S_OK;
  1861. }
  1862. ////////////////////////////////////////////////////////////////////////////
  1863. ////////////////////////////////////////////////////////////////////////////
  1864. // Now starting the code for the name and location page
  1865. ////////////////////////////////////////////////////////////////////////////
  1866. ////////////////////////////////////////////////////////////////////////////
  1867. //=========================================================================
  1868. void DocFind_SizeControl(HWND hwndDlg, int id, int cx, BOOL fCombo)
  1869. {
  1870.     RECT rc;
  1871.     RECT rcList;
  1872.     HWND hwndCtl;
  1873.     GetWindowRect(hwndCtl = GetDlgItem(hwndDlg, id), &rc);
  1874.     MapWindowPoints(HWND_DESKTOP, hwndDlg, (POINT *)&rc, 2);
  1875.     if (fCombo)
  1876.     {
  1877.         // These guys are comboboxes so work with them...
  1878.         SendMessage(hwndCtl, CB_GETDROPPEDCONTROLRECT, 0,
  1879.                 (LPARAM)(RECT *)&rcList);
  1880.         rc.bottom += (rcList.bottom - rcList.top);
  1881.     }
  1882.     SetWindowPos(hwndCtl, NULL, 0, 0, cx - rc.left,
  1883.             rc.bottom - rc.top, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
  1884. }
  1885. //==========================================================================
  1886. //
  1887. // Process the WM_SIZE of the details page
  1888. //
  1889. void DocFind_DFNameLocOnSize(HWND hwndDlg, UINT state, int cx, int cy)
  1890. {
  1891.     RECT rc;
  1892.     int cxMargin;
  1893.     HWND hwndCtl;
  1894.     if (state == SIZE_MINIMIZED)
  1895.         return;         // don't bother when we are minimized...
  1896.     // Get the location of first static to calculate margin
  1897.     GetWindowRect(GetDlgItem(hwndDlg, IDD_STATIC), &rc);
  1898.     MapWindowPoints(HWND_DESKTOP, hwndDlg, (POINT *)&rc, 2);
  1899.     cxMargin = rc.left;
  1900.     cx -= cxMargin;
  1901.     DocFind_SizeControl(hwndDlg, IDD_FILESPEC, cx, TRUE);
  1902.     DocFind_SizeControl(hwndDlg, IDD_CONTAINS, cx, FALSE);
  1903.     // Now move the browse button
  1904.     GetWindowRect(hwndCtl = GetDlgItem(hwndDlg, IDD_BROWSE), &rc);
  1905.     MapWindowPoints(HWND_DESKTOP, hwndDlg, (POINT *)&rc, 2);
  1906.     SetWindowPos(hwndCtl, NULL, cx - (rc.right - rc.left), rc.top, 0, 0,
  1907.             SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
  1908.     // And size the path field
  1909. #if 1
  1910.     DocFind_SizeControl(hwndDlg, IDD_PATH, cx, TRUE);
  1911. #else
  1912.     DocFind_SizeControl(hwndDlg, IDD_PATH, cx - cxMargin - (rc.right - rc.left), TRUE);
  1913. #endif            
  1914. }
  1915. //==========================================================================
  1916. // Add a string to our name location list...
  1917. //==========================================================================
  1918. int DFNameLocAddString(LPDOCFINDPROPSHEETPAGE pdfpsp, LPTSTR pszPath)
  1919. {
  1920.     LPTSTR pszT;
  1921.     LPITEMIDLIST pidl;
  1922.     int iSel;
  1923.     LPITEMIDLIST pidlT;
  1924.     HWND hwndCtl = GetDlgItem(pdfpsp->hwndDlg, IDD_PATH);
  1925.     TCHAR szPath[MAX_PATH];
  1926.     int iNew = CB_ERR;
  1927.     // Don't muck with original as it might have been passed to us by someone who
  1928.     // allocated an exact size...
  1929.     lstrcpy(szPath, pszPath);
  1930.     // If we only have one path
  1931.     pszT = szPath + StrCSpn(szPath, TEXT(",;"));
  1932.     if (*pszT == TEXT(''))
  1933.     {
  1934.         // Try to parse the display name into a Pidl
  1935.         PathQualify(szPath);
  1936.         pidl = ILCreateFromPath(szPath);
  1937.         if (!pidl)
  1938.         {
  1939.             TCHAR szDisplayName[MAX_PATH];
  1940.             int cch;
  1941.             // See if the beginning of the string matches the
  1942.             // start of an item in the list.  If so we should
  1943.             // Try to see if we can convert it to a valid
  1944.             // pidl/string...
  1945.             for (iSel=(int)SendMessage(hwndCtl,
  1946.                     CB_GETCOUNT, 0, 0); iSel >= 1; iSel--)
  1947.             {
  1948.                 SendMessage(hwndCtl, CB_GETLBTEXT,
  1949.                         (WPARAM)iSel, (LPARAM)szDisplayName);
  1950.                 cch = lstrlen(szDisplayName);
  1951.                 if ((CompareString(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE,
  1952.                         szDisplayName, cch, szPath, cch) == 2) &&
  1953.                         (szPath[cch] == TEXT('\')))
  1954.                 {
  1955.                     pidlT = (LPITEMIDLIST)SendMessage(hwndCtl,
  1956.                             CB_GETITEMDATA, (WPARAM)iSel, 0);
  1957.                     // Don't blow up if we get a failure here
  1958.                     if (pidlT != (LPITEMIDLIST)-1)
  1959.                     {
  1960.                         SHGetPathFromIDList(pidlT, szDisplayName);
  1961.                         PathAppend(szDisplayName, CharNext(szPath+cch));
  1962.                         pidl = ILCreateFromPath(szDisplayName);
  1963.                         if (pidl)
  1964.                         {
  1965.                             lstrcpy(szPath, szDisplayName);
  1966.                             break;
  1967.                         }
  1968.                     }
  1969. #ifdef DEBUG
  1970.                     else
  1971.                     {
  1972.                         DebugMsg(DM_TRACE, TEXT("DFNameLocAddString - CBItem ptr = -1"));
  1973.                     }
  1974. #endif
  1975.                 }
  1976.             }
  1977.         }
  1978.     }
  1979.     else
  1980.     {
  1981.         // Multiple things let it run by itself...
  1982.         pidl = NULL;      // dont have a pidl to begin with...
  1983.     }
  1984.     if (pidl)
  1985.     {
  1986.         IShellFolder *psfParent;
  1987.         HRESULT hres = SHBindToIDListParent(pidl, &IID_IShellFolder, (void **)&psfParent, NULL);
  1988.         if (SUCCEEDED(hres))
  1989.         {
  1990.             // DocFind_LocCBAddPidl fist ILCombine()s parent and child, since
  1991.             // we didn't separate the parent from the child, pass in the full
  1992.             // pidl and NULL child -- they'll get ILCombine()d appropriately.
  1993.             iNew = DocFind_LocCBAddPidl(hwndCtl, psfParent, pidl, NULL, NULL, TRUE, 0);
  1994.             psfParent->lpVtbl->Release(psfParent);
  1995.         }
  1996.         ILFree(pidl);
  1997.     }
  1998.     else
  1999.     {
  2000.         // Add the whole string as an item...
  2001.         iNew = DocFind_LocCBAddItem(hwndCtl, NULL, -1, 0, -1, szPath);
  2002.     }
  2003.     if (iNew != CB_ERR)
  2004.         SendMessage(hwndCtl, CB_SETCURSEL, iNew, 0);
  2005.     return iNew;
  2006. }
  2007. /*----------------------------------------------------------------------------
  2008. / build_drive_string implementation
  2009. / ------------------
  2010. / Purpose:
  2011. /   Convert from a bit stream ( 1 bit per drive ) to a comma seperated
  2012. /   list of drives.
  2013. /
  2014. / Notes:
  2015. /
  2016. / In:
  2017. /   uDrives = 1 bit per drive (bit 0 == A:, bit 25 == Z:) bit == 1 indicates drive
  2018. /              to be listed.
  2019. /   pszBiffer -> buffer to place text into
  2020. /   iBufferSize = size of the buffer.
  2021. /   pSepStr -> seperating string used to seperate drive names
  2022. /
  2023. / Out:
  2024. /   -
  2025. /----------------------------------------------------------------------------*/
  2026. static void build_drive_string( UINT uDrives, LPTSTR pBuffer, int iSize, LPTSTR pSepStr )
  2027. {
  2028.     TCHAR szDrive[] = TEXT("A:");
  2029.     int iMaxStrLen = lstrlen( szDrive ) + lstrlen( pSepStr );
  2030.     ASSERT( pBuffer != NULL );                      // sanitise the parameters
  2031.     ASSERT( iSize > 0 );
  2032.     *pBuffer = L'';
  2033.     while ( uDrives && ( iSize > iMaxStrLen ) )
  2034.     {
  2035.         if ( uDrives & 1 )
  2036.         {
  2037.             lstrcat( pBuffer, szDrive );
  2038.             if ( uDrives & ~1 )
  2039.                 lstrcat( pBuffer, pSepStr );
  2040.             iSize -= iMaxStrLen;
  2041.         }
  2042.         szDrive[0]++;
  2043.         uDrives >>= 1;
  2044.     }
  2045. }
  2046. //=============================================================================
  2047. // Helper function to build the string of
  2048. //     "<Desktop Directory>;<My Documents Directory>"
  2049. //=============================================================================
  2050. void build_documentfolders_string(LPDOCFINDPROPSHEETPAGE pdfpsp, LPTSTR pszPath, BOOL bDesktopOnly)
  2051. {
  2052.     LPITEMIDLIST pidlDeskDir;
  2053.     TCHAR szTemp[MAX_PATH];
  2054.     
  2055.     *pszPath = TEXT('');
  2056.     // add the all user desktop directory...
  2057.     if (SHGetSpecialFolderLocation(pdfpsp->hwndDlg, CSIDL_COMMON_DESKTOPDIRECTORY, &pidlDeskDir) == S_OK)
  2058.     {
  2059.         SHGetPathFromIDList(pidlDeskDir, pszPath);
  2060.         ILFree(pidlDeskDir);
  2061.         pidlDeskDir = NULL;
  2062.     }
  2063.     
  2064.     // Add the desktop directory...
  2065.     if (SHGetSpecialFolderLocation(pdfpsp->hwndDlg, CSIDL_DESKTOPDIRECTORY, &pidlDeskDir) == S_OK)
  2066.     {
  2067.         SHGetPathFromIDList(pidlDeskDir, szTemp);
  2068.         if (szTemp[0] && lstrlen(szTemp)+lstrlen(pszPath) + 1 < ARRAYSIZE(szTemp))
  2069.         {
  2070.             lstrcat(pszPath,TEXT(";"));
  2071.             lstrcat(pszPath,szTemp);
  2072.         }
  2073.     }
  2074.     if (!bDesktopOnly)
  2075.     {
  2076.         LPITEMIDLIST pidlMyDocuments;
  2077.         
  2078.         // Check to see if the "My Documents" directory should be added or
  2079.         // whether it will implicitly be picked up because of disk hierarchy
  2080.         // and search options...
  2081.         if (SHGetSpecialFolderLocation(pdfpsp->hwndDlg, CSIDL_PERSONAL, &pidlMyDocuments) == S_OK)
  2082.         {
  2083.             BOOL fParent = ILIsParent(pidlDeskDir, pidlMyDocuments, FALSE);
  2084.     
  2085.             if (!fParent || (fParent && !pdfpsp->pdff->fTopLevelOnly))
  2086.             {
  2087.                 SHGetPathFromIDList(pidlMyDocuments, szTemp);
  2088.     
  2089.                 if (szTemp[0] && lstrlen(szTemp)+lstrlen(pszPath) + 1 < ARRAYSIZE(szTemp))
  2090.                 {
  2091.                     lstrcat(pszPath,TEXT(";"));
  2092.                     lstrcat(pszPath,szTemp);
  2093.                 }
  2094.             }
  2095.         }
  2096.     
  2097.         if (pidlMyDocuments)
  2098.             ILFree(pidlMyDocuments);
  2099.     }
  2100.     if (pidlDeskDir)
  2101.         ILFree(pidlDeskDir);
  2102. }
  2103. STDAPI_(BOOL) NextIDL(IEnumIDList *penum, LPITEMIDLIST *ppidl)
  2104. {
  2105.     UINT celt;
  2106.     *ppidl = NULL;
  2107.     return penum->lpVtbl->Next(penum, 1, ppidl, &celt) == NOERROR && celt == 1;
  2108. }
  2109. //==========================================================================
  2110. // Initialize the Name and loacation page
  2111. //==========================================================================
  2112. DWORD CALLBACK DocFind_RealDFNameLocInit(LPVOID lpThreadParameters)
  2113. {
  2114.     LPDOCFINDPROPSHEETPAGE pdfpsp = lpThreadParameters;
  2115.     CDFFilter *pdff = pdfpsp->pdff;    
  2116.     // We process the message after the WM_CREATE or WM_INITDLG as to
  2117.     // allow the dialog to come up quicker...
  2118.     TCHAR szPath[MAX_PATH];
  2119.     LPITEMIDLIST pidlWindows;
  2120.     IShellFolder * psf;
  2121.     HWND hwndCtl;
  2122.     HRESULT hres;
  2123.     LPITEMIDLIST pidlAbs, pidlTemp, pidlStart = pdff->pidlStart;
  2124.     int ipidlStart = -1;        // If pidl passed in and in our list already...
  2125.     int iLocalDrives = -1;
  2126.     HANDLE hEnum;
  2127.     UINT uFixedDrives = 0;      // 1 bit per 'fixed' drive, start at 0.
  2128.     int iMyComputer;
  2129.     int iDrive;
  2130.     IShellFolder *psfDesktop;
  2131.     DOCFINDSAVELOOKIN dfsli = {DFSLI_VER, DFSLI_TYPE_DOCUMENTFOLDERS};
  2132.     CoInitialize(0);
  2133.     SHGetDesktopFolder(&psfDesktop);
  2134.     hwndCtl = GetDlgItem(pdfpsp->hwndDlg, IDD_PATH);
  2135.     SendMessage(hwndCtl, CBEM_SETEXSTYLE, CBES_EX_PATHWORDBREAKPROC, 0L);
  2136.     // If we do not have a pidl Start, default to last place we searched.
  2137.     if (!pidlStart)
  2138.     {
  2139.         // May move this to helper function...
  2140.         // Stream format:
  2141.         //  DWORD:  Version=0
  2142.         //  DWORD:  Type: 0 - Pidl, 1 = Local Drives, 2 = Document Folder
  2143.         //      Pidl if Type = 0
  2144.         IStream *pstm = OpenRegStream(HKEY_CURRENT_USER, REGSTR_PATH_EXPLORER, TEXT("DocFindLastLookIn"), STGM_READ);
  2145.         if (pstm)
  2146.         {
  2147.             int cb;