Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1247 lines
40 KiB

  1. #include "shellprv.h"
  2. #include "util.h"
  3. #include "ids.h"
  4. #include "infotip.h"
  5. #include "fstreex.h"
  6. #include "lm.h"
  7. #include "shgina.h"
  8. #include "prop.h"
  9. #include "datautil.h"
  10. #include "filefldr.h"
  11. #include "buytasks.h"
  12. #pragma hdrstop
  13. // this define causes the shared folder code to work on domains (for debug)
  14. //#define SHOW_SHARED_FOLDERS
  15. // filter out the current user accounts
  16. #define FILTER_CURRENT_USER 0
  17. // where do we store the doc folder paths
  18. #define REGSTR_PATH_DOCFOLDERPATH TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\DocFolderPaths")
  19. // state API for showing the shared documents folder
  20. STDAPI_(BOOL) SHShowSharedFolders()
  21. {
  22. #ifndef SHOW_SHARED_FOLDERS
  23. // restriction overrides all logic for the shared documents
  24. if (SHRestricted(REST_NOSHAREDDOCUMENTS))
  25. return FALSE;
  26. // if we haven't computed the "show shared folders flag" then do so
  27. static int iShow = -1;
  28. if (iShow == -1)
  29. iShow = (IsOS(OS_DOMAINMEMBER) || IsOS(OS_ANYSERVER)) ? 0:1; // only works if we are not a domain/server user
  30. return (iShow >= 1);
  31. #else
  32. return true;
  33. #endif
  34. }
  35. // implementation of a delegate shell folder for merging in shared documents
  36. STDAPI_(void) SHChangeNotifyRegisterAlias(LPCITEMIDLIST pidlReal, LPCITEMIDLIST pidlAlias);
  37. HRESULT CSharedDocsEnum_CreateInstance(HDPA hItems, DWORD grfFlags, IEnumIDList **ppenum);
  38. #pragma pack(1)
  39. typedef struct
  40. {
  41. // these memebers overlap DELEGATEITEMID struct
  42. // for our IDelegateFolder support
  43. WORD cbSize;
  44. WORD wOuter;
  45. WORD cbInner;
  46. // our stuff
  47. DWORD dwType; // our type of folder
  48. TCHAR wszID[1]; // unique ID for the user
  49. } SHAREDITEM;
  50. #pragma pack()
  51. typedef UNALIGNED SHAREDITEM * LPSHAREDITEM;
  52. typedef const UNALIGNED SHAREDITEM * LPCSHAREDITEM;
  53. #define SHAREDID_COMMON 0x0
  54. #define SHAREDID_USER 0x2
  55. class CSharedDocuments : public IDelegateFolder, IPersistFolder2, IShellFolder2, IShellIconOverlay
  56. {
  57. public:
  58. CSharedDocuments();
  59. ~CSharedDocuments();
  60. // IUnknown
  61. STDMETHOD(QueryInterface)(REFIID riid, void **ppv);
  62. STDMETHOD_(ULONG, AddRef)();
  63. STDMETHOD_(ULONG, Release)();
  64. // IDelegateFolder
  65. STDMETHODIMP SetItemAlloc(IMalloc *pmalloc);
  66. // IPersist
  67. STDMETHODIMP GetClassID(CLSID* pclsid)
  68. { *pclsid = CLSID_SharedDocuments; return S_OK; }
  69. // IPersistFolder
  70. STDMETHODIMP Initialize(LPCITEMIDLIST pidl);
  71. // IPersistFolder2
  72. STDMETHODIMP GetCurFolder(LPITEMIDLIST* ppidl);
  73. // IShellFolder
  74. STDMETHODIMP ParseDisplayName(HWND hwnd, LPBC pbc, LPOLESTR lpszDisplayName, ULONG* pchEaten, LPITEMIDLIST* ppidl, ULONG* pdwAttributes);
  75. STDMETHODIMP EnumObjects(HWND hwnd, DWORD grfFlags, IEnumIDList **ppenumIDList);
  76. STDMETHODIMP BindToObject(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppv);
  77. STDMETHODIMP BindToStorage(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppv)
  78. { return BindToObject(pidl, pbc, riid, ppv); }
  79. STDMETHODIMP CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2);
  80. STDMETHODIMP CreateViewObject(HWND hwnd, REFIID riid, void **ppv)
  81. { return E_NOTIMPL; }
  82. STDMETHODIMP GetAttributesOf(UINT cidl, LPCITEMIDLIST* apidl, ULONG* rgfInOut);
  83. STDMETHODIMP GetUIObjectOf(HWND hwnd, UINT cidl, LPCITEMIDLIST* apidl,REFIID riid, UINT* prgfInOut, void **ppv);
  84. STDMETHODIMP GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD uFlags, LPSTRRET lpName);
  85. STDMETHODIMP SetNameOf(HWND hwnd, LPCITEMIDLIST pidl, LPCOLESTR lpszName, DWORD uFlags, LPITEMIDLIST* ppidlOut)
  86. { return E_NOTIMPL; }
  87. // IShellFolder2
  88. STDMETHODIMP GetDefaultSearchGUID(LPGUID lpGuid)
  89. { return E_NOTIMPL; }
  90. STDMETHODIMP EnumSearches(LPENUMEXTRASEARCH *ppenum)
  91. { return E_NOTIMPL; }
  92. STDMETHODIMP GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay)
  93. { return E_NOTIMPL; }
  94. STDMETHODIMP GetDefaultColumnState(UINT iColumn, DWORD *pbState)
  95. { return E_NOTIMPL; }
  96. STDMETHODIMP GetDetailsEx(LPCITEMIDLIST pidl, const SHCOLUMNID *pscid, VARIANT *pv);
  97. STDMETHODIMP GetDetailsOf(LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS *pDetails)
  98. { return E_NOTIMPL; }
  99. STDMETHODIMP MapColumnToSCID(UINT iCol, SHCOLUMNID *pscid)
  100. { return E_NOTIMPL; }
  101. // IShellIconOverlay
  102. STDMETHODIMP GetOverlayIndex(LPCITEMIDLIST pidl, int *pIndex)
  103. { return _GetOverlayIndex(pidl, pIndex, FALSE); }
  104. STDMETHODIMP GetOverlayIconIndex(LPCITEMIDLIST pidl, int *pIconIndex)
  105. { return _GetOverlayIndex(pidl, pIconIndex, TRUE); }
  106. private:
  107. LONG _cRef;
  108. IMalloc *_pmalloc;
  109. LPITEMIDLIST _pidl;
  110. CRITICAL_SECTION _cs; // critical section for managing lifetime of the cache
  111. TCHAR _szCurrentUser[UNLEN+1]; // user name (cached for current user)
  112. BOOL _fCachedAllUser:1; // cached the all user account
  113. TCHAR _szCachedUser[UNLEN+1]; // if (FALSE) then this contains the user ID.
  114. IUnknown *_punkCached; // IUnknown object (from FS folder) that we cache
  115. LPITEMIDLIST _pidlCached; // IDLIST of the cached folder
  116. void _ClearCachedObjects();
  117. BOOL _IsCached(LPCITEMIDLIST pidl);
  118. HRESULT _CreateFolder(LPBC pbc, LPCITEMIDLIST pidl, REFIID riid, void **ppv, BOOL fRegisterAlias);
  119. HRESULT _GetTarget(LPCITEMIDLIST pidl, LPITEMIDLIST *ppidl);
  120. HRESULT _GetTargetIDList(BOOL fForceReCache, LPCITEMIDLIST pidl, LPITEMIDLIST *ppidl);
  121. HRESULT _AddIDList(HDPA hdpa, DWORD dwType, LPCTSTR pszUser);
  122. HRESULT _AllocIDList(DWORD dwType, LPCTSTR pszUser, LPITEMIDLIST *ppidl);
  123. HRESULT _GetSharedFolders(HDPA *phItems);
  124. HRESULT _GetAttributesOf(LPCITEMIDLIST pidl, DWORD rgfIn, DWORD *prgfOut);
  125. LPCTSTR _GetUserFromIDList(LPCITEMIDLIST pidl, LPTSTR pszBuffer, INT cchBuffer);
  126. HRESULT _GetPathForUser(LPCTSTR pcszUser, LPTSTR pszBuffer, int cchBuffer);
  127. HRESULT _GetOverlayIndex(LPCITEMIDLIST pidl, int *pIndex, BOOL fIcon);
  128. static HRESULT s_FolderMenuCB(IShellFolder *psf, HWND hwnd, IDataObject *pdo, UINT uMsg, WPARAM wParam, LPARAM lParam);
  129. friend class CSharedDocsEnum;
  130. };
  131. // constructors
  132. CSharedDocuments::CSharedDocuments() :
  133. _cRef(1)
  134. {
  135. InitializeCriticalSection(&_cs);
  136. }
  137. CSharedDocuments::~CSharedDocuments()
  138. {
  139. ATOMICRELEASE(_pmalloc);
  140. ATOMICRELEASE(_punkCached);
  141. ILFree(_pidlCached);
  142. ILFree(_pidl);
  143. DeleteCriticalSection(&_cs);
  144. }
  145. STDAPI CSharedDocFolder_CreateInstance(IUnknown *punkOut, REFIID riid, void **ppv)
  146. {
  147. CSharedDocuments *psdf = new CSharedDocuments;
  148. if (!psdf)
  149. return E_OUTOFMEMORY;
  150. HRESULT hr = psdf->QueryInterface(riid, ppv);
  151. psdf->Release();
  152. return hr;
  153. }
  154. // IUnknown handling
  155. STDMETHODIMP CSharedDocuments::QueryInterface(REFIID riid, void **ppv)
  156. {
  157. static const QITAB qit[] =
  158. {
  159. QITABENT(CSharedDocuments, IDelegateFolder), // IID_IDelegateFolder
  160. QITABENTMULTI(CSharedDocuments, IShellFolder, IShellFolder2), // IID_IShellFOlder
  161. QITABENT(CSharedDocuments, IShellFolder2), // IID_IShellFolder2
  162. QITABENTMULTI(CSharedDocuments, IPersistFolder, IPersistFolder2), // IID_IPersistFolder
  163. QITABENTMULTI(CSharedDocuments, IPersist, IPersistFolder2), // IID_IPersist
  164. QITABENT(CSharedDocuments, IPersistFolder2), // IID_IPersistFolder2
  165. QITABENT(CSharedDocuments, IShellIconOverlay), // IID_IShellIconOverlay
  166. QITABENTMULTI2(CSharedDocuments, IID_IPersistFreeThreadedObject, IPersist), // IID_IPersistFreeThreadedObject
  167. { 0 },
  168. };
  169. if (riid == CLSID_SharedDocuments)
  170. {
  171. *ppv = this; // no ref
  172. return S_OK;
  173. }
  174. return QISearch(this, qit, riid, ppv);
  175. }
  176. STDMETHODIMP_(ULONG) CSharedDocuments::AddRef()
  177. {
  178. return InterlockedIncrement(&_cRef);
  179. }
  180. STDMETHODIMP_(ULONG) CSharedDocuments::Release()
  181. {
  182. ASSERT( 0 != _cRef );
  183. ULONG cRef = InterlockedDecrement(&_cRef);
  184. if ( 0 == cRef )
  185. {
  186. delete this;
  187. }
  188. return cRef;
  189. }
  190. // IDelegateFolder
  191. HRESULT CSharedDocuments::SetItemAlloc(IMalloc *pmalloc)
  192. {
  193. IUnknown_Set((IUnknown**)&_pmalloc, pmalloc);
  194. return S_OK;
  195. }
  196. HRESULT CSharedDocuments::Initialize(LPCITEMIDLIST pidl)
  197. {
  198. ILFree(_pidl);
  199. return SHILClone(pidl, &_pidl);
  200. }
  201. HRESULT CSharedDocuments::GetCurFolder(LPITEMIDLIST* ppidl)
  202. {
  203. return SHILClone(_pidl, ppidl);
  204. }
  205. // single level cache for the objects
  206. void CSharedDocuments::_ClearCachedObjects()
  207. {
  208. ATOMICRELEASE(_punkCached); // clear out the cached items (old)
  209. ILFree(_pidlCached);
  210. _pidlCached = NULL;
  211. }
  212. BOOL CSharedDocuments::_IsCached(LPCITEMIDLIST pidl)
  213. {
  214. BOOL fResult = FALSE;
  215. TCHAR szUser[UNLEN+1];
  216. if (_GetUserFromIDList(pidl, szUser, ARRAYSIZE(szUser)))
  217. {
  218. // did we cache the users account information?
  219. if (!_szCachedUser[0] || (StrCmpI(_szCachedUser, szUser) != 0))
  220. {
  221. _fCachedAllUser = FALSE;
  222. StrCpyN(_szCachedUser, szUser, ARRAYSIZE(_szCachedUser));
  223. _ClearCachedObjects();
  224. }
  225. else
  226. {
  227. fResult = TRUE; // were set!
  228. }
  229. }
  230. else
  231. {
  232. // the all user case is keyed on a flag rather than the
  233. // account name we are supposed to be using.
  234. if (!_fCachedAllUser)
  235. {
  236. _fCachedAllUser = TRUE;
  237. _szCachedUser[0] = TEXT('\0');
  238. _ClearCachedObjects();
  239. }
  240. else
  241. {
  242. fResult = TRUE; // were set
  243. }
  244. }
  245. return fResult;
  246. }
  247. // IShellFolder methods
  248. HRESULT CSharedDocuments::_CreateFolder(LPBC pbc, LPCITEMIDLIST pidl, REFIID riid, void **ppv, BOOL fRegisterAlias)
  249. {
  250. HRESULT hr = S_OK;
  251. EnterCriticalSection(&_cs);
  252. // get the target folder (were already in a critical section)
  253. // and then bind down to the shell folder if we have not already
  254. // cached one for ourselves.
  255. if (!_IsCached(pidl) || !_punkCached)
  256. {
  257. LPITEMIDLIST pidlTarget;
  258. hr = _GetTargetIDList(TRUE, pidl, &pidlTarget); // clears _punkCached in here (so no leak)
  259. if (SUCCEEDED(hr))
  260. {
  261. LPITEMIDLIST pidlInit;
  262. hr = SHILCombine(_pidl, pidl, &pidlInit);
  263. if (SUCCEEDED(hr))
  264. {
  265. hr = SHCoCreateInstance(NULL, &CLSID_ShellFSFolder, NULL, IID_PPV_ARG(IUnknown, &_punkCached));
  266. if (SUCCEEDED(hr))
  267. {
  268. IPersistFolder3 *ppf;
  269. hr = _punkCached->QueryInterface(IID_PPV_ARG(IPersistFolder3, &ppf));
  270. if (SUCCEEDED(hr))
  271. {
  272. PERSIST_FOLDER_TARGET_INFO pfti = {0};
  273. pfti.pidlTargetFolder = (LPITEMIDLIST)pidlTarget;
  274. pfti.dwAttributes = FILE_ATTRIBUTE_DIRECTORY;
  275. pfti.csidl = -1;
  276. hr = ppf->InitializeEx(NULL, pidlInit, &pfti);
  277. ppf->Release();
  278. }
  279. if (SUCCEEDED(hr) && fRegisterAlias)
  280. SHChangeNotifyRegisterAlias(pidlTarget, pidlInit);
  281. if (FAILED(hr))
  282. {
  283. _punkCached->Release();
  284. _punkCached = NULL;
  285. }
  286. }
  287. ILFree(pidlInit);
  288. }
  289. ILFree(pidlTarget);
  290. }
  291. }
  292. if (SUCCEEDED(hr))
  293. hr = _punkCached->QueryInterface(riid, ppv);
  294. LeaveCriticalSection(&_cs);
  295. return hr;
  296. }
  297. HRESULT CSharedDocuments::_GetTarget(LPCITEMIDLIST pidl, LPITEMIDLIST *ppidl)
  298. {
  299. EnterCriticalSection(&_cs);
  300. HRESULT hr = _GetTargetIDList(FALSE, pidl, ppidl);
  301. LeaveCriticalSection(&_cs);
  302. return hr;
  303. }
  304. HRESULT CSharedDocuments::_GetTargetIDList(BOOL fForceReCache, LPCITEMIDLIST pidl, LPITEMIDLIST *ppidl)
  305. {
  306. HRESULT hr = S_OK;
  307. if (fForceReCache || !_IsCached(pidl) || !_pidlCached)
  308. {
  309. _ClearCachedObjects(); // we don't have it cached now
  310. LPCSHAREDITEM psid = (LPCSHAREDITEM)pidl;
  311. if (psid->dwType == SHAREDID_COMMON)
  312. {
  313. hr = SHGetSpecialFolderLocation(NULL, CSIDL_COMMON_DOCUMENTS|CSIDL_FLAG_NO_ALIAS, &_pidlCached);
  314. }
  315. else if (psid->dwType == SHAREDID_USER)
  316. {
  317. TCHAR szPath[MAX_PATH], szUser[UNLEN+1];
  318. hr = _GetPathForUser(_GetUserFromIDList(pidl, szUser, ARRAYSIZE(szUser)), szPath, ARRAYSIZE(szPath));
  319. if (SUCCEEDED(hr))
  320. {
  321. hr = ILCreateFromPathEx(szPath, NULL, ILCFP_FLAG_NO_MAP_ALIAS, &_pidlCached, NULL);
  322. }
  323. }
  324. else
  325. {
  326. hr = E_INVALIDARG; // invalid IDLIST passed
  327. }
  328. }
  329. if (SUCCEEDED(hr))
  330. hr = SHILClone(_pidlCached, ppidl);
  331. return hr;
  332. }
  333. HRESULT CSharedDocuments::_AddIDList(HDPA hdpa, DWORD dwType, LPCTSTR pszUser)
  334. {
  335. LPITEMIDLIST pidl;
  336. HRESULT hr = _AllocIDList(dwType, pszUser, &pidl);
  337. if (SUCCEEDED(hr))
  338. {
  339. DWORD grfFlags = SFGAO_FOLDER;
  340. hr = _GetAttributesOf(pidl, SFGAO_FOLDER, &grfFlags);
  341. if (SUCCEEDED(hr) && grfFlags & SFGAO_FOLDER)
  342. {
  343. if (-1 == DPA_AppendPtr(hdpa, pidl))
  344. {
  345. ILFree(pidl);
  346. hr = E_OUTOFMEMORY;
  347. }
  348. else
  349. {
  350. hr = S_OK;
  351. }
  352. }
  353. else
  354. {
  355. ILFree(pidl);
  356. }
  357. }
  358. return hr;
  359. }
  360. HRESULT CSharedDocuments::_AllocIDList(DWORD dwType, LPCTSTR pszUser, LPITEMIDLIST *ppidl)
  361. {
  362. DWORD cb = sizeof(SHAREDITEM);
  363. int cchUser = pszUser ? lstrlen(pszUser) + 1 : 0;
  364. // ID list contains strings if its a user
  365. if (dwType == SHAREDID_USER)
  366. cb += sizeof(TCHAR) * cchUser;
  367. SHAREDITEM *psid = (SHAREDITEM*)_pmalloc->Alloc(cb);
  368. if (!psid)
  369. return E_OUTOFMEMORY;
  370. psid->dwType = dwType; // type is universal
  371. if (dwType == SHAREDID_USER)
  372. StrCpyW(psid->wszID, pszUser); // strcpy okay, just got allocated
  373. *ppidl = (LPITEMIDLIST)psid;
  374. return S_OK;
  375. }
  376. LPCTSTR CSharedDocuments::_GetUserFromIDList(LPCITEMIDLIST pidl, LPTSTR pszUser, int cchUser)
  377. {
  378. LPCSHAREDITEM psid = (LPCSHAREDITEM)pidl;
  379. if (psid->dwType == SHAREDID_COMMON)
  380. {
  381. pszUser[0] = 0; // initialize
  382. return NULL;
  383. }
  384. ualstrcpynW(pszUser, psid->wszID, cchUser);
  385. return pszUser;
  386. }
  387. HRESULT CSharedDocuments::_GetPathForUser(LPCTSTR pszUser, LPTSTR pszBuffer, int cchBuffer)
  388. {
  389. HRESULT hr = E_FAIL;
  390. BOOL fResult = FALSE;
  391. if (!pszUser)
  392. {
  393. // get the common documents path (which covers all users), this user is always defined
  394. // so lets return TRUE if they just want to check to see if its defined, otherwise
  395. // just pass out the result from fetching the path.
  396. fResult = !pszBuffer || ((cchBuffer >= MAX_PATH) && SHGetSpecialFolderPath(NULL, pszBuffer, CSIDL_COMMON_DOCUMENTS, FALSE));
  397. }
  398. else
  399. {
  400. // we have a user ID, so lets attempt to get the path fro that from the registry
  401. // if we get it then pass it back to the caller.
  402. DWORD dwType;
  403. DWORD cbBuffer = cchBuffer*sizeof(TCHAR);
  404. if (ERROR_SUCCESS == SHGetValue(HKEY_LOCAL_MACHINE, REGSTR_PATH_DOCFOLDERPATH, pszUser, &dwType, pszBuffer, &cbBuffer))
  405. {
  406. fResult = ((dwType == REG_SZ) && cbBuffer); // did we get a value back?
  407. }
  408. }
  409. if (fResult)
  410. {
  411. hr = S_OK;
  412. }
  413. return hr;
  414. }
  415. HRESULT CSharedDocuments::_GetSharedFolders(HDPA *phItems)
  416. {
  417. HRESULT hr = E_OUTOFMEMORY;
  418. HDPA hItems = DPA_Create(16);
  419. if (hItems)
  420. {
  421. if (!IsUserAGuest()) // all other users' my documents folders should appear in my computer for non-guest users on workgroup machines
  422. {
  423. ILogonEnumUsers *peu;
  424. hr = SHCoCreateInstance(NULL, &CLSID_ShellLogonEnumUsers, NULL, IID_PPV_ARG(ILogonEnumUsers, &peu));
  425. if (SUCCEEDED(hr))
  426. {
  427. UINT cUsers, iUser;
  428. hr = peu->get_length(&cUsers);
  429. for (iUser = 0; (cUsers != iUser) && SUCCEEDED(hr); iUser++)
  430. {
  431. VARIANT varUser = {VT_I4};
  432. InitVariantFromInt(&varUser, iUser);
  433. ILogonUser *plu;
  434. hr = peu->item(varUser, &plu);
  435. if (SUCCEEDED(hr))
  436. {
  437. // only show document folders for users that can log in
  438. VARIANT_BOOL vbLogonAllowed;
  439. hr = plu->get_interactiveLogonAllowed(&vbLogonAllowed);
  440. if (SUCCEEDED(hr) && (vbLogonAllowed != VARIANT_FALSE))
  441. {
  442. // get the user name as this is our key to to the users documents path
  443. VARIANT var = {0};
  444. hr = plu->get_setting(L"LoginName", &var);
  445. if (SUCCEEDED(hr))
  446. {
  447. #if FILTER_CURRENT_USER
  448. if (!_szCurrentUser[0])
  449. {
  450. DWORD cchUser = ARRAYSIZE(_szCurrentUser);
  451. if (!GetUserName(_szCurrentUser, &cchUser))
  452. {
  453. _szCurrentUser[0] = TEXT('\0');
  454. }
  455. }
  456. if (!_szCurrentUser[0] || (StrCmpI(var.bstrVal, _szCurrentUser) != 0))
  457. {
  458. HRESULT hrT = _AddIDList(hItems, SHAREDID_USER, var.bstrVal);
  459. if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hrT)
  460. {
  461. SHDeleteValue(HKEY_LOCAL_MACHINE, REGSTR_PATH_DOCFOLDERPATH, var.bstrVal);
  462. }
  463. }
  464. #else
  465. HRESULT hrT = _AddIDList(hItems, SHAREDID_USER, var.bstrVal);
  466. if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hrT)
  467. {
  468. SHDeleteValue(HKEY_LOCAL_MACHINE, REGSTR_PATH_DOCFOLDERPATH, var.bstrVal);
  469. }
  470. #endif
  471. VariantClear(&var);
  472. }
  473. }
  474. plu->Release();
  475. }
  476. }
  477. peu->Release();
  478. }
  479. }
  480. _AddIDList(hItems, SHAREDID_COMMON, NULL);
  481. hr = S_OK;
  482. }
  483. *phItems = hItems;
  484. return hr;
  485. }
  486. // parsing support allows us to pick off SharedDocuments from the root
  487. // of the shell namespace and navigate there - this a canonical name
  488. // that we use for binding to the shared documents folder attached
  489. // to the My Computer namespace.
  490. HRESULT CSharedDocuments::ParseDisplayName(HWND hwnd, LPBC pbc, LPTSTR pszName, ULONG* pchEaten, LPITEMIDLIST* ppidl, ULONG* pdwAttributes)
  491. {
  492. HRESULT hr = E_INVALIDARG;
  493. if (SHShowSharedFolders())
  494. {
  495. if (0 == StrCmpI(pszName, L"SharedDocuments"))
  496. {
  497. hr = _AllocIDList(SHAREDID_COMMON, NULL, ppidl);
  498. if (SUCCEEDED(hr) && pdwAttributes)
  499. {
  500. hr = _GetAttributesOf(*ppidl, *pdwAttributes, pdwAttributes);
  501. }
  502. }
  503. }
  504. return hr;
  505. }
  506. // enumerate the shared documents folders
  507. HRESULT CSharedDocuments::EnumObjects(HWND hwnd, DWORD grfFlags, IEnumIDList **ppenumIDList)
  508. {
  509. *ppenumIDList = NULL; // no enumerator yet
  510. HRESULT hr = S_FALSE;
  511. if (SHShowSharedFolders())
  512. {
  513. HDPA hItems;
  514. hr = _GetSharedFolders(&hItems);
  515. if (SUCCEEDED(hr))
  516. {
  517. hr = CSharedDocsEnum_CreateInstance(hItems, grfFlags, ppenumIDList);
  518. if (FAILED(hr))
  519. {
  520. DPA_FreeIDArray(hItems);
  521. }
  522. }
  523. }
  524. return hr;
  525. }
  526. // return the display name for the folders that we have
  527. HRESULT CSharedDocuments::GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD uFlags, LPSTRRET lpName)
  528. {
  529. HRESULT hr = S_OK;
  530. TCHAR szName[MAX_PATH] = {0};
  531. LPCSHAREDITEM psid = (LPCSHAREDITEM)pidl;
  532. if (((uFlags & (SHGDN_INFOLDER|SHGDN_FORPARSING)) == SHGDN_INFOLDER) &&
  533. (psid && (psid->dwType == SHAREDID_USER)))
  534. {
  535. // compute the <user>'s Documents name that we will show, we key this on
  536. // the user name we have in the IDList and its display string.
  537. USER_INFO_10 *pui;
  538. TCHAR szUser[MAX_PATH];
  539. if (NERR_Success == NetUserGetInfo(NULL, _GetUserFromIDList(pidl, szUser, ARRAYSIZE(szUser)), 10, (LPBYTE*)&pui))
  540. {
  541. if (*pui->usri10_full_name)
  542. {
  543. StrCpyN(szUser, pui->usri10_full_name, ARRAYSIZE(szUser));
  544. }
  545. NetApiBufferFree(pui);
  546. }
  547. TCHAR szFmt[MAX_PATH];
  548. LoadString(g_hinst, IDS_LOCALGDN_FLD_THEIRDOCUMENTS, szFmt, ARRAYSIZE(szFmt));
  549. wnsprintf(szName, ARRAYSIZE(szName), szFmt, szUser);
  550. }
  551. else
  552. {
  553. // all other scenarios dump down to the real folder to get their display
  554. // name for this folder.
  555. LPITEMIDLIST pidlTarget;
  556. hr = _GetTarget(pidl, &pidlTarget);
  557. if (SUCCEEDED(hr))
  558. {
  559. hr = SHGetNameAndFlags(pidlTarget, uFlags, szName, ARRAYSIZE(szName), NULL);
  560. ILFree(pidlTarget);
  561. }
  562. }
  563. if (SUCCEEDED(hr))
  564. hr = StringToStrRet(szName, lpName);
  565. return hr;
  566. }
  567. LONG CSharedDocuments::_GetAttributesOf(LPCITEMIDLIST pidl, DWORD rgfIn, DWORD *prgfOut)
  568. {
  569. DWORD dwResult = rgfIn;
  570. LPITEMIDLIST pidlTarget;
  571. HRESULT hr = _GetTarget(pidl, &pidlTarget);
  572. if (SUCCEEDED(hr))
  573. {
  574. IShellFolder *psf;
  575. LPCITEMIDLIST pidlChild;
  576. hr = SHBindToIDListParent(pidlTarget, IID_PPV_ARG(IShellFolder, &psf), &pidlChild);
  577. if (SUCCEEDED(hr))
  578. {
  579. hr = psf->GetAttributesOf(1, &pidlChild, &dwResult);
  580. psf->Release();
  581. }
  582. ILFree(pidlTarget);
  583. }
  584. if (!SHShowSharedFolders())
  585. dwResult |= SFGAO_NONENUMERATED;
  586. *prgfOut = *prgfOut & (dwResult & ~(SFGAO_CANDELETE|SFGAO_CANRENAME|SFGAO_CANMOVE|SFGAO_CANCOPY));
  587. return hr;
  588. }
  589. HRESULT CSharedDocuments::GetAttributesOf(UINT cidl, LPCITEMIDLIST* apidl, ULONG* rgfInOut)
  590. {
  591. ULONG rgfOut = *rgfInOut;
  592. if (!cidl || !apidl)
  593. return E_INVALIDARG;
  594. for (UINT i = 0; i < cidl; i++)
  595. _GetAttributesOf(apidl[i], *rgfInOut, &rgfOut);
  596. *rgfInOut = rgfOut;
  597. return S_OK;
  598. }
  599. // bind through our folder
  600. HRESULT CSharedDocuments::BindToObject(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppv)
  601. {
  602. HRESULT hr = E_OUTOFMEMORY;
  603. if (IsEqualIID(riid, IID_IShellIconOverlay))
  604. {
  605. hr = this->QueryInterface(riid, ppv);
  606. }
  607. else
  608. {
  609. LPITEMIDLIST pidlFirst = ILCloneFirst(pidl);
  610. if (pidlFirst)
  611. {
  612. IShellFolder *psf;
  613. hr = _CreateFolder(pbc, pidlFirst, IID_PPV_ARG(IShellFolder, &psf), TRUE);
  614. if (SUCCEEDED(hr))
  615. {
  616. LPCITEMIDLIST pidlNext = _ILNext(pidl);
  617. if (ILIsEmpty(pidlNext))
  618. {
  619. hr = psf->QueryInterface(riid, ppv);
  620. }
  621. else
  622. {
  623. hr = psf->BindToObject(pidlNext, pbc, riid, ppv);
  624. }
  625. psf->Release();
  626. }
  627. ILFree(pidlFirst);
  628. }
  629. }
  630. return hr;
  631. }
  632. // handle UI objects - for the most part we delegate to the real namespace implementation
  633. HRESULT CSharedDocuments::s_FolderMenuCB(IShellFolder *psf, HWND hwnd, IDataObject *pdo, UINT uMsg, WPARAM wParam, LPARAM lParam)
  634. {
  635. CSharedDocuments *psd;
  636. psf->QueryInterface(CLSID_SharedDocuments, (void **)&psd);
  637. // defcm will only add the default handlers (eg. Open/Explore) if we have a callback
  638. // and the DFM_MERGECONTEXTMENU is successful. so lets honor that so we can navigate
  639. if (uMsg == DFM_MERGECONTEXTMENU)
  640. {
  641. return S_OK;
  642. }
  643. else if (uMsg == DFM_INVOKECOMMAND)
  644. {
  645. HRESULT hr;
  646. DFMICS *pdfmics = (DFMICS *)lParam;
  647. switch (wParam)
  648. {
  649. case DFM_CMD_LINK:
  650. hr = SHCreateLinks(hwnd, NULL, pdo, SHCL_CONFIRM|SHCL_USETEMPLATE|SHCL_USEDESKTOP, NULL);
  651. break;
  652. case DFM_CMD_PROPERTIES:
  653. hr = SHLaunchPropSheet(CFSFolder_PropertiesThread, pdo, (LPCTSTR)lParam, NULL, (void *)&c_idlDesktop);
  654. break;
  655. default:
  656. hr = S_FALSE; // use the default handler for this item
  657. break;
  658. }
  659. return hr;
  660. }
  661. return E_NOTIMPL;
  662. }
  663. HRESULT CSharedDocuments::GetUIObjectOf(HWND hwnd, UINT cidl, LPCITEMIDLIST* apidl, REFIID riid, UINT* prgfInOut, void **ppv)
  664. {
  665. if (cidl != 1)
  666. return E_FAIL;
  667. HRESULT hr = E_FAIL;
  668. if (IsEqualIID(riid, IID_IContextMenu))
  669. {
  670. // we must construct our own context menu for this item, we do this using the
  671. // shell default implementation and we pass it the information about a folder
  672. // that way we can navigate up and down through the namespace.
  673. IQueryAssociations *pqa;
  674. hr = GetUIObjectOf(hwnd, 1, apidl, IID_PPV_ARG_NULL(IQueryAssociations, &pqa));
  675. if (SUCCEEDED(hr))
  676. {
  677. // this is broken for docfiles (shell\ext\stgfldr's keys work though)
  678. // maybe because GetClassFile punts when it's not fs?
  679. HKEY ahk[MAX_ASSOC_KEYS];
  680. DWORD cKeys = SHGetAssocKeys(pqa, ahk, ARRAYSIZE(ahk));
  681. hr = CDefFolderMenu_Create2(_pidl, hwnd, cidl, apidl, this,
  682. s_FolderMenuCB,
  683. cKeys, ahk,
  684. (IContextMenu **)ppv);
  685. SHRegCloseKeys(ahk, cKeys);
  686. pqa->Release();
  687. }
  688. }
  689. else if (IsEqualIID(riid, IID_IDataObject))
  690. {
  691. hr = SHCreateFileDataObject(_pidl, cidl, apidl, NULL, (IDataObject **)ppv);
  692. }
  693. else if (IsEqualIID(riid, IID_IQueryInfo))
  694. {
  695. IQueryAssociations *pqa;
  696. hr = AssocCreate(CLSID_QueryAssociations, IID_PPV_ARG(IQueryAssociations, &pqa));
  697. if (SUCCEEDED(hr))
  698. {
  699. WCHAR szCLSID[GUIDSTR_MAX];
  700. SHStringFromGUIDW(CLSID_SharedDocuments, szCLSID, ARRAYSIZE(szCLSID));
  701. hr = pqa->Init(0, szCLSID, NULL, NULL);
  702. if (SUCCEEDED(hr))
  703. {
  704. WCHAR szInfotip[INFOTIPSIZE];
  705. DWORD cchInfotip = ARRAYSIZE(szInfotip);
  706. hr = pqa->GetString(0, ASSOCSTR_INFOTIP, NULL, szInfotip, &cchInfotip);
  707. if (SUCCEEDED(hr))
  708. {
  709. hr = CreateInfoTipFromText(szInfotip, IID_IQueryInfo, ppv); // _the_ InfoTip COM object
  710. }
  711. }
  712. pqa->Release();
  713. }
  714. }
  715. else if (IsEqualIID(riid, IID_IQueryAssociations))
  716. {
  717. LPITEMIDLIST pidlTarget;
  718. hr = _GetTarget(apidl[0], &pidlTarget);
  719. if (SUCCEEDED(hr))
  720. {
  721. hr = SHGetUIObjectOf(pidlTarget, hwnd, riid, ppv);
  722. ILFree(pidlTarget);
  723. }
  724. }
  725. else if (IsEqualIID(riid, IID_IExtractIconA) || IsEqualIID(riid, IID_IExtractIconW))
  726. {
  727. UINT iIcon = II_FOLDER;
  728. UINT iIconOpen = II_FOLDEROPEN;
  729. TCHAR szModule[MAX_PATH];
  730. GetModuleFileName(HINST_THISDLL, szModule, ARRAYSIZE(szModule));
  731. hr = SHCreateDefExtIcon(szModule, iIcon, iIconOpen, GIL_PERCLASS, -1, riid, ppv);
  732. }
  733. else if (IsEqualIID(riid, IID_IDropTarget))
  734. {
  735. IShellFolder *psf;
  736. hr = _CreateFolder(NULL, *apidl, IID_PPV_ARG(IShellFolder, &psf), TRUE);
  737. if (SUCCEEDED(hr))
  738. {
  739. hr = psf->CreateViewObject(hwnd, riid, ppv);
  740. psf->Release();
  741. }
  742. }
  743. return hr;
  744. }
  745. HRESULT CSharedDocuments::CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
  746. {
  747. HRESULT hr = ResultFromShort(0);
  748. // compare the contents of our IDLIST before we attemt to compare other elements
  749. // within it.
  750. LPCSHAREDITEM psid1 = (LPCSHAREDITEM)pidl1;
  751. LPCSHAREDITEM psid2 = (LPCSHAREDITEM)pidl2;
  752. if (psid1->dwType == psid2->dwType)
  753. {
  754. if (psid1->dwType == SHAREDID_USER)
  755. {
  756. hr = ResultFromShort(ualstrcmpi(psid1->wszID, psid2->wszID));
  757. }
  758. else
  759. {
  760. hr = ResultFromShort(0); // common item == common item?
  761. }
  762. }
  763. else
  764. {
  765. hr = ResultFromShort(psid1->dwType - psid2->dwType);
  766. }
  767. // if there was an exact match then lets compare the trailing elements of the IDLIST
  768. // if there are some (by binding down) etc.
  769. if (hr == ResultFromShort(0))
  770. {
  771. LPITEMIDLIST pidlNext1 = _ILNext(pidl1);
  772. LPITEMIDLIST pidlNext2 = _ILNext(pidl2);
  773. if (ILIsEmpty(pidlNext1))
  774. {
  775. if (ILIsEmpty(pidlNext2))
  776. {
  777. hr = ResultFromShort(0); // pidl1 == pidl2 (in length)
  778. }
  779. else
  780. {
  781. hr = ResultFromShort(-1); // pidl1 < pidl2 (in length)
  782. }
  783. }
  784. else
  785. {
  786. // if IDLIST2 is shorter then return > otherwise we should just
  787. // recurse down the IDLIST and let the next level compare.
  788. if (ILIsEmpty(pidlNext2))
  789. {
  790. hr = ResultFromShort(+1); // pidl1 > pidl2 (in lenght)
  791. }
  792. else
  793. {
  794. LPITEMIDLIST pidlFirst = ILCloneFirst(pidl1);
  795. if (pidlFirst)
  796. {
  797. IShellFolder *psf;
  798. hr = _CreateFolder(NULL, pidlFirst, IID_PPV_ARG(IShellFolder, &psf), FALSE);
  799. if (SUCCEEDED(hr))
  800. {
  801. hr = psf->CompareIDs(lParam, pidlNext1, pidlNext2);
  802. psf->Release();
  803. }
  804. ILFree(pidlFirst);
  805. }
  806. else
  807. {
  808. hr = E_OUTOFMEMORY;
  809. }
  810. }
  811. }
  812. }
  813. return hr;
  814. }
  815. HRESULT CSharedDocuments::GetDetailsEx(LPCITEMIDLIST pidl, const SHCOLUMNID *pscid, VARIANT *pv)
  816. {
  817. HRESULT hr = E_FAIL;
  818. if (IsEqualSCID(SCID_DESCRIPTIONID, *pscid))
  819. {
  820. SHDESCRIPTIONID did = {0};
  821. did.dwDescriptionId = SHDID_COMPUTER_SHAREDDOCS;
  822. did.clsid = CLSID_NULL;
  823. hr = InitVariantFromBuffer(pv, &did, sizeof(did));
  824. }
  825. else
  826. {
  827. LPITEMIDLIST pidlTarget;
  828. hr = _GetTarget(pidl, &pidlTarget);
  829. if (SUCCEEDED(hr))
  830. {
  831. IShellFolder2 *psf2;
  832. LPCITEMIDLIST pidlChild;
  833. hr = SHBindToIDListParent(pidlTarget, IID_PPV_ARG(IShellFolder2, &psf2), &pidlChild);
  834. if (SUCCEEDED(hr))
  835. {
  836. hr = psf2->GetDetailsEx(pidlChild, pscid, pv);
  837. psf2->Release();
  838. }
  839. ILFree(pidlTarget);
  840. }
  841. }
  842. return hr;
  843. }
  844. // icon overlay handling. deligate this to the right handler
  845. HRESULT CSharedDocuments::_GetOverlayIndex(LPCITEMIDLIST pidl, int *pIndex, BOOL fGetIconIndex)
  846. {
  847. LPITEMIDLIST pidlTarget;
  848. HRESULT hr = _GetTarget(pidl, &pidlTarget);
  849. if (SUCCEEDED(hr))
  850. {
  851. IShellIconOverlay *psio;
  852. LPCITEMIDLIST pidlChild;
  853. hr = SHBindToIDListParent(pidlTarget, IID_PPV_ARG(IShellIconOverlay, &psio), &pidlChild);
  854. if (SUCCEEDED(hr))
  855. {
  856. if (fGetIconIndex)
  857. {
  858. hr = psio->GetOverlayIconIndex(pidlChild, pIndex);
  859. }
  860. else
  861. {
  862. hr = psio->GetOverlayIndex(pidlChild, pIndex);
  863. }
  864. psio->Release();
  865. }
  866. ILFree(pidlTarget);
  867. }
  868. return hr;
  869. }
  870. // enumerator for listing all the shared documents in the system.
  871. class CSharedDocsEnum : public IEnumIDList
  872. {
  873. private:
  874. LONG _cRef;
  875. HDPA _hItems;
  876. DWORD _grfFlags;
  877. int _index;
  878. public:
  879. CSharedDocsEnum(HDPA hItems, DWORD grf);
  880. ~CSharedDocsEnum();
  881. // IUnknown
  882. STDMETHOD(QueryInterface)(REFIID riid, void **ppv);
  883. STDMETHOD_(ULONG, AddRef)();
  884. STDMETHOD_(ULONG, Release)();
  885. // IEnumIDList
  886. STDMETHODIMP Next(ULONG celt, LPITEMIDLIST *rgelt, ULONG *pceltFetched);
  887. STDMETHODIMP Skip(ULONG celt)
  888. { return E_NOTIMPL; }
  889. STDMETHODIMP Reset()
  890. { _index = 0; return S_OK; }
  891. STDMETHODIMP Clone(IEnumIDList **ppenum)
  892. { return E_NOTIMPL; };
  893. };
  894. CSharedDocsEnum::CSharedDocsEnum(HDPA hItems, DWORD grfFlags) :
  895. _cRef(1),
  896. _hItems(hItems),
  897. _grfFlags(grfFlags),
  898. _index(0)
  899. {
  900. }
  901. CSharedDocsEnum::~CSharedDocsEnum()
  902. {
  903. DPA_FreeIDArray(_hItems);
  904. }
  905. HRESULT CSharedDocsEnum_CreateInstance(HDPA hItems, DWORD grfFlags, IEnumIDList **ppenum)
  906. {
  907. CSharedDocsEnum *penum = new CSharedDocsEnum(hItems, grfFlags);
  908. if (!penum)
  909. return E_OUTOFMEMORY;
  910. HRESULT hr = penum->QueryInterface(IID_PPV_ARG(IEnumIDList, ppenum));
  911. penum->Release();
  912. return hr;
  913. }
  914. // IUnknown handling
  915. STDMETHODIMP CSharedDocsEnum::QueryInterface(REFIID riid, void **ppv)
  916. {
  917. static const QITAB qit[] =
  918. {
  919. QITABENT(CSharedDocsEnum, IEnumIDList), // IID_IEnumIDList
  920. { 0 },
  921. };
  922. return QISearch(this, qit, riid, ppv);
  923. }
  924. STDMETHODIMP_(ULONG) CSharedDocsEnum::AddRef()
  925. {
  926. return InterlockedIncrement(&_cRef);
  927. }
  928. STDMETHODIMP_(ULONG) CSharedDocsEnum::Release()
  929. {
  930. ASSERT( 0 != _cRef );
  931. ULONG cRef = InterlockedDecrement(&_cRef);
  932. if ( 0 == cRef )
  933. {
  934. delete this;
  935. }
  936. return cRef;
  937. }
  938. // enumeration handling
  939. HRESULT CSharedDocsEnum::Next(ULONG celt, LPITEMIDLIST *rgelt, ULONG *pceltFetched)
  940. {
  941. HRESULT hr = S_FALSE;
  942. ULONG cFetched = 0;
  943. if (_grfFlags & SHCONTF_FOLDERS)
  944. {
  945. // if we have more items to return and the buffer is still not full
  946. // then lets ensure that we return them.
  947. while (SUCCEEDED(hr) && (celt != cFetched) && (_index != DPA_GetPtrCount(_hItems)))
  948. {
  949. if (_index != DPA_GetPtrCount(_hItems))
  950. {
  951. hr = SHILClone((LPITEMIDLIST)DPA_GetPtr(_hItems, _index), &rgelt[cFetched]);
  952. if (SUCCEEDED(hr))
  953. {
  954. cFetched++;
  955. }
  956. }
  957. _index++;
  958. }
  959. }
  960. if (pceltFetched)
  961. *pceltFetched = cFetched;
  962. return hr;
  963. }
  964. // handle system initialization of the shared documents objects
  965. void _SetLocalizedName(INT csidl, LPTSTR pszResModule, INT idsRes)
  966. {
  967. TCHAR szPath[MAX_PATH];
  968. if (SHGetSpecialFolderPath(NULL, szPath, csidl, TRUE))
  969. {
  970. SHSetLocalizedName(szPath, pszResModule, idsRes);
  971. }
  972. }
  973. HRESULT SHGetSampleMediaFolder(int nAllUsersMediaFolder, LPITEMIDLIST *ppidlSampleMedia);
  974. #define PICTURES_BUYURL L"SamplePictures"
  975. #define SAMPLEMUSIC_BUYURL L"http://windowsmedia.com/redir/xpsample.asp"
  976. STDAPI_(void) InitializeSharedDocs(BOOL fWow64)
  977. {
  978. // ACL the DocFolder paths key so that users can touch the keys and store their paths
  979. // for the document folders they have.
  980. // we want the "Everyone" to have read/write access
  981. SHELL_USER_PERMISSION supEveryone;
  982. supEveryone.susID = susEveryone;
  983. supEveryone.dwAccessType = ACCESS_ALLOWED_ACE_TYPE;
  984. supEveryone.dwAccessMask = KEY_READ|KEY_WRITE;
  985. supEveryone.fInherit = TRUE;
  986. supEveryone.dwInheritMask = (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE);
  987. supEveryone.dwInheritAccessMask = GENERIC_READ;
  988. // we want the "SYSTEM" to have full control
  989. SHELL_USER_PERMISSION supSystem;
  990. supSystem.susID = susSystem;
  991. supSystem.dwAccessType = ACCESS_ALLOWED_ACE_TYPE;
  992. supSystem.dwAccessMask = KEY_ALL_ACCESS;
  993. supSystem.fInherit = TRUE;
  994. supSystem.dwInheritMask = (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE);
  995. supSystem.dwInheritAccessMask = GENERIC_ALL;
  996. // we want the "Administrators" to have full control
  997. SHELL_USER_PERMISSION supAdministrators;
  998. supAdministrators.susID = susAdministrators;
  999. supAdministrators.dwAccessType = ACCESS_ALLOWED_ACE_TYPE;
  1000. supAdministrators.dwAccessMask = KEY_ALL_ACCESS;
  1001. supAdministrators.fInherit = TRUE;
  1002. supAdministrators.dwInheritMask = (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE);
  1003. supAdministrators.dwInheritAccessMask = GENERIC_ALL;
  1004. PSHELL_USER_PERMISSION aPerms[3] = {&supEveryone, &supSystem, &supAdministrators};
  1005. SECURITY_DESCRIPTOR* psd = GetShellSecurityDescriptor(aPerms, ARRAYSIZE(aPerms));
  1006. if (psd)
  1007. {
  1008. HKEY hk;
  1009. // setting security right afterwards.
  1010. if (RegCreateKeyEx(HKEY_LOCAL_MACHINE, REGSTR_PATH_DOCFOLDERPATH, 0, NULL, REG_OPTION_NON_VOLATILE, MAXIMUM_ALLOWED, NULL, &hk, NULL) == ERROR_SUCCESS)
  1011. {
  1012. RegSetKeySecurity(hk, DACL_SECURITY_INFORMATION, psd);
  1013. RegCloseKey(hk);
  1014. }
  1015. LocalFree(psd);
  1016. }
  1017. // do file system initialization as needed so that the shared music/pictures folders
  1018. // have the correct display names.
  1019. if (!fWow64 && !IsOS(OS_ANYSERVER))
  1020. {
  1021. _SetLocalizedName(CSIDL_COMMON_PICTURES, TEXT("shell32.dll"), IDS_SHAREDPICTURES);
  1022. _SetLocalizedName(CSIDL_COMMON_MUSIC, TEXT("shell32.dll"), IDS_SHAREDMUSIC);
  1023. // Set the Sample Pictures buy URL
  1024. LPITEMIDLIST pidl;
  1025. if (SUCCEEDED(SHGetSampleMediaFolder(CSIDL_COMMON_PICTURES, &pidl)))
  1026. {
  1027. WCHAR szPath[MAX_PATH];
  1028. WCHAR szDesktopIni[MAX_PATH];
  1029. if (SUCCEEDED(SHGetPathFromIDList(pidl, szPath)) && PathCombine(szDesktopIni, szPath, L"desktop.ini"))
  1030. {
  1031. WritePrivateProfileString(L".ShellClassInfo", c_BuySamplePictures.szURLKey, PICTURES_BUYURL, szDesktopIni);
  1032. // Ensure this is a system folder
  1033. PathMakeSystemFolder(szPath);
  1034. }
  1035. ILFree(pidl);
  1036. }
  1037. // Set the Sample Music buy URL
  1038. if (SUCCEEDED(SHGetSampleMediaFolder(CSIDL_COMMON_MUSIC, &pidl)))
  1039. {
  1040. WCHAR szPath[MAX_PATH];
  1041. WCHAR szDesktopIni[MAX_PATH];
  1042. if (SUCCEEDED(SHGetPathFromIDList(pidl, szPath)) && PathCombine(szDesktopIni, szPath, L"desktop.ini"))
  1043. {
  1044. WritePrivateProfileString(L".ShellClassInfo", c_BuySampleMusic.szURLKey, SAMPLEMUSIC_BUYURL, szDesktopIni);
  1045. // Ensure this is a system folder
  1046. PathMakeSystemFolder(szPath);
  1047. }
  1048. ILFree(pidl);
  1049. }
  1050. }
  1051. }