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

Windows Kernel

Development Platform:

Visual C++

  1. #include "precomp.hxx"
  2. #pragma hdrstop
  3. #include <shguidp.h>    // CLSID_MyDocuments, CLSID_ShellFSFolder
  4. #include <shlobjp.h>    // SHFlushSFCache()
  5. #include "util.h"
  6. #include "dll.h"
  7. #include "resource.h"
  8. // this is where shell32 looks for per user regitem names
  9. TCHAR const c_szDesktopIni[] = TEXT("desktop.ini");
  10. TCHAR const c_szUserShellFolders[] = TEXT("Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders");
  11. TCHAR const c_szPersonal[] = TEXT("Personal");
  12. TCHAR const c_szMyPics[] = TEXT("My Pictures");
  13. // Determine if we're running under Winstone 97 (at least whether we're in
  14. // the state where Winstone messes up CSIDL_PERSONAL)
  15. BOOL IsWinstone97()
  16. {
  17.     BOOL fRet = FALSE;
  18.     HKEY hkey;
  19.     // Winstone97 sets CSIDL_PERSONAL in HKEY_LOCAL_MACHINE to be 
  20.     // C:wstempmydocs. if that is there we are running under winstone
  21.     if (ERROR_SUCCESS == RegOpenKey(HKEY_LOCAL_MACHINE, c_szUserShellFolders, &hkey))
  22.     {
  23.         TCHAR szPath[MAX_PATH];
  24.         DWORD cbSize = SIZEOF(szPath);
  25.         if (ERROR_SUCCESS == RegQueryValueEx(hkey, c_szPersonal, NULL, NULL, (LPBYTE)szPath, &cbSize))
  26.         {
  27.             if (cbSize > (3 * sizeof(TCHAR)))
  28.             {
  29.                 // szPath+3 is to skip the drive letter & :...
  30.                 fRet = StrCmpI( &szPath[3], TEXT("wstemp\mydocs")) == 0;
  31.             }
  32.         }
  33.         RegCloseKey(hkey);
  34.     }
  35.     return fRet;
  36. }
  37. // check the enumerated bit in the name space to see if this is visible to the user
  38. BOOL IsMyDocsHidden(void)
  39. {
  40.     BOOL bHidden = TRUE;
  41.     IShellFolder *psf;
  42.     if (SUCCEEDED(SHGetDesktopFolder(&psf)))
  43.     {
  44.         LPITEMIDLIST pidl;
  45.         DWORD dwAttrib = SFGAO_NONENUMERATED;
  46.         WCHAR wszName[128];
  47.         SHTCharToUnicode(TEXT("::") MYDOCS_CLSID, wszName, ARRAYSIZE(wszName));
  48.         if (SUCCEEDED(psf->ParseDisplayName(NULL, NULL, wszName, NULL, &pidl, &dwAttrib)))
  49.         {
  50.             bHidden = dwAttrib & SFGAO_NONENUMERATED;
  51.             ILFree(pidl);
  52.         }
  53.         psf->Release();
  54.     }
  55.     return bHidden;
  56. }
  57. // Return the current display name for "My Documents"
  58. HRESULT GetMyDocumentsDisplayName(LPTSTR pszPath, UINT cch)
  59. {
  60.     *pszPath = 0;
  61.     IShellFolder *psf;
  62.     if (SUCCEEDED(SHGetDesktopFolder(&psf)))
  63.     {
  64.         LPITEMIDLIST pidl;
  65.         WCHAR wszName[128];
  66.         SHTCharToUnicode(TEXT("::") MYDOCS_CLSID, wszName, ARRAYSIZE(wszName));
  67.         if (SUCCEEDED(psf->ParseDisplayName(NULL, NULL, wszName, NULL, &pidl, NULL)))
  68.         {
  69.             STRRET sr;
  70.             if (SUCCEEDED(psf->GetDisplayNameOf(pidl, SHGDN_NORMAL, &sr)))
  71.             {
  72.                 StrRetToBuf(&sr, pidl, pszPath, cch);
  73.             }
  74.             ILFree(pidl);
  75.         }
  76.         psf->Release();
  77.     }
  78.     return *pszPath ? S_OK : E_FAIL;
  79. }
  80. LPITEMIDLIST MyDocsIDList(void)
  81. {
  82.     LPITEMIDLIST pidl = NULL;
  83.     IShellFolder *psf;
  84.     if (SUCCEEDED(SHGetDesktopFolder(&psf)))
  85.     {
  86.         WCHAR wszName[128];
  87.         SHTCharToUnicode(TEXT("::") MYDOCS_CLSID, wszName, ARRAYSIZE(wszName));
  88.         psf->ParseDisplayName(NULL, NULL, wszName, NULL, &pidl, NULL);
  89.         psf->Release();
  90.     }
  91.     return pidl;
  92. }
  93. void SHChangeNotifyMyDocs(UINT nNotify)
  94. {
  95.     LPITEMIDLIST pidlMyDocs = MyDocsIDList();
  96.     if (pidlMyDocs)
  97.     {
  98.         SHChangeNotify(nNotify, SHCNF_IDLIST, pidlMyDocs, NULL);
  99.         SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_IDLIST, pidlMyDocs, NULL);
  100.         ILFree(pidlMyDocs);
  101.     }
  102. }
  103. DWORD MyDocsGetAttributes()
  104. {
  105.     DWORD dwAttributes = SFGAO_CANLINK |            // 00000004
  106.                          SFGAO_CANRENAME |          // 00000010
  107.                          SFGAO_CANDELETE |          // 00000020
  108.                          SFGAO_HASPROPSHEET |       // 00000040
  109.                          SFGAO_DROPTARGET |         // 00000100
  110.                          SFGAO_FILESYSANCESTOR |    // 10000000
  111.                          SFGAO_FOLDER |             // 20000000
  112.                          SFGAO_FILESYSTEM |         // 40000000
  113.                          SFGAO_HASSUBFOLDER |       // 80000000
  114.                          SFGAO_CANMONIKER;          // 00400000
  115.                          // SFGAO_NONENUMERATED     // 00100000
  116.                          //                         // F0400174
  117.     HKEY hkey;
  118.     if (ERROR_SUCCESS == RegOpenKey(HKEY_CLASSES_ROOT, TEXT("CLSID\") MYDOCS_CLSID TEXT("\ShellFolder"), &hkey))
  119.     {
  120.         DWORD dwSize = sizeof(dwAttributes);
  121.         RegQueryValueEx(hkey, TEXT("Attributes"), NULL, NULL, (BYTE *)&dwAttributes, &dwSize);
  122.         RegCloseKey(hkey);
  123.     }
  124.     return dwAttributes;
  125. }
  126. HRESULT MyDocsSetAttributes(DWORD dwMask, DWORD dwNewBits)
  127. {
  128.     HKEY hkey;
  129.     HRESULT hr = E_FAIL;
  130.     if (ERROR_SUCCESS == RegOpenKey(HKEY_CURRENT_USER, TEXT("Software\Microsoft\Windows\CurrentVersion\Explorer\CSLID\") MYDOCS_CLSID TEXT("\ShellFolder"), &hkey))
  131.     {
  132.         DWORD dwValue, cbSize = SIZEOF(dwValue);
  133.         if (RegQueryValueEx(hkey, TEXT("Attributes"), NULL, NULL, (BYTE *)&dwValue, &cbSize) == ERROR_SUCCESS)
  134.         {
  135.             dwValue = (dwValue & ~dwMask) | (dwNewBits & dwMask);
  136.             if (RegSetValueEx(hkey, TEXT("Attributes"), 0, REG_DWORD, (BYTE *)&dwValue, SIZEOF(dwValue)) == ERROR_SUCCESS)
  137.             {
  138.                 hr = S_OK;
  139.             }
  140.         }
  141.         RegCloseKey(hkey);
  142.     }
  143.     return hr;
  144. }
  145. void HideMyDocs()
  146. {
  147.     MyDocsSetAttributes(SFGAO_NONENUMERATED, 0);
  148. }
  149. void UnHideMyDocs()
  150. {
  151.     MyDocsSetAttributes(SFGAO_NONENUMERATED, SFGAO_NONENUMERATED);
  152. }
  153. // Resets special registry value so that My Docs will be visible...
  154. void RestoreMyDocsFolder(void)
  155. {
  156.     // delete the HideMyDocs value
  157.     UnHideMyDocs();
  158.     // Add item to sendto directory
  159.     UpdateSendToFile(FALSE);
  160.     // Tell the shell we're back...
  161.     SHChangeNotifyMyDocs(SHCNE_CREATE);
  162. }
  163. // Create/Updates file in SendTo directory to have current display name
  164. void UpdateSendToFile(BOOL bDeleteOnly)
  165. {
  166.     TCHAR szSendToDir[MAX_PATH];
  167.     
  168.     if (S_OK == SHGetFolderPath(NULL, CSIDL_SENDTO, NULL, SHGFP_TYPE_CURRENT, szSendToDir))
  169.     {
  170.         // Create c:winntprofilechrisgsendto<dislpay name>.mydocs
  171.         TCHAR szNewFile[MAX_PATH];
  172.         if (!bDeleteOnly)
  173.         {
  174.             TCHAR szName[MAX_PATH];
  175.             if (SUCCEEDED(GetMyDocumentsDisplayName(szName, ARRAYSIZE(szName))))
  176.             {
  177.                 PathCombine(szNewFile, szSendToDir, szName);
  178.                 lstrcat(szNewFile, TEXT(".mydocs"));
  179.             }
  180.             else
  181.             {
  182.                 // we can't create a new file, because we don't have a name
  183.                 bDeleteOnly = TRUE;
  184.             }
  185.         }
  186.         
  187.         TCHAR szFile[MAX_PATH];
  188.         WIN32_FIND_DATA fd;
  189.         // delete c:winntprofilechrisgsendto*.mydocs
  190.         PathCombine(szFile, szSendToDir, TEXT("*.mydocs"));
  191.         HANDLE hFind = FindFirstFile(szFile, &fd);
  192.         if (hFind != INVALID_HANDLE_VALUE )
  193.         {
  194.             do
  195.             {
  196.                 PathCombine(szFile, szSendToDir, fd.cFileName);
  197.                 if (0 == lstrcmp(szFile, szNewFile))
  198.                 {
  199.                     // The file that we needed to create already exists,
  200.                     // just leave it in place instead of deleting it and
  201.                     // then creating it again below (this fixes
  202.                     // app compat problems - see NT bug 246932)
  203.                     bDeleteOnly = TRUE;
  204.                 }
  205.                 else
  206.                 {
  207.                     DeleteFile(szFile);
  208.                 }
  209.             } while (FindNextFile(hFind, &fd));
  210.             FindClose(hFind);
  211.         }
  212.         if (!bDeleteOnly)
  213.         {
  214.             hFind = CreateFile(szNewFile, GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
  215.             if (hFind != INVALID_HANDLE_VALUE)
  216.             {
  217.                 CloseHandle(hFind);
  218.             }
  219.         }
  220.     }
  221. }
  222. // test pszChild against pszParent to see if
  223. // pszChild is equal (PATH_IS_EQUAL) or 
  224. // a DIRECT child (PATH_IS_CHILD)
  225. DWORD ComparePaths(LPCTSTR pszChild, LPCTSTR pszParent)
  226. {
  227.     DWORD dwRet = PATH_IS_DIFFERENT;
  228.     INT cchParent = lstrlen( pszParent );
  229.     INT cchChild = lstrlen( pszChild );
  230.     if (cchParent <= cchChild)
  231.     {
  232.         TCHAR szChild[MAX_PATH];
  233.         lstrcpyn(szChild, pszChild, ARRAYSIZE(szChild));
  234.         LPTSTR pszChildSlice = szChild + cchParent;
  235.         TCHAR cSave = *pszChildSlice;
  236.         *pszChildSlice = 0;
  237.         if (lstrcmpi( szChild, pszParent ) == 0 )
  238.         {
  239.             if (cchChild > cchParent)
  240.             {
  241.                 LPTSTR pTmp = pszChildSlice + 1;
  242.                 while( *pTmp && *pTmp!=TEXT('\') )
  243.                 {
  244.                     pTmp++;
  245.                 }
  246.                 if (!(*pTmp))
  247.                 {
  248.                     dwRet = PATH_IS_CHILD;
  249.                 }
  250.             }
  251.             else
  252.             {
  253.                 dwRet = PATH_IS_EQUAL;
  254.             }
  255.         }
  256.         *pszChildSlice = cSave;
  257.     }
  258.     return dwRet;
  259. }
  260. TCHAR const c_szShellInfo[]= TEXT(".ShellClassInfo");
  261. // Checks the path to see if it is marked as system or read only and
  262. // then check desktop.ini for CLSID or CLSID2 entry...
  263. BOOL IsPathAlreadyShellFolder(LPCTSTR pPath, DWORD dwAttrib)
  264. {
  265.     TCHAR szDesktopIni[MAX_PATH];
  266.     TCHAR szBuffer[MAX_PATH];
  267.     if (!PathIsSystemFolder(pPath, dwAttrib))
  268.         return FALSE;
  269.     PathCombine(szDesktopIni, pPath, c_szDesktopIni);
  270.     // Check for CLSID entry...
  271.     GetPrivateProfileString( c_szShellInfo, TEXT("CLSID"), TEXT("foo"), szBuffer, ARRAYSIZE(szBuffer), szDesktopIni );
  272.     if ( (lstrcmpi( szBuffer, TEXT("foo") ) !=0 ) &&
  273.          (lstrcmpi( szBuffer, MYDOCS_CLSID ) !=0 ) )
  274.     {
  275.         return TRUE;
  276.     }
  277.     // Check for CLSID2 entry...
  278.     GetPrivateProfileString( c_szShellInfo, TEXT("CLSID2"), TEXT("foo"), szBuffer, ARRAYSIZE(szBuffer), szDesktopIni );
  279.     if ( (lstrcmpi( szBuffer, TEXT("foo") ) != 0) &&
  280.          (lstrcmpi( szBuffer, MYDOCS_CLSID ) != 0) )
  281.     {
  282.         return TRUE;
  283.     }
  284.     return FALSE;
  285. }
  286. const struct
  287. {
  288.     DWORD dwDir;
  289.     DWORD dwFlags;
  290.     DWORD dwRet;
  291. }
  292. _adirs[] =
  293. {
  294.     { CSIDL_DESKTOP,            PATH_IS_EQUAL | PATH_IS_CHILD, PATH_IS_DESKTOP   },
  295.     { CSIDL_PERSONAL,           PATH_IS_EQUAL                , PATH_IS_MYDOCS    },
  296.     { CSIDL_SENDTO,             PATH_IS_EQUAL | PATH_IS_CHILD, PATH_IS_SENDTO    },
  297.     { CSIDL_RECENT,             PATH_IS_EQUAL | PATH_IS_CHILD, PATH_IS_RECENT    },
  298.     { CSIDL_HISTORY,            PATH_IS_EQUAL | PATH_IS_CHILD, PATH_IS_HISTORY   },
  299.     { CSIDL_COOKIES,            PATH_IS_EQUAL | PATH_IS_CHILD, PATH_IS_COOKIES   },
  300.     { CSIDL_PRINTHOOD,          PATH_IS_EQUAL | PATH_IS_CHILD, PATH_IS_PRINTHOOD },
  301.     { CSIDL_NETHOOD,            PATH_IS_EQUAL | PATH_IS_CHILD, PATH_IS_NETHOOD   },
  302.     { CSIDL_STARTMENU,          PATH_IS_EQUAL | PATH_IS_CHILD, PATH_IS_STARTMENU },
  303.     { CSIDL_TEMPLATES,          PATH_IS_EQUAL | PATH_IS_CHILD, PATH_IS_TEMPLATES },
  304.     { CSIDL_FAVORITES,          PATH_IS_EQUAL | PATH_IS_CHILD, PATH_IS_FAVORITES },
  305.     { CSIDL_FONTS,              PATH_IS_EQUAL | PATH_IS_CHILD, PATH_IS_FONTS     },
  306.     { CSIDL_APPDATA,            PATH_IS_EQUAL | PATH_IS_CHILD, PATH_IS_APPDATA   },
  307.     { CSIDL_INTERNET_CACHE,     PATH_IS_EQUAL | PATH_IS_CHILD, PATH_IS_TEMP_INET },
  308.     { CSIDL_COMMON_STARTMENU,   PATH_IS_EQUAL | PATH_IS_CHILD, PATH_IS_STARTMENU },
  309.     { CSIDL_COMMON_DESKTOPDIRECTORY, PATH_IS_EQUAL | PATH_IS_CHILD, PATH_IS_DESKTOP },
  310.     { CSIDL_WINDOWS,            PATH_IS_EQUAL | PATH_IS_CHILD, PATH_IS_WINDOWS },
  311.     { CSIDL_SYSTEM,             PATH_IS_EQUAL | PATH_IS_CHILD, PATH_IS_SYSTEM },
  312.     { CSIDL_PROFILE,            PATH_IS_EQUAL                , PATH_IS_PROFILE },
  313. };
  314. #ifdef DEBUG
  315. BOOL PathHasBackslash(LPCTSTR pszPath)
  316. {
  317.     BOOL fRet = FALSE;
  318.     TCHAR* pszTest = StrDup(pszPath);
  319.     if (pszTest)
  320.     {
  321.         PathRemoveBackslash(pszTest);
  322.         fRet = (lstrcmpi(pszTest, pszPath) != 0);
  323.         LocalFree(pszTest);
  324.     }
  325.     return fRet;
  326. }
  327. #endif
  328. #ifdef UNICODE
  329. #define CharN(psz, n)  ((psz)[n])
  330. #else
  331. TCHAR CharN(LPCTSTR psz, int n)
  332. {
  333.     ASSERT(n < lstrlen(psz));
  334.     while (n--)
  335.     {
  336.         psz = CharNext(psz);
  337.     }
  338.     return *psz;
  339. }
  340. #endif
  341. BOOL PathEndsInDot(LPCTSTR pszPath)
  342. {
  343.     //
  344.     // CreateDirectory("c:foo.") or CreateDirectory("c:foo.....")
  345.     // will succeed but create a directory named "c:foo", which isn't
  346.     // what the user asked for.  So we use this function to guard
  347.     // against those cases.
  348.     //
  349.     // Note that this simple test also picks off "c:foo." -- ok for
  350.     // our purposes.
  351.     //
  352.     ASSERT(!PathHasBackslash(pszPath));
  353.     UINT cLen = lstrlen(pszPath);
  354.     if (cLen >= 1)
  355.     {
  356.         if (CharN(pszPath, cLen - 1) == TEXT('.'))
  357.         {
  358.             return TRUE;
  359.         }
  360.     }
  361.     return FALSE;
  362. }
  363. //
  364. // Checks the path to see if it is okay as a MyDocs path
  365. //
  366. DWORD IsPathGoodMyDocsPath( HWND hwnd, LPCTSTR pPath )
  367. {
  368.     if (NULL == pPath)
  369.     {
  370.         return PATH_IS_ERROR;
  371.     }
  372.     
  373.     TCHAR szRootPath[MAX_PATH];
  374.     lstrcpyn(szRootPath, pPath, ARRAYSIZE(szRootPath));
  375.     if (!PathStripToRoot(szRootPath))
  376.     {
  377.         return PATH_IS_ERROR;
  378.     }
  379.     if (PathEndsInDot(pPath))
  380.     {
  381.         return PATH_IS_ERROR;
  382.     }
  383.     
  384.     DWORD dwRes, dwAttr = GetFileAttributes( pPath );
  385.     if (dwAttr == 0xFFFFFFFF)
  386.     {
  387.         if (0xFFFFFFFF == GetFileAttributes(szRootPath))
  388.         {
  389.             // If the root path doesn't exist, then we're not going
  390.             // to be able to create a path:
  391.             return PATH_IS_ERROR;
  392.         }
  393.         else
  394.         {
  395.             return PATH_IS_NONEXISTENT;
  396.         }
  397.     }
  398.     if (!(dwAttr & FILE_ATTRIBUTE_DIRECTORY))
  399.     {
  400.         return PATH_IS_NONDIR;
  401.     }
  402.     for (int i = 0; i < ARRAYSIZE(_adirs); i++)
  403.     {
  404.         TCHAR szPathToCheck[MAX_PATH];
  405.         //
  406.         // Check for various special shell folders
  407.         //
  408.         if (S_OK == SHGetFolderPath(hwnd, _adirs[i].dwDir | CSIDL_FLAG_DONT_VERIFY, NULL, SHGFP_TYPE_CURRENT, szPathToCheck))
  409.         {
  410.             dwRes = ComparePaths(pPath, szPathToCheck);
  411.             if (dwRes & _adirs[i].dwFlags)
  412.             {
  413.                 //
  414.                 // The inevitable exceptions
  415.                 //
  416.                 switch(_adirs[i].dwDir) 
  417.                 {
  418.                 case CSIDL_DESKTOP:
  419.                     if (PATH_IS_CHILD == dwRes) 
  420.                     {
  421.                         continue;   // allowing subfolder of CSIDL_DESKTOP
  422.                     }
  423.                     break;
  424.                 default:
  425.                     break;
  426.                 } // switch
  427.                 return _adirs[i].dwRet;
  428.             }
  429.         }
  430.     }
  431.     
  432.     //
  433.     // Make sure path isn't set as a system or some other kind of
  434.     // folder that already has a CLSID or CLSID2 entry...
  435.     //
  436.     if (IsPathAlreadyShellFolder(pPath, dwAttr))
  437.     {
  438.         return PATH_IS_SHELLFOLDER;
  439.     }
  440.     return PATH_IS_GOOD;
  441. }
  442. // Scans a desktop.ini file for sections to see if all of them are empty...
  443. BOOL IsDesktopIniEmpty(LPCTSTR pIniFile)
  444. {
  445.     TCHAR szSections[1024];  // for section names
  446.     if (GetPrivateProfileSectionNames(szSections, ARRAYSIZE(szSections), pIniFile))
  447.     {
  448.         for (LPTSTR pTmp = szSections; *pTmp; pTmp += lstrlen(pTmp) + 1)
  449.         {
  450.             TCHAR szSection[1024];   // for section key names and values
  451.             GetPrivateProfileSection(pTmp, szSection, ARRAYSIZE(szSection), pIniFile);
  452.             if (szSection[0])
  453.             {
  454.                 return FALSE;
  455.             }
  456.         }
  457.     }
  458.     return TRUE;
  459. }
  460. // Remove our entries from the desktop.ini file in this directory, and
  461. // then test the desktop.ini to see if it's empty.  If it is, delete it
  462. // and remove the system/readonly bit from the directory...
  463. void MyDocsUnmakeSystemFolder( LPCTSTR pPath )
  464. {
  465.     TCHAR szIniFile[MAX_PATH];
  466.     PathCombine( szIniFile, pPath, c_szDesktopIni );
  467.     // Remove CLSID2
  468.     WritePrivateProfileString(c_szShellInfo, TEXT("CLSID2"), NULL, szIniFile);
  469.     // Remove InfoTip
  470.     WritePrivateProfileString(c_szShellInfo, TEXT("InfoTip"), NULL, szIniFile);
  471.     // Remove Icon
  472.     WritePrivateProfileString( c_szShellInfo, TEXT("IconFile"), NULL, szIniFile);
  473.     DWORD dwAttrb = GetFileAttributes( szIniFile );
  474.     if (dwAttrb != 0xFFFFFFFF)
  475.     {
  476.         if (IsDesktopIniEmpty(szIniFile))
  477.         {
  478.             dwAttrb &= ~( FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN );
  479.             SetFileAttributes( szIniFile, dwAttrb );
  480.             DeleteFile( szIniFile );
  481.         }
  482.         PathUnmakeSystemFolder( pPath );
  483.     }
  484. }
  485. // Delete the desktop.ini (if it exists)
  486. // and remove the system/readonly bit from the directory...
  487. void MyPicsUnmakeSystemFolder(LPCTSTR pPath)
  488. {
  489.     // nuke old mypics' desktop.ini and fix attribs on old mypics dir
  490.     TCHAR szIniFile[MAX_PATH];
  491.     PathCombine(szIniFile, pPath, c_szDesktopIni);
  492.     DWORD dwAttrb = GetFileAttributes(szIniFile);
  493.     if (dwAttrb != 0xFFFFFFFF)
  494.     {
  495.         dwAttrb &= ~(FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN);
  496.         SetFileAttributes(szIniFile, dwAttrb);
  497.         DeleteFile(szIniFile);
  498.         PathUnmakeSystemFolder(pPath);
  499.     }
  500. }
  501. void SetFolderPath(LPCTSTR pszFolder, LPCTSTR pszPath)
  502. {
  503.     HKEY hkey;
  504.     if (ERROR_SUCCESS == RegCreateKey(HKEY_CURRENT_USER, c_szUserShellFolders, &hkey))
  505.     {
  506.         TCHAR szPath[MAX_PATH];
  507.         if (pszPath)
  508.         {
  509. #ifdef WINNT
  510.             if (!PathUnExpandEnvStrings(pszPath, szPath, ARRAYSIZE(szPath)))
  511.                 lstrcpyn(szPath, pszPath, ARRAYSIZE(szPath));
  512.             RegSetValueEx(hkey, pszFolder, 0, REG_EXPAND_SZ, (BYTE *)szPath, (lstrlen(szPath) + 1) * sizeof(TCHAR));
  513. #else
  514.             lstrcpyn(szPath, pszPath, ARRAYSIZE(szPath));
  515.             RegSetValueEx(hkey, pszFolder, 0, REG_SZ, (BYTE *)szPath, (lstrlen(szPath) + 1) * sizeof(TCHAR));
  516. #endif
  517.         }
  518.         else
  519.             RegDeleteValue(hkey, pszFolder);
  520.         RegCloseKey(hkey);
  521.         
  522.         SHFlushSFCache();   // invalidate the shells folder cached to keep them in sync
  523.     }
  524. }
  525. // Change CSIDL_PERSONAL to the specified path.  If pszOld is NULL we
  526. // assume we're creating CSIDL_PERSONAL from setup, and can therefore
  527. // whack the registry directly.
  528. HRESULT ChangePersonalPath(LPCTSTR pszNew, LPCTSTR pszOld, BOOL* pfResetMyPics)
  529. {
  530.     HRESULT hr = S_OK;
  531.     BOOL fResetMyPics = TRUE;
  532.     BOOL fSetReadOnly = FALSE;
  533.     LPITEMIDLIST pidlOld = NULL, pidlNew = NULL;
  534.     TCHAR szNewPath[MAX_PATH], szOldPath[MAX_PATH];
  535.     szNewPath[0] = 0; 
  536.     szOldPath[0] = 0;
  537.     if (pszNew)
  538.         ExpandEnvironmentStrings(pszNew, szNewPath, ARRAYSIZE(szNewPath));
  539.     if (szNewPath[0] == 0)
  540.         return E_INVALIDARG;
  541.     if (pszOld)
  542.         ExpandEnvironmentStrings(pszOld, szOldPath, ARRAYSIZE(szOldPath));
  543.     if (szOldPath[0])
  544.     {
  545.         TCHAR szMyPics[MAX_PATH];
  546.         if (S_OK == SHGetFolderPath(NULL, CSIDL_MYPICTURES | CSIDL_FLAG_DONT_VERIFY, NULL, SHGFP_TYPE_CURRENT, szMyPics))
  547.         {
  548.             fResetMyPics = (PATH_IS_CHILD == ComparePaths(szMyPics, szOldPath));
  549.         }
  550.         // Check if old target folder is read only.
  551.         DWORD dwAtt = GetFileAttributes(szOldPath);
  552.         if (0xFFFFFFFF != dwAtt)
  553.         {
  554.             fSetReadOnly = (FILE_ATTRIBUTE_READONLY == (dwAtt & FILE_ATTRIBUTE_READONLY));
  555.         }
  556.         // pidlOld may be NULL if the szOldPath does not exist
  557.         pidlOld = ILCreateFromPath(szOldPath);
  558.         // Clean up old attributes and desktop.ini, if possible...
  559.         MyDocsUnmakeSystemFolder(szOldPath);
  560.     }
  561.     pidlNew = ILCreateFromPath(szNewPath);
  562.     if (pidlNew)
  563.     {
  564.         // Restore read only settings from old target. Needed to ensure customized
  565.         // WebView settings are rendered (348749)
  566.         if (fSetReadOnly)
  567.         {
  568.             SetFileAttributes(szNewPath, FILE_ATTRIBUTE_READONLY);
  569.         }
  570.         
  571.         SetFolderPath(c_szPersonal, szNewPath);
  572.         SHChangeNotify( SHCNE_UPDATEITEM, SHCNF_IDLIST, pidlNew, NULL );
  573.         ILFree( pidlNew );
  574.     }
  575.     else
  576.         hr = E_FAIL;
  577.     if (pidlOld)
  578.     {
  579.         SHChangeNotify( SHCNE_UPDATEITEM, SHCNF_IDLIST, pidlOld, NULL );
  580.         ILFree( pidlOld );
  581.     }
  582.     if (pfResetMyPics)
  583.         *pfResetMyPics = fResetMyPics;
  584.     return hr;
  585. }
  586. void ChangeMyPicsPath( LPCTSTR pszNewPath, LPCTSTR pszOldPath )
  587. {
  588.     ASSERT( pszOldPath );
  589.     if( *pszOldPath )
  590.     {
  591.         MyPicsUnmakeSystemFolder( pszOldPath );
  592.     }
  593.     SetFolderPath( c_szMyPics, pszNewPath );
  594.     InstallMyPictures();
  595. }
  596. void ResetMyPics(LPCTSTR pszOldMyPics)
  597. {
  598.     TCHAR   szPath[MAX_PATH];
  599.     ChangeMyPicsPath( NULL, pszOldMyPics );
  600.     // 99/05/24 #341098 vtan: When the call to SetFolderPath() in
  601.     // InstallMyPictures() was removed for #316476 that introduced
  602.     // this bug. Put back the functionality but make it specific
  603.     // to ResetMyPics() which deliberately removes the entry so
  604.     // that the default install case doesn't mess with the USF
  605.     // registry value.
  606.     if (S_OK == SHGetFolderPath(NULL, CSIDL_MYPICTURES | CSIDL_FLAG_CREATE, NULL, SHGFP_TYPE_CURRENT, szPath))
  607.     {
  608.         SetFolderPath(c_szMyPics, szPath);
  609.     }
  610. }
  611. void InstallMyPictures()
  612. {
  613.     TCHAR szPath[MAX_PATH];
  614.     // Create the My Pictures folder
  615.     HRESULT hr = SHGetFolderPath(NULL, CSIDL_MYPICTURES | CSIDL_FLAG_CREATE, NULL, SHGFP_TYPE_CURRENT, szPath);
  616.     if (hr == S_OK)
  617.     {
  618.         // Set the default custom settings for the folder.
  619.         SHFOLDERCUSTOMSETTINGS fcs = {sizeof(fcs), FCSM_VIEWID | FCSM_WEBVIEWTEMPLATE | FCSM_ICONFILE | FCSM_INFOTIP, 0};
  620.         SHELLVIEWID vid = CLSID_ThumbnailViewExt;
  621.         fcs.pvid = &vid;
  622.         TCHAR szWebViewTemplate[MAX_PATH];
  623.         GetWindowsDirectory(szWebViewTemplate, ARRAYSIZE(szWebViewTemplate));
  624.         PathAppend(szWebViewTemplate, TEXT("Web\ImgView.htt"));
  625.         fcs.pszWebViewTemplate = szWebViewTemplate;   // template path
  626.         fcs.pszWebViewTemplateVersion = TEXT("NT5");   // template version
  627.         
  628.         TCHAR szInfoTip[128];
  629.         LoadString(g_hInstance, IDS_MYPICS_INFOTIP, szInfoTip, ARRAYSIZE(szInfoTip) );
  630.         fcs.pszInfoTip = szInfoTip;
  631.         // Get the IconFile and IconIndex for the Recent Files Folder
  632.         // BUGBUG: Ideally, we could just write "mydocs.dll" or
  633.         // "%SystemRoot%system32mydocs.dll", but neither work,
  634.         // so we write the full path here:
  635.         TCHAR szIconFile[MAX_PATH];
  636.         GetSystemDirectory(szIconFile, ARRAYSIZE(szIconFile));
  637.         PathAppend(szIconFile, TEXT("mydocs.dll"));
  638.         fcs.pszIconFile = szIconFile;
  639.         fcs.iIconIndex = -IDI_MYPICS;
  640.         // NOTE: we need FCS_FORCEWRITE because we didn't used to specify iIconIndex
  641.         // and so "0" was written to the ini file.  When we upgrade, this API won't
  642.         // fix the ini file unless we pass FCS_FORCEWRITE
  643.         SHGetSetFolderCustomSettings(&fcs, szPath, FCS_FORCEWRITE);
  644.     }
  645. }
  646. #define _ILSkip(pidl, cb)       ((LPITEMIDLIST)(((BYTE*)(pidl))+cb))
  647. #define _ILNext(pidl)           _ILSkip(pidl, (pidl)->mkid.cb)
  648. BOOL IsMyDocsIDList(LPCITEMIDLIST pidl)
  649. {
  650.     if (pidl && !ILIsEmpty(pidl) && ILIsEmpty(_ILNext(pidl)))
  651.     {
  652.         BOOL bIsMyDocs = FALSE;
  653.         IShellFolder *psf;
  654.         if (SUCCEEDED(SHGetDesktopFolder(&psf)))
  655.         {
  656.             LPITEMIDLIST pidlMyDocs = MyDocsIDList();
  657.             if (pidlMyDocs)
  658.             {
  659.                 bIsMyDocs = psf->CompareIDs(0, pidl, pidlMyDocs) == 0;
  660.                 ILFree(pidlMyDocs);
  661.             }
  662.             psf->Release();
  663.         }
  664.         return bIsMyDocs;
  665.     }
  666.     return FALSE;
  667. }