Source code of Windows XP (NT5)
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.

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