prop.cpp
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 27k
Category:

Windows Kernel

Development Platform:

Visual C++

  1. #include "precomp.hxx"
  2. #pragma hdrstop
  3. #include "util.h"
  4. #include "dll.h"
  5. #include "resource.h"
  6. #include "prop.h"
  7. #include <shellids.h>   // IDH_ values
  8. #include "shlguidp.h"
  9. #include "inetreg.h"
  10. STDAPI SHGetIDispatchForFolder(LPCITEMIDLIST pidl, IWebBrowserApp **ppauto);    // <shdocvw.h>
  11. typedef struct {
  12.     HWND hDlg;
  13.     BOOL bDirty;
  14.     BOOL bInitDone;
  15.     IPersistFolder* ppf;
  16.     TCHAR szMyDocs[ MAX_PATH ];
  17. } CUSTINFO;
  18. TCHAR g_szPropTitle[ MAX_PATH + 32 ];
  19. const static DWORD rgdwHelpTarget[] = {
  20.     IDD_TARGET_TXT,                   IDH_MYDOCS_TARGET,
  21.     IDD_TARGET,                       IDH_MYDOCS_TARGET,
  22.     IDD_FIND,                         IDH_MYDOCS_FIND_TARGET,
  23.     IDD_BROWSE,                       IDH_MYDOCS_BROWSE,
  24.     IDD_RESET,                        IDH_MYDOCS_RESET,
  25.     0, 0
  26. };
  27. LPTSTR GetMessageTitle( VOID )
  28. {
  29.     if (!(*g_szPropTitle))
  30.     {
  31.         TCHAR szFormat[ 64 ];
  32.         TCHAR szName[ MAX_PATH ];
  33.         LoadString( g_hInstance, IDS_PROP_ERROR_TITLE, szFormat, ARRAYSIZE(szFormat) );
  34.         GetMyDocumentsDisplayName( szName, ARRAYSIZE(szName) );
  35.         wnsprintf( g_szPropTitle, ARRAYSIZE(g_szPropTitle), szFormat, szName );
  36.     }
  37.     return g_szPropTitle;
  38. }
  39. // pPath is assumed to be MAX_PATH big
  40. void GetTargetPath( HWND hDlg, LPTSTR pPath )
  41. {
  42.     TCHAR szUnExPath[ MAX_PATH ];
  43.     *pPath = 0;
  44.     szUnExPath[0] = 0; 
  45.     GetDlgItemText( hDlg, IDD_TARGET, szUnExPath, ARRAYSIZE(szUnExPath) );
  46.     if (szUnExPath[0])
  47.     {
  48.         // Turn "c:" into "c:", but don't change other paths:
  49.         PathAddBackslash(szUnExPath);
  50.         PathRemoveBackslash(szUnExPath);
  51.         ExpandEnvironmentStrings( szUnExPath, pPath, MAX_PATH );
  52.     }
  53. }
  54. // Check known key in the registry to see if policy has disabled changing
  55. // of My Docs location.
  56. BOOL CanChangePersonalPath( void )
  57. {
  58.     HKEY hkey;
  59.     BOOL bChange = TRUE;
  60.     if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("Software\Microsoft\Windows\CurrentVersion\Policies\Explorer"), 0, KEY_READ, &hkey))
  61.     {
  62.         bChange = (ERROR_SUCCESS != RegQueryValueEx(hkey, TEXT("DisablePersonalDirChange"), NULL, NULL, NULL, NULL));
  63.         RegCloseKey(hkey);
  64.     }
  65.     return bChange;
  66. }
  67. BOOL InitTargetPage( HWND hDlg, LPARAM lParam )
  68. {
  69.     TCHAR szPath[ MAX_PATH ];
  70.     CUSTINFO *pci;
  71.     TCHAR szFormat[ MAX_PATH ];
  72.     TCHAR szText[ ARRAYSIZE(szFormat) + MAX_NAME_LEN ];
  73.     TCHAR szName[ MAX_PATH ];
  74.     *g_szPropTitle = 0;
  75.     pci = (CUSTINFO *)LocalAlloc(LPTR, sizeof(*pci));
  76.     if (pci == NULL)
  77.         return FALSE;
  78.     SetWindowLongPtr(hDlg, DWLP_USER, (LONG_PTR)pci);
  79.     pci->hDlg = hDlg;
  80.     // Fill in title/instructions...
  81.     GetMyDocumentsDisplayName( szName, ARRAYSIZE(szName) );
  82.     if (lstrlen(szName) > MAX_NAME_LEN)
  83.     {
  84.         lstrcpy( &szName[MAX_NAME_LEN], TEXT("...") );
  85.     }
  86.     LoadString(g_hInstance, IDS_PROP_INSTRUCTIONS, szFormat, ARRAYSIZE(szFormat));
  87.     wnsprintf(szText, ARRAYSIZE(szText), szFormat, szName);
  88.     SetDlgItemText( hDlg, IDD_INSTRUCTIONS, szText );
  89.     // Limit edit field to MAX_PATH-13 characters.  Why -13?
  90.     // Well, 13 is the number of characters in a DOS style 8.3
  91.     // filename with a '', and CreateDirectory will fail if you try to create
  92.     // a directory that can't at least contain 8.3 file names.
  93.     SendDlgItemMessage( hDlg, IDD_TARGET, EM_SETLIMITTEXT, MAX_DIR_PATH, 0 );
  94.     // Check whether path can be changed
  95.     if (CanChangePersonalPath())
  96.     {
  97.         // set up autocomplete in target edit box:
  98.         HRESULT hr = CoCreateInstance(CLSID_ACListISF, NULL, CLSCTX_INPROC_SERVER, IID_IPersistFolder, (void **)&(pci->ppf));
  99.         if (SUCCEEDED(hr))
  100.         {
  101.             IAutoComplete2* pac;
  102.             // Create the AutoComplete Object
  103.             hr = CoCreateInstance(CLSID_AutoComplete, NULL, CLSCTX_INPROC_SERVER, IID_IAutoComplete2, (void **)&pac);
  104.             if (SUCCEEDED(hr))
  105.             {
  106.                 hr = pac->Init(GetDlgItem(hDlg, IDD_TARGET), pci->ppf, NULL, NULL);
  107.                 // Set the autocomplete options
  108.                 DWORD dwOptions = 0;
  109.                 if (SHRegGetBoolUSValue(REGSTR_PATH_AUTOCOMPLETE, REGSTR_VAL_USEAUTOAPPEND, FALSE, /*default:*/FALSE))
  110.                 {
  111.                     dwOptions |= ACO_AUTOAPPEND;
  112.                 }
  113.                 if (SHRegGetBoolUSValue(REGSTR_PATH_AUTOCOMPLETE, REGSTR_VAL_USEAUTOSUGGEST, FALSE, /*default:*/TRUE))
  114.                 {
  115.                     dwOptions |= ACO_AUTOSUGGEST;
  116.                 }
  117.                 pac->SetOptions(dwOptions);
  118.                 pac->Release();
  119.             }
  120.         }
  121.     }
  122.     else
  123.     {
  124.         // Make edit field read only
  125.         SendDlgItemMessage( hDlg, IDD_TARGET, EM_SETREADONLY, (WPARAM)TRUE, 0L );
  126.         ShowWindow( GetDlgItem( hDlg, IDD_RESET ), SW_HIDE );
  127.         ShowWindow( GetDlgItem( hDlg, IDD_FIND ), SW_HIDE );
  128.         ShowWindow( GetDlgItem( hDlg, IDD_BROWSE ), SW_HIDE );
  129.     }
  130.     SHGetFolderPath(NULL, CSIDL_PERSONAL | CSIDL_FLAG_DONT_VERIFY, NULL, SHGFP_TYPE_CURRENT, szPath);
  131.     if (szPath[0])
  132.     {
  133.         SetDlgItemText(hDlg, IDD_TARGET, szPath);
  134.         lstrcpy(pci->szMyDocs, szPath);
  135.     }
  136.     LPITEMIDLIST pidlMyDocs = MyDocsIDList();
  137.     if (pidlMyDocs)
  138.     {
  139.         SHFILEINFO sfi;
  140.         SHGetFileInfo((LPCTSTR)pidlMyDocs, 0, &sfi, SIZEOF(sfi), SHGFI_ICON | SHGFI_LARGEICON | SHGFI_PIDL);
  141.         if (sfi.hIcon)
  142.         {
  143.             if (sfi.hIcon = (HICON)SendDlgItemMessage(hDlg, IDD_ITEMICON, STM_SETICON, (WPARAM)sfi.hIcon, 0L))
  144.                 DestroyIcon(sfi.hIcon);
  145.         }
  146.         ILFree(pidlMyDocs);
  147.     }
  148.     pci->bInitDone = TRUE;
  149.     return TRUE;
  150. }
  151. int MyMoveFiles( HWND hDlg, LPCTSTR pNewPath, LPCTSTR pOldPath, LPCTSTR pMyPicsPath, BOOL *pfResetMyPics )
  152. {
  153.     TCHAR           szSrcPath[ MAX_PATH + 1 ];    // +1 for double null
  154.     TCHAR           szDestPath[ MAX_PATH ];
  155.     SHFILEOPSTRUCT  FileOp;
  156.     BOOL            fMyPicsCollide = FALSE;
  157.     memset(&szSrcPath, 0, sizeof(szSrcPath));
  158.     memset(&szDestPath, 0, sizeof(szDestPath));
  159.     memset(&FileOp, 0, sizeof(FileOp));
  160.     ASSERT( pfResetMyPics );
  161.     if( *pfResetMyPics && pMyPicsPath && *pMyPicsPath )
  162.     {
  163.         LPTSTR pszMyPicsName = PathFindFileName( pMyPicsPath );
  164.         PathCombine( szDestPath, pNewPath, pszMyPicsName );
  165.         DWORD dwAtt;
  166.         if( PathFileExistsAndAttributes( szDestPath, &dwAtt ))
  167.         {
  168.             fMyPicsCollide = (FILE_ATTRIBUTE_DIRECTORY == (FILE_ATTRIBUTE_DIRECTORY & dwAtt));
  169.         }
  170.     }
  171.     
  172.     FileOp.hwnd = hDlg;
  173.     FileOp.wFunc = FO_MOVE;
  174.     // While we'll no longer create a duplicate MyPictures, using this
  175.     // flag will create "Copy of..." for other duplicated folders. Adding
  176.     // full folder merging capabilities to SHFileOperation would require
  177.     // numerous changes to the copy engine.
  178.     FileOp.fFlags = FOF_RENAMEONCOLLISION;
  179.     if( fMyPicsCollide )
  180.     {
  181.         ChangeMyPicsPath( szDestPath, pMyPicsPath );    // szDestPath set above
  182.         // Don't want ResetMyPictures to be called later on
  183.         *pfResetMyPics = FALSE;
  184.         
  185.         // Move items in current MyPics to new location
  186.         PathCombine( szSrcPath, pMyPicsPath, TEXT("*.*") );
  187.         FileOp.pFrom = szSrcPath;
  188.         FileOp.pTo = szDestPath;        
  189.         int iResult = SHFileOperation( &FileOp );
  190.         if( 0 != iResult || FileOp.fAnyOperationsAborted )
  191.         {
  192.             return iResult;
  193.         }
  194.         RemoveDirectory( pMyPicsPath );
  195.         // FileOp.pFrom is double  terminated, so must reset this
  196.         memset(&szSrcPath, 0, sizeof(szSrcPath));
  197.     }
  198.     // Move all other items
  199.     PathCombine(szSrcPath, pOldPath, TEXT("*.*"));
  200.     lstrcpy(szDestPath, pNewPath);
  201.     FileOp.pFrom = szSrcPath;
  202.     FileOp.pTo = szDestPath;
  203.     return SHFileOperation(&FileOp);
  204. }
  205. // Ask the user if they want to create the directory of a given path.
  206. // Returns TRUE if the user decided to create it, FALSE if not.
  207. // If TRUE, the dir attributes are returned in pdwAttr.
  208. BOOL QueryCreateTheDirectory(HWND hDlg, LPCTSTR pPath, DWORD* pdwAttr)
  209. {
  210.     *pdwAttr = 0;
  211.     UINT id = ShellMessageBox(g_hInstance, hDlg,
  212.                               (LPTSTR)IDS_CREATE_FOLDER, (LPTSTR)IDS_CREATE_FOLDER_TITLE,
  213.                               MB_YESNO | MB_ICONQUESTION, pPath );
  214.     if (IDYES == id)
  215.     {
  216.         // user asked us to create the folder
  217.         if (ERROR_SUCCESS == SHCreateDirectoryEx(hDlg, pPath, NULL))
  218.             *pdwAttr = GetFileAttributes(pPath);
  219.     }
  220.     return IDYES == id;
  221. }
  222. void _MaybeUnpinOldFolder(LPCTSTR pszPath, HWND hwnd, BOOL fPrompt)
  223. {
  224.     //
  225.     // Convert the path to canonical UNC form (the CSC and CSCUI
  226.     // functions require the path to be in this form)
  227.     //
  228.     // WNetGetUniversalName fails if you give it a path that's already
  229.     // in canonical UNC form, so in the failure case just try using
  230.     // pszPath.  CSCQueryFileStatus will validate it.
  231.     //
  232.     LPCTSTR pszUNC;
  233.     struct {
  234.        UNIVERSAL_NAME_INFO uni;
  235.        TCHAR szBuf[MAX_PATH];
  236.     } s;
  237.     DWORD cbBuf = SIZEOF(s);
  238.     if (ERROR_SUCCESS == WNetGetUniversalName(pszPath, UNIVERSAL_NAME_INFO_LEVEL,
  239.                                 &s, &cbBuf))
  240.     {
  241.         pszUNC = s.uni.lpUniversalName;
  242.     }
  243.     else
  244.     {
  245.         pszUNC = pszPath;
  246.     }
  247.     //
  248.     // Ask CSC if the folder is pinned for this user
  249.     //
  250.     DWORD dwHintFlags = 0;
  251.     if (CSCQueryFileStatus(pszUNC, NULL, NULL, &dwHintFlags))
  252.     {
  253.         if (dwHintFlags & FLAG_CSC_HINT_PIN_USER)
  254.         {
  255.             //
  256.             // Yes; figure out if we should unpin it
  257.             //
  258.             BOOL fUnpin;
  259.             if (fPrompt)
  260.             {
  261.                 //
  262.                 // Give the unconverted path name in the message box, since
  263.                 // that's the name the user knows
  264.                 //
  265.                 UINT id = ShellMessageBox(g_hInstance, hwnd,
  266.                                   (LPTSTR)IDS_UNPIN_OLDTARGET, (LPTSTR)IDS_UNPIN_OLD_TITLE,
  267.                                   MB_YESNO | MB_ICONQUESTION | MB_TOPMOST | MB_DEFBUTTON2,
  268.                                   pszPath);
  269.                 fUnpin = (id == IDNO);
  270.             }
  271.             else
  272.             {
  273.                 fUnpin = TRUE;
  274.             }
  275.             if (fUnpin)
  276.             {
  277.                 USES_CONVERSION;
  278.                 CSCUIRemoveFolderFromCache(T2CW(pszUNC), 0, NULL, 0);
  279.             }
  280.         }
  281.     }
  282. }
  283. void _DoApply(CUSTINFO *pci)
  284. {
  285.     LONG lres = PSNRET_NOERROR;
  286.     TCHAR szPath[ MAX_PATH ], szText[ MAX_PATH ];
  287.     DWORD dwAttr;
  288.     GetDlgItemText( pci->hDlg, IDD_TARGET, szText, ARRAYSIZE(szText) );
  289.     // Turn "c:" into "c:", but don't change other paths:
  290.     PathAddBackslash(szText);
  291.     PathRemoveBackslash(szText);
  292.     GetTargetPath( pci->hDlg, szPath );
  293.     if (pci->bDirty && (lstrcmpi(szPath, pci->szMyDocs) != 0))
  294.     {
  295.         DWORD dwRes = IsPathGoodMyDocsPath( pci->hDlg, szPath );
  296.         // all of the special cases
  297.         switch( dwRes )
  298.         {
  299.         case PATH_IS_DESKTOP:   // desktop is not good
  300.             ShellMessageBox( g_hInstance, pci->hDlg,
  301.                              (LPTSTR)IDS_NODESKTOP_FOLDERS, GetMessageTitle(),
  302.                              MB_OK | MB_ICONSTOP | MB_TOPMOST);
  303.             lres = PSNRET_INVALID_NOCHANGEPAGE;
  304.             break;
  305.         case PATH_IS_SYSTEM:
  306.         case PATH_IS_WINDOWS:   // these would be bad
  307.             ShellMessageBox( g_hInstance, pci->hDlg,
  308.                              (LPTSTR)IDS_NOWINDIR_FOLDER, GetMessageTitle(),
  309.                              MB_OK | MB_ICONSTOP | MB_TOPMOST);
  310.             lres = PSNRET_INVALID_NOCHANGEPAGE;
  311.             break;
  312.         case PATH_IS_PROFILE:   // profile is bad
  313.             ShellMessageBox( g_hInstance, pci->hDlg,
  314.                              (LPTSTR)IDS_NOPROFILEDIR_FOLDER, GetMessageTitle(),
  315.                              MB_OK | MB_ICONSTOP | MB_TOPMOST );
  316.             lres = PSNRET_INVALID_NOCHANGEPAGE;
  317.             break;
  318.         case PATH_IS_NONEXISTENT:
  319.         case PATH_IS_NONDIR:
  320.         case PATH_IS_GOOD:
  321.             dwAttr = GetFileAttributes( szPath );
  322.             if (dwAttr == 0xFFFFFFFF)
  323.             {
  324.                 // Ask user if we should create the directory...
  325.                 if (FALSE == QueryCreateTheDirectory(pci->hDlg, szPath, &dwAttr))
  326.                 {
  327.                     // They don't want to create the directory.. break here
  328.                     lres = PSNRET_INVALID_NOCHANGEPAGE;
  329.                     break;
  330.                 }
  331.             }
  332.             if (dwAttr & FILE_ATTRIBUTE_DIRECTORY)
  333.             {
  334.                 // insure that both paths don't have backslashes so we can proceed safely:
  335.                 PathRemoveBackslash(szText);
  336.                 PathRemoveBackslash(pci->szMyDocs);
  337.                 if (lstrcmpi( szText, pci->szMyDocs )!=0 )
  338.                 {
  339.                     // if PathCommonPrefix() returns the same number of chars as szMyDocs,
  340.                     // then szText must be a subdir
  341.                     TCHAR szCommon[MAX_PATH], szOldMyPics[MAX_PATH];
  342.                     BOOL fSubDir = (PathCommonPrefix(pci->szMyDocs, szText, szCommon) == lstrlen(pci->szMyDocs));
  343.                     BOOL fResetMyPics = TRUE;
  344.                     SHGetFolderPath(NULL, CSIDL_MYPICTURES | CSIDL_FLAG_DONT_VERIFY, NULL, SHGFP_TYPE_CURRENT, szOldMyPics);
  345.                     if (SUCCEEDED(ChangePersonalPath(szText, pci->szMyDocs, &fResetMyPics)))
  346.                     {
  347.                         BOOL fPrompt = TRUE;
  348.                         if (fSubDir)
  349.                         {
  350.                             // can't move old content to a subdir
  351.                             ShellMessageBox(g_hInstance, pci->hDlg,
  352.                                     (LPTSTR) IDS_CANT_MOVE_TO_SUBDIR, (LPTSTR) IDS_MOVE_DOCUMENTS_TITLE,
  353.                                     MB_OK | MB_ICONINFORMATION | MB_TOPMOST,
  354.                                     pci->szMyDocs);
  355.                         }
  356.                         else if (IDYES == ShellMessageBox(g_hInstance, pci->hDlg,
  357.                                         (LPTSTR)IDS_MOVE_DOCUMENTS,
  358.                                         (LPTSTR)IDS_MOVE_DOCUMENTS_TITLE,
  359.                                         MB_YESNO | MB_ICONQUESTION | MB_TOPMOST,
  360.                                         pci->szMyDocs, szText))
  361.                         {
  362.                             // move old mydocs content -- returns 0 on success
  363.                             if (0 != MyMoveFiles(pci->hDlg, szText, pci->szMyDocs, szOldMyPics, &fResetMyPics)) 
  364.                             {
  365.                                 ShellMessageBox(g_hInstance, pci->hDlg,
  366.                                     (LPTSTR) IDS_MOVE_ERROR, (LPTSTR) IDS_MOVE_ERROR_TITLE,
  367.                                     MB_OK | MB_ICONSTOP | MB_TOPMOST,
  368.                                     szText, pci->szMyDocs);
  369.                             }
  370.                             else
  371.                             {
  372.                                 //
  373.                                 // Move succeeded, the old target dir is now empty, so
  374.                                 // no need to prompt about unpinning it (just go ahead
  375.                                 // and do it).
  376.                                 //
  377.                                 fPrompt = FALSE;
  378.                                 // If the move succeeded, then there is no need to reset
  379.                                 // mypics, because if it was a subdirectory, then it
  380.                                 // was moved and the shell copyhook will have noticed
  381.                                 // that mypics has been moved
  382.                                 fResetMyPics = FALSE;
  383.                             }
  384.                         }
  385.                         if (fResetMyPics)
  386.                         {
  387.                             ResetMyPics(szOldMyPics);
  388.                         }
  389.                         if (!fSubDir && pci->szMyDocs[0])
  390.                         {
  391.                             //
  392.                             // If the old folder was pinned, offer to unpin it.
  393.                             //
  394.                             // (Do this only if new target is not a subdir of the 
  395.                             // old target, since otherwise we'd end up unpinning
  396.                             // the new target as well.)
  397.                             //
  398.                             _MaybeUnpinOldFolder(pci->szMyDocs, pci->hDlg, fPrompt);
  399.                         }
  400.                     }
  401.                     else
  402.                     {
  403.                         ShellMessageBox( g_hInstance, pci->hDlg,
  404.                                          (LPTSTR)IDS_GENERAL_BADDIR, (LPTSTR)IDS_INVALID_TITLE,
  405.                                          MB_OK | MB_ICONSTOP | MB_TOPMOST);
  406.                         lres = PSNRET_INVALID_NOCHANGEPAGE;
  407.                     }
  408.                 }
  409.             }
  410.             else if (dwAttr)
  411.             {
  412.                 DWORD id = IDS_NONEXISTENT_FOLDER;
  413.                 // The user entered a path that doesn't exist or isn't a
  414.                 // directory...
  415.                 if ((dwAttr != 0xFFFFFFFF) && (dwAttr != 0))
  416.                 {
  417.                     id = IDS_NOT_DIRECTORY;
  418.                 }
  419.                 ShellMessageBox( g_hInstance, pci->hDlg,
  420.                                  (LPTSTR)id, (LPTSTR)IDS_INVALID_TITLE,
  421.                                  MB_OK | MB_ICONERROR | MB_TOPMOST);
  422.                 lres = PSNRET_INVALID_NOCHANGEPAGE;
  423.             }
  424.             else
  425.             {
  426.                 ShellMessageBox( g_hInstance, pci->hDlg,
  427.                                  (LPTSTR)IDS_GENERAL_BADDIR, (LPTSTR)IDS_INVALID_TITLE,
  428.                                  MB_OK | MB_ICONSTOP | MB_TOPMOST);
  429.                 lres = PSNRET_INVALID_NOCHANGEPAGE;
  430.             }
  431.             break;
  432.         default:
  433.             //
  434.             // Looks like someone is trying to set the path
  435.             // to something isn't allowed.  Don't allow them to!
  436.             //
  437.             ShellMessageBox( g_hInstance, pci->hDlg,
  438.                              (LPTSTR)IDS_NOTALLOWED_FOLDERS, GetMessageTitle(),
  439.                              MB_OK | MB_ICONSTOP | MB_TOPMOST
  440.                             );
  441.             lres = PSNRET_INVALID_NOCHANGEPAGE;
  442.             break;
  443.         }
  444.     }
  445.     if (lres == PSNRET_NOERROR)
  446.     {
  447.         pci->bDirty = FALSE;
  448.         lstrcpy(pci->szMyDocs, szPath);
  449.     }
  450.     SetWindowLongPtr( pci->hDlg, DWLP_MSGRESULT, lres );
  451. }
  452. SAFEARRAY * MakeSafeArrayFromData(const BYTE *pData,DWORD cbData)
  453. {
  454.     SAFEARRAY * psa = SafeArrayCreateVector(VT_UI1,0,cbData);
  455.     if (psa) 
  456.     {
  457.         memcpy(psa->pvData, pData, cbData);
  458.     }
  459.     return psa;
  460. }
  461. BOOL _InitVARIANTFromPidl(VARIANT* pvar, LPCITEMIDLIST pidl)
  462. {
  463.     UINT cb = ILGetSize(pidl);
  464.     SAFEARRAY* psa = MakeSafeArrayFromData((const BYTE *)pidl, cb);
  465.     if (psa) 
  466.     {
  467.         VariantInit(pvar);
  468.         pvar->vt = VT_ARRAY | VT_UI1;
  469.         pvar->parray = psa;
  470.         return TRUE;
  471.     }
  472.     return FALSE;
  473. }
  474. HRESULT SelectPidlInSFV(IShellFolderViewDual *psfv, LPCITEMIDLIST pidl, DWORD dwOpts)
  475. {
  476.     HRESULT hres = E_FAIL;
  477.     VARIANT var;
  478.     if (_InitVARIANTFromPidl(&var, pidl))
  479.     {
  480.         hres = psfv->SelectItem(&var, dwOpts);
  481.         VariantClear(&var);
  482.     }
  483.     return hres;
  484. }
  485. HRESULT OpenContainingFolderAndGetShellFolderView(LPCITEMIDLIST pidlFolder, IShellFolderViewDual **ppsfv)
  486. {
  487.     *ppsfv = NULL;
  488.     IWebBrowserApp *pauto;
  489.     HRESULT hres = SHGetIDispatchForFolder(pidlFolder, &pauto);
  490.     if (SUCCEEDED(hres))
  491.     {
  492.         // We have IDispatch for window, now try to get one for
  493.         // the folder object...
  494.         HWND hwnd;
  495.         if (SUCCEEDED(pauto->get_HWND((LONG*)&hwnd)))
  496.         {
  497.             // Make sure we make this the active window
  498.             SetForegroundWindow(hwnd);
  499.             ShowWindow(hwnd, SW_SHOWNORMAL);
  500.         }
  501.         IDispatch * pautoDoc;
  502.         hres = pauto->get_Document(&pautoDoc);
  503.         if (SUCCEEDED(hres))
  504.         {
  505.             hres = pautoDoc->QueryInterface(IID_IShellFolderViewDual, (void **)ppsfv);
  506.             pautoDoc->Release();
  507.         }
  508.         pauto->Release();
  509.     }
  510.     return hres;
  511. }
  512. //
  513. // Stolen (and modified) from link.c in shell32.dll
  514. //
  515. void _FindTarget(HWND hDlg, LPTSTR pPath)
  516. {
  517.     USHORT uSave;
  518.     LPITEMIDLIST pidl = ILCreateFromPath( pPath );
  519.     if (!pidl)
  520.     {
  521.         ShellMessageBox( g_hInstance, hDlg,
  522.                      (LPTSTR)IDS_GENERAL_BADDIR, (LPTSTR)IDS_INVALID_TITLE,
  523.                      MB_OK | MB_ICONSTOP | MB_TOPMOST);
  524.         return;
  525.     }
  526.     LPITEMIDLIST pidlLast = ILFindLastID(pidl);
  527.     // get the folder, special case for root objects (My Computer, Network)
  528.     // hack off the end if it is not the root item
  529.     if (pidl != pidlLast)
  530.     {
  531.         uSave = pidlLast->mkid.cb;
  532.         pidlLast->mkid.cb = 0;
  533.     }
  534.     else
  535.         uSave = 0;
  536.     LPITEMIDLIST pidlDesk;
  537.     if (SUCCEEDED(SHGetFolderLocation(NULL, CSIDL_DESKTOPDIRECTORY, NULL, 0, &pidlDesk)))
  538.     {
  539.         BOOL fIsDesktopDir = pidlDesk && ILIsEqual(pidl, pidlDesk);
  540.         if (fIsDesktopDir || !uSave)  // if it's in the desktop dir or pidl == pidlLast (uSave == 0 from above)
  541.         {
  542.             //
  543.             // It's on the desktop...
  544.             //
  545.             ShellMessageBox(g_hInstance, hDlg, (LPTSTR)IDS_ON_DESKTOP, (LPTSTR)IDS_FIND_TITLE,
  546.                              MB_OK | MB_ICONINFORMATION | MB_TOPMOST);
  547.         }
  548.         else
  549.         {
  550.             IShellFolderViewDual *psfv;
  551.             if (SUCCEEDED(OpenContainingFolderAndGetShellFolderView(uSave ? pidl : pidlDesk, &psfv)))
  552.             {
  553.                 if (uSave)
  554.                     pidlLast->mkid.cb = uSave;
  555.                 SelectPidlInSFV(psfv, pidlLast, SVSI_SELECT | SVSI_FOCUSED | SVSI_DESELECTOTHERS | SVSI_ENSUREVISIBLE);
  556.                 psfv->Release();
  557.             }
  558.         }
  559.         ILFree(pidlDesk);
  560.     }
  561.     ILFree(pidl);
  562. }
  563. int _BrowseCallbackProc( HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData )
  564. {
  565.     if ((uMsg == BFFM_SELCHANGED) && lParam)
  566.     {
  567.         TCHAR szPath[ MAX_PATH ];
  568.         szPath[0] = 0;
  569.         SHGetPathFromIDList( (LPITEMIDLIST)lParam, szPath );
  570.         DWORD dwRes = IsPathGoodMyDocsPath( hwnd, szPath );
  571.         if (dwRes == PATH_IS_GOOD || dwRes == PATH_IS_MYDOCS)
  572.         {
  573.             SendMessage( hwnd, BFFM_ENABLEOK, 0, (LPARAM)TRUE);
  574.             SendMessage( hwnd, BFFM_SETSTATUSTEXT, 0, 0 );
  575.         }
  576.         else
  577.         {
  578.             TCHAR szStatus[ 128 ];
  579.             SendMessage( hwnd, BFFM_ENABLEOK, 0, 0 );
  580.             szStatus[0] = 0;
  581.             LoadString( g_hInstance, IDS_NOSHELLEXT_FOLDERS, szStatus, ARRAYSIZE(szStatus) );
  582.             SendMessage( hwnd, BFFM_SETSTATUSTEXT, 0, (LPARAM)szStatus );
  583.         }
  584.     }
  585.     return 0;
  586. }
  587. void _MakeDirty(CUSTINFO *pci)
  588. {
  589.     pci->bDirty = TRUE;
  590.     PropSheet_Changed( GetParent( pci->hDlg ), pci->hDlg );
  591. }
  592. void _DoFind(CUSTINFO *pci)
  593. {
  594.     TCHAR szPath[ MAX_PATH ];
  595.     GetTargetPath( pci->hDlg, szPath );
  596.     DWORD dwAttrb = GetFileAttributes( szPath );
  597.     if ( szPath[0] && (dwAttrb != 0xFFFFFFFF) && (dwAttrb & FILE_ATTRIBUTE_DIRECTORY) )
  598.     {
  599.         _FindTarget( pci->hDlg, szPath );
  600.     }
  601.     else
  602.     {
  603.         ShellMessageBox( g_hInstance, pci->hDlg,
  604.                      (LPTSTR)IDS_GENERAL_BADDIR, (LPTSTR)IDS_INVALID_TITLE,
  605.                      MB_OK | MB_ICONSTOP | MB_TOPMOST);
  606.     }
  607. }
  608. void _DoBrowse(CUSTINFO *pci)
  609. {
  610.     BROWSEINFO bi;
  611.     TCHAR szName[ MAX_PATH ];
  612.     TCHAR szTitle[ 128 ];
  613.     LoadString( g_hInstance, IDS_BROWSE_TITLE, szTitle, ARRAYSIZE(szTitle) );
  614.     bi.hwndOwner = pci->hDlg;
  615.     bi.pidlRoot = NULL;
  616.     bi.pszDisplayName = szName;
  617.     bi.lpszTitle = szTitle;
  618.     bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_STATUSTEXT | BIF_USENEWUI;
  619.     bi.lParam = 0;
  620.     bi.iImage = 0;
  621.     bi.lpfn = _BrowseCallbackProc;
  622.     // the default root for this folder is MyDocs so we don't need to set that up.
  623.     LPITEMIDLIST pidl = SHBrowseForFolder( &bi );
  624.     if (pidl)
  625.     {
  626.         if (SHGetPathFromIDList( pidl, szName ))
  627.         {
  628.             SetDlgItemText( pci->hDlg, IDD_TARGET, szName );
  629.             _MakeDirty(pci);
  630.         }
  631.         ILFree( pidl );
  632.     }
  633. }
  634. void DoReset(CUSTINFO *pci)
  635. {
  636.     TCHAR szPath[MAX_PATH];
  637.     if (S_OK == SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_DEFAULT, szPath))
  638.     {
  639.         SetDlgItemText(pci->hDlg, IDD_TARGET, szPath);
  640.         _MakeDirty(pci);
  641.     }
  642. }
  643. INT_PTR CALLBACK TargetDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  644. {
  645.     CUSTINFO *pci = (CUSTINFO *)GetWindowLongPtr( hDlg, DWLP_USER );
  646.     switch (uMsg)
  647.     {
  648.     case WM_INITDIALOG:
  649.         if (!InitTargetPage( hDlg, lParam ))
  650.         {
  651.             ShellMessageBox( g_hInstance, hDlg, (LPTSTR)IDS_INIT_FAILED_TEXT, GetMessageTitle(),
  652.                              MB_OK | MB_ICONSTOP | MB_TOPMOST );
  653.             return 0;
  654.         }
  655.         return 1;
  656.     case WM_DESTROY:
  657.         if (NULL != pci)
  658.         {
  659.             ATOMICRELEASE(pci->ppf);
  660.         }
  661.         LocalFree( pci );
  662.         SetWindowLongPtr( hDlg, DWLP_USER, 0 );
  663.         return 1;
  664.     case WM_COMMAND:
  665.         switch(GET_WM_COMMAND_ID(wParam, lParam))
  666.         {
  667.         case IDD_RESET:
  668.             DoReset(pci);
  669.             return 1;
  670.         case IDD_TARGET:
  671.     if ((GET_WM_COMMAND_CMD(wParam, lParam) == EN_UPDATE) && pci && (pci->bInitDone) && (!pci->bDirty))
  672.             {
  673.                 _MakeDirty(pci);
  674.             }
  675.             return 1;
  676.         case IDD_FIND:
  677.             _DoFind(pci);
  678.             return 1;
  679.         case IDD_BROWSE:
  680.             _DoBrowse(pci);
  681.             return 1;
  682.         }
  683.         break;
  684.     case WM_HELP:               /* F1 or title-bar help button */
  685.         if ((((LPHELPINFO)lParam)->iCtrlId != IDD_ITEMICON )     &&
  686.             (((LPHELPINFO)lParam)->iCtrlId != IDD_INSTRUCTIONS ) &&
  687.             (((LPHELPINFO)lParam)->iCtrlId != IDC_TARGET_GBOX ))
  688.         {
  689.             WinHelp((HWND)((LPHELPINFO) lParam)->hItemHandle,
  690.                      NULL, HELP_WM_HELP, (DWORD_PTR) rgdwHelpTarget);
  691.         }
  692.         break;
  693.     case WM_CONTEXTMENU:        /* right mouse click */
  694.         {
  695.             POINT p;
  696.             HWND hwndChild;
  697.             INT ctrlid;
  698.             //
  699.             // Get the point where the user clicked...
  700.             //
  701.             p.x = (LONG)(LOWORD(lParam));
  702.             p.y = (LONG)(HIWORD(lParam));
  703.             //
  704.             // Now, map that to a child control if possible...
  705.             //
  706.             ScreenToClient( hDlg, &p );
  707.             hwndChild = ChildWindowFromPoint( (HWND)wParam, p );
  708.             ctrlid = GetDlgCtrlID( hwndChild );
  709.             //
  710.             // Don't put up the help context menu for the items
  711.             // that don't have help...
  712.             //
  713.             if (( ctrlid != IDD_ITEMICON )     &&
  714.                 ( ctrlid != IDD_INSTRUCTIONS ))
  715.             {
  716.                 WinHelp((HWND)wParam, NULL, HELP_CONTEXTMENU, (DWORD_PTR)rgdwHelpTarget);
  717.             }
  718.         }
  719.         break;
  720.     case WM_NOTIFY:
  721.         switch (((NMHDR *)lParam)->code)
  722.         {
  723.             case PSN_APPLY:
  724.                 _DoApply(pci);
  725.                 return 1;
  726.         }
  727.         break;
  728.     }
  729.     return 0;
  730. }