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

Windows Kernel

Development Platform:

Visual C++

  1. //---------------------------------------------------------------------------
  2. //
  3. // Copyright (c) Microsoft Corporation 1993-1994
  4. //
  5. // File: status.c
  6. //
  7. //  This file contains the dialog code for the Status property sheet
  8. //
  9. // History:
  10. //  08-06-93 ScottH     Transferred from twin code
  11. //
  12. //---------------------------------------------------------------------------
  13. #include "brfprv.h"         // common headers
  14. #include <brfcasep.h>
  15. #include "res.h"
  16. #include "recact.h"
  17. #ifdef WINNT
  18. #include <help.h>
  19. #else
  20. #include "......wincoreinchelp.h"   // help IDs
  21. #endif
  22. typedef struct tagSTAT
  23.     {
  24.     HWND        hwnd;              // dialog handle
  25.     PPAGEDATA   ppagedata;
  26.     FileInfo *  pfi;
  27.     TCHAR        szFolder[MAX_PATH];
  28.     BOOL        bInit;
  29.     } STAT, * PSTAT;
  30. #define Stat_Pcbs(this)         ((this)->ppagedata->pcbs)
  31. #define Stat_AtomBrf(this)      ((this)->ppagedata->pcbs->atomBrf)
  32. #define Stat_GetPtr(hwnd)       (PSTAT)GetWindowLongPtr(hwnd, DWLP_USER)
  33. #define Stat_SetPtr(hwnd, lp)   (PSTAT)SetWindowLongPtr(hwnd, DWLP_USER, (LRESULT)(lp))
  34. #define LNKM_ACTIVATEOTHER      (WM_USER + 0)
  35. /*----------------------------------------------------------
  36. Purpose: Disable all the controls in the property page
  37. Returns: --
  38. Cond:    --
  39. */
  40. void PRIVATE Stat_DisableAll(
  41.     PSTAT this)
  42.     {
  43.     HWND hwnd = this->hwnd;
  44.     HWND hwndFocus = GetFocus();
  45.     RecAct_DeleteAllItems(GetDlgItem(hwnd, IDC_UPDATEACTIONS));
  46.     RecAct_Enable(GetDlgItem(hwnd, IDC_UPDATEACTIONS), FALSE);
  47.         
  48.     Button_Enable(GetDlgItem(hwnd, IDC_PBTSRECON), FALSE);
  49.     Button_Enable(GetDlgItem(hwnd, IDC_PBTSFIND), FALSE);
  50.     Button_Enable(GetDlgItem(hwnd, IDC_PBTSSPLIT), FALSE);
  51.     if ( !hwndFocus || !IsWindowEnabled(hwndFocus) )
  52.         {
  53.         SetFocus(GetDlgItem(GetParent(hwnd), IDOK));
  54.         SendMessage(GetParent(hwnd), DM_SETDEFID, IDOK, 0);
  55.         }
  56.     }
  57. /*----------------------------------------------------------
  58. Purpose: Set the directions static text
  59. Returns: --
  60. Cond:    --
  61. */
  62. void PRIVATE Stat_SetDirections(
  63.     PSTAT this)
  64.     {
  65.     HWND hwnd = this->hwnd;
  66.     HWND hwndRA = GetDlgItem(this->hwnd, IDC_UPDATEACTIONS);
  67.     RA_ITEM item;
  68.     TCHAR sz[MAXBUFLEN];
  69.     *sz = 0;
  70.     // This function shouldn't be called if this is an orphan
  71.     ASSERT(S_OK == PageData_Query(this->ppagedata, hwnd, NULL, NULL));
  72.     item.mask = RAIF_INSIDE | RAIF_OUTSIDE | RAIF_ACTION;
  73.     item.iItem = 0;
  74.     ASSERT(RecAct_GetItemCount(hwndRA) == 1);
  75.     if (RecAct_GetItem(hwndRA, &item))
  76.         {
  77.         UINT ids;
  78.         ASSERT(IsFlagSet(item.mask, RAIF_INSIDE | RAIF_OUTSIDE));
  79.         switch (item.uAction)
  80.             {
  81.         case RAIA_TOIN:
  82.         case RAIA_TOOUT:
  83.         case RAIA_DELETEOUT:
  84.         case RAIA_DELETEIN:
  85.         case RAIA_MERGE:
  86.         case RAIA_SOMETHING:
  87.             // Instructions to update
  88.             if (this->ppagedata->bFolder)
  89.                 ids = IDS_STATPROP_PressButton;
  90.             else
  91.                 ids = IDS_STATPROP_Update;
  92.             break;
  93.         case RAIA_CONFLICT:
  94.             ids = IDS_STATPROP_Conflict;
  95.             break;
  96.         default:
  97.             if (SI_UNAVAILABLE == item.siOutside.uState)
  98.                 {
  99.                 // The original file is unavailable.  We don't know if 
  100.                 // everything is up-to-date.
  101.                 ids = IDS_STATPROP_Unavailable;
  102.                 }
  103.             else
  104.                 {
  105.                 // They are up-to-date
  106.                 ids = IDS_STATPROP_Uptodate;
  107.                 }
  108.             break;
  109.             }
  110.         SzFromIDS(ids, sz, ARRAYSIZE(sz));
  111.         }
  112.     Static_SetText(GetDlgItem(hwnd, IDC_STTSDIRECT), sz);
  113.     }
  114. /*----------------------------------------------------------
  115. Purpose: Sets the reconciliation action control
  116. Returns: standard result
  117.          S_OK if the item is still a twin
  118.          S_FALSE if the item is an orphan
  119. Cond:    --
  120. */
  121. HRESULT PRIVATE Stat_SetRecAct(
  122.     PSTAT this,
  123.     PRECLIST prl,
  124.     PFOLDERTWINLIST pftl)
  125.     {
  126.     HRESULT hres;
  127.     HWND hwnd = this->hwnd;
  128.     HWND hwndRA = GetDlgItem(hwnd, IDC_UPDATEACTIONS);
  129.     LPCTSTR pszPath = Atom_GetName(this->ppagedata->atomPath);
  130.     RA_ITEM * pitem;
  131.     // This function shouldn't be called if this is an orphan
  132.     ASSERT(S_OK == PageData_Query(this->ppagedata, hwnd, NULL, NULL));
  133.     hres = RAI_Create(&pitem, Atom_GetName(Stat_AtomBrf(this)), pszPath, 
  134.         prl, pftl);
  135.     if (SUCCEEDED(hres))
  136.         {
  137.         if (RAIA_ORPHAN == pitem->uAction)
  138.             {
  139.             // This is a pending orphan
  140.             PageData_Orphanize(this->ppagedata);
  141.             hres = S_FALSE;
  142.             }
  143.         else if ( !this->ppagedata->bFolder )
  144.             {
  145.             pitem->mask |= RAIF_LPARAM;
  146.             pitem->lParam = (LPARAM)prl->priFirst;
  147.             }
  148.         if (S_OK == hres)
  149.             {
  150.             BOOL bEnable;
  151.             HWND hwndFocus = GetFocus();
  152.             // Add the item to the recact control.
  153.             RecAct_InsertItem(hwndRA, pitem);
  154.             // Determine the state of the buttons
  155.             bEnable = !(pitem->uAction == RAIA_SKIP ||
  156.                         pitem->uAction == RAIA_CONFLICT || 
  157.                         pitem->uAction == RAIA_NOTHING);
  158.             Button_Enable(GetDlgItem(hwnd, IDC_PBTSRECON), bEnable);
  159.             bEnable = (SI_UNAVAILABLE != pitem->siOutside.uState);
  160.             Button_Enable(GetDlgItem(hwnd, IDC_PBTSFIND), bEnable);
  161.             if ( !hwndFocus || !IsWindowEnabled(hwndFocus) )
  162.                 {
  163.                 SetFocus(GetDlgItem(hwnd, IDC_PBTSSPLIT));
  164.                 SendMessage(hwnd, DM_SETDEFID, IDC_PBTSSPLIT, 0);
  165.                 }
  166.             }
  167.         RAI_Free(pitem);
  168.         }
  169.     return hres;
  170.     }
  171. /*----------------------------------------------------------
  172. Purpose: Sets the controls in the status property page.
  173. Returns: --
  174. Cond:    --
  175. */
  176. void PRIVATE Stat_SetControls(
  177.     PSTAT this)
  178.     {
  179.     HWND hwnd = this->hwnd;
  180.     HRESULT hres;
  181.     PRECLIST prl;
  182.     PFOLDERTWINLIST pftl;
  183.     // Is this a twin?
  184.     hres = PageData_Query(this->ppagedata, hwnd, &prl, &pftl);
  185.     if (S_OK == hres)
  186.         {
  187.         // Yes
  188.         RecAct_DeleteAllItems(GetDlgItem(hwnd, IDC_UPDATEACTIONS));
  189.         // Is it still a twin?
  190.         hres = Stat_SetRecAct(this, prl, pftl);
  191.         if (S_OK == hres)
  192.             {
  193.             // Yes
  194.             Stat_SetDirections(this);
  195.             }
  196.         else if (S_FALSE == hres)
  197.             {
  198.             // No
  199.             goto WipeOut;
  200.             }
  201.         }
  202.     else if (S_FALSE == hres)
  203.         {
  204.         // No; disable the controls
  205.         TCHAR sz[MAXBUFLEN];
  206. WipeOut:
  207.         Stat_DisableAll(this);
  208.         // Is this a subfolder twin?
  209.         if (IsSubfolderTwin(PageData_GetHbrf(this->ppagedata), 
  210.             Atom_GetName(this->ppagedata->atomPath)))
  211.             {
  212.             // Yes; use subfolder twin message.
  213.             SzFromIDS(IDS_STATPROP_SubfolderTwin, sz, ARRAYSIZE(sz));
  214.             }
  215.         else
  216.             {
  217.             // No; use orphan message.
  218.             if (this->ppagedata->bFolder)
  219.                 SzFromIDS(IDS_STATPROP_OrphanFolder, sz, ARRAYSIZE(sz));
  220.             else
  221.                 SzFromIDS(IDS_STATPROP_OrphanFile, sz, ARRAYSIZE(sz));
  222.             }
  223.         Static_SetText(GetDlgItem(hwnd, IDC_STTSDIRECT), sz);
  224.         }
  225.     }
  226. /*----------------------------------------------------------
  227. Purpose: Gets the icon of the file
  228. Returns: HICON
  229. Cond:    --
  230. */
  231. HICON PRIVATE GetIconHelper(
  232.     LPCTSTR pszPath)
  233.     {
  234.     SHFILEINFO sfi;
  235.     if (SHGetFileInfo(pszPath, 0, &sfi, sizeof(sfi), SHGFI_ICON))
  236.         {
  237.         return sfi.hIcon;
  238.         }
  239.     return NULL;
  240.     }
  241. /*----------------------------------------------------------
  242. Purpose: Stat WM_INITDIALOG Handler
  243. Returns: FALSE when we assign the control focus
  244. Cond:    --
  245. */
  246. BOOL PRIVATE Stat_OnInitDialog(
  247.     PSTAT this,
  248.     HWND hwndFocus,
  249.     LPARAM lParam)              // expected to be LPPROPSHEETPAGE
  250.     {
  251.     HWND hwnd = this->hwnd;
  252.     LPCTSTR pszPath;
  253.     this->ppagedata = (PPAGEDATA)((LPPROPSHEETPAGE)lParam)->lParam;
  254.     // Set up the display of the dialog
  255.     pszPath = Atom_GetName(this->ppagedata->atomPath);
  256.     if (SUCCEEDED(FICreate(pszPath, &this->pfi, FIF_ICON)))
  257.         {
  258.         Static_SetIcon(GetDlgItem(hwnd, IDC_ICTSMAIN), this->pfi->hicon);
  259.         Static_SetText(GetDlgItem(hwnd, IDC_NAME), FIGetDisplayName(this->pfi));
  260.         }
  261.     // Save the folder of the twin away.
  262.     lstrcpy(this->szFolder, pszPath);
  263.     if (!this->ppagedata->bFolder)
  264.         PathRemoveFileSpec(this->szFolder);
  265.     this->bInit = TRUE;
  266.     return FALSE;   // we set the initial focus
  267.     }
  268. /*----------------------------------------------------------
  269. Purpose: PSN_SETACTIVE handler
  270. Returns: --
  271. Cond:    --
  272. */
  273. void PRIVATE Stat_OnSetActive(
  274.     PSTAT this)
  275.     {
  276.     HWND hwnd = this->hwnd;
  277.     // Cause the page to be painted right away 
  278.     HideCaret(NULL);
  279.     SetWindowRedraw(hwnd, TRUE);
  280.     InvalidateRect(hwnd, NULL, TRUE);
  281.     UpdateWindow(hwnd);
  282.     if (this->bInit)
  283.         {
  284.         PageData_Init(this->ppagedata, GetParent(this->hwnd));
  285.         this->bInit = FALSE;
  286.         }
  287.     ShowCaret(NULL);
  288.     Stat_SetControls(this);
  289.     }
  290. /*----------------------------------------------------------
  291. Purpose: Reconcile the twins in this property sheet.  
  292.           For folder twins, we invoke the Update dialog.  
  293.           For object twins, we reconcile from here.
  294. Returns: --
  295. Cond:    --
  296. */
  297. void PRIVATE Stat_OnUpdate(
  298.     PSTAT this,
  299.     PRECLIST prl)
  300.     {
  301.     HWND hwnd = this->hwnd;
  302.     HWND hwndRA = GetDlgItem(hwnd, IDC_UPDATEACTIONS);
  303.     LPCTSTR pszPath = Atom_GetName(this->ppagedata->atomPath);
  304.     if (0 == RecAct_GetItemCount(hwndRA))
  305.         return;
  306.     ASSERT(S_OK == PageData_Query(this->ppagedata, hwnd, NULL, NULL));
  307.     // Is this a folder?
  308.     if (this->ppagedata->bFolder)
  309.         {
  310.         // Yes; let the Update dialog do the work
  311.         Upd_DoModal(hwnd, Stat_Pcbs(this), pszPath, 1, UF_SELECTION);
  312.         }
  313.     else
  314.         {
  315.         // No; we do the work.  
  316.         HWND hwndProgress;
  317.         hwndProgress = UpdBar_Show(hwnd, UB_UPDATING, 0);
  318.             
  319.         Sync_ReconcileRecList(prl, Atom_GetName(Stat_AtomBrf(this)), 
  320.             hwndProgress, RF_DEFAULT);
  321.         UpdBar_Kill(hwndProgress);
  322.         }
  323.     this->ppagedata->bRecalc = TRUE;
  324.     PropSheet_CancelToClose(GetParent(hwnd));
  325.     }
  326. /*----------------------------------------------------------
  327. Purpose: Separate the twins.  
  328. Returns: --
  329. Cond:    --
  330. */
  331. void PRIVATE Stat_OnSplit(
  332.     PSTAT this)
  333.     {
  334.     HWND hwnd = this->hwnd;
  335.     HWND hwndRA = GetDlgItem(hwnd, IDC_UPDATEACTIONS);
  336.     LPCTSTR pszPath = Atom_GetName(this->ppagedata->atomPath);
  337.     if (0 == RecAct_GetItemCount(hwndRA))
  338.         return;
  339.     ASSERT(S_OK == PageData_Query(this->ppagedata, hwnd, NULL, NULL));
  340.     // Was the twin successfully deleted?
  341.     if (S_OK == Sync_Split(PageData_GetHbrf(this->ppagedata), pszPath, 1, hwnd, 0))
  342.         {
  343.         // Yes; remove the cache references
  344.         CRL_Nuke(this->ppagedata->atomPath);
  345.         Stat_DisableAll(this);
  346.         PropSheet_CancelToClose(GetParent(hwnd));
  347.         // Notify the shell of the change
  348.         PathNotifyShell(pszPath, NSE_UPDATEITEM, FALSE);
  349.         }
  350.     }
  351. /*----------------------------------------------------------
  352. Purpose: Attempt to bind to an object to see if it exists.
  353. Returns: TRUE if the object exists
  354. Cond:    --
  355. */
  356. BOOL PRIVATE VerifyExists(
  357.     LPCITEMIDLIST pidlParent,
  358.     LPCITEMIDLIST pidl)
  359.     {
  360.     BOOL bRet = FALSE;
  361.     LPSHELLFOLDER psfDesktop;
  362.     ASSERT(pidlParent);
  363.     ASSERT(pidl);
  364.     psfDesktop = GetDesktopShellFolder();
  365.     if (psfDesktop)
  366.         {
  367.         LPSHELLFOLDER psf;
  368.         HRESULT hres;
  369.         hres = psfDesktop->lpVtbl->BindToObject(psfDesktop, pidlParent, NULL, &IID_IShellFolder, &psf);
  370.         if (SUCCEEDED(hres))
  371.             {
  372.             ULONG rgfAttr = SFGAO_VALIDATE;
  373.             bRet = SUCCEEDED(psf->lpVtbl->GetAttributesOf(psf, 1, &pidl, &rgfAttr));
  374.             psf->lpVtbl->Release(psf);
  375.             }
  376.         }
  377.     return bRet;
  378.     }
  379. /*----------------------------------------------------------
  380. Purpose: Open a file (taken from ShellExecFile)
  381. Returns: value of ShellExecuteEx
  382. Cond:    --
  383. */
  384. BOOL PUBLIC ExecFile(
  385.     HWND hwnd, 
  386.     LPCTSTR pszVerb, 
  387.     LPCTSTR pszFile,        // Fully qualified and fully resolved path to the file
  388.     LPCTSTR pszParams,
  389.     LPCTSTR pszDir,         // If NULL then working dir is derived from lpszFile (except for UNC's)
  390.     LPCITEMIDLIST pidl,
  391.     int nShow)
  392.     {
  393.     SHELLEXECUTEINFO execinfo;
  394.     execinfo.cbSize          = sizeof(execinfo);
  395.     execinfo.hwnd            = hwnd;
  396.     execinfo.lpVerb          = pszVerb;
  397.     execinfo.lpFile          = pszFile;
  398.     execinfo.lpParameters    = pszParams;
  399.     execinfo.lpDirectory     = pszDir;
  400.     execinfo.nShow           = nShow;
  401.     execinfo.fMask           = 0;
  402.     execinfo.lpIDList        = (LPITEMIDLIST)pidl;
  403.     if (pidl)
  404.         {
  405.         execinfo.fMask |= SEE_MASK_IDLIST;
  406.         }
  407.     return ShellExecuteEx(&execinfo);
  408.     }
  409. /*----------------------------------------------------------
  410. Purpose: Selects an item in the given cabinet window.  Optionally
  411.          sets it to be renamed.
  412.          This function does not verify if the window is really
  413.          a cabinet window.
  414. Returns: --
  415. Cond:    --
  416. */
  417. void PUBLIC SelectItemInCabinet(
  418.     HWND hwndCabinet,
  419.     LPCITEMIDLIST pidl,
  420.     BOOL bEdit)
  421.     {
  422.     if (IsWindow(hwndCabinet)) 
  423.         {
  424.         if (pidl)
  425.             {
  426.             LPITEMIDLIST pidlItem;
  427.             // we need to global clone this because hwndCabinet might be
  428.             // in a different process...  could happen with common dialog
  429.             pidlItem = ILGlobalClone(pidl);
  430.             if (pidlItem) 
  431.                 {
  432.                 UINT uFlagsEx;
  433.                 if (bEdit)
  434.                     uFlagsEx = SVSI_EDIT;
  435.                 else
  436.                     uFlagsEx = 0;
  437.                 SendMessage(hwndCabinet, CWM_SELECTITEM, 
  438.                     uFlagsEx | SVSI_SELECT | SVSI_ENSUREVISIBLE | 
  439.                     SVSI_FOCUSED | SVSI_DESELECTOTHERS, 
  440.                     (LPARAM)pidlItem);
  441.                 ILGlobalFree(pidlItem);
  442.                 }
  443.             }
  444.         }
  445.     }
  446. /*----------------------------------------------------------
  447. Purpose: Open a cabinet window and set the focus on the object.
  448. Returns: --
  449. Cond:    --
  450. */
  451. void PUBLIC OpenCabinet(
  452.     HWND hwnd,
  453.     LPCITEMIDLIST pidlFolder,
  454.     LPCITEMIDLIST pidl,
  455.     BOOL bEdit)             // TRUE: set the focus to edit the label
  456.     {
  457.     if (!VerifyExists(pidlFolder, pidl))
  458.         {
  459.         MsgBox(hwnd, MAKEINTRESOURCE(IDS_MSG_CantFindOriginal), MAKEINTRESOURCE(IDS_CAP_STATUS),
  460.                NULL, MB_INFO);
  461.         }
  462.     else
  463.         {
  464.         HWND hwndCabinet;
  465.         SHWaitForFileToOpen(pidlFolder, WFFO_ADD, 0L);
  466.         if (ExecFile(hwnd, c_szOpen, NULL, NULL, NULL, pidlFolder, SW_NORMAL))
  467.             {
  468.             // This will wait for the window to open or time out
  469.             // We need to disable the dialog box while we are waiting.
  470.             DECLAREHOURGLASS;
  471.             SetHourglass();
  472.             EnableWindow(hwnd, FALSE);
  473.             SHWaitForFileToOpen(pidlFolder, WFFO_REMOVE | WFFO_WAIT, WFFO_WAITTIME);
  474.             EnableWindow(hwnd, TRUE);
  475.             ResetHourglass();
  476.             hwndCabinet = FindWindow(c_szCabinetClass, NULL);
  477.             }
  478.         else
  479.             {
  480.             // If it failed clear out our wait
  481.             hwndCabinet = NULL;
  482.             SHWaitForFileToOpen(pidlFolder, WFFO_REMOVE, 0L);
  483.             }
  484.         if (hwndCabinet)
  485.             {
  486.             SelectItemInCabinet(hwndCabinet, pidl, bEdit);
  487.             // we need to post to the other because we can't activate another
  488.             // thread from within a button's callback
  489.             PostMessage(hwnd, LNKM_ACTIVATEOTHER, 0, (LPARAM)hwndCabinet);
  490.             }
  491.         }
  492.     }
  493. /*----------------------------------------------------------
  494. Purpose: Opens the cabinet with the item pointed to by the twin.
  495.          (copied and modified from link.c in shelldll)
  496. Returns: --
  497. Cond:    --
  498. */
  499. void PRIVATE Stat_OnFind(
  500.     PSTAT this)
  501.     {
  502.     HWND hwnd = this->hwnd;
  503.     HWND hwndRA = GetDlgItem(hwnd, IDC_UPDATEACTIONS);
  504.     RA_ITEM item;
  505.     if (0 == RecAct_GetItemCount(hwndRA))
  506.         return;
  507.     ASSERT(S_OK == PageData_Query(this->ppagedata, hwnd, NULL, NULL));
  508.     item.mask = RAIF_OUTSIDE | RAIF_NAME;
  509.     item.iItem = 0;
  510.     if (RecAct_GetItem(hwndRA, &item))
  511.         {
  512.         TCHAR szCanon[MAX_PATH];
  513.         LPITEMIDLIST pidlFolder;
  514.         LPITEMIDLIST pidl;
  515.         // Use UNC name to find it on the net
  516.         BrfPathCanonicalize(item.siOutside.pszDir, szCanon);
  517.         pidlFolder = ILCreateFromPath(szCanon);
  518.         if (pidlFolder)
  519.             {
  520.             pidl = ILCreateFromPath(item.pszName);
  521.             if (pidl)
  522.                 {
  523.                 OpenCabinet(hwnd, pidlFolder, ILFindLastID(pidl), FALSE);
  524.                 ILFree(pidl);
  525.                 }
  526.             ILFree(pidlFolder);
  527.             }
  528.         }
  529.     }
  530. /*----------------------------------------------------------
  531. Purpose: Stat WM_COMMAND Handler
  532. Returns: --
  533. Cond:    --
  534. */
  535. void PRIVATE Stat_OnCommand(
  536.     PSTAT this,
  537.     int id,
  538.     HWND hwndCtl,
  539.     UINT uNotifyCode)
  540.     {
  541.     PRECLIST prl;
  542.     HRESULT hres;
  543.     switch (id)
  544.         {
  545.     case IDC_PBTSRECON:
  546.     case IDC_PBTSFIND:
  547.     case IDC_PBTSSPLIT: 
  548.         RETRY_BEGIN(FALSE)
  549.             {
  550.             hres = PageData_Query(this->ppagedata, this->hwnd, &prl, NULL);
  551.             if (FAILED(hres))
  552.                 {
  553.                 // Error
  554.                 // Unavailable disk?
  555.                 if (E_TR_UNAVAILABLE_VOLUME == hres)
  556.                     {
  557.                     // Yes; ask user to retry/cancel
  558.                     int id = MsgBox(this->hwnd, MAKEINTRESOURCE(IDS_ERR_UNAVAIL_VOL),
  559.                         MAKEINTRESOURCE(IDS_CAP_STATUS), NULL, MB_RETRYCANCEL | MB_ICONWARNING);
  560.                     if (IDRETRY == id)
  561.                         RETRY_SET();    // Try again
  562.                     }
  563.                 }
  564.             }
  565.         RETRY_END()
  566.         
  567.         // Is this a twin?
  568.         if (S_OK == hres)
  569.             {
  570.             // Yes; do the operation
  571.             switch (id)
  572.                 {
  573.             case IDC_PBTSRECON:
  574.                 Stat_OnUpdate(this, prl);
  575.                 break;
  576.             
  577.             case IDC_PBTSFIND:
  578.                 Stat_OnFind(this);
  579.                 break;
  580.             
  581.             case IDC_PBTSSPLIT:
  582.                 Stat_OnSplit(this);
  583.                 break;
  584.                 }
  585.             Stat_SetControls(this);
  586.             }
  587.         else if (S_FALSE == hres)
  588.             {
  589.             Stat_SetControls(this);
  590.             }
  591.         break;
  592.         }
  593.     }
  594. /*----------------------------------------------------------
  595. Purpose: Handle RN_ITEMCHANGED
  596. Returns: --
  597. Cond:    --
  598. */
  599. void PRIVATE Stat_HandleItemChange(
  600.     PSTAT this,
  601.     NM_RECACT  * lpnm)
  602.     {
  603.     PRECITEM pri;
  604.     ASSERT((lpnm->mask & RAIF_LPARAM) != 0);
  605.     pri = (PRECITEM)lpnm->lParam;
  606.     // The action has changed, update the recnode accordingly
  607.     //
  608.     if (lpnm->mask & RAIF_ACTION)
  609.         {
  610.         BOOL bEnable;
  611.         HWND hwndFocus = GetFocus();
  612.         Sync_ChangeRecItemAction(pri, Atom_GetName(Stat_AtomBrf(this)), 
  613.             this->szFolder, lpnm->uAction);
  614.         bEnable = (RAIA_SKIP != lpnm->uAction && RAIA_CONFLICT != lpnm->uAction);
  615.         Button_Enable(GetDlgItem(this->hwnd, IDC_PBTSRECON), bEnable);
  616.         if ( !hwndFocus || !IsWindowEnabled(hwndFocus) )
  617.             {
  618.             SetFocus(GetDlgItem(this->hwnd, IDC_PBTSSPLIT));
  619.             SendMessage(this->hwnd, DM_SETDEFID, IDC_PBTSSPLIT, 0);
  620.             }
  621.         }
  622.     }    
  623. /*----------------------------------------------------------
  624. Purpose: WM_NOTIFY handler
  625. Returns: varies
  626. Cond:    --
  627. */
  628. LRESULT PRIVATE Stat_OnNotify(
  629.     PSTAT this,
  630.     int idFrom,
  631.     NMHDR  * lpnmhdr)
  632.     {
  633.     LRESULT lRet = PSNRET_NOERROR;
  634.     
  635.     switch (lpnmhdr->code)
  636.         {
  637.     case RN_ITEMCHANGED:
  638.         Stat_HandleItemChange(this, (NM_RECACT  *)lpnmhdr);
  639.         break;
  640.     case PSN_SETACTIVE:
  641.         Stat_OnSetActive(this);
  642.         break;
  643.     case PSN_KILLACTIVE:
  644.         // N.b. This message is not sent if user clicks Cancel!
  645.         // N.b. This message is sent prior to PSN_APPLY
  646.         //
  647.         break;
  648.     case PSN_APPLY:
  649.         break;
  650.     default:
  651.         break;
  652.         }
  653.     return lRet;
  654.     }
  655. /*----------------------------------------------------------
  656. Purpose: WM_DESTROY handler
  657. Returns: --
  658. Cond:    --
  659. */
  660. void PRIVATE Stat_OnDestroy(
  661.     PSTAT this)
  662.     {
  663.     FIFree(this->pfi);
  664.     }
  665. /////////////////////////////////////////////////////  EXPORTED FUNCTIONS
  666. static BOOL s_bStatRecurse = FALSE;
  667. LRESULT INLINE Stat_DefProc(
  668.     HWND hDlg, 
  669.     UINT msg,
  670.     WPARAM wParam,
  671.     LPARAM lParam) 
  672.     {
  673.     ENTEREXCLUSIVE()
  674.         {
  675.         s_bStatRecurse = TRUE;
  676.         }
  677.     LEAVEEXCLUSIVE()
  678.     return DefDlgProc(hDlg, msg, wParam, lParam); 
  679.     }
  680. /*----------------------------------------------------------
  681. Purpose: Real Create Folder Twin dialog proc
  682. Returns: varies
  683. Cond:    --
  684. */
  685. LRESULT Stat_DlgProc(
  686.     PSTAT this,
  687.     UINT message,
  688.     WPARAM wParam,
  689.     LPARAM lParam)
  690.     {
  691. #pragma data_seg(DATASEG_READONLY)
  692.     const static DWORD rgHelpIDs[] = {
  693.         IDC_ICTSMAIN,       IDH_BFC_PROP_FILEICON,
  694.         IDC_NAME,           IDH_BFC_PROP_FILEICON,
  695.         IDC_STTSDIRECT,     IDH_BFC_UPDATE_SCREEN,
  696.         IDC_UPDATEACTIONS,  IDH_BFC_UPDATE_SCREEN,      // different
  697.         IDC_PBTSRECON,      IDH_BFC_UPDATE_BUTTON,
  698.         IDC_PBTSSPLIT,      IDH_BFC_PROP_SPLIT_BUTTON,
  699.         IDC_PBTSFIND,       IDH_BFC_PROP_FINDORIG_BUTTON,
  700.         0, 0 };
  701. #pragma data_seg()
  702.     DWORD_PTR dw;
  703.     switch (message)
  704.         {
  705.         HANDLE_MSG(this, WM_INITDIALOG, Stat_OnInitDialog);
  706.         HANDLE_MSG(this, WM_COMMAND, Stat_OnCommand);
  707.         HANDLE_MSG(this, WM_NOTIFY, Stat_OnNotify);
  708.         HANDLE_MSG(this, WM_DESTROY, Stat_OnDestroy);
  709.     case WM_HELP:
  710.         dw = (DWORD_PTR)rgHelpIDs;
  711.         if ( IDC_STATIC != ((LPHELPINFO)lParam)->iCtrlId )
  712.             WinHelp(((LPHELPINFO)lParam)->hItemHandle, c_szWinHelpFile, HELP_WM_HELP, dw);
  713.         return 0;
  714.     case WM_CONTEXTMENU:
  715.         dw = (DWORD_PTR)rgHelpIDs;
  716.         WinHelp((HWND)wParam, c_szWinHelpFile, HELP_CONTEXTMENU, dw);
  717.         return 0;
  718.     case LNKM_ACTIVATEOTHER:
  719.         SwitchToThisWindow(GetLastActivePopup((HWND)lParam), TRUE);
  720.         SetForegroundWindow((HWND)lParam);
  721.         return 0;
  722.         
  723.     default:
  724.         return Stat_DefProc(this->hwnd, message, wParam, lParam);
  725.         }
  726.     return 0;
  727.     }
  728. /*----------------------------------------------------------
  729. Purpose: Create Folder Twin Dialog Wrapper
  730. Returns: varies
  731. Cond:    --
  732. */
  733. INT_PTR CALLBACK Stat_WrapperProc(
  734.     HWND hDlg,          // std params
  735.     UINT message,
  736.     WPARAM wParam,
  737.     LPARAM lParam)
  738.     {
  739.     PSTAT this;
  740.     // Cool windowsx.h dialog technique.  For full explanation, see
  741.     //  WINDOWSX.TXT.  This supports multiple-instancing of dialogs.
  742.     //
  743.     ENTEREXCLUSIVE()
  744.         {
  745.         if (s_bStatRecurse)
  746.             {
  747.             s_bStatRecurse = FALSE;
  748.             LEAVEEXCLUSIVE()
  749.             return FALSE;
  750.             }
  751.         }
  752.     LEAVEEXCLUSIVE()
  753.     this = Stat_GetPtr(hDlg);
  754.     if (this == NULL)
  755.         {
  756.         if (message == WM_INITDIALOG)
  757.             {
  758.             this = GAlloc(sizeof(*this));
  759.             if (!this)
  760.                 {
  761.                 MsgBox(hDlg, MAKEINTRESOURCE(IDS_OOM_STATUS), MAKEINTRESOURCE(IDS_CAP_STATUS),
  762.                        NULL, MB_ERROR);
  763.                 EndDialog(hDlg, IDCANCEL);
  764.                 return Stat_DefProc(hDlg, message, wParam, lParam);
  765.                 }
  766.             this->hwnd = hDlg;
  767.             Stat_SetPtr(hDlg, this);
  768.             }
  769.         else
  770.             {
  771.             return Stat_DefProc(hDlg, message, wParam, lParam);
  772.             }
  773.         }
  774.     if (message == WM_DESTROY)
  775.         {
  776.         Stat_DlgProc(this, message, wParam, lParam);
  777.         GFree(this);
  778.         Stat_SetPtr(hDlg, NULL);
  779.         return 0;
  780.         }
  781.     return SetDlgMsgResult(hDlg, message, Stat_DlgProc(this, message, wParam, lParam));
  782.     }