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

Windows Kernel

Development Platform:

Visual C++

  1. #include "shellprv.h"
  2. #pragma hdrstop
  3. #include "bitbuck.h"
  4. #include "fstreex.h"
  5. #include "util.h"
  6. #include "copy.h"
  7. #include "mrsw.h"
  8. #include "prop.h" // for COL_DATA
  9. #include "datautil.h"
  10. STDAPI_(LPITEMIDLIST) ILResize(LPITEMIDLIST pidl, UINT cbRequired, UINT cbExtra);
  11. // mulprsht.c
  12. void SetDateTimeText(HWND hdlg, int id, const FILETIME *pftUTC);
  13. // defext.c
  14. STDMETHODIMP CCommonShellPropSheetExt_ReplacePage(IShellPropSheetExt * pspx, UINT uPageID, LPFNADDPROPSHEETPAGE lpfnReplaceWith, LPARAM lParam);
  15. // fstreex.c
  16. int  FS_CreateMoveCopyList(IDataObject *pdtobj, void *hNameMappings, LPITEMIDLIST **pppidl);
  17. void FS_PositionItems(HWND hwndOwner, UINT cidl, const LPITEMIDLIST *ppidl, IDataObject *pdtobj, POINT *pptOrigin, BOOL fMove);
  18. void FS_FreeMoveCopyList(LPITEMIDLIST *ppidl, UINT cidl);
  19. HRESULT CFSIDLData_QueryGetData(IDataObject * pdtobj, FORMATETC * pformatetc); // subclass member function to support CF_HDROP and CF_NETRESOURCE
  20. //
  21. // Prototypes
  22. //
  23. void BBGetDisplayName(LPCIDFOLDER pidf, LPTSTR pszPath);
  24. void BBGetItemPath(LPCIDFOLDER pidf, LPTSTR pszPath);
  25. STDMETHODIMP CBitBucket_PS_AddPages(IShellPropSheetExt * pspx, LPFNADDPROPSHEETPAGE pfnAddPage, LPARAM lParam);
  26. LPITEMIDLIST DeletedFilePathToBBPidl(LPTSTR lpszPath);
  27. //
  28. // structs
  29. //
  30. typedef struct _bbpropsheetinfo
  31. {
  32.     PROPSHEETPAGE psp;
  33.     int idDrive;
  34.     BOOL fNukeOnDelete;
  35.     BOOL fOriginalNukeOnDelete;
  36.     int iPercent;
  37.     int iOriginalPercent;
  38.     // the following two fields are valid only for the "global" tab, where they represent the state
  39.     // of the "Configure drives independently" / "Use one setting for all drives" checkbox
  40.     BOOL fUseGlobalSettings;
  41.     BOOL fOriginalUseGlobalSettings;
  42.     // this is a pointer to the global property sheet page after it has been copied somewhere by the 
  43.     // CreatePropertySheetPage(), we use this to get to the global state of the % slider and fNukeOnDelete
  44.     // from the other tabs
  45.     struct _bbpropsheetinfo* pGlobal;
  46. } BBPROPSHEETINFO, *LPBBPROPSHEETINFO;
  47. const static DWORD aBitBucketPropHelpIDs[] = {  // Context Help IDs
  48.     IDD_ATTR_GROUPBOX,  IDH_COMM_GROUPBOX,
  49.     IDC_INDEPENDENT,    IDH_RECYCLE_CONFIG_INDEP,
  50.     IDC_GLOBAL,         IDH_RECYCLE_CONFIG_ALL,
  51.     IDC_DISKSIZE,       IDH_RECYCLE_DRIVE_SIZE,
  52.     IDC_DISKSIZEDATA,   IDH_RECYCLE_DRIVE_SIZE,
  53.     IDC_BYTESIZE,       IDH_RECYCLE_BIN_SIZE,
  54.     IDC_BYTESIZEDATA,   IDH_RECYCLE_BIN_SIZE,
  55.     IDC_NUKEONDELETE,   IDH_RECYCLE_PURGE_ON_DEL,
  56.     IDC_BBSIZE,         IDH_RECYCLE_MAX_SIZE,
  57.     IDC_BBSIZETEXT,     IDH_RECYCLE_MAX_SIZE,
  58.     IDC_CONFIRMDELETE,  IDH_DELETE_CONFIRM_DLG,
  59.     IDC_TEXT,           NO_HELP,
  60.     0, 0
  61. };
  62. const static DWORD aBitBucketHelpIDs[] = {  // Context Help IDs
  63.     IDD_LINE_1,        NO_HELP,
  64.     IDD_LINE_2,        NO_HELP,
  65.     IDD_ITEMICON,      IDH_FPROP_GEN_ICON,
  66.     IDD_NAME,          IDH_FPROP_GEN_NAME,
  67.     IDD_FILETYPE_TXT,  IDH_FPROP_GEN_TYPE,
  68.     IDD_FILETYPE,      IDH_FPROP_GEN_TYPE,
  69.     IDD_FILESIZE_TXT,  IDH_FPROP_GEN_SIZE,
  70.     IDD_FILESIZE,      IDH_FPROP_GEN_SIZE,
  71.     IDD_LOCATION_TXT,  IDH_FCAB_DELFILEPROP_LOCATION,
  72.     IDD_LOCATION,      IDH_FCAB_DELFILEPROP_LOCATION,
  73.     IDD_DELETED_TXT,   IDH_FCAB_DELFILEPROP_DELETED,
  74.     IDD_DELETED,       IDH_FCAB_DELFILEPROP_DELETED,
  75.     IDD_CREATED_TXT,   IDH_FPROP_GEN_DATE_CREATED,
  76.     IDD_CREATED,       IDH_FPROP_GEN_DATE_CREATED,
  77.     IDD_READONLY,      IDH_FCAB_DELFILEPROP_READONLY,
  78.     IDD_HIDDEN,        IDH_FCAB_DELFILEPROP_HIDDEN,
  79.     IDD_ARCHIVE,       IDH_FCAB_DELFILEPROP_ARCHIVE,
  80.     IDD_ATTR_GROUPBOX, IDH_COMM_GROUPBOX,
  81.     0, 0
  82. };
  83. //
  84. // for the pidls
  85. //
  86. enum
  87. {
  88.     ICOL_NAME = 0,
  89.     ICOL_ORIGINAL,
  90.     ICOL_MODIFIED,
  91.     ICOL_TYPE,
  92.     ICOL_SIZE,
  93. };
  94. const COL_DATA c_bb_cols[] = {
  95.     {ICOL_NAME,     IDS_NAME_COL,           20, LVCFMT_LEFT,    &SCID_NAME},
  96.     {ICOL_ORIGINAL, IDS_DELETEDFROM_COL,    20, LVCFMT_LEFT,    &SCID_ORIGINALLOCATION},
  97.     {ICOL_MODIFIED, IDS_DATEDELETED_COL,    18, LVCFMT_LEFT,    &SCID_DATEDELETED},
  98.     {ICOL_TYPE,     IDS_TYPE_COL,           20, LVCFMT_LEFT,    &SCID_TYPE},
  99.     {ICOL_SIZE,     IDS_SIZE_COL,           8,  LVCFMT_RIGHT,   &SCID_SIZE}
  100. };
  101. //========================================================================
  102. // CBitBucket members
  103. //========================================================================
  104. STDMETHODIMP CBitBucket_SF_QueryInterface(IShellFolder2 *psf, REFIID riid, void **ppvObj)
  105. {
  106.     CBitBucket *this = IToClass(CBitBucket, isf, psf);
  107.     if (IsEqualIID(riid, &IID_IShellFolder)  ||
  108.         IsEqualIID(riid, &IID_IShellFolder2) ||
  109.         IsEqualIID(riid, &IID_IUnknown))
  110.     {
  111.         *ppvObj = &this->isf;
  112.     }
  113.     else if (IsEqualIID(riid, &IID_IPersistFolder) ||
  114.              IsEqualIID(riid, &IID_IPersistFolder2) ||
  115.              IsEqualIID(riid, &IID_IPersist))
  116.     {
  117.         *ppvObj = &this->ipf;
  118.     }
  119.     else if (IsEqualIID(riid, &IID_IContextMenu) )
  120.     {
  121.         *ppvObj = &this->icm;
  122.     }
  123.     else if (IsEqualIID(riid, &IID_IShellPropSheetExt))
  124.     {
  125.         *ppvObj = &this->ips;
  126.     }
  127.     else if (IsEqualIID(riid, &IID_IShellExtInit))
  128.     {
  129.         *ppvObj = &this->isei;
  130.     }
  131.     else
  132.     {
  133.         *ppvObj = NULL;
  134.         return E_NOINTERFACE;
  135.     }
  136.     this->cRef++;
  137.     return NOERROR;
  138. }
  139. STDMETHODIMP_(ULONG) CBitBucket_SF_Release(IShellFolder2 *psf)
  140. {
  141.     CBitBucket *this = IToClass(CBitBucket, isf, psf);
  142.     if (InterlockedDecrement(&this->cRef))
  143.         return this->cRef;
  144.     ILFree(this->pidl);
  145.     LocalFree((HLOCAL)this);
  146.     return 0;
  147. }
  148. STDMETHODIMP_(ULONG) CBitBucket_SF_AddRef(IShellFolder2 *psf)
  149. {
  150.     CBitBucket *this = IToClass(CBitBucket, isf, psf);
  151.     return InterlockedIncrement(&this->cRef);
  152. }
  153. BOOL BBGetOriginalPath(LPBBDATAENTRYIDA pbbidl, TCHAR *pszOrig, UINT cch)
  154. {
  155. #ifdef UNICODE
  156.     if (pbbidl->cb == SIZEOF(BBDATAENTRYIDW)) 
  157.     {
  158.         LPBBDATAENTRYIDW pbbidlw = DATAENTRYIDATOW(pbbidl);
  159.         ualstrcpyn(pszOrig, pbbidlw->wszOriginal, cch);
  160.         return (BOOL)*pszOrig;
  161.     }
  162. #endif
  163.     SHAnsiToTChar(pbbidl->bbde.szOriginal, pszOrig, cch);
  164.     return (BOOL)*pszOrig;
  165. }
  166. //
  167. // We need to be able to compare the names of two bbpidls.  Since either of
  168. // them could be a unicode name, we might have to convert both to unicode.
  169. //
  170. int _BBCompareOriginal(LPBBDATAENTRYIDA lpbbidl1, LPBBDATAENTRYIDA lpbbidl2 )
  171. {
  172.     TCHAR szOrig1[MAX_PATH];
  173.     TCHAR szOrig2[MAX_PATH];
  174.     BBGetOriginalPath(lpbbidl1, szOrig1, ARRAYSIZE(szOrig1));
  175.     BBGetOriginalPath(lpbbidl2, szOrig2, ARRAYSIZE(szOrig2));
  176.     PathRemoveFileSpec(szOrig1);
  177.     PathRemoveFileSpec(szOrig2);
  178.     return lstrcmpi(szOrig1,szOrig2);
  179. }
  180. STDMETHODIMP CBitBucket_SF_CompareIDs(IShellFolder2 *psf, LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
  181. {
  182.     HRESULT hres = ResultFromShort(-1);
  183.     LPBBDATAENTRYIDA pbbidl1, pbbidl2;
  184.     LPCIDFOLDER pidf1 = FS_IsValidID(pidl1);
  185.     LPCIDFOLDER pidf2 = FS_IsValidID(pidl2);
  186.     short nCmp;
  187.     if (!pidf1 || !pidf2)
  188.     {
  189.         ASSERT(0);
  190.         return E_INVALIDARG;
  191.     }
  192.     
  193.     pbbidl1 = PIDLTODATAENTRYID(pidl1);
  194.     pbbidl2 = PIDLTODATAENTRYID(pidl2);
  195.     // don't worry about recursing down because we don't have children.
  196.     switch (lParam) 
  197.     {
  198.         case ICOL_TYPE:
  199.             nCmp = _CompareFileTypes((IShellFolder *)psf, pidf1, pidf2);
  200.             if (nCmp)
  201.             {
  202.                 return ResultFromShort(nCmp);
  203.             }
  204.             else
  205.             {
  206.                 goto CompareNames;
  207.             }
  208.             break;
  209.         case ICOL_SIZE:
  210.         {
  211.             ULONGLONG qw1, qw2;
  212.             // BUGBUG (reinerf) - directories are not dealt with properly
  213.             // when sorting by size.
  214.             FS_GetSize(NULL, pidf1, &qw1);
  215.             FS_GetSize(NULL, pidf2, &qw2);
  216.             if (qw1 < qw2)
  217.             {
  218.                 return ResultFromShort(-1);
  219.             }
  220.             if (qw1 > qw2)
  221.             {
  222.                 return ResultFromShort(1);
  223.             }
  224.         } // else fall through
  225. CompareNames:
  226.         case ICOL_NAME:
  227.             hres = FS_CompareNamesCase(pidf1, pidf2);
  228.             // compare the real filenames first, if they are different,
  229.             // try comparing the display name
  230.             if ((hres != ResultFromShort(0)) && (BB_IsRealID(pidl1) && BB_IsRealID(pidl2)))
  231.             {
  232.                 HRESULT hresOld = hres;
  233.                 TCHAR szName1[MAX_PATH], szName2[MAX_PATH];
  234.                 BBGetDisplayName(pidf1, szName1);
  235.                 BBGetDisplayName(pidf2, szName2);
  236.                 hres = ResultFromShort(lstrcmpi(szName1, szName2));
  237.                 // if they are from the same location, sort them by delete times
  238.                 if (hres == ResultFromShort(0))
  239.                 {
  240.                     // if the items are same in title, sort by drive
  241.                     hres = ResultFromShort(pbbidl1->bbde.idDrive - pbbidl2->bbde.idDrive);
  242.                     if (hres == ResultFromShort(0))
  243.                     {
  244.                         // if the items are still the same, sort by index
  245.                         hres = ResultFromShort(pbbidl1->bbde.iIndex - pbbidl2->bbde.iIndex);
  246.                         // once we're not equal, we can never be equal again
  247.                         ASSERT(hres != ResultFromShort(0));
  248.                         if (hres == ResultFromShort(0))
  249.                         {
  250.                             hres = hresOld;
  251.                         }
  252.                     }
  253.                 }
  254.             }
  255.             break;
  256.         case ICOL_ORIGINAL:
  257.             hres = ResultFromShort(_BBCompareOriginal(pbbidl1, pbbidl2));
  258.             break;
  259.         case ICOL_MODIFIED:
  260.             if (pbbidl1->bbde.ft.dwHighDateTime < pbbidl2->bbde.ft.dwHighDateTime) 
  261.             {
  262.                 hres = ResultFromShort(-1);
  263.             }
  264.             else if (pbbidl1->bbde.ft.dwHighDateTime > pbbidl2->bbde.ft.dwHighDateTime)
  265.             {
  266.                 hres = ResultFromShort(1);
  267.             }
  268.             else
  269.             {
  270.                 if (pbbidl1->bbde.ft.dwLowDateTime < pbbidl2->bbde.ft.dwLowDateTime) 
  271.                 {
  272.                     hres = ResultFromShort(-1);
  273.                 }
  274.                 else if (pbbidl1->bbde.ft.dwLowDateTime > pbbidl2->bbde.ft.dwLowDateTime)
  275.                 {
  276.                     hres = ResultFromShort(1);
  277.                 }
  278.                 else
  279.                 {
  280.                     return 0;
  281.                 }
  282.             }
  283.             break;
  284.     }
  285.     return hres;
  286. }
  287. STDMETHODIMP CBitBucket_SF_GetAttributesOf(IShellFolder2 *psf, UINT cidl, LPCITEMIDLIST * apidl, ULONG * rgfOut)
  288. {
  289.     CBitBucket *this = IToClass(CBitBucket, isf, psf);
  290.     ULONG gfOut = *rgfOut;
  291.     // asking about the root itself
  292.     if (cidl == 0)
  293.     {
  294.         gfOut = SFGAO_HASPROPSHEET;
  295.     }
  296.     else
  297.     {
  298.         LPCIDFOLDER pidf = FS_IsValidID(apidl[0]);
  299.         gfOut &= (SFGAO_CANMOVE | SFGAO_CANDELETE | SFGAO_HASPROPSHEET | SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM);
  300.         if (*rgfOut & SFGAO_LINK)
  301.         {
  302.             if (SHGetClassFlags(pidf) & SHCF_IS_LINK)
  303.             {
  304.                 gfOut |= SFGAO_LINK;
  305.             }
  306.         }
  307.     }
  308.     *rgfOut = gfOut;
  309.     return NOERROR;
  310. }
  311. int DataObjToFileOpString(IDataObject * pdtobj, LPTSTR * ppszSrc, LPTSTR * ppszDest)
  312. {
  313.     int cItems = 0;
  314.     STGMEDIUM medium;
  315.     LPIDA pida = DataObj_GetHIDA(pdtobj, &medium);
  316.     
  317.     if (pida)
  318.     {
  319.         LPTSTR lpszSrc, lpszDest;
  320.         int i, cchSrc, cchDest;
  321.         cItems = pida->cidl;
  322.         // start with null terminated strings
  323.         cchSrc = cchDest = 1;
  324.         
  325.         if (ppszSrc)
  326.             lpszSrc = (void*)LocalAlloc(LPTR, cchSrc * SIZEOF(TCHAR));
  327.         if (ppszDest)
  328.             lpszDest = (void*)LocalAlloc(LPTR, cchDest * SIZEOF(TCHAR));
  329.         for (i = 0 ; i < cItems ; i++) 
  330.         {
  331.             LPCITEMIDLIST pidl = IDA_GetIDListPtr(pida, i);
  332.             LPBBDATAENTRYIDA pbbidl = PIDLTODATAENTRYID(pidl);
  333.             if (ppszSrc) 
  334.             {
  335.                 TCHAR szSrc[MAX_PATH];
  336.                 int cchSrcFile;
  337.                 LPTSTR psz;
  338.                 BBGetItemPath((LPIDFOLDER)pidl, szSrc);
  339.                 cchSrcFile = lstrlen(szSrc) + 1;
  340.                 psz = (LPTSTR)LocalReAlloc((HLOCAL)lpszSrc, (cchSrc + cchSrcFile) * SIZEOF(TCHAR), LMEM_MOVEABLE | LMEM_ZEROINIT);
  341.                 if (!psz)
  342.                 {
  343.                     // out of memory!
  344.                     // bugbug: do something real
  345.                     LocalFree((HLOCAL)lpszSrc);
  346.                     if (ppszDest)
  347.                         LocalFree((HLOCAL)lpszDest);
  348.                     cItems = 0;
  349.                     goto Bail;
  350.                 }
  351.                 lpszSrc = psz;
  352.                 lstrcpy(lpszSrc + cchSrc - 1, szSrc);
  353.                 cchSrc += cchSrcFile;
  354.             }
  355.             if (ppszDest) 
  356.             {
  357.                 TCHAR szOrig[MAX_PATH];
  358.                 int cchDestFile;
  359.                 LPTSTR psz;
  360.                 BBGetOriginalPath(pbbidl, szOrig, ARRAYSIZE(szOrig));
  361.                 cchDestFile = lstrlen(szOrig) + 1;
  362.                 psz = (LPTSTR)LocalReAlloc((HLOCAL)lpszDest, (cchDest + cchDestFile) * SIZEOF(TCHAR), LMEM_MOVEABLE | LMEM_ZEROINIT);
  363.                 if (!psz)
  364.                 {
  365.                     // out of memory!
  366.                     LocalFree((HLOCAL)lpszDest);
  367.                     if (ppszSrc) 
  368.                         LocalFree((HLOCAL)lpszSrc);
  369.                     cItems = 0;
  370.                     goto Bail;
  371.                 }
  372.                 lpszDest = psz;
  373.                 lstrcpy(lpszDest + cchDest - 1, szOrig);
  374.                 cchDest += cchDestFile;
  375.             }
  376.         }
  377.         if (ppszSrc)
  378.             *ppszSrc = lpszSrc;
  379.         if (ppszDest)
  380.             *ppszDest = lpszDest;
  381. Bail:
  382.         HIDA_ReleaseStgMedium(pida, &medium);
  383.     }
  384.     return cItems;
  385. }
  386. //
  387. // restores the list of files in the IDataObject
  388. //
  389. void BBRestoreFileList(CBitBucket *this, HWND hwndOwner, IDataObject * pdtobj)
  390. {
  391.     LPTSTR pszSrc, pszDest;
  392.     if (DataObjToFileOpString(pdtobj, &pszSrc, &pszDest))
  393.     {
  394.         // now do the actual restore.
  395.         SHFILEOPSTRUCT sFileOp = {hwndOwner,
  396.                                   FO_MOVE,
  397.                                   pszSrc,
  398.                                   pszDest,
  399.                                   FOF_MULTIDESTFILES | FOF_SIMPLEPROGRESS | FOF_NOCONFIRMMKDIR,
  400.                                   FALSE,
  401.                                   NULL,
  402.                                   MAKEINTRESOURCE(IDS_BB_RESTORINGFILES)};
  403.         DECLAREWAITCURSOR;
  404.         SetWaitCursor();
  405.         if (SHFileOperation(&sFileOp) == ERROR_SUCCESS)
  406.         {
  407.             // success!;
  408.             SHChangeNotifyHandleEvents();
  409.             BBCheckRestoredFiles(pszSrc);
  410.         }
  411.         LocalFree((HLOCAL)pszSrc);
  412.         LocalFree((HLOCAL)pszDest);
  413.         ResetWaitCursor();
  414.     }
  415. }
  416. //
  417. // nukes the list of files in the IDataObject
  418. //
  419. void BBNukeFileList(CBitBucket *this, HWND hwndOwner, IDataObject * pdtobj)
  420. {
  421.     LPTSTR lpszSrc, lpszDest;
  422.     int nFiles = DataObjToFileOpString(pdtobj, &lpszSrc, &lpszDest);
  423.     
  424.     if (nFiles)
  425.     {
  426.         // now do the actual nuke.
  427.         int iItems;
  428.         WIN32_FIND_DATA fd;
  429.         CONFIRM_DATA cd = {CONFIRM_DELETE_FILE | CONFIRM_DELETE_FOLDER | CONFIRM_PROGRAM_FILE | CONFIRM_MULTIPLE, 0};
  430.         SHFILEOPSTRUCT sFileOp ={hwndOwner,
  431.                                  FO_DELETE,
  432.                                  lpszSrc,
  433.                                  NULL,
  434.                                  FOF_NOCONFIRMATION | FOF_SIMPLEPROGRESS,
  435.                                  FALSE,
  436.                                  NULL,
  437.                                  MAKEINTRESOURCE(IDS_BB_DELETINGWASTEBASKETFILES)};
  438.         DECLAREWAITCURSOR;
  439.         SetWaitCursor();
  440.         fd.dwFileAttributes = FILE_ATTRIBUTE_NORMAL;
  441.         if (ConfirmFileOp(hwndOwner, NULL, &cd, nFiles, 0, CONFIRM_DELETE_FILE | CONFIRM_WASTEBASKET_PURGE, lpszDest, &fd, NULL, &fd, NULL) == IDYES)
  442.         {
  443.             SHFileOperation(&sFileOp);
  444.             
  445.             SHChangeNotifyHandleEvents();
  446.             // update the icon if there are objects left in the list
  447.             iItems = (int) ShellFolderView_GetObjectCount(hwndOwner);
  448.             UpdateIcon(iItems);
  449.         }
  450.         LocalFree((HLOCAL)lpszSrc);
  451.         LocalFree((HLOCAL)lpszDest);
  452.         ResetWaitCursor();
  453.     }
  454. }
  455. void EnableTrackbarAndFamily(HWND hDlg, BOOL f)
  456. {
  457.     EnableWindow(GetDlgItem(hDlg, IDC_BBSIZE), f);
  458.     EnableWindow(GetDlgItem(hDlg, IDC_BBSIZETEXT), f);
  459.     EnableWindow(GetDlgItem(hDlg, IDC_TEXT), f);
  460. }
  461. void BBGlobalPropOnCommand(HWND hDlg, int id, HWND hwndCtl, UINT codeNotify)
  462. {
  463.     LPBBPROPSHEETINFO ppsi = (LPBBPROPSHEETINFO)GetWindowLongPtr(hDlg, DWLP_USER);
  464.     BOOL fNukeOnDelete;
  465.     switch (id)
  466.     {
  467.         case IDC_GLOBAL:
  468.         case IDC_INDEPENDENT:
  469.             fNukeOnDelete = IsDlgButtonChecked(hDlg, IDC_NUKEONDELETE);
  470.             ppsi->fUseGlobalSettings = (IsDlgButtonChecked(hDlg, IDC_GLOBAL) == BST_CHECKED) ? TRUE : FALSE;
  471.             EnableWindow(GetDlgItem(hDlg, IDC_NUKEONDELETE), ppsi->fUseGlobalSettings);
  472.             EnableTrackbarAndFamily(hDlg, ppsi->fUseGlobalSettings && !fNukeOnDelete);
  473.             SendMessage(GetParent(hDlg), PSM_CHANGED, (WPARAM)hDlg, 0);
  474.             break;
  475.         case IDC_NUKEONDELETE:
  476.             fNukeOnDelete = IsDlgButtonChecked(hDlg, IDC_NUKEONDELETE);
  477.     if (fNukeOnDelete)
  478.             {                
  479.         // In order to help protect users, when they turn on "Remove files immedately" we also
  480.         // check the "show delete confimation" box automatically for them. Thus, they will have
  481.         // to explicitly uncheck it if they do not want confimation that their files will be nuked.
  482. CheckDlgButton(hDlg, IDC_CONFIRMDELETE, BST_CHECKED);
  483.             }
  484.             EnableTrackbarAndFamily(hDlg, !fNukeOnDelete);
  485.             // fall through
  486.         case IDC_CONFIRMDELETE:
  487.             SendMessage(GetParent(hDlg), PSM_CHANGED, (WPARAM)hDlg, 0L);
  488.             break;
  489.     }
  490. }
  491. void  RelayMessageToChildren(HWND hwnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
  492. {
  493.     HWND hwndChild;
  494.     for (hwndChild = GetWindow(hwnd, GW_CHILD); hwndChild != NULL; hwndChild = GetWindow(hwndChild, GW_HWNDNEXT))
  495.     {
  496.         SendMessage(hwndChild, uMessage, wParam, lParam);
  497.     }
  498. }
  499. //
  500. // This is the dlg proc for the "Global" tab on the recycle bin
  501. //
  502. BOOL_PTR CALLBACK BBGlobalPropDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  503. {
  504.     LPBBPROPSHEETINFO ppsi = (LPBBPROPSHEETINFO)GetWindowLongPtr(hDlg, DWLP_USER);
  505.     switch (uMsg) 
  506.     {
  507.     HANDLE_MSG(hDlg, WM_COMMAND, BBGlobalPropOnCommand);
  508.     case WM_INITDIALOG: 
  509.     {
  510.         HWND  hwndTrack = GetDlgItem(hDlg, IDC_BBSIZE);
  511. SHELLSTATE ss;
  512. // make sure the info we have is current
  513. RefreshAllBBDriveSettings();
  514.         ppsi = (LPBBPROPSHEETINFO)lParam;
  515.         SetWindowLongPtr(hDlg, DWLP_USER, lParam);
  516.         SendMessage(hwndTrack, TBM_SETTICFREQ, 10, 0);
  517.         SendMessage(hwndTrack, TBM_SETRANGE, FALSE, MAKELONG(0, 100));
  518.         SendMessage(hwndTrack, TBM_SETPOS, TRUE, ppsi->iOriginalPercent);
  519.         EnableWindow(GetDlgItem(hDlg, IDC_NUKEONDELETE), ppsi->fUseGlobalSettings);
  520.         EnableTrackbarAndFamily(hDlg, ppsi->fUseGlobalSettings && !ppsi->fNukeOnDelete);
  521.         CheckDlgButton(hDlg, IDC_NUKEONDELETE, ppsi->fNukeOnDelete);
  522.         CheckRadioButton(hDlg, IDC_INDEPENDENT, IDC_GLOBAL, ppsi->fUseGlobalSettings ? IDC_GLOBAL : IDC_INDEPENDENT);
  523.         SHGetSetSettings(&ss, SSF_NOCONFIRMRECYCLE, FALSE);
  524.         CheckDlgButton(hDlg, IDC_CONFIRMDELETE, !ss.fNoConfirmRecycle);
  525.     }
  526.     // fall through to set iGlobalPercent
  527.     case WM_HSCROLL: 
  528.     {
  529.         TCHAR szPercent[20];
  530.         HWND hwndTrack = GetDlgItem(hDlg, IDC_BBSIZE);
  531.         ppsi->iPercent = (int) SendMessage(hwndTrack, TBM_GETPOS, 0, 0);
  532.         wsprintf(szPercent, TEXT("%d%%"), ppsi->iPercent);
  533.         SetDlgItemText(hDlg, IDC_BBSIZETEXT, szPercent);
  534.         if (ppsi->iPercent != ppsi->iOriginalPercent)
  535.         {
  536.             SendMessage(GetParent(hDlg), PSM_CHANGED, (WPARAM)hDlg, 0L);
  537.     if (ppsi->iPercent == 0)
  538.             {
  539.         // In order to help protect users, when they set the % slider to zero we also
  540.         // check the "show delete confimation" box automatically for them. Thus, they will have
  541.         // to explicitly uncheck it if they do not want confimation that their files will be nuked.
  542. CheckDlgButton(hDlg, IDC_CONFIRMDELETE, BST_CHECKED);
  543.             }
  544. }
  545.         return TRUE;
  546.     }
  547.     case WM_HELP:
  548.         WinHelp((HWND)((LPHELPINFO) lParam)->hItemHandle, NULL,
  549.             HELP_WM_HELP, (ULONG_PTR)(LPTSTR) aBitBucketPropHelpIDs);
  550.         return TRUE;
  551.     case WM_CONTEXTMENU:
  552.         WinHelp((HWND) wParam, NULL, HELP_CONTEXTMENU,
  553.             (ULONG_PTR)(LPVOID) aBitBucketPropHelpIDs);
  554.         return TRUE;
  555.     case WM_WININICHANGE:
  556.     case WM_SYSCOLORCHANGE:
  557.     case WM_DISPLAYCHANGE:
  558.         RelayMessageToChildren(hDlg, uMsg, wParam, lParam);
  559.         break;
  560.     case WM_DESTROY:
  561.         CheckCompactAndPurge();
  562.         SHUpdateRecycleBinIcon();
  563.         break;
  564.     case WM_NOTIFY:
  565.         switch (((NMHDR *)lParam)->code)
  566.         {
  567.             case PSN_APPLY:
  568.             {
  569.                 SHELLSTATE ss;
  570.                 ss.fNoConfirmRecycle = !IsDlgButtonChecked(hDlg, IDC_CONFIRMDELETE);
  571.                 SHGetSetSettings(&ss, SSF_NOCONFIRMRECYCLE, TRUE);
  572.                 
  573.                 ppsi->fNukeOnDelete = (IsDlgButtonChecked(hDlg, IDC_NUKEONDELETE) == BST_CHECKED) ? TRUE : FALSE;
  574.                 ppsi->fUseGlobalSettings = (IsDlgButtonChecked(hDlg, IDC_INDEPENDENT) == BST_CHECKED) ? FALSE : TRUE;
  575. // if anything on the global tab changed, update all the drives
  576. if (ppsi->fUseGlobalSettings != ppsi->fOriginalUseGlobalSettings    ||
  577.                     ppsi->fNukeOnDelete != ppsi->fOriginalNukeOnDelete              ||
  578.                     ppsi->iPercent != ppsi->iOriginalPercent)
  579.                 {
  580.                     int i;
  581.                     // NOTE: We get a PSN_APPLY after all the drive tabs. This has to be this way so that
  582.                     // if global settings change, then the global tab will re-apply all the most current settings
  583.                     // bassed on the global variables that get set above.
  584.                     // this sets the new global settings in the registry
  585.                     if (!PersistGlobalSettings(ppsi->fUseGlobalSettings, ppsi->fNukeOnDelete, ppsi->iPercent))
  586.                     {
  587.                         // we failed, so show the error dialog and bail
  588.                         ShellMessageBox(HINST_THISDLL,
  589.                                         hDlg,
  590.                                         MAKEINTRESOURCE(IDS_BB_CANNOTCHANGESETTINGS),
  591.                                         MAKEINTRESOURCE(IDS_WASTEBASKET),
  592.                                         MB_OK | MB_ICONEXCLAMATION);
  593.                         SetDlgMsgResult(hDlg, WM_NOTIFY, PSNRET_INVALID_NOCHANGEPAGE);
  594.                         return TRUE;
  595.                     }
  596.                     for (i = 0; i < MAX_BITBUCKETS ; i++)
  597.                     {
  598.                         if (MakeBitBucket(i))
  599.                         {
  600.                             BOOL bPurge = TRUE;
  601.                             // we need to purge all the drives in this case
  602.                             RegSetValueEx(g_pBitBucket[i]->hkeyPerUser, TEXT("NeedToPurge"), 0, REG_DWORD, (LPBYTE)&bPurge, SIZEOF(bPurge));
  603.                             RefreshBBDriveSettings(i);
  604.                         }
  605.                     }
  606.                     ppsi->fOriginalUseGlobalSettings = ppsi->fUseGlobalSettings;
  607.                     ppsi->fOriginalNukeOnDelete = ppsi->fNukeOnDelete; 
  608.                     ppsi->iOriginalPercent = ppsi->iPercent;
  609.                 }
  610.             }
  611.         }
  612.         break;
  613.         SetDlgMsgResult(hDlg, WM_NOTIFY, 0);
  614.         return TRUE;
  615.     }
  616.     return FALSE;
  617. }
  618. BOOL_PTR CALLBACK BBDriveDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  619. {
  620.     LPBBPROPSHEETINFO ppsi = (LPBBPROPSHEETINFO)GetWindowLongPtr(hDlg, DWLP_USER);
  621.     TCHAR szDiskSpace[40];
  622.     HWND hwndTrack;
  623.     switch (uMsg) 
  624.     {
  625.         case WM_INITDIALOG: 
  626.         {
  627.             hwndTrack = GetDlgItem(hDlg, IDC_BBSIZE);
  628.             ppsi = (LPBBPROPSHEETINFO)lParam;
  629.             SetWindowLongPtr(hDlg, DWLP_USER, lParam);
  630.             SendMessage(hwndTrack, TBM_SETTICFREQ, 10, 0);
  631.             SendMessage(hwndTrack, TBM_SETRANGE, FALSE, MAKELONG(0, 100));
  632.             SendMessage(hwndTrack, TBM_SETPOS, TRUE, ppsi->iPercent);
  633.             CheckDlgButton(hDlg, IDC_NUKEONDELETE, ppsi->fNukeOnDelete);
  634.             // set the disk space info
  635.             StrFormatByteSize64(g_pBitBucket[ppsi->idDrive]->qwDiskSize, szDiskSpace, ARRAYSIZE(szDiskSpace));
  636.             SetDlgItemText(hDlg, IDC_DISKSIZEDATA, szDiskSpace);
  637.             wParam = 0;
  638.         }
  639.         // fall through
  640.         case WM_HSCROLL:
  641.         {
  642.             ULARGE_INTEGER ulBucketSize;
  643.             HWND hwndTrack = GetDlgItem(hDlg, IDC_BBSIZE);
  644.             ppsi->iPercent = (int)SendMessage(hwndTrack, TBM_GETPOS, 0, 0);
  645.             wsprintf(szDiskSpace, TEXT("%d%%"), ppsi->iPercent);
  646.             SetDlgItemText(hDlg, IDC_BBSIZETEXT, szDiskSpace);
  647.                        
  648.             if (ppsi->iPercent != ppsi->iOriginalPercent) 
  649.             {
  650.                 SendMessage(GetParent(hDlg), PSM_CHANGED, (WPARAM)hDlg, 0);
  651.             }
  652.             // we peg the max size of the recycle bin to 4 gig
  653.             ulBucketSize.QuadPart = (ppsi->pGlobal->fUseGlobalSettings ? ppsi->pGlobal->iPercent : ppsi->iPercent) * (g_pBitBucket[ppsi->idDrive]->qwDiskSize / 100);
  654.             StrFormatByteSize64(ulBucketSize.HighPart ? (DWORD)-1 : ulBucketSize.LowPart, szDiskSpace, ARRAYSIZE(szDiskSpace));
  655.             SetDlgItemText(hDlg, IDC_BYTESIZEDATA, szDiskSpace);
  656.             return TRUE;
  657.         }
  658.         case WM_HELP:
  659.             WinHelp((HWND)((LPHELPINFO) lParam)->hItemHandle, NULL,
  660.                 HELP_WM_HELP, (ULONG_PTR)(LPTSTR) aBitBucketPropHelpIDs);
  661.             return TRUE;
  662.         case WM_CONTEXTMENU:
  663.             WinHelp((HWND) wParam, NULL, HELP_CONTEXTMENU,
  664.                 (ULONG_PTR)(LPVOID) aBitBucketPropHelpIDs);
  665.             return TRUE;
  666.         case WM_COMMAND:
  667.         {
  668.             WORD wCommandID = GET_WM_COMMAND_ID(wParam, lParam);
  669.             
  670.             if (wCommandID == IDC_NUKEONDELETE)
  671.             {
  672.                 SendMessage(GetParent(hDlg), PSM_CHANGED, (WPARAM)hDlg, 0L);
  673.                 EnableTrackbarAndFamily(hDlg, !IsDlgButtonChecked(hDlg, IDC_NUKEONDELETE));
  674.                 EnableWindow(GetDlgItem(hDlg, IDC_BYTESIZE), !IsDlgButtonChecked(hDlg, IDC_NUKEONDELETE));
  675.                 EnableWindow(GetDlgItem(hDlg, IDC_BYTESIZEDATA), !IsDlgButtonChecked(hDlg, IDC_NUKEONDELETE));
  676.             }
  677.             break;
  678.         }
  679.         case WM_NOTIFY:
  680.             switch (((NMHDR *)lParam)->code) 
  681.             {
  682.                 case PSN_APPLY:
  683.                 {
  684.                     ppsi->fNukeOnDelete = (IsDlgButtonChecked(hDlg, IDC_NUKEONDELETE) == BST_CHECKED) ? TRUE : FALSE;
  685.                     // update the info in the registry
  686.                     if (!PersistBBDriveSettings(ppsi->idDrive, ppsi->iPercent, ppsi->fNukeOnDelete))
  687.                     {
  688.                         // we failed, so show the error dialog and bail
  689.                         ShellMessageBox(HINST_THISDLL,
  690.                                         hDlg,
  691.                                         MAKEINTRESOURCE(IDS_BB_CANNOTCHANGESETTINGS),
  692.                                         MAKEINTRESOURCE(IDS_WASTEBASKET),
  693.                                         MB_OK | MB_ICONEXCLAMATION);
  694.                         SetDlgMsgResult(hDlg, WM_NOTIFY, PSNRET_INVALID_NOCHANGEPAGE);
  695.                         return TRUE;
  696.                     }
  697.                     
  698.                     // only purge this drive if the user set the slider to a smaller value       
  699.                     if (ppsi->iPercent < ppsi->iOriginalPercent)
  700.                     {
  701.                         BOOL bPurge = TRUE;
  702.                         // since this drive just shrunk, we need to purge the files in it
  703.                         RegSetValueEx(g_pBitBucket[ppsi->idDrive]->hkeyPerUser, TEXT("NeedToPurge"), 0, REG_DWORD, (LPBYTE)&bPurge, SIZEOF(bPurge));
  704.                     }
  705.                     ppsi->iOriginalPercent = ppsi->iPercent;
  706.                     ppsi->fOriginalNukeOnDelete = ppsi->fNukeOnDelete;
  707.                     
  708.                     // update the g_pBitBucket[] for this drive
  709.                     // NOTE: We get a PSN_APPLY before the global tab does. This has to be this way so that
  710.                     // if global settings change, then the global tab will re-apply all the most current settings
  711.                     // bassed on the global variables that get set in his tab.
  712.                     RefreshBBDriveSettings(ppsi->idDrive);
  713.                 }
  714.                 break;
  715.                 case PSN_SETACTIVE:
  716.                 {   
  717.                     BOOL fNukeOnDelete = IsDlgButtonChecked(hDlg, IDC_NUKEONDELETE);
  718.                     EnableWindow(GetDlgItem(hDlg, IDC_NUKEONDELETE), !ppsi->pGlobal->fUseGlobalSettings);
  719.                     EnableTrackbarAndFamily(hDlg, !ppsi->pGlobal->fUseGlobalSettings && !fNukeOnDelete);
  720.                     EnableWindow(GetDlgItem(hDlg, IDC_BYTESIZE), !fNukeOnDelete);
  721.                     EnableWindow(GetDlgItem(hDlg, IDC_BYTESIZEDATA), !fNukeOnDelete);
  722.                     // send this to make sure that the "space reserved" field is accurate when using global settings
  723.                     SendMessage(hDlg, WM_HSCROLL, 0, 0);
  724.                 }
  725.                 break;
  726.             }
  727.             SetDlgMsgResult(hDlg, WM_NOTIFY, 0);
  728.             return TRUE;
  729.     }
  730.     return FALSE;
  731. }
  732. //
  733. // this is the property sheet page for a file/folder in the bitbucket
  734. //
  735. BOOL_PTR CALLBACK BBFilePropDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  736. {
  737.     BBFILEPROPINFO * pbbfpi = (BBFILEPROPINFO *)GetWindowLongPtr(hDlg, DWLP_USER);
  738.     TCHAR szTemp[MAX_PATH];
  739.     switch (uMsg)
  740.     {
  741.         case WM_INITDIALOG:
  742.         {
  743.             LPCITEMIDLIST pidl;
  744.             LPBBDATAENTRYIDA pbbidl;
  745.             HICON hIcon;
  746.             ULONGLONG cbSize;
  747.             pbbfpi = (BBFILEPROPINFO *)lParam;
  748.             SetWindowLongPtr(hDlg, DWLP_USER, lParam);
  749.             pidl = pbbfpi->pidl;
  750.             pbbidl = PIDLTODATAENTRYID(pidl);
  751.             BBGetOriginalPath(pbbidl, szTemp, ARRAYSIZE(szTemp));
  752. #ifdef WINNT
  753.             //
  754.             // We don't allow user to change compression attribute on a deleted file
  755.             // but we do show the current compressed state
  756.             //
  757.             {
  758.                TCHAR szRoot[_MAX_PATH + 1];
  759.                DWORD dwVolumeFlags = 0;
  760.                DWORD dwFileAttributes;
  761.                TCHAR szFSName[12];
  762.                //
  763.                // If file's volume doesn't support compression, don't show
  764.                // "Compressed" checkbox.
  765.                // If compression is supported, show the checkbox and check/uncheck
  766.                // it to indicate compression state of the file.
  767.                // Perform this operation while szTemp contains complete path name.
  768.                //
  769.                lstrcpy(szRoot, szTemp);
  770.                PathQualify(szRoot);
  771.                PathStripToRoot(szRoot);
  772.                dwFileAttributes = GetFileAttributes(szTemp);
  773.                if (GetVolumeInformation(szRoot, NULL, 0, NULL, NULL, &dwVolumeFlags, szFSName, ARRAYSIZE(szFSName)) &&
  774.                    (dwFileAttributes != (DWORD)-1))
  775.                {
  776.                     if (dwVolumeFlags & FS_FILE_COMPRESSION)
  777.                     {
  778.                         if (dwFileAttributes & FILE_ATTRIBUTE_COMPRESSED)
  779.                         {
  780.                             CheckDlgButton(hDlg, IDD_COMPRESS, 1);
  781.                         }
  782.                         ShowWindow(GetDlgItem(hDlg, IDD_COMPRESS), SW_SHOW);
  783.                     }
  784.                     if (g_bRunOnNT5)
  785.                     {
  786.                      // BUGBUG (ccteng) - HACK
  787.                      // Before NTFS implements FS_FILE_ENCRYPTION, we check the compression
  788.                      // flag instead, which works as long as we also check for g_bRunOnNT5.
  789.                      // After we switch to FS_FILE_ENCRYPTION,
  790.                      // we can also remove if (g_bRunOnNT5).
  791.                         // if (dwVolumeFlags & FS_FILE_ENCRYPTION)
  792.                         if (dwVolumeFlags & FS_FILE_COMPRESSION)
  793.                         {
  794.                             if (dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED)
  795.                             {
  796.                                 CheckDlgButton(hDlg, IDD_ENCRYPT, 1);
  797.                             }
  798.                             ShowWindow(GetDlgItem(hDlg, IDD_ENCRYPT), SW_SHOW);
  799.                         }
  800.                     }
  801.                }
  802.             }
  803. #else
  804.             //
  805.             // Win95 doesn't support compression/encryption
  806.             //
  807. #endif
  808.             PathRemoveExtension(szTemp);
  809.             SetDlgItemText(hDlg, IDD_NAME, PathFindFileName(szTemp));
  810.             // origin
  811.             PathRemoveFileSpec(szTemp);
  812.             SetDlgItemText(hDlg, IDD_LOCATION, PathFindFileName(szTemp));
  813.             // Type
  814.             FS_GetTypeName((LPIDFOLDER)pidl, szTemp, ARRAYSIZE(szTemp));
  815.             SetDlgItemText(hDlg, IDD_FILETYPE, szTemp);
  816.             // Size
  817.             if (FS_IsFolder((LPIDFOLDER)pidl))
  818.                 cbSize = pbbidl->bbde.dwSize;
  819.             else
  820.                 FS_GetSize(NULL, (LPIDFOLDER)pidl, &cbSize);
  821.             StrFormatByteSize64(cbSize, szTemp, ARRAYSIZE(szTemp));
  822.             SetDlgItemText(hDlg, IDD_FILESIZE, szTemp);
  823.             // deleted time
  824.             {
  825.                 FILETIME ft = pbbidl->bbde.ft;
  826.                 SetDateTimeText(hDlg, IDD_DELETED, &ft);
  827.             }
  828.             {
  829.                 HANDLE hfind;
  830.                 WIN32_FIND_DATA fd;
  831.                 BBGetItemPath((LPIDFOLDER)pidl, szTemp);
  832.                 hfind = FindFirstFile(szTemp, &fd);
  833.                 if (hfind != INVALID_HANDLE_VALUE)
  834.                 {
  835.                     SetDateTimeText(hDlg, IDD_CREATED, &fd.ftCreationTime);
  836.                     FindClose(hfind);
  837.                 }
  838.                 // file attributes
  839.                 if (fd.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
  840.                     CheckDlgButton(hDlg, IDD_READONLY, 1);
  841.                 if (fd.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE)
  842.                     CheckDlgButton(hDlg, IDD_ARCHIVE, 1);
  843.                 if (fd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
  844.                     CheckDlgButton(hDlg, IDD_HIDDEN, 1);
  845.                 // icon
  846.                 hIcon = SHGetFileIcon(NULL, szTemp, fd.dwFileAttributes, SHGFI_LARGEICON|SHGFI_USEFILEATTRIBUTES);
  847.                 if (hIcon)
  848.                 {
  849.                     hIcon = (HICON)SendDlgItemMessage(hDlg, IDD_ITEMICON, STM_SETICON, (WPARAM)hIcon, 0L);
  850.                     if (hIcon)
  851.                         DestroyIcon(hIcon);
  852.                 }
  853.             }
  854.             break;
  855.         }
  856.         case WM_WININICHANGE:
  857.         case WM_SYSCOLORCHANGE:
  858.         case WM_DISPLAYCHANGE:
  859.             RelayMessageToChildren(hDlg, uMsg, wParam, lParam);
  860.             break;
  861.         case WM_NOTIFY:
  862.             switch (((NMHDR *)lParam)->code) 
  863.             {
  864.                 case PSN_APPLY:
  865.                 case PSN_SETACTIVE:
  866.                 case PSN_KILLACTIVE:
  867.                     return TRUE;
  868.             }
  869.             break;
  870.         case WM_HELP:
  871.             WinHelp((HWND)((LPHELPINFO) lParam)->hItemHandle, NULL,
  872.                 HELP_WM_HELP, (ULONG_PTR)(LPTSTR) aBitBucketHelpIDs);
  873.             return TRUE;
  874.         case WM_CONTEXTMENU:
  875.             WinHelp((HWND) wParam, NULL, HELP_CONTEXTMENU,
  876.                 (ULONG_PTR)(LPVOID) aBitBucketHelpIDs);
  877.             return TRUE;
  878.     }
  879.     return FALSE;
  880. }
  881. void BBGetDriveDisplayName(int idDrive, LPTSTR pszName, UINT cchSize)
  882. {
  883.     TCHAR szDrive[MAX_PATH];
  884.     SHFILEINFO sfi;
  885.     VDATEINPUTBUF(pszName, TCHAR, cchSize);
  886.     DriveIDToBBRoot(idDrive, szDrive);
  887.     if (SHGetFileInfo(szDrive, 0, &sfi, SIZEOF(sfi), SHGFI_DISPLAYNAME)) 
  888.     {
  889.         lstrcpyn(pszName, sfi.szDisplayName, cchSize);
  890.     }
  891.     
  892.     // If SERVERDRIVE, attempt to overwrite the default display name with the display
  893.     // name for the mydocs folder on the desktop, since SERVERDRIVE==mydocs for now
  894.     if (idDrive == SERVERDRIVE) 
  895.     {
  896.         GetMyDocumentsDisplayName(pszName, cchSize);
  897.     }
  898. }
  899. BOOL CALLBACK _BB_AddPage(HPROPSHEETPAGE psp, LPARAM lParam)
  900. {
  901.     LPPROPSHEETHEADER ppsh = (LPPROPSHEETHEADER)lParam;
  902.     ppsh->phpage[ppsh->nPages++] = psp;
  903.     return TRUE;
  904. }
  905. DWORD CALLBACK _BB_PropertiesThread(IDataObject * pdtobj)
  906. {
  907.     HPROPSHEETPAGE ahpage[MAXPROPPAGES];
  908.     TCHAR szTitle[80];
  909.     PROPSHEETHEADER psh;
  910.     UNIQUESTUBINFO usi;
  911.     LPITEMIDLIST pidlBitBucket = SHCloneSpecialIDList(NULL, CSIDL_BITBUCKET, FALSE);
  912.     BOOL fUnique;
  913.     psh.dwSize = SIZEOF(psh);
  914.     psh.dwFlags = PSH_PROPTITLE;
  915.     psh.hInstance = HINST_THISDLL;
  916. //  psh.hwndParent = NULL;      // will be filled in later
  917.     psh.nStartPage = 0;
  918.     psh.phpage = ahpage;
  919.     psh.nPages = 0;
  920.     if (pdtobj)
  921.     {
  922.         // this is the recycled file properties case, 
  923.         // we only show the proeprties for the first file if
  924.         // there is a multiple selection
  925.         BBFILEPROPINFO bbfpi;
  926.         STGMEDIUM medium;
  927.         LPITEMIDLIST pidlSave;
  928.         TCHAR szTemp[MAX_PATH];
  929.         LPBBDATAENTRYIDA lpbbidl;
  930.         LPIDA pida;
  931.         pida = DataObj_GetHIDA(pdtobj, &medium);
  932.         pidlSave = ILCombine(pidlBitBucket, IDA_GetIDListPtr(pida, 0));
  933.         fUnique = EnsureUniqueStub(pidlSave, STUBCLASS_PROPSHEET, NULL, &usi);
  934.         ILFree(pidlSave);
  935.         if (!fUnique) // found other window
  936.             goto Cleanup;
  937.         bbfpi.psp.dwFlags = 0;
  938.         bbfpi.psp.dwSize = SIZEOF(bbfpi);
  939.         bbfpi.psp.hInstance = HINST_THISDLL;
  940.         bbfpi.psp.pszTemplate = MAKEINTRESOURCE(DLG_DELETEDFILEPROP);
  941.         bbfpi.psp.pfnDlgProc = BBFilePropDlgProc;
  942.         bbfpi.psp.pszTitle = szTitle;
  943.         bbfpi.hida = medium.hGlobal;
  944.         bbfpi.pidl = IDA_GetIDListPtr(pida, 0);
  945.         lpbbidl = PIDLTODATAENTRYID(bbfpi.pidl);
  946.         BBGetOriginalPath(lpbbidl, szTemp, ARRAYSIZE(szTemp));
  947.         lstrcpyn(szTitle, PathFindFileName(szTemp), ARRAYSIZE(szTitle));
  948.         PathRemoveExtension(szTitle);
  949.         psh.phpage[0] = CreatePropertySheetPage(&bbfpi.psp);
  950.         HIDA_ReleaseStgMedium(pida, &medium);
  951.         psh.nPages = 1;
  952.         psh.pszCaption = szTitle;
  953.     }
  954.     else
  955.     {
  956.         // this is the recycle bin property sheet case
  957.         fUnique = EnsureUniqueStub(pidlBitBucket, STUBCLASS_PROPSHEET, NULL, &usi);
  958.         if (!fUnique)
  959.             goto Cleanup;
  960.         CBitBucket_PS_AddPages(NULL, _BB_AddPage, (LPARAM)&psh);
  961.         psh.pszCaption = MAKEINTRESOURCE(IDS_WASTEBASKET);
  962.     }
  963.     psh.hwndParent = usi.hwndStub;
  964.     PropertySheet(&psh);
  965. Cleanup:
  966.     if (pidlBitBucket)
  967.         ILFree(pidlBitBucket);
  968.     FreeUniqueStub(&usi);
  969.     return TRUE;
  970. }
  971. typedef struct _bb_threaddata {
  972.     CBitBucket* pbb;
  973.     HWND hwndOwner;
  974.     IDataObject * pdtobj;
  975.     IStream *pstmDataObj;
  976.     ULONG_PTR idCmd;
  977.     POINT ptDrop;
  978.     BOOL fSameHwnd;
  979.     BOOL fDragDrop;
  980. } BBTHREADDATA;
  981. DWORD WINAPI BB_DropThreadInit(BBTHREADDATA *pbbtd)
  982. {
  983.     STGMEDIUM medium;
  984.     FORMATETC fmte = {CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  985.     if (SUCCEEDED(pbbtd->pdtobj->lpVtbl->GetData(pbbtd->pdtobj, &fmte, &medium))) 
  986.     {
  987.         // call delete here so that files will be moved in
  988.         // their respective bins, not necessarily this one.
  989.         DRAGINFO di;
  990.         di.uSize = SIZEOF(DRAGINFO);
  991.         if (DragQueryInfo(medium.hGlobal, &di))
  992.         {
  993.             // Since BBWillRecycle() can return true even when the file will NOT be
  994.             // recycled (eg the file will be nuked), we want to warn the user when we 
  995.             // are going to nuke something that they initiall thought that it would
  996.             // be recycled
  997.             UINT fOptions = SD_WARNONNUKE; 
  998.             if (!BBWillRecycle(di.lpFileList, NULL) ||
  999.                 (di.lpFileList && (di.lpFileList[lstrlen(di.lpFileList)+1] == 0)
  1000.                  && PathIsShortcutToProgram(di.lpFileList)))
  1001.                 fOptions = SD_USERCONFIRMATION; 
  1002.             if (IsFileInBitBucket(di.lpFileList)) 
  1003.             {
  1004.                 LPITEMIDLIST *ppidl = NULL;
  1005.                 int cidl = FS_CreateMoveCopyList(pbbtd->pdtobj, NULL, &ppidl);
  1006.                 if (ppidl) 
  1007.                 {
  1008.                     FS_PositionItems(pbbtd->hwndOwner, cidl, ppidl, pbbtd->pdtobj, &pbbtd->ptDrop, pbbtd->fDragDrop);
  1009.                     FS_FreeMoveCopyList(ppidl, cidl);
  1010.                 }
  1011.             } 
  1012.             else 
  1013.             {
  1014.                 TransferDelete(pbbtd->hwndOwner, medium.hGlobal, fOptions);
  1015.             }
  1016.             SHChangeNotifyHandleEvents();
  1017.             SHFree(di.lpFileList);
  1018.         }
  1019.         ReleaseStgMedium(&medium);
  1020.     }
  1021.     return 0;
  1022. }
  1023. DWORD CALLBACK _BB_DispatchThreadProc(void *pv)
  1024. {
  1025.     BBTHREADDATA *pbbtd = (BBTHREADDATA *)pv;
  1026.     if (pbbtd->pstmDataObj)
  1027.     {
  1028.         CoGetInterfaceAndReleaseStream(pbbtd->pstmDataObj, &IID_IDataObject, (void **)&pbbtd->pdtobj);
  1029.         pbbtd->pstmDataObj = NULL;  // this is dead
  1030.     }
  1031.     switch(pbbtd->idCmd)
  1032.     {
  1033.     case DFM_CMD_MOVE:
  1034.         if (pbbtd->pdtobj)
  1035.             BB_DropThreadInit(pbbtd);
  1036.         break;
  1037.     case DFM_CMD_PROPERTIES:
  1038.     case FSIDM_PROPERTIESBG:    // NULL pdtobj is valid
  1039.         _BB_PropertiesThread(pbbtd->pdtobj);
  1040.         break;
  1041.     case DFM_CMD_DELETE:
  1042.         if (pbbtd->pdtobj)
  1043.             BBNukeFileList(pbbtd->pbb, pbbtd->hwndOwner, pbbtd->pdtobj);
  1044.         break;
  1045.     case FSIDM_RESTORE:
  1046.         if (pbbtd->pdtobj)
  1047.             BBRestoreFileList(pbbtd->pbb, pbbtd->hwndOwner, pbbtd->pdtobj);
  1048.         break;
  1049.     }
  1050.     if (pbbtd->pdtobj)
  1051.         pbbtd->pdtobj->lpVtbl->Release(pbbtd->pdtobj);
  1052.     if (pbbtd->pbb)
  1053.         pbbtd->pbb->isf.lpVtbl->Release(&pbbtd->pbb->isf);
  1054.     LocalFree((HLOCAL)pbbtd);
  1055.     return 0;
  1056. }
  1057. HRESULT BB_LaunchThread(CBitBucket *this, HWND hwndOwner, IDataObject * pdtobj, WPARAM idCmd)
  1058. {
  1059.     HRESULT hr = E_OUTOFMEMORY;
  1060.     BBTHREADDATA *pbbtd = (BBTHREADDATA *)LocalAlloc(LPTR, SIZEOF(*pbbtd));
  1061.     if (pbbtd)
  1062.     {
  1063.         pbbtd->pbb = this;
  1064.         pbbtd->hwndOwner = hwndOwner;
  1065.         pbbtd->idCmd = idCmd;
  1066.         if (idCmd == DFM_CMD_MOVE)
  1067.         {
  1068.             pbbtd->fDragDrop = (BOOL) ShellFolderView_GetDropPoint(hwndOwner, &pbbtd->ptDrop);
  1069.         }
  1070.         if (this)
  1071.             this->isf.lpVtbl->AddRef(&this->isf);
  1072.         if (pdtobj)
  1073.             CoMarshalInterThreadInterfaceInStream(&IID_IDataObject, (IUnknown *)pdtobj, &pbbtd->pstmDataObj);
  1074.         if (SHCreateThread(_BB_DispatchThreadProc, pbbtd, CTF_COINIT, NULL))
  1075.         {
  1076.             hr = NOERROR;
  1077.         }
  1078.         else
  1079.         {
  1080.             if (pbbtd->pstmDataObj)
  1081.                 pbbtd->pstmDataObj->lpVtbl->Release(pbbtd->pstmDataObj);
  1082.             if (this)
  1083.                 this->isf.lpVtbl->Release(&this->isf);
  1084.             LocalFree((HLOCAL)pbbtd);
  1085.         }
  1086.     }
  1087.     return hr;
  1088. }
  1089. const TCHAR c_szUnDelete[] = TEXT("undelete");
  1090. const TCHAR c_szPurgeAll[] = TEXT("empty");
  1091. HRESULT GetVerb(UINT_PTR idCmd, LPSTR pszName, UINT cchMax, BOOL bUnicode)
  1092. {
  1093.     HRESULT hres;
  1094.     LPCTSTR pszNameT;
  1095.     switch (idCmd)
  1096.     {
  1097.         case FSIDM_RESTORE:
  1098.             pszNameT = c_szUnDelete;
  1099.             break;
  1100.         case FSIDM_PURGEALL:
  1101.             pszNameT = c_szPurgeAll;
  1102.             break;
  1103.         default:
  1104.             return E_NOTIMPL;
  1105.     }
  1106.     if (bUnicode)
  1107.         hres = SHTCharToUnicode(pszNameT, (LPWSTR)pszName, cchMax);
  1108.     else
  1109.         hres = SHTCharToAnsi(pszNameT, (LPSTR)pszName, cchMax);
  1110.     return hres;
  1111. }
  1112. //
  1113. // Callback from DefCM
  1114. //
  1115. HRESULT CALLBACK CBitBucket_DFMCallBack(IShellFolder *psf, HWND hwndOwner,
  1116.                 IDataObject * pdtobj, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1117. {
  1118.     CBitBucket *this = IToClass(CBitBucket, isf, psf);
  1119.     HRESULT hres = NOERROR;     // assume no error
  1120.     switch(uMsg)
  1121.     {
  1122.         case DFM_MERGECONTEXTMENU:
  1123.             CDefFolderMenu_MergeMenu(HINST_THISDLL, POPUP_BITBUCKET_ITEM, 0, (LPQCMINFO)lParam);
  1124.             hres = ResultFromShort(-1); // return 1 so default reg commands won't be added
  1125.             break;
  1126.         case DFM_MAPCOMMANDNAME:
  1127.             if (lstrcmpi((LPCTSTR)lParam, c_szUnDelete) == 0)
  1128.             {
  1129.                 *(int *)wParam = FSIDM_RESTORE;
  1130.             }
  1131.             else
  1132.             {
  1133.                 // command not found
  1134.                 hres = E_FAIL;
  1135.             }
  1136.             break;
  1137.         case DFM_INVOKECOMMAND:
  1138.             switch (wParam) 
  1139.             {
  1140.                 case FSIDM_RESTORE:
  1141.                 case DFM_CMD_DELETE:
  1142.                 case DFM_CMD_PROPERTIES:
  1143.                     hres = BB_LaunchThread(this, hwndOwner, pdtobj, wParam);
  1144.                     break;
  1145.                 default:
  1146.                     hres = S_FALSE;
  1147.                     break;
  1148.             }
  1149.             break;
  1150.         case DFM_GETHELPTEXT:
  1151.             LoadStringA(HINST_THISDLL, LOWORD(wParam) + IDS_MH_FSIDM_FIRST, (LPSTR)lParam, HIWORD(wParam));;
  1152.             break;
  1153.         case DFM_GETHELPTEXTW:
  1154.             LoadStringW(HINST_THISDLL, LOWORD(wParam) + IDS_MH_FSIDM_FIRST, (LPWSTR)lParam, HIWORD(wParam));;
  1155.             break;
  1156.         case DFM_GETVERBA:
  1157.         case DFM_GETVERBW:
  1158.             hres = GetVerb((UINT_PTR)(LOWORD(wParam)), (LPSTR)lParam, (UINT)(HIWORD(wParam)), uMsg == DFM_GETVERBW);
  1159.             break;
  1160.         default:
  1161.             hres = E_NOTIMPL;
  1162.             break;
  1163.     }
  1164.     return hres;
  1165. }
  1166. //
  1167. // CBitBucketIDLDropTarget::DragEnter
  1168. //
  1169. //  This function puts DROPEFFECT_LINK in *pdwEffect, only if the data object
  1170. //  contains one or more net resource.
  1171. //
  1172. STDMETHODIMP CBitBucketIDLDropTarget_DragEnter(IDropTarget *pdropt, IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
  1173. {
  1174.     CIDLDropTarget *this = IToClass(CIDLDropTarget, dropt, pdropt);
  1175.     TraceMsg(TF_BITBUCKET, "Bitbucket: CBitBucketIDLDropTarget::DragEnter");
  1176.     // Call the base class first
  1177.     CIDLDropTarget_DragEnter(pdropt, pDataObj, grfKeyState, pt, pdwEffect);
  1178.     // we don't really care what is in the data object, as long as move
  1179.     // is supported by the source we say you can move it to the wastbasket
  1180.     // in the case of files we will do the regular recycle bin stuff, if
  1181.     // it is not files we will just say it is moved and let the source delete it
  1182.     *pdwEffect &= DROPEFFECT_MOVE;
  1183.     this->dwEffectLastReturned = *pdwEffect;
  1184.     return NOERROR;
  1185. }
  1186. //
  1187. // CBitBucketIDLDropTarget::Drop
  1188. //
  1189. //  This function creates a connection to a dropped net resource object.
  1190. //
  1191. STDMETHODIMP CBitBucketIDLDropTarget_Drop(IDropTarget * pdropt, IDataObject * pDataObj, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect)
  1192. {
  1193.     CIDLDropTarget *this = IToClass(CIDLDropTarget, dropt, pdropt);
  1194.     HRESULT hres;
  1195.     BOOL fWebFoldersHack;
  1196.     // only move operation is allowed
  1197.     *pdwEffect &= DROPEFFECT_MOVE;
  1198.     fWebFoldersHack = FALSE;
  1199.     if (*pdwEffect)
  1200.     {
  1201.         hres = CIDLDropTarget_DragDropMenu(this, DROPEFFECT_MOVE, pDataObj,
  1202.                 pt, pdwEffect, NULL, NULL, POPUP_NONDEFAULTDD, grfKeyState);
  1203.         if (hres == S_FALSE)
  1204.         {
  1205.             // let callers know where this is about to go
  1206.             // Defview cares where it went so it can handle non-filesys items
  1207.             // SHScrap cares because it needs to close the file so we can delete it
  1208.             DataObj_SetDropTarget(pDataObj, &CLSID_RecycleBin);
  1209.             if (DataObj_GetDWORD(pDataObj, g_cfNotRecyclable, 0))
  1210.             {
  1211.                 if (ShellMessageBox(HINST_THISDLL, NULL,
  1212.                                     MAKEINTRESOURCE(IDS_CONFIRMNOTRECYCLABLE),
  1213.                                     MAKEINTRESOURCE(IDS_RECCLEAN_NAMETEXT),
  1214.                                     MB_SETFOREGROUND | MB_ICONQUESTION | MB_YESNO) == IDNO)
  1215.                 {
  1216.                     *pdwEffect = DROPEFFECT_NONE;
  1217.                     goto lCancel;
  1218.                 }
  1219.             }
  1220.             if (this->dwData & DTID_HDROP)  // CF_HDROP
  1221.             {
  1222.                 BB_LaunchThread(NULL, this->hwndOwner, pDataObj, DFM_CMD_MOVE);
  1223.                 // since we will move the file ourself, known as an optimised move, 
  1224.                 // we return zero here. this is per the OLE spec
  1225.                 *pdwEffect = DROPEFFECT_NONE;
  1226.             }
  1227.             else
  1228.             {
  1229.                 // if it was not files, we just say we moved the data, letting the
  1230.                 // source deleted it. lets hope they support undo...
  1231.                 *pdwEffect = DROPEFFECT_MOVE;
  1232.                 // HACK: Put up a "you can't undo this" warning for web folders.
  1233.                 {
  1234.                     LPIDA pida;
  1235.                     STGMEDIUM stgmed;
  1236.                     pida = DataObj_GetHIDA (pDataObj, &stgmed);
  1237.                     if (pida)
  1238.                     {
  1239.                         CLSID clsidSource;
  1240.                         IPersist *pPers;
  1241.                         LPCITEMIDLIST pidl;
  1242.                         pidl = IDA_GetIDListPtr (pida, -1);
  1243.                         if (pidl)
  1244.                         {
  1245.                             hres = SHBindToIDListParent (pidl, &IID_IPersist, (void **) &pPers, NULL);
  1246.                             if (FAILED(hres))
  1247.                             {
  1248.                                 IShellFolder *psf;
  1249.                                 hres = SHBindToObject(NULL, &IID_IShellFolder, pidl, (void **) &psf);
  1250.                                 if (SUCCEEDED(hres))
  1251.                                 {
  1252.                                     hres = psf->lpVtbl->QueryInterface (psf, &IID_IPersist, (void **) &pPers);
  1253.                                     psf->lpVtbl->Release(psf);
  1254.                                 }
  1255.                             }
  1256.                             if (SUCCEEDED(hres))
  1257.                             {
  1258.                                 hres = pPers->lpVtbl->GetClassID (pPers, &clsidSource);
  1259.                                 if (SUCCEEDED(hres) &&
  1260.                                     IsEqualGUID (&clsidSource, &CLSID_WebFolders))
  1261.                                 {
  1262.                                     if (ShellMessageBox(HINST_THISDLL, NULL,
  1263.                                                         MAKEINTRESOURCE(IDS_CONFIRMNOTRECYCLABLE),
  1264.                                                         MAKEINTRESOURCE(IDS_RECCLEAN_NAMETEXT),
  1265.                                                         MB_SETFOREGROUND | MB_ICONQUESTION | MB_YESNO) == IDNO)
  1266.                                     {
  1267.                                         *pdwEffect = DROPEFFECT_NONE;
  1268.                                         pPers->lpVtbl->Release(pPers);
  1269.                                         HIDA_ReleaseStgMedium (pida, &stgmed);
  1270.                                         goto lCancel;
  1271.                                     }
  1272.                                     else
  1273.                                     {
  1274.                                         fWebFoldersHack = TRUE;
  1275.                                     }
  1276.                                 }
  1277.                                 pPers->lpVtbl->Release(pPers);
  1278.                             }
  1279.                         }
  1280.                         HIDA_ReleaseStgMedium (pida, &stgmed);
  1281.                     }
  1282.                 }
  1283.             }
  1284. lCancel:
  1285.             if (!fWebFoldersHack)
  1286.             {
  1287.                 DataObj_SetDWORD(pDataObj, g_cfPerformedDropEffect, *pdwEffect);
  1288.                 DataObj_SetDWORD(pDataObj, g_cfLogicalPerformedDropEffect, DROPEFFECT_MOVE);
  1289.             }
  1290.             else
  1291.             {
  1292.                 // Make web folders really delete its source file.
  1293.                 DataObj_SetDWORD (pDataObj, g_cfPerformedDropEffect, 0);
  1294.             }
  1295.         }
  1296.     }
  1297.     CIDLDropTarget_DragLeave(pdropt);
  1298.     return S_OK;
  1299. }
  1300. const IDropTargetVtbl c_CBBDropTargetVtbl =
  1301. {
  1302.     CIDLDropTarget_QueryInterface, CIDLDropTarget_AddRef, CIDLDropTarget_Release,
  1303.     CBitBucketIDLDropTarget_DragEnter,
  1304.     CIDLDropTarget_DragOver,
  1305.     CIDLDropTarget_DragLeave,
  1306.     CBitBucketIDLDropTarget_Drop,
  1307. };
  1308. void BBInitializeViewWindow(HWND hwndView)
  1309. {
  1310.     int i;
  1311.     for (i = 0 ; i < MAX_BITBUCKETS; i++)
  1312.     {
  1313.         SHChangeNotifyEntry fsne;
  1314.         fsne.fRecursive = FALSE;
  1315.         // make it if it's there so that we'll get any events
  1316.         if (MakeBitBucket(i))
  1317.         {
  1318.             UINT u;
  1319.             fsne.pidl = g_pBitBucket[i]->pidl;
  1320.             u = SHChangeNotifyRegister(hwndView,
  1321.                                        SHCNRF_NewDelivery | SHCNRF_ShellLevel | SHCNRF_InterruptLevel,
  1322.                                        SHCNE_DISKEVENTS,
  1323.                                        WM_DSV_FSNOTIFY, 
  1324.                                        1, 
  1325.                                        &fsne);
  1326. #ifdef DEBUG
  1327.             {
  1328.                 TCHAR szTemp[MAX_PATH];
  1329.                 SHGetPathFromIDList(fsne.pidl, szTemp);
  1330.                 TraceMsg(TF_BITBUCKET, "Bitbucket: SHChangeNotifyRegister returned %d on path %s", u ,szTemp);
  1331.             }
  1332. #endif
  1333.         }
  1334.     }
  1335. }
  1336. HRESULT BBHandleFSNotify(HWND hwnd, LONG lEvent, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
  1337. {
  1338.     HRESULT hres = S_OK;
  1339.     TCHAR szPath[MAX_PATH];
  1340.     LPTSTR pszFileName;
  1341.     // pidls must be child of drives or network
  1342.     // (actually only drives work for right now)
  1343.     // that way we won't get duplicate events
  1344.     if ((!ILIsParent((LPCITEMIDLIST)&c_idlDrives, pidl1, FALSE) && !ILIsParent((LPCITEMIDLIST)&c_idlNet, pidl1, FALSE)) ||
  1345.         (pidl2 && !ILIsParent((LPCITEMIDLIST)&c_idlDrives, pidl2, FALSE) && !ILIsParent((LPCITEMIDLIST)&c_idlNet, pidl2, FALSE)))
  1346.     {
  1347.         return S_FALSE;
  1348.     }
  1349.     SHGetPathFromIDList(pidl1, szPath);
  1350.     pszFileName = PathFindFileName(szPath);
  1351.     if (!lstrcmpi(pszFileName, c_szInfo2) ||
  1352.         !lstrcmpi(pszFileName, c_szInfo) ||
  1353.         !lstrcmpi(pszFileName, c_szDesktopIni))
  1354.     {
  1355.         // we ignore changes to these files because they mean we were simply doing bookeeping 
  1356.         // (eg updating the info file, re-creating the desktop.ini, etc)
  1357.         return S_FALSE;
  1358.     }
  1359.     TraceMsg(TF_BITBUCKET, "Bitbucket: BBHandleFSNotify event %x on path %s", lEvent, szPath);
  1360.     switch (lEvent)
  1361.     {
  1362.         case SHCNE_RENAMEFOLDER:
  1363.         case SHCNE_RENAMEITEM:
  1364.         {
  1365.             int idDrive;
  1366.             // if the rename's target is in a bitbucket, then do a create.
  1367.             // otherwise, return NOERROR..
  1368.             idDrive = DriveIDFromBBPath(szPath);
  1369.             if (MakeBitBucket(idDrive) && ILIsParent(g_pBitBucket[idDrive]->pidl, pidl1, TRUE))
  1370.             {
  1371.                 hres = BBHandleFSNotify(hwnd, (lEvent == SHCNE_RENAMEITEM) ? SHCNE_DELETE : SHCNE_RMDIR, pidl1, NULL);
  1372.             }
  1373.         }
  1374.         break;
  1375.         case SHCNE_CREATE:
  1376.         case SHCNE_MKDIR:
  1377.         {
  1378.             LPITEMIDLIST pidl;
  1379.             pidl = DeletedFilePathToBBPidl(szPath);
  1380.             
  1381.             if (pidl)
  1382.             {
  1383.                 ShellFolderView_AddObject(hwnd, pidl);
  1384.                 hres = S_FALSE;
  1385.             }
  1386.         }
  1387.         break;
  1388.         case SHCNE_DELETE:
  1389.         case SHCNE_RMDIR: 
  1390.         {
  1391.             // if this was a delete into the recycle bin, pidl2 will exist
  1392.             if (pidl2)
  1393.             {
  1394.                 hres = BBHandleFSNotify(hwnd, (lEvent == SHCNE_DELETE) ? SHCNE_CREATE : SHCNE_MKDIR, pidl2, NULL);
  1395.             }
  1396.             else
  1397.             {
  1398.                 ShellFolderView_RemoveObject(hwnd, ILFindLastID(pidl1));
  1399.                 hres = S_FALSE;
  1400.             }
  1401.         }
  1402.         break;
  1403.         case SHCNE_UPDATEDIR:
  1404.         {
  1405.             // we recieved an updatedir, which means we probably had more than 10 fsnotify events come in,
  1406.             // so we just refresh our brains out.
  1407.             ShellFolderView_RefreshAll(hwnd);
  1408.         }
  1409.         break;
  1410.         default:
  1411.         {
  1412.             // didn't handle this message
  1413.             hres = S_FALSE;
  1414.         }
  1415.         break;
  1416.     }
  1417.     return hres;
  1418. }
  1419. void BBSort(HWND hwndOwner, int id)
  1420. {
  1421.     switch(id) 
  1422.     {
  1423.         case FSIDM_SORTBYNAME:
  1424.             ShellFolderView_ReArrange(hwndOwner, 0);
  1425.             break;
  1426.         case FSIDM_SORTBYORIGIN:
  1427.             ShellFolderView_ReArrange(hwndOwner, 1);
  1428.             break;
  1429.         case FSIDM_SORTBYDELETEDDATE:
  1430.             ShellFolderView_ReArrange(hwndOwner, 2);
  1431.             break;
  1432.         case FSIDM_SORTBYTYPE:
  1433.             ShellFolderView_ReArrange(hwndOwner, 3);
  1434.             break;
  1435.         case FSIDM_SORTBYSIZE:
  1436.             ShellFolderView_ReArrange(hwndOwner, 4);
  1437.             break;
  1438.     }
  1439. }
  1440. HRESULT CALLBACK CBitBucket_DFMCallBackBG(IShellFolder *psf, HWND hwndOwner,
  1441.                 IDataObject * pdtobj, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1442. {
  1443.     CBitBucket *this = IToClass(CBitBucket, isf, psf);
  1444.     HRESULT hres = NOERROR;
  1445.     switch(uMsg)
  1446.     {
  1447.         case DFM_MERGECONTEXTMENU:
  1448.             if (!(wParam & CMF_DVFILE)) //In the case of the file menu
  1449.                 CDefFolderMenu_MergeMenu(HINST_THISDLL, POPUP_BITBUCKET_BACKGROUND, POPUP_BITBUCKET_POPUPMERGE, (LPQCMINFO)lParam);
  1450.             break;
  1451.         case DFM_GETHELPTEXT:
  1452.             LoadStringA(HINST_THISDLL, LOWORD(wParam) + IDS_MH_FSIDM_FIRST, (LPSTR)lParam, HIWORD(wParam));
  1453.             break;
  1454.         case DFM_GETHELPTEXTW:
  1455.             LoadStringW(HINST_THISDLL, LOWORD(wParam) + IDS_MH_FSIDM_FIRST, (LPWSTR)lParam, HIWORD(wParam));
  1456.             break;
  1457.         case DFM_INVOKECOMMAND:
  1458.             switch(wParam)
  1459.             {
  1460.                 case FSIDM_SORTBYNAME:
  1461.                 case FSIDM_SORTBYORIGIN:
  1462.                 case FSIDM_SORTBYDELETEDDATE:
  1463.                 case FSIDM_SORTBYTYPE:
  1464.                 case FSIDM_SORTBYSIZE:
  1465.                     BBSort(hwndOwner, (int) wParam);
  1466.                     break;
  1467.                 case FSIDM_PROPERTIESBG:
  1468.                     hres = BB_LaunchThread(NULL, hwndOwner, NULL, FSIDM_PROPERTIESBG);
  1469.                     break;
  1470.                 case DFM_CMD_PASTE:
  1471.                 case DFM_CMD_PROPERTIES:
  1472.                     // GetAttributesOf cidl==0 has SFGAO_HASPROPSHEET,
  1473.                     // let defcm handle this
  1474.                     hres = S_FALSE;
  1475.                     break;
  1476.                 default:
  1477.                     // GetAttributesOf cidl==0 does not set _CANMOVE, _CANDELETE, etc,
  1478.                     // BUT accelerator keys will get these unavailable menu items...
  1479.                     // so we need to return failure here
  1480.                     hres = E_NOTIMPL;
  1481.                     break;
  1482.             }
  1483.             break;
  1484.         default:
  1485.             hres = E_NOTIMPL;
  1486.             break;
  1487.     }
  1488.     return hres;
  1489. }
  1490. STDMETHODIMP CBitBucket_SF_CreateViewObject(IShellFolder2 *psf, HWND hwnd, REFIID riid, void **ppvOut)
  1491. {
  1492.     HRESULT hres;
  1493.     CBitBucket *this = IToClass(CBitBucket, isf, psf);
  1494.     if (IsEqualIID(riid, &IID_IShellView))
  1495.     {
  1496.         SFV_CREATE sSFV;
  1497.         sSFV.cbSize   = sizeof(sSFV);
  1498.         sSFV.pshf     = (IShellFolder *)psf;
  1499.         sSFV.psvOuter = NULL;
  1500.         sSFV.psfvcb   = BitBucket_CreateSFVCB((IShellFolder *)psf, this);
  1501.         hres = SHCreateShellFolderView(&sSFV, (IShellView**)ppvOut);
  1502.         if (sSFV.psfvcb)
  1503.             sSFV.psfvcb->lpVtbl->Release(sSFV.psfvcb);
  1504.     }
  1505.     else if (IsEqualIID(riid, &IID_IDropTarget))
  1506.     {
  1507.         hres = CIDLDropTarget_Create(hwnd, &c_CBBDropTargetVtbl, this->pidl, (IDropTarget **)ppvOut);
  1508.     }
  1509.     else if (IsEqualIID(riid, &IID_IContextMenu))
  1510.     {
  1511.         hres = CDefFolderMenu_Create(NULL, hwnd, 0, NULL, (IShellFolder *)psf, CBitBucket_DFMCallBackBG,
  1512.                                      NULL, NULL, (IContextMenu **)ppvOut);
  1513.     }
  1514.     else
  1515.     {
  1516.         *ppvOut = NULL;
  1517.         hres = E_NOINTERFACE;
  1518.     }
  1519.     return hres;
  1520. }
  1521. STDMETHODIMP CBitBucket_SF_ParseDisplayName(IShellFolder2 *psf, HWND hwnd, LPBC pbc, 
  1522.                                             LPOLESTR pwszDisplayName, ULONG *pchEaten, LPITEMIDLIST *ppidl, ULONG * pdwAttributes)
  1523. {
  1524.     *ppidl = NULL;
  1525.     return E_NOTIMPL;
  1526. }
  1527. STDMETHODIMP CBBIDLData_QueryGetData(IDataObject * pdtobj, FORMATETC * pformatetc)
  1528. {
  1529.     ASSERT(g_cfFileNameMap);
  1530.     if (pformatetc->cfFormat == g_cfFileNameMap && (pformatetc->tymed & TYMED_HGLOBAL))
  1531.     {
  1532.         return NOERROR; // same as S_OK
  1533.     }
  1534.     return CFSIDLData_QueryGetData(pdtobj, pformatetc);
  1535. }
  1536. // subclass member function to support CF_HDROP and CF_NETRESOURCE
  1537. // in:
  1538. //      hida    bitbucket id array
  1539. //
  1540. // out:
  1541. //      HGLOBAL with double NULL terminated string list of destination names
  1542. //
  1543. HGLOBAL BuildDestSpecs(LPIDA pida)
  1544. {
  1545.     LPCITEMIDLIST pidl;
  1546.     LPBBDATAENTRYIDA pbbidl;
  1547.     LPTSTR pszRet;
  1548.     TCHAR szTemp[MAX_PATH];
  1549.     UINT i, cbAlloc = SIZEOF(TCHAR);    // for double NULL termination
  1550.     for (i = 0; pidl = IDA_GetIDListPtr(pida, i); i++)
  1551.     {
  1552.         pbbidl = PIDLTODATAENTRYID(pidl);
  1553.         BBGetOriginalPath(pbbidl, szTemp, ARRAYSIZE(szTemp));
  1554.         cbAlloc += lstrlen(PathFindFileName(szTemp)) * SIZEOF(TCHAR) + SIZEOF(TCHAR);
  1555.     }
  1556.     pszRet = LocalAlloc(LPTR, cbAlloc);
  1557.     if (pszRet)
  1558.     {
  1559.         LPTSTR pszDest = pszRet;
  1560.         for (i = 0; pidl = IDA_GetIDListPtr(pida, i); i++)
  1561.         {
  1562.             pbbidl = PIDLTODATAENTRYID(pidl);
  1563.             BBGetOriginalPath(pbbidl, szTemp, ARRAYSIZE(szTemp));
  1564.             lstrcpy(pszDest, PathFindFileName(szTemp));
  1565.             pszDest += lstrlen(pszDest) + 1;
  1566.             ASSERT((ULONG_PTR)((LPBYTE)pszDest - (LPBYTE)pszRet) < cbAlloc);
  1567.             ASSERT(*(pszDest) == 0);    // zero init alloc
  1568.         }
  1569.         ASSERT((LPTSTR)((LPBYTE)pszRet + cbAlloc - SIZEOF(TCHAR)) == pszDest);
  1570.         ASSERT(*pszDest == 0);  // zero init alloc
  1571.     }
  1572.     return pszRet;
  1573. }
  1574. extern HRESULT CFSIDLData_GetData(IDataObject * pdtobj, FORMATETC * pformatetcIn, STGMEDIUM * pmedium);
  1575. STDMETHODIMP CBBIDLData_GetData(IDataObject * pdtobj, FORMATETC * pformatetcIn, STGMEDIUM * pmedium)
  1576. {
  1577.     HRESULT hres = E_INVALIDARG;
  1578.     ASSERT(g_cfFileNameMap);
  1579.     if (pformatetcIn->cfFormat == g_cfFileNameMap && (pformatetcIn->tymed & TYMED_HGLOBAL))
  1580.     {
  1581.         STGMEDIUM medium;
  1582.         LPIDA pida = DataObj_GetHIDA(pdtobj, &medium);
  1583.         if (medium.hGlobal)
  1584.         {
  1585.             pmedium->hGlobal = BuildDestSpecs(pida);
  1586.             pmedium->tymed = TYMED_HGLOBAL;
  1587.             pmedium->pUnkForRelease = NULL;
  1588.             HIDA_ReleaseStgMedium(pida, &medium);
  1589.             hres = pmedium->hGlobal ? NOERROR : E_OUTOFMEMORY;
  1590.         }
  1591.     }
  1592.     else
  1593.     {
  1594.         hres = CFSIDLData_GetData(pdtobj, pformatetcIn, pmedium);
  1595.     }
  1596.     return hres;
  1597. }
  1598. const IDataObjectVtbl c_CBBIDLDataVtbl = {
  1599.     CIDLData_QueryInterface, CIDLData_AddRef, CIDLData_Release,
  1600.     CBBIDLData_GetData,
  1601.     CIDLData_GetDataHere,
  1602.     CBBIDLData_QueryGetData,
  1603.     CIDLData_GetCanonicalFormatEtc,
  1604.     CIDLData_SetData,
  1605.     CIDLData_EnumFormatEtc,
  1606.     CIDLData_Advise,
  1607.     CIDLData_Unadvise,
  1608.     CIDLData_EnumAdvise
  1609. };
  1610. HRESULT _CreateDefExtIcon(LPCIDFOLDER pidf, REFIID riid, void **ppxicon)
  1611. {
  1612.     HRESULT hres = E_OUTOFMEMORY;
  1613.     if (FS_IsFileFolder(pidf))
  1614.     {
  1615.         return SHCreateDefExtIcon(NULL, II_FOLDER, II_FOLDEROPEN, GIL_PERCLASS, riid, ppxicon);
  1616.     }
  1617.     else
  1618.     {
  1619.         DWORD dwFlags = SHGetClassFlags(pidf);
  1620.         if (dwFlags & SHCF_ICON_PERINSTANCE)
  1621.         {
  1622.             TCHAR szPath[MAX_PATH];
  1623.              
  1624.             BBGetItemPath(pidf, szPath);
  1625.             if (dwFlags & SHCF_HAS_ICONHANDLER)
  1626.             {
  1627.                 LPITEMIDLIST pidlFull = SHSimpleIDListFromPath(szPath);
  1628.                 if (pidlFull)
  1629.                 {
  1630.                     // We hit this case for .lnk files in the recycle bin. We used to call FSLoadHandler
  1631.                     // but guz decided he only wanted the fstree code using that function (and it takes a fs psf
  1632.                     // nowdays anyway). So we just bind our brains out.
  1633.                     hres = SHGetUIObjectFromFullPIDL(pidlFull, NULL, riid, ppxicon);
  1634.                     ILFree(pidlFull);
  1635.                 }
  1636.                 else
  1637.                 {
  1638.                     hres = E_OUTOFMEMORY;
  1639.                 }
  1640.             }
  1641.             else
  1642.             {
  1643.                 DWORD uid = FS_GetUID(pidf);
  1644.                 hres = SHCreateDefExtIcon(szPath, uid, uid, GIL_PERINSTANCE | GIL_NOTFILENAME, riid, ppxicon);
  1645.             }
  1646.         }
  1647.         else
  1648.         {
  1649.             UINT iIcon = (dwFlags & SHCF_ICON_INDEX);
  1650.             hres = SHCreateDefExtIcon(c_szStar, iIcon, iIcon, GIL_PERCLASS | GIL_NOTFILENAME, riid, ppxicon);
  1651.         }
  1652.         return hres;
  1653.     }
  1654. }
  1655. STDMETHODIMP CBitBucket_GetUIObjectOf(IShellFolder2 *psf, HWND hwnd, UINT cidl, LPCITEMIDLIST *apidl,
  1656.                                       REFIID riid, UINT *prgfInOut, void **ppvOut)
  1657. {
  1658.     CBitBucket *this = IToClass(CBitBucket, isf, psf);
  1659.     HRESULT hres;
  1660.     *ppvOut = NULL;
  1661.     if (cidl && IsEqualIID(riid, &IID_IDataObject))
  1662.     {
  1663.         hres = CIDLData_CreateFromIDArray2(&c_CBBIDLDataVtbl, this->pidl, cidl, apidl, (IDataObject **)ppvOut);
  1664.     }
  1665.     else if ((cidl == 1) && 
  1666.         (IsEqualIID(riid, &IID_IExtractIconA) || IsEqualIID(riid, &IID_IExtractIconW)))
  1667.     {
  1668.         hres = _CreateDefExtIcon(FS_IsValidID(apidl[0]), riid, ppvOut);
  1669.     }
  1670.     else if (IsEqualIID(riid, &IID_IContextMenu))
  1671.     {
  1672.         hres = CDefFolderMenu_Create(this->pidl, hwnd, cidl, apidl,
  1673.             (IShellFolder *)psf, CBitBucket_DFMCallBack, NULL, NULL, (IContextMenu**)ppvOut);
  1674.     }
  1675.     else
  1676.     {
  1677.         hres = E_NOTIMPL;
  1678.     }
  1679.     return hres;
  1680. }
  1681. HRESULT FindDataFromBBPidl(LPCITEMIDLIST bbpidl, WIN32_FIND_DATAW *pfd)
  1682. {
  1683.     LPBBDATAENTRYIDA pbbdei = PIDLTODATAENTRYID(bbpidl);
  1684.     LPIDFOLDER pidf = (LPIDFOLDER)bbpidl;
  1685.     ULONGLONG cbSize;                       // 64 bits
  1686.     ZeroMemory(pfd, sizeof(*pfd));
  1687.     if (bbpidl->mkid.cb < sizeof(BBDATAENTRYIDA))
  1688.         return E_INVALIDARG;
  1689.     // this code copied from the size column in details view, so webview will match that
  1690.     if (FS_IsFolder(pidf))
  1691.     {
  1692.         cbSize = pbbdei->bbde.dwSize;       // we cache the size of the folder, rounded to cluster
  1693.     }
  1694.     else
  1695.     {
  1696.         FS_GetSize(NULL, pidf, &cbSize);
  1697.     }
  1698.     pfd->nFileSizeHigh = HIDWORD(cbSize);
  1699.     pfd->nFileSizeLow = LODWORD(cbSize);
  1700.     pfd->dwFileAttributes = pidf->fs.wAttrs; // right?
  1701.     DosDateTimeToFileTime(pidf->fs.dateModified, pidf->fs.timeModified, &pfd->ftLastWriteTime);
  1702.     return S_OK;
  1703. }
  1704. LPITEMIDLIST BBDataEntryToPidl(int idDrive, LPBBDATAENTRYW pbbde)
  1705. {
  1706.     WIN32_FIND_DATA fd;
  1707.     TCHAR chDrive;
  1708.     TCHAR szPath[MAX_PATH];
  1709.     TCHAR szDeletedPath[MAX_PATH];
  1710.     TCHAR szOriginalFileName[MAX_PATH];
  1711.     LPITEMIDLIST pidl = NULL;
  1712.     LPITEMIDLIST pidlRet = NULL;
  1713.     BBDATAENTRYIDW bbpidl;
  1714.     void *lpv;
  1715.     if (g_pBitBucket[idDrive]->fIsUnicode)
  1716.     {
  1717.         WCHAR szTemp[MAX_PATH];
  1718.         // save off the original filename so we have the extension (needed to construct the delete file name)
  1719.         SHUnicodeToTChar(pbbde->szOriginal, szOriginalFileName, ARRAYSIZE(szOriginalFileName));
  1720.         bbpidl.bbde.iIndex  = pbbde->iIndex;
  1721.         bbpidl.bbde.idDrive = pbbde->idDrive;
  1722.         bbpidl.bbde.ft      = pbbde->ft;
  1723.         bbpidl.bbde.dwSize  = pbbde->dwSize;
  1724.         SHAnsiToUnicode(pbbde->szShortName, szTemp, ARRAYSIZE(szTemp));
  1725.         
  1726.         if (StrCmpW(pbbde->szOriginal, szTemp) == 0)
  1727.         {
  1728.             // The short and long names match, so we can use an ansi pidl
  1729.             bbpidl.cb = SIZEOF(BBDATAENTRYIDA);
  1730.             lpv = &bbpidl.cb;
  1731.         }
  1732.         else
  1733.         {
  1734.             // The short and long names DO NOT match, so create a full 
  1735.             // blown unicode pidl (both ansi and unicode names)
  1736.             bbpidl.cb = SIZEOF(BBDATAENTRYIDW);
  1737.             StrCpyW(bbpidl.wszOriginal, pbbde->szOriginal);
  1738.             lpv = &bbpidl;
  1739.         }
  1740.         bbpidl.bbde = *((LPBBDATAENTRYA)pbbde);
  1741.     }
  1742.     else
  1743.     {
  1744.         LPBBDATAENTRYA pbbdea = (LPBBDATAENTRYA)pbbde;
  1745.         // save off the original filename so we have the extension (needed to construct the delete file name)
  1746.         SHAnsiToTChar(pbbdea->szOriginal, szOriginalFileName, ARRAYSIZE(szOriginalFileName));
  1747.         // just create an ansi pidl
  1748.         bbpidl.cb = SIZEOF(BBDATAENTRYIDA);
  1749.         bbpidl.bbde = *pbbdea;
  1750.         lpv = &bbpidl.cb;
  1751.     }
  1752.     chDrive = TEXT('a') + pbbde->idDrive;
  1753.     if (chDrive == (TEXT('a') + SERVERDRIVE))
  1754.     {
  1755.         chDrive = TEXT('@');
  1756.     }
  1757.     DriveIDToBBPath(idDrive, szPath);
  1758.     lstrcpyn(szDeletedPath, szPath, ARRAYSIZE(szDeletedPath));
  1759.     // create the full path to the delete file so we can get its attributes
  1760.     wsprintf(&szDeletedPath[lstrlen(szDeletedPath)], TEXT("\D%c%d%s"), chDrive, pbbde->iIndex, PathFindExtension(szOriginalFileName));
  1761.     
  1762.     fd.dwFileAttributes = GetFileAttributes(szDeletedPath);
  1763.     
  1764.     if (fd.dwFileAttributes == -1)
  1765.     {
  1766.         TraceMsg(TF_BITBUCKET, "Bitbucket: unable to get file attributes for path %s , cannot create pidl!!", szDeletedPath);
  1767.         return NULL;
  1768.     }
  1769.     fd.ftCreationTime = pbbde->ft;
  1770.     fd.ftLastAccessTime = pbbde->ft;
  1771.     fd.ftLastWriteTime = pbbde->ft;
  1772.     fd.nFileSizeHigh = 0;
  1773.     fd.nFileSizeLow = pbbde->dwSize;
  1774.     fd.dwReserved0 = 0;
  1775.     fd.dwReserved1 = 0;
  1776.     lstrcpyn(fd.cFileName, PathFindFileName(szDeletedPath), ARRAYSIZE(fd.cFileName));  
  1777.     fd.cAlternateFileName[0] = TEXT(''); // no one uses this anyway...
  1778.     SHCreateFSIDList(szPath, &fd, &pidl);
  1779.     if (pidl)
  1780.     {
  1781.         UINT cbSize = ILGetSize(pidl);
  1782.         pidlRet = ILResize(pidl, cbSize + bbpidl.cb,0);
  1783.         if (pidlRet)
  1784.         {
  1785.             // Append this BBDATAENTRYID (A or W) onto the end
  1786.             memcpy(_ILSkip(pidlRet,cbSize - SIZEOF(pidl->mkid.cb)), lpv, bbpidl.cb);
  1787.             // And 0 terminate the thing
  1788.             _ILSkip(pidlRet, cbSize + bbpidl.cb - SIZEOF(pidl->mkid.cb))->mkid.cb = 0;
  1789.             // Now edit it into one larger id
  1790.             pidlRet->mkid.cb += bbpidl.cb;
  1791.             ASSERT(ILGetSize(pidlRet) == cbSize + bbpidl.cb);
  1792.         }
  1793.     }
  1794.     return pidlRet;
  1795. }
  1796. __inline int CALLBACK BBFDCompare(void *p1, void *p2, LPARAM lParam)
  1797. {
  1798.     return ((LPBBFINDDATA)p1)->iIndex - ((LPBBFINDDATA)p2)->iIndex;
  1799. }
  1800. __inline int CALLBACK BBFDIndexCompare(void *iIndex, void *p2, LPARAM lParam)
  1801. {
  1802.     return (int)((INT_PTR)iIndex - ((LPBBFINDDATA)p2)->iIndex);
  1803. }
  1804. BOOL CALLBACK BBEnumDPADestroyCallback(LPVOID pidl, LPVOID pData)
  1805. {
  1806.     ILFree(pidl);
  1807.     return TRUE;
  1808. }
  1809. LPITEMIDLIST BBEnum_GetNextPidl(LPENUMDELETED ped)
  1810. {
  1811.     LPITEMIDLIST pidlRet = FALSE;
  1812.     ASSERT(NULL != ped);
  1813.     if (NULL == ped->hdpa)
  1814.     {
  1815.         // This is the first Next() call - so snapshot the info files:
  1816.         if (NULL != (ped->hdpa = DPA_CreateEx(0, NULL)))
  1817.         {
  1818.             int iBitBucket;
  1819.             int nItem = 0;
  1820.             // loop through the bitbucket drives to find an info file
  1821.             for (iBitBucket = 0; iBitBucket < MAX_BITBUCKETS; iBitBucket++)
  1822.             {
  1823.                 if (MakeBitBucket(iBitBucket)) 
  1824.                 {
  1825.                     HANDLE hFile;
  1826.                     int cDeleted = 0;
  1827.                     // since we are going to start reading this bitbucket, we take the mrsw
  1828. #ifdef BB_USE_MRSW
  1829.                     MRSW_EnterRead(g_pBitBucket[iBitBucket]->pmrsw);
  1830. #endif // BB_USE_MRSW
  1831.                     hFile = OpenBBInfoFile(iBitBucket, OPENBBINFO_WRITE, 0);
  1832.                     if (INVALID_HANDLE_VALUE != hFile)
  1833.                     {
  1834.                         BBDATAENTRYW bbdew;
  1835.                         DWORD dwDataEntrySize = g_pBitBucket[iBitBucket]->fIsUnicode ? SIZEOF(BBDATAENTRYW) : SIZEOF(BBDATAENTRYA);
  1836.                         while (ReadNextDataEntry(hFile, &bbdew, FALSE, dwDataEntrySize, iBitBucket))
  1837.                         {
  1838.                             LPITEMIDLIST pidl = NULL;
  1839.                             if (IsDeletedEntry(&bbdew))
  1840.                             {
  1841.                                 cDeleted++;
  1842.                             }
  1843.                             else
  1844.                             {
  1845.                                 pidl = BBDataEntryToPidl(iBitBucket, &bbdew);
  1846.                             }
  1847.                             if (pidl)
  1848.                             {
  1849.                                 DPA_SetPtr(ped->hdpa, nItem++, pidl);
  1850.                             }
  1851.                         }
  1852.                         if (cDeleted > BB_DELETED_ENTRY_MAX)
  1853.                         {
  1854.                             BOOL bTrue = TRUE;
  1855.                             // set the registry key so that we will compact the info file after the next delete operation
  1856.                             RegSetValueEx(g_pBitBucket[iBitBucket]->hkeyPerUser, TEXT("NeedToCompact"), 0, REG_DWORD, (LPBYTE)&bTrue, SIZEOF(bTrue));
  1857.                         }
  1858.                         CloseBBInfoFile(hFile, iBitBucket);
  1859.                     }
  1860. #ifdef BB_USE_MRSW
  1861.                     MRSW_LeaveRead(g_pBitBucket[iBitBucket]->pmrsw);
  1862. #endif // BB_USE_MRSW
  1863.                 }
  1864.             }
  1865.         }
  1866.     }
  1867.     if (NULL != ped->hdpa)
  1868.     {
  1869.         pidlRet = DPA_GetPtr(ped->hdpa, ped->nItem);
  1870.         if (NULL != pidlRet)
  1871.         {
  1872.             // We're returning an allocated pidl, so replace the pointer
  1873.             // in the DPA with NULL so that we don't free it later:
  1874.             DPA_SetPtr(ped->hdpa, ped->nItem, NULL);
  1875.         }
  1876.         else
  1877.         {
  1878.             // We've reached the end, so destroy our snapshot:
  1879.             DPA_DestroyCallback(ped->hdpa, BBEnumDPADestroyCallback, NULL);
  1880.             ped->hdpa = NULL;
  1881.         }
  1882.         ped->nItem++;
  1883.     }
  1884.     return pidlRet;
  1885. }
  1886. //
  1887. // To be called back from within SHCreateEnumObjects
  1888. //
  1889. HRESULT CALLBACK CBitBucket_EnumCallBack(LPARAM lParam, void *pvData, UINT ecid, UINT index)
  1890. {
  1891.     HRESULT hres = NOERROR;
  1892.     ENUMDELETED * ped = (ENUMDELETED *)pvData;
  1893.     switch (ecid)
  1894.     {
  1895.         case ECID_SETNEXTID:
  1896.         {
  1897.             LPITEMIDLIST pidl;
  1898.             if (!(ped->grfFlags & SHCONTF_NONFOLDERS))
  1899.                 return S_FALSE; //  "no more element"
  1900.             pidl = BBEnum_GetNextPidl(ped);
  1901.             if (!pidl)
  1902.             {
  1903.                 hres = S_FALSE; //  "no more element"
  1904.             }
  1905.             else
  1906.             {
  1907.                 CDefEnum_SetReturn(lParam, pidl);
  1908.                 TraceMsg(TF_BITBUCKET, "Bitbucket: EnumCallBack,  returns %S", PIDLTODATAENTRYID(pidl)->bbde.szOriginal);
  1909.                 
  1910.                 //hres = NOERROR; // in success
  1911.             }
  1912.             break;
  1913.         }
  1914.         
  1915.         case ECID_RESET:
  1916.             if (NULL != ped->hdpa)
  1917.             {
  1918.                 DPA_DestroyCallback(ped->hdpa, BBEnumDPADestroyCallback, NULL);
  1919.                 ped->hdpa = NULL;
  1920.             }
  1921.             ped->nItem = 0;
  1922.             break;
  1923.         case ECID_RELEASE:
  1924.             if (NULL != ped->hdpa)
  1925.             {
  1926.                 DPA_DestroyCallback(ped->hdpa, BBEnumDPADestroyCallback, NULL);
  1927.             }
  1928.             LocalFree((HLOCAL)ped);
  1929.             break;
  1930.     }
  1931.     return hres;
  1932. }
  1933. STDMETHODIMP CBitBucket_SF_EnumObjects(IShellFolder2 *psf, HWND hwndOwner,
  1934.             DWORD grfFlags, LPENUMIDLIST * ppenumUnknown)
  1935. {
  1936.     CBitBucket *this = IToClass(CBitBucket, isf, psf);
  1937.     ENUMDELETED * ped = (void*)LocalAlloc(LPTR, SIZEOF(ENUMDELETED));
  1938.     if (ped) 
  1939.     {
  1940.         ped->grfFlags = grfFlags;
  1941.         ped->pbb = this;
  1942.         return SHCreateEnumObjects(hwndOwner, ped, CBitBucket_EnumCallBack, ppenumUnknown);
  1943.     }
  1944.     return E_OUTOFMEMORY;
  1945. }
  1946. STDMETHODIMP CBitBucket_BindToObject(IShellFolder2 *psf, LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppvOut)
  1947. {
  1948.     *ppvOut = NULL;
  1949.     return E_NOTIMPL;
  1950. }
  1951. STDMETHODIMP CBitBucket_BindToStorage(IShellFolder2 *psf, LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppvOut)
  1952. {
  1953.     *ppvOut = NULL;
  1954.     return E_NOTIMPL;
  1955. }
  1956. // get the path name of the file in the file system
  1957. void BBGetItemPath(LPCIDFOLDER pidf, LPTSTR pszPath)
  1958. {
  1959.     TCHAR szFile[MAX_PATH];
  1960.     LPBBDATAENTRYIDA pbbidl = PIDLTODATAENTRYID(pidf);
  1961.     DriveIDToBBPath(pbbidl->bbde.idDrive, pszPath);
  1962.     PathAppend(pszPath, FS_CopyName(pidf, szFile, ARRAYSIZE(szFile)));
  1963. }
  1964. // get the friendly looking name of this file
  1965. void BBGetDisplayName(LPCIDFOLDER pidf, LPTSTR pszName)
  1966. {
  1967.     TCHAR szTemp[MAX_PATH];
  1968.     LPBBDATAENTRYIDA pbbid = PIDLTODATAENTRYID(pidf);
  1969.     BBGetOriginalPath(pbbid, szTemp, ARRAYSIZE(szTemp));
  1970.     lstrcpy(pszName, PathFindFileName(szTemp));
  1971.     if (!FS_ShowExtension(pidf))
  1972.         PathRemoveExtension(pszName);
  1973. }
  1974. STDMETHODIMP CBitBucket_SF_GetDisplayNameOf(IShellFolder2 *psf, LPCITEMIDLIST pidl, DWORD uFlags, LPSTRRET pStrRet)
  1975. {
  1976.     LPCIDFOLDER pidf;
  1977.     pStrRet->uType = STRRET_CSTR;
  1978.     pStrRet->cStr[0] = 0;
  1979.     pidf = FS_IsValidID(pidl);
  1980.     if (pidf)
  1981.     {
  1982.         TCHAR szName[MAX_PATH];
  1983.         if (uFlags & SHGDN_FORPARSING)
  1984.             BBGetItemPath(pidf, szName);
  1985.         else
  1986.             BBGetDisplayName(pidf, szName);
  1987.         return StringToStrRet(szName, pStrRet);
  1988.     }
  1989.     return E_INVALIDARG;
  1990. }
  1991. STDMETHODIMP CBitBucket_SetNameOf(IShellFolder2 *psf, HWND hwnd,
  1992.         LPCITEMIDLIST pidl, LPCOLESTR lpszName, DWORD dwReserved, LPITEMIDLIST * ppidlOut)
  1993. {
  1994.     return E_FAIL;
  1995. }
  1996. STDMETHODIMP CBitBucket_EnumSearches(IShellFolder2 *psf, LPENUMEXTRASEARCH *ppenum)
  1997. {
  1998.     *ppenum = NULL;
  1999.     return E_NOTIMPL;
  2000. }
  2001. STDMETHODIMP CBitBucket_GetDefaultColumn(IShellFolder2 *psf, DWORD dwRes, ULONG *pSort, ULONG *pDisplay)
  2002. {
  2003.     return E_NOTIMPL;
  2004. }
  2005. STDMETHODIMP CBitBucket_GetDefaultColumnState(IShellFolder2 *psf, UINT iColumn, DWORD *pbState)
  2006. {
  2007.     return E_NOTIMPL;
  2008. }
  2009. STDMETHODIMP CBitBucket_GetDetailsEx(IShellFolder2 *psf, LPCITEMIDLIST pidl, const SHCOLUMNID *pscid, VARIANT *pv)
  2010. {
  2011.     CBitBucket *this = IToClass(CBitBucket, isf, psf);
  2012.     HRESULT hres = E_NOTIMPL;
  2013.     if (IsEqualSCID(*pscid, SCID_FINDDATA))
  2014.     {
  2015.         WIN32_FIND_DATAW wfd;
  2016.         hres = FindDataFromBBPidl(pidl, &wfd);
  2017.         if (SUCCEEDED(hres))
  2018.         {
  2019.             hres = InitVariantFromBuffer(pv, (PVOID)&wfd, sizeof(wfd));
  2020.         }
  2021.     }
  2022.     return hres;
  2023. }
  2024. STDMETHODIMP CBitBucket_GetDetailsOf(IShellFolder2 *psf, LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS *pDetails)
  2025. {
  2026.     CBitBucket *this = IToClass(CBitBucket, isf, psf);
  2027.     HRESULT hres = NOERROR;
  2028.     if (iColumn >= ARRAYSIZE(c_bb_cols))
  2029.         return E_NOTIMPL;
  2030.     pDetails->str.uType = STRRET_CSTR;
  2031.     pDetails->str.cStr[0] = 0;
  2032.     if (!pidl) 
  2033.     {
  2034.         // getting the headers
  2035.         hres = ResToStrRet(c_bb_cols[iColumn].ids, &pDetails->str);
  2036.         pDetails->fmt = c_bb_cols[iColumn].iFmt;
  2037.         pDetails->cxChar = c_bb_cols[iColumn].cchCol;
  2038.     } 
  2039.     else 
  2040.     {
  2041.         TCHAR  szTemp[MAX_PATH];
  2042.         LPCIDFOLDER pidf = FS_IsValidID(pidl);
  2043.         UNALIGNED BBDATAENTRYIDA * pbbidl = PIDLTODATAENTRYID(pidl);
  2044.         switch (iColumn) {
  2045.         case ICOL_NAME:
  2046.             BBGetDisplayName(pidf, szTemp);
  2047.             hres = StringToStrRet(szTemp, &pDetails->str);
  2048.             break;
  2049.         case ICOL_SIZE:
  2050.             {
  2051.                 ULONGLONG cbSize;
  2052.                 if (FS_IsFolder(pidf))
  2053.                     cbSize = pbbidl->bbde.dwSize;
  2054.                 else
  2055.                     FS_GetSize(NULL, pidf, &cbSize);
  2056.                 StrFormatKBSize(cbSize, szTemp, ARRAYSIZE(szTemp));
  2057.                 hres = StringToStrRet(szTemp, &pDetails->str);
  2058.             }
  2059.             break;
  2060.         case ICOL_ORIGINAL:
  2061.             BBGetOriginalPath(pbbidl, szTemp, ARRAYSIZE(szTemp));
  2062.             PathRemoveFileSpec(szTemp);
  2063.             hres = StringToStrRet(szTemp, &pDetails->str);
  2064.             break;
  2065.         case ICOL_TYPE:
  2066.             FS_GetTypeName(pidf, szTemp, ARRAYSIZE(szTemp));
  2067.             hres = StringToStrRet(szTemp, &pDetails->str);
  2068.             break;
  2069.         case ICOL_MODIFIED:
  2070.             {
  2071.             // need stack ft since pbbidl is UNALIGNED
  2072.             FILETIME ft = pbbidl->bbde.ft;
  2073.             DWORD dwFlags = FDTF_DEFAULT;
  2074.             switch (pDetails->fmt)
  2075.             {
  2076.                 case LVCFMT_LEFT_TO_RIGHT :
  2077.                     dwFlags |= FDTF_LTRDATE;
  2078.                 break;
  2079.                 case LVCFMT_RIGHT_TO_LEFT :
  2080.                     dwFlags |= FDTF_RTLDATE;
  2081.                 break;
  2082.             }
  2083.             SHFormatDateTime(&ft, &dwFlags, szTemp, ARRAYSIZE(szTemp));
  2084.             hres = StringToStrRet(szTemp, &pDetails->str);
  2085.             break;
  2086.             }
  2087.         }
  2088.     }
  2089.     return hres;
  2090. }
  2091. STDMETHODIMP CBitBucket_MapColumnToSCID(IShellFolder2 *psf, UINT iColumn, SHCOLUMNID *pscid)
  2092. {
  2093.     return MapColumnToSCIDImpl(c_bb_cols, ARRAYSIZE(c_bb_cols), iColumn, pscid);
  2094. }
  2095. IShellFolder2Vtbl c_CBitBucketSFVtbl =
  2096. {
  2097.     CBitBucket_SF_QueryInterface, CBitBucket_SF_AddRef, CBitBucket_SF_Release,
  2098.     CBitBucket_SF_ParseDisplayName,
  2099.     CBitBucket_SF_EnumObjects,
  2100.     CBitBucket_BindToObject,
  2101.     CBitBucket_BindToStorage,
  2102.     CBitBucket_SF_CompareIDs,
  2103.     CBitBucket_SF_CreateViewObject,
  2104.     CBitBucket_SF_GetAttributesOf,
  2105.     CBitBucket_GetUIObjectOf,
  2106.     CBitBucket_SF_GetDisplayNameOf,
  2107.     CBitBucket_SetNameOf,
  2108.     FindFileOrFolders_GetDefaultSearchGUID,
  2109.     CBitBucket_EnumSearches,
  2110.     CBitBucket_GetDefaultColumn,
  2111.     CBitBucket_GetDefaultColumnState,
  2112.     CBitBucket_GetDetailsEx,
  2113.     CBitBucket_GetDetailsOf,
  2114.     CBitBucket_MapColumnToSCID,
  2115. };
  2116. //========================================================================
  2117. // CBitBucket's PersistFile  members
  2118. //========================================================================
  2119. STDMETHODIMP CBitBucket_PF_QueryInterface(IPersistFolder2 *ppf, REFIID riid, void **ppvObj)
  2120. {
  2121.     CBitBucket *this = IToClass(CBitBucket, ipf, ppf);
  2122.     return CBitBucket_SF_QueryInterface(&this->isf, riid, ppvObj);
  2123. }
  2124. STDMETHODIMP_(ULONG) CBitBucket_PF_Release(IPersistFolder2 *ppf)
  2125. {
  2126.     CBitBucket *this = IToClass(CBitBucket, ipf, ppf);
  2127.     return CBitBucket_SF_Release(&this->isf);
  2128. }
  2129. STDMETHODIMP_(ULONG) CBitBucket_PF_AddRef(IPersistFolder2 *ppf)
  2130. {
  2131.     CBitBucket *this = IToClass(CBitBucket, ipf, ppf);
  2132.     return CBitBucket_SF_AddRef(&this->isf);
  2133. }
  2134. STDMETHODIMP CBitBucket_PF_GetClassID(IPersistFolder2 *ppf, LPCLSID lpClassID)
  2135. {
  2136.     *lpClassID = CLSID_RecycleBin;
  2137.     return NOERROR;
  2138. }
  2139. STDMETHODIMP CBitBucket_PF_Initialize(IPersistFolder2 *ppf, LPCITEMIDLIST pidl)
  2140. {
  2141.     CBitBucket *this = IToClass(CBitBucket, ipf, ppf);
  2142.     ASSERT(this->pidl == NULL);
  2143.     this->pidl = ILClone(pidl);
  2144.     return this->pidl ? S_OK : E_OUTOFMEMORY;
  2145. }
  2146. STDMETHODIMP CBitBucket_PF_GetCurFolder(IPersistFolder2 *ppf, LPITEMIDLIST *ppidl)
  2147. {
  2148.     CBitBucket *this = IToClass(CBitBucket, ipf, ppf);
  2149.     return GetCurFolderImpl(this->pidl, ppidl);
  2150. }
  2151. IPersistFolder2Vtbl c_CBitBucketPFVtbl =
  2152. {
  2153.     CBitBucket_PF_QueryInterface, CBitBucket_PF_AddRef, CBitBucket_PF_Release,
  2154.     CBitBucket_PF_GetClassID,
  2155.     CBitBucket_PF_Initialize,
  2156.     CBitBucket_PF_GetCurFolder
  2157. };
  2158. STDMETHODIMP CBitBucket_SEI_QueryInterface(IShellExtInit* psei, REFIID riid, void **ppvObj)
  2159. {
  2160.     CBitBucket *this = IToClass(CBitBucket, isei, psei);
  2161.     return CBitBucket_SF_QueryInterface(&this->isf, riid, ppvObj);
  2162. }
  2163. STDMETHODIMP_(ULONG) CBitBucket_SEI_Release(IShellExtInit* psei)
  2164. {
  2165.     CBitBucket *this = IToClass(CBitBucket, isei, psei);
  2166.     return CBitBucket_SF_Release(&this->isf);
  2167. }
  2168. STDMETHODIMP_(ULONG) CBitBucket_SEI_AddRef(IShellExtInit* psei)
  2169. {
  2170.     CBitBucket *this = IToClass(CBitBucket, isei, psei);
  2171.     return CBitBucket_SF_AddRef(&this->isf);
  2172. }
  2173. STDMETHODIMP_(ULONG) CBitBucket_SEI_Initialize(IShellExtInit* psei,
  2174.                                                     LPCITEMIDLIST pidlFolder,
  2175.                                                     IDataObject * pdtobj, HKEY hkeyProgID)
  2176. {
  2177.     return NOERROR;
  2178. }
  2179. STDMETHODIMP CBitBucket_CM_QueryInterface(IContextMenu* pcm, REFIID riid, void **ppvObj)
  2180. {
  2181.     CBitBucket *this = IToClass(CBitBucket, icm, pcm);
  2182.     return CBitBucket_SF_QueryInterface(&this->isf, riid, ppvObj);
  2183. }
  2184. STDMETHODIMP_(ULONG) CBitBucket_CM_Release(IContextMenu* pcm)
  2185. {
  2186.     CBitBucket *this = IToClass(CBitBucket, icm, pcm);
  2187.     return CBitBucket_SF_Release(&this->isf);
  2188. }
  2189. STDMETHODIMP_(ULONG) CBitBucket_CM_AddRef(IContextMenu* pcm)
  2190. {
  2191.     CBitBucket *this = IToClass(CBitBucket, icm, pcm);
  2192.     return CBitBucket_SF_AddRef(&this->isf);
  2193. }
  2194. STDMETHODIMP CBitBucket_QueryContextMenu(IContextMenu * pcm,
  2195.         HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast,
  2196.         UINT uFlags)
  2197. {
  2198.     int idMax = idCmdFirst;
  2199.     HMENU hmMerge = SHLoadPopupMenu(HINST_THISDLL, POPUP_BITBUCKET_POPUPMERGE);
  2200.     
  2201.     if (hmMerge)
  2202.     {
  2203.         idMax = Shell_MergeMenus(hmenu, hmMerge, indexMenu, idCmdFirst, idCmdLast, 0);
  2204.         
  2205.         if (IsRecycleBinEmpty())
  2206.         {
  2207.             EnableMenuItem(hmenu, idCmdFirst + FSIDM_PURGEALL, MF_GRAYED | MF_BYCOMMAND);
  2208.         }
  2209.         DestroyMenu(hmMerge);
  2210.     }
  2211.     return ResultFromShort(idMax - idCmdFirst);
  2212. }
  2213. STDMETHODIMP CBitBucket_InvokeCommand(IContextMenu* pcm,
  2214.                                            LPCMINVOKECOMMANDINFO pici)
  2215. {
  2216.     CBitBucket *this = IToClass(CBitBucket, icm, pcm);
  2217.     TraceMsg(TF_BITBUCKET, "Bitbucket: BitBucket_invokeCommand %d %d", pici->lpVerb, FSIDM_PURGEALL);
  2218.     switch ((ULONG_PTR)pici->lpVerb)
  2219.     {
  2220.     case FSIDM_PURGEALL:
  2221.         BBPurgeAll(this, pici->hwnd, 0);
  2222.         break;
  2223.     }
  2224.     return NOERROR;
  2225. }
  2226. STDMETHODIMP CBitBucket_GetCommandString(IContextMenu *pcm,
  2227.         UINT_PTR idCmd, UINT  wFlags, UINT * pwReserved, LPSTR pszName, UINT cchMax)
  2228. {
  2229.     TraceMsg(TF_BITBUCKET, "Bitbucket: GetCommandString, idCmd = %d", idCmd);
  2230.     switch(wFlags)
  2231.     {
  2232.         case GCS_VERBA:
  2233.         case GCS_VERBW:
  2234.             return GetVerb(idCmd, pszName, cchMax, wFlags == GCS_VERBW);
  2235.         case GCS_HELPTEXTA:
  2236.             return LoadStringA(HINST_THISDLL,
  2237.                               (UINT)(idCmd + IDS_MH_FSIDM_FIRST),
  2238.                               pszName, cchMax) ? NOERROR : E_OUTOFMEMORY;
  2239.         case GCS_HELPTEXTW:
  2240.             return LoadStringW(HINST_THISDLL,
  2241.                               (UINT)(idCmd + IDS_MH_FSIDM_FIRST),
  2242.                               (LPWSTR)pszName, cchMax) ? NOERROR : E_OUTOFMEMORY;
  2243.         default:
  2244.             return E_NOTIMPL;
  2245.     }
  2246. }
  2247. STDMETHODIMP CBitBucket_PS_QueryInterface(LPSHELLPROPSHEETEXT pps, REFIID riid,
  2248.                                         void **ppvObj)
  2249. {
  2250.     CBitBucket *this = IToClass(CBitBucket, ips, pps);
  2251.     return CBitBucket_SF_QueryInterface(&this->isf, riid, ppvObj);
  2252. }
  2253. STDMETHODIMP_(ULONG) CBitBucket_PS_Release(LPSHELLPROPSHEETEXT pps)
  2254. {
  2255.     CBitBucket *this = IToClass(CBitBucket, ips, pps);
  2256.     return CBitBucket_SF_Release(&this->isf);
  2257. }
  2258. STDMETHODIMP_(ULONG) CBitBucket_PS_AddRef(LPSHELLPROPSHEETEXT pps)
  2259. {
  2260.     CBitBucket *this = IToClass(CBitBucket, ips, pps);
  2261.     return CBitBucket_SF_AddRef(&this->isf);
  2262. }
  2263. //
  2264. //  Callback function that saves the location of the HPROPSHEETPAGE's
  2265. //  LPPROPSHEETPAGE so we can pass it to other propsheet pages.
  2266. //
  2267. UINT CALLBACK BBGlobalSettingsCalback(HWND hwnd, UINT uMsg, LPPROPSHEETPAGE ppsp)
  2268. {
  2269.     LPBBPROPSHEETINFO ppsiTemplate;
  2270.     LPBBPROPSHEETINFO ppsiGlobal;
  2271.     switch (uMsg)
  2272.     {
  2273.         case PSPCB_ADDREF:
  2274.             // we save off the address of the "real" ppsi in the pGlobal param of the
  2275.             // the template, so that the other drives can get to the global page information
  2276.             ppsiGlobal = (LPBBPROPSHEETINFO)ppsp;
  2277.             ppsiTemplate = (LPBBPROPSHEETINFO)ppsp->lParam;
  2278.             ppsiTemplate->pGlobal = ppsiGlobal;
  2279.             ppsiGlobal->pGlobal = ppsiGlobal;
  2280.             break;
  2281.         case PSPCB_CREATE:
  2282.             return TRUE;                    // Yes, please create me
  2283.     }
  2284.     return 0;
  2285. }
  2286. STDMETHODIMP CBitBucket_PS_AddPages(IShellPropSheetExt * pspx,
  2287.                                     LPFNADDPROPSHEETPAGE lpfnAddPage,
  2288.                                     LPARAM lParam)
  2289. {
  2290.     HPROPSHEETPAGE hpage;
  2291.     int idDrive;
  2292.     int iPage;
  2293.     BBPROPSHEETINFO bbpsp;
  2294.     TCHAR szTitle[MAX_PATH];
  2295.     DWORD dwSize1, dwSize2, dwSize3;
  2296.     
  2297.     // read in the global settings
  2298.     dwSize1 = SIZEOF(bbpsp.fUseGlobalSettings);
  2299.     dwSize2 = SIZEOF(bbpsp.iOriginalPercent);
  2300.     dwSize3 = SIZEOF(bbpsp.fOriginalNukeOnDelete);
  2301.     if (RegQueryValueEx(g_hkBitBucket, TEXT("UseGlobalSettings"), NULL, NULL, (LPBYTE)&bbpsp.fOriginalUseGlobalSettings, &dwSize1) != ERROR_SUCCESS ||
  2302.         RegQueryValueEx(g_hkBitBucket, TEXT("Percent"), NULL, NULL, (LPBYTE)&bbpsp.iOriginalPercent, &dwSize2) != ERROR_SUCCESS ||
  2303.         RegQueryValueEx(g_hkBitBucket, TEXT("NukeOnDelete"), NULL, NULL, (LPBYTE)&bbpsp.fOriginalNukeOnDelete, &dwSize3) != ERROR_SUCCESS)
  2304.     {
  2305.         ASSERTMSG(FALSE, "Bitbucket: could not read global settings from the registry, re-regsvr32 shell32.dll!!");
  2306.         bbpsp.fUseGlobalSettings = TRUE;
  2307.         bbpsp.iOriginalPercent = 10;
  2308.         bbpsp.fOriginalNukeOnDelete = FALSE;
  2309.     }
  2310.     bbpsp.fUseGlobalSettings = bbpsp.fOriginalUseGlobalSettings;
  2311.     bbpsp.fNukeOnDelete = bbpsp.fOriginalNukeOnDelete;
  2312.     bbpsp.iPercent = bbpsp.iOriginalPercent;
  2313.     bbpsp.psp.dwSize = SIZEOF(bbpsp);
  2314.     bbpsp.psp.dwFlags = PSP_DEFAULT | PSP_USECALLBACK;
  2315.     bbpsp.psp.hInstance = HINST_THISDLL;
  2316.     bbpsp.psp.pszTemplate = MAKEINTRESOURCE(DLG_BITBUCKET_GENCONFIG);
  2317.     bbpsp.psp.pfnDlgProc = BBGlobalPropDlgProc;
  2318.     bbpsp.psp.lParam = (LPARAM)&bbpsp;
  2319.     // the callback will fill the bbpsp.pGlobal with the pointer to the "real" psp after it has been copied
  2320.     // so that the other drive pages can get to the global information
  2321.     bbpsp.psp.pfnCallback = BBGlobalSettingsCalback;
  2322.     // add the "Global" settings page
  2323.     hpage = CreatePropertySheetPage(&bbpsp.psp);
  2324. #ifdef UNICODE
  2325.     // If this assertion fires, it means that comctl32 lost
  2326.     // backwards-compatibility with Win95 shell, WinNT4 shell,
  2327.     // and IE4 shell, all of which relied on this undocumented
  2328.     // behavior.
  2329.     ASSERT(bbpsp.pGlobal == (LPBBPROPSHEETINFO)((LPBYTE)hpage + 2 * sizeof(LPVOID)));
  2330. #else
  2331.     ASSERT(bbpsp.pGlobal == (LPBBPROPSHEETINFO)hpage);
  2332. #endif
  2333.     lpfnAddPage(hpage, lParam);
  2334.     // now create the pages for the individual drives
  2335.     bbpsp.psp.dwFlags = PSP_USETITLE;
  2336.     bbpsp.psp.pszTemplate = MAKEINTRESOURCE(DLG_BITBUCKET_CONFIG);
  2337.     bbpsp.psp.pfnDlgProc = BBDriveDlgProc;
  2338.     bbpsp.psp.pszTitle = szTitle;
  2339.     for (idDrive = 0, iPage = 1; (idDrive < MAX_BITBUCKETS) && (iPage < MAXPROPPAGES); idDrive++)
  2340.     {
  2341.         if (MakeBitBucket(idDrive))
  2342.         {
  2343.             dwSize1 = SIZEOF(bbpsp.iOriginalPercent);
  2344.             dwSize2 = SIZEOF(bbpsp.fOriginalNukeOnDelete);
  2345.             if (RegQueryValueEx(g_pBitBucket[idDrive]->hkey, TEXT("Percent"), NULL, NULL, (LPBYTE)&bbpsp.iOriginalPercent, &dwSize1) != ERROR_SUCCESS ||
  2346.                 RegQueryValueEx(g_pBitBucket[idDrive]->hkey, TEXT("NukeOnDelete"), NULL, NULL, (LPBYTE)&bbpsp.fOriginalNukeOnDelete, &dwSize2) != ERROR_SUCCESS)
  2347.             {
  2348.                 TraceMsg(TF_BITBUCKET, "Bitbucket: could not read settings from the registry for drive %d, using lame defaults", idDrive);
  2349.                 bbpsp.iOriginalPercent = 10;
  2350.                 bbpsp.fNukeOnDelete = FALSE;
  2351.             }
  2352.             bbpsp.iPercent = bbpsp.iOriginalPercent;
  2353.             bbpsp.fNukeOnDelete = bbpsp.fOriginalNukeOnDelete;
  2354.             bbpsp.idDrive = idDrive;
  2355.             BBGetDriveDisplayName(idDrive, szTitle, ARRAYSIZE(szTitle));
  2356.             hpage = CreatePropertySheetPage(&bbpsp.psp);
  2357.             lpfnAddPage(hpage, lParam);
  2358.         }
  2359.     }
  2360.     return NOERROR;
  2361. }
  2362. IContextMenuVtbl c_CBitBucketCMVtbl =
  2363. {
  2364.     CBitBucket_CM_QueryInterface,
  2365.     CBitBucket_CM_AddRef,
  2366.     CBitBucket_CM_Release,
  2367.     CBitBucket_QueryContextMenu,
  2368.     CBitBucket_InvokeCommand,
  2369.     CBitBucket_GetCommandString
  2370. };
  2371. IShellPropSheetExtVtbl c_CBitBucketPSVtbl =
  2372. {
  2373.     CBitBucket_PS_QueryInterface,
  2374.     CBitBucket_PS_AddRef,
  2375.     CBitBucket_PS_Release,
  2376.     CBitBucket_PS_AddPages,
  2377.     CCommonShellPropSheetExt_ReplacePage,
  2378. };
  2379. IShellExtInitVtbl c_CBitBucketSEIVtbl =
  2380. {
  2381.     CBitBucket_SEI_QueryInterface,
  2382.     CBitBucket_SEI_AddRef,
  2383.     CBitBucket_SEI_Release,
  2384.     CBitBucket_SEI_Initialize
  2385. };
  2386. HRESULT CBitBucket_CreateInstance(IUnknown* punkOuter, REFIID riid, void **ppvOut)
  2387. {
  2388.     HRESULT hres;
  2389.     CBitBucket *pbb = (void*)LocalAlloc(LPTR, SIZEOF(CBitBucket));
  2390.     if (pbb && InitBBGlobals())
  2391.     {
  2392.         pbb->isf.lpVtbl  = &c_CBitBucketSFVtbl;
  2393.         pbb->ipf.lpVtbl  = &c_CBitBucketPFVtbl;
  2394.         pbb->icm.lpVtbl  = &c_CBitBucketCMVtbl;
  2395.         pbb->isei.lpVtbl = &c_CBitBucketSEIVtbl;
  2396.         pbb->ips.lpVtbl  = &c_CBitBucketPSVtbl;
  2397.         pbb->cRef = 1;
  2398.         hres = CBitBucket_SF_QueryInterface(&pbb->isf, riid, ppvOut);
  2399.         CBitBucket_SF_Release(&pbb->isf);
  2400.     }
  2401.     else
  2402.     {
  2403.         *ppvOut = NULL;
  2404.         hres = E_OUTOFMEMORY;
  2405.     }
  2406.     return hres;
  2407. }
  2408. //
  2409. // takes a full path to a file in a bucket and creates a pidl for it.
  2410. //
  2411. LPITEMIDLIST DeletedFilePathToBBPidl(LPTSTR pszPath)
  2412. {
  2413.     BBDATAENTRYW bbdew;
  2414.     LPITEMIDLIST pidl = NULL;
  2415.     int idDrive = DriveIDFromBBPath(pszPath);
  2416.     int iIndex;
  2417.     DWORD dwDataEntrySize;
  2418.     HANDLE hFile;
  2419.     ASSERT(idDrive >= 0);       // general UNC case will generate -1
  2420.     iIndex = BBPathToIndex(pszPath);
  2421.     if (iIndex == -1)
  2422.         return NULL;
  2423.     dwDataEntrySize = g_pBitBucket[idDrive]->fIsUnicode ? SIZEOF(BBDATAENTRYW) : SIZEOF(BBDATAENTRYA);
  2424. #ifdef BB_USE_MRSW
  2425.     MRSW_EnterRead(g_pBitBucket[idDrive]->pmrsw);
  2426. #endif // BB_USE_MRSW
  2427.     
  2428.     hFile = OpenBBInfoFile(idDrive, OPENBBINFO_WRITE, 0);
  2429.     if (hFile != INVALID_HANDLE_VALUE)
  2430.     {
  2431.         // read records (skipping deleted)
  2432.         // until we find an index match
  2433.         while(ReadNextDataEntry(hFile, &bbdew, TRUE, dwDataEntrySize, idDrive))
  2434.         {
  2435.             if (bbdew.iIndex == iIndex)
  2436.             {
  2437.                 pidl = BBDataEntryToPidl(idDrive, &bbdew);
  2438.                 break;
  2439.             }
  2440.         }
  2441.         CloseBBInfoFile(hFile, idDrive);
  2442.     }
  2443.     
  2444. #ifdef BB_USE_MRSW
  2445.     MRSW_LeaveRead(g_pBitBucket[idDrive]->pmrsw);
  2446. #endif // BB_USE_MRSW
  2447.     return pidl;
  2448. }
  2449. BOOL_PTR CALLBACK NewDiskFullDlgProc(HWND hDlg, UINT wMsg, WPARAM wParam, LPARAM lParam)
  2450. {
  2451.     switch (wMsg) {
  2452.     case WM_INITDIALOG:
  2453.     {
  2454.         int idDrive = (int)lParam;
  2455.         TCHAR szNewText[MAX_PATH];
  2456.         TCHAR szText[MAX_PATH];
  2457.         GetDlgItemText(hDlg, IDD_TEXT, szText, ARRAYSIZE(szText));
  2458.         wsprintf(szNewText, szText, TEXT('A') + idDrive);
  2459.         SetDlgItemText(hDlg, IDD_TEXT, szNewText);
  2460.         break;
  2461.     }
  2462.     case WM_COMMAND:
  2463.         switch (GET_WM_COMMAND_ID(wParam, lParam)) {
  2464.         case IDC_DISKFULL_CLEANUP:
  2465.         case IDCANCEL:
  2466.             EndDialog(hDlg, GET_WM_COMMAND_ID(wParam, lParam));
  2467.             break;
  2468.         }
  2469.         break;
  2470.     default:
  2471.         return FALSE;
  2472.     }
  2473.     return TRUE;
  2474. }
  2475. void WINAPI HandleDiskFull(HWND hwnd, int idDrive)
  2476. {
  2477.     INT_PTR ret;
  2478.     if ((idDrive >= 0) && (idDrive < MAX_DRIVES))
  2479.     {
  2480.        if (IsBitBucketableDrive(idDrive)) 
  2481.        {
  2482.           ret = DialogBoxParam(HINST_THISDLL, MAKEINTRESOURCE(DLG_DISKFULL_NEW),
  2483.                             hwnd, NewDiskFullDlgProc, (LPARAM)idDrive);
  2484.           switch(ret)
  2485.           {
  2486.              case IDC_DISKFULL_CLEANUP:
  2487.                 LaunchDiskCleanup(hwnd, idDrive);
  2488.                 break;
  2489.              default:
  2490.                 break;
  2491.            }
  2492.        }
  2493.     }
  2494. }
  2495. STDAPI_(void) SHHandleDiskFull(HWND hwnd, int idDrive)
  2496. {
  2497.     // We will only do anything if noone has created the following named event 
  2498.     HANDLE hDisable = OpenEvent(EVENT_ALL_ACCESS, FALSE, TEXT("DisableLowDiskWarning"));
  2499.     if (!hDisable)
  2500.     {
  2501.         if (GetDiskCleanupPath(NULL, 0) && IsBitBucketableDrive(idDrive))
  2502.         {
  2503.             HandleDiskFull(hwnd, idDrive);
  2504.         }
  2505.     }
  2506.     else
  2507.     {
  2508.        CloseHandle(hDisable);
  2509.     }
  2510. }