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.

2425 lines
65 KiB

  1. #include "pch.h"
  2. #include <shsemip.h> // ILClone, ILIsEmpty, etc.
  3. #include <sddl.h>
  4. #include "security.h"
  5. #include "idlhelp.h"
  6. #include "shguidp.h"
  7. #include "folder.h"
  8. #include "strings.h"
  9. #include <ccstock.h>
  10. #ifdef DEBUG
  11. #define SZ_DEBUGINI "ccshell.ini"
  12. #define SZ_DEBUGSECTION "CSC UI"
  13. #define SZ_MODULE "CSCUI.DLL"
  14. // (These are deliberately CHAR)
  15. EXTERN_C const CHAR c_szCcshellIniFile[] = SZ_DEBUGINI;
  16. EXTERN_C const CHAR c_szCcshellIniSecDebug[] = SZ_DEBUGSECTION;
  17. EXTERN_C const WCHAR c_wszTrace[] = L"t " TEXTW(SZ_MODULE) L" ";
  18. EXTERN_C const WCHAR c_wszErrorDbg[] = L"err " TEXTW(SZ_MODULE) L" ";
  19. EXTERN_C const WCHAR c_wszWarningDbg[] = L"wn " TEXTW(SZ_MODULE) L" ";
  20. EXTERN_C const WCHAR c_wszAssertMsg[] = TEXTW(SZ_MODULE) L" Assert: ";
  21. EXTERN_C const WCHAR c_wszAssertFailed[] = TEXTW(SZ_MODULE) L" Assert %ls, line %d: (%ls)\r\n";
  22. EXTERN_C const WCHAR c_wszRip[] = TEXTW(SZ_MODULE) L" RIP in %s at %s, line %d: (%s)\r\n";
  23. EXTERN_C const WCHAR c_wszRipNoFn[] = TEXTW(SZ_MODULE) L" RIP at %s, line %d: (%s)\r\n";
  24. // (These are deliberately CHAR)
  25. EXTERN_C const CHAR c_szTrace[] = "t " SZ_MODULE " ";
  26. EXTERN_C const CHAR c_szErrorDbg[] = "err " SZ_MODULE " ";
  27. EXTERN_C const CHAR c_szWarningDbg[] = "wn " SZ_MODULE " ";
  28. EXTERN_C const CHAR c_szAssertMsg[] = SZ_MODULE " Assert: ";
  29. EXTERN_C const CHAR c_szAssertFailed[] = SZ_MODULE " Assert %s, line %d: (%s)\r\n";
  30. EXTERN_C const CHAR c_szRip[] = SZ_MODULE " RIP in %s at %s, line %d: (%s)\r\n";
  31. EXTERN_C const CHAR c_szRipNoFn[] = SZ_MODULE " RIP at %s, line %d: (%s)\r\n";
  32. EXTERN_C const CHAR c_szRipMsg[] = SZ_MODULE " RIP: ";
  33. #endif
  34. //
  35. // Purpose: Return UNC version of a path
  36. //
  37. // Parameters: pszInName - initial path
  38. // ppszOutName - UNC path returned here
  39. //
  40. //
  41. // Return: HRESULT
  42. // S_OK - UNC path returned
  43. // S_FALSE - drive not connected (UNC not returned)
  44. // or failure code
  45. //
  46. // Notes: The function fails is the path is not a valid
  47. // network path. If the path is already UNC,
  48. // a copy is made without validating the path.
  49. // *ppszOutName must be LocalFree'd by the caller.
  50. //
  51. HRESULT GetRemotePath(LPCTSTR pszInName, LPTSTR *ppszOutName)
  52. {
  53. HRESULT hr = HRESULT_FROM_WIN32(ERROR_BAD_PATHNAME);
  54. *ppszOutName = NULL;
  55. // Don't bother calling GetFullPathName first, since we always
  56. // deal with full (complete) paths.
  57. if (pszInName[1] == TEXT(':'))
  58. {
  59. TCHAR szLocalName[3];
  60. szLocalName[0] = pszInName[0];
  61. szLocalName[1] = pszInName[1];
  62. szLocalName[2] = 0;
  63. // Call GetDriveType before WNetGetConnection, to avoid loading
  64. // MPR.DLL until absolutely necessary.
  65. if (DRIVE_REMOTE == GetDriveType(szLocalName))
  66. {
  67. TCHAR szRemoteName[MAX_PATH];
  68. DWORD dwLen = ARRAYSIZE(szRemoteName);
  69. DWORD dwErr = WNetGetConnection(szLocalName, szRemoteName, &dwLen);
  70. if (NO_ERROR == dwErr)
  71. {
  72. dwLen = lstrlen(szRemoteName);
  73. // Skip the drive letter and add the length of the rest of the path
  74. // (including NULL)
  75. pszInName += 2;
  76. dwLen += lstrlen(pszInName) + 1;
  77. // We should never get incomplete paths, so we should always
  78. // see a backslash after the "X:". If this isn't true, then
  79. // we should call GetFullPathName above.
  80. TraceAssert(TEXT('\\') == *pszInName);
  81. // Allocate the return buffer
  82. *ppszOutName = (LPTSTR)LocalAlloc(LPTR, dwLen * sizeof(TCHAR));
  83. if (*ppszOutName)
  84. {
  85. lstrcpy(*ppszOutName, szRemoteName); // root part
  86. lstrcat(*ppszOutName, pszInName); // rest of path
  87. hr = S_OK;
  88. }
  89. else
  90. {
  91. hr = E_OUTOFMEMORY;
  92. }
  93. }
  94. else if (ERROR_NOT_CONNECTED == dwErr)
  95. {
  96. hr = S_FALSE;
  97. }
  98. else
  99. {
  100. hr = HRESULT_FROM_WIN32(dwErr);
  101. }
  102. }
  103. else
  104. {
  105. hr = S_FALSE;
  106. }
  107. }
  108. else if (PathIsUNC(pszInName))
  109. {
  110. // Just copy the path without validating it
  111. hr = LocalAllocString(ppszOutName, pszInName) ? S_OK : E_OUTOFMEMORY;
  112. }
  113. if (S_OK == hr)
  114. PathRemoveBackslash(*ppszOutName);
  115. return hr;
  116. }
  117. //
  118. // Purpose: TCHAR version of itoa
  119. //
  120. // Parameters: UINT i - unsigned integer to convert
  121. // LPTSTR psz - location to store string result
  122. // UINT cchMax - size of buffer pointed to by psz
  123. //
  124. LPTSTR ULongToString(ULONG i, LPTSTR psz, ULONG cchMax)
  125. {
  126. wnsprintf(psz, cchMax, TEXT("%d%"), i);
  127. return psz;
  128. }
  129. //
  130. // Purpose: Free a string allocated with LocalAlloc[String]
  131. //
  132. // Parameters: LPTSTR *ppsz - location of pointer to string
  133. //
  134. void LocalFreeString(LPTSTR *ppsz)
  135. {
  136. if (ppsz && *ppsz)
  137. {
  138. LocalFree(*ppsz);
  139. *ppsz = NULL;
  140. }
  141. }
  142. //
  143. // Purpose: Copy a string into a newly allocated buffer
  144. //
  145. // Parameters: LPTSTR *ppszDest - location to store string copy
  146. // LPCTSTR pszSrc - string to copy
  147. //
  148. // Return: BOOL - FALSE if LocalAlloc fails or invalid parameters
  149. //
  150. BOOL LocalAllocString(LPTSTR *ppszDest, LPCTSTR pszSrc)
  151. {
  152. if (!ppszDest)
  153. return FALSE;
  154. *ppszDest = StrDup(pszSrc);
  155. return *ppszDest ? TRUE : FALSE;
  156. }
  157. //
  158. // Purpose: Find the length (in chars) of a string resource
  159. //
  160. // Parameters: HINSTANCE hInstance - module containing the string
  161. // UINT idStr - ID of string
  162. //
  163. //
  164. // Return: UINT - # of chars in string, not including NULL
  165. //
  166. // Notes: Based on code from user32.
  167. //
  168. UINT SizeofStringResource(HINSTANCE hInstance, UINT idStr)
  169. {
  170. UINT cch = 0;
  171. HRSRC hRes = FindResource(hInstance, (LPTSTR)((LONG_PTR)(((USHORT)idStr >> 4) + 1)), RT_STRING);
  172. if (NULL != hRes)
  173. {
  174. HGLOBAL hStringSeg = LoadResource(hInstance, hRes);
  175. if (NULL != hStringSeg)
  176. {
  177. LPWSTR psz = (LPWSTR)LockResource(hStringSeg);
  178. if (NULL != psz)
  179. {
  180. idStr &= 0x0F;
  181. while(true)
  182. {
  183. cch = *psz++;
  184. if (idStr-- == 0)
  185. break;
  186. psz += cch;
  187. }
  188. }
  189. }
  190. }
  191. return cch;
  192. }
  193. //
  194. // Purpose: Loads a string resource into an alloc'd buffer
  195. //
  196. // Parameters: ppszResult - string resource returned here
  197. // hInstance - module to load string from
  198. // idStr - string resource ID
  199. //
  200. // Return: same as LoadString
  201. //
  202. // Notes: On successful return, the caller must
  203. // LocalFree *ppszResult
  204. //
  205. int LoadStringAlloc(LPTSTR *ppszResult, HINSTANCE hInstance, UINT idStr)
  206. {
  207. int nResult = 0;
  208. UINT cch = SizeofStringResource(hInstance, idStr);
  209. if (cch)
  210. {
  211. cch++; // for NULL
  212. *ppszResult = (LPTSTR)LocalAlloc(LPTR, cch * sizeof(TCHAR));
  213. if (*ppszResult)
  214. nResult = LoadString(hInstance, idStr, *ppszResult, cch);
  215. }
  216. return nResult;
  217. }
  218. //
  219. // Purpose: Wrapper for SHChangeNotify
  220. //
  221. // Parameters: pszPath - path of file that changed
  222. // bFlush - TRUE forces a flush of the shell's
  223. // notify queue.
  224. //
  225. // Return: none
  226. //
  227. // Notes: SHCNF_PATH doesn't work outside of the shell,
  228. // so we create a pidl and use SHCNF_IDLIST.
  229. //
  230. // Force a flush every 8 calls so the shell
  231. // doesn't start ignoring notifications.
  232. //
  233. void
  234. ShellChangeNotify(
  235. LPCTSTR pszPath,
  236. WIN32_FIND_DATA *pfd,
  237. BOOL bFlush,
  238. LONG nEvent
  239. )
  240. {
  241. LPITEMIDLIST pidlFile = NULL;
  242. LPCVOID pvItem = NULL;
  243. UINT uFlags = 0;
  244. static int cNoFlush = 0;
  245. if (pszPath)
  246. {
  247. if ((pfd && SUCCEEDED(SHSimpleIDListFromFindData(pszPath, pfd, &pidlFile)))
  248. || (pidlFile = ILCreateFromPath(pszPath)))
  249. {
  250. uFlags = SHCNF_IDLIST;
  251. pvItem = pidlFile;
  252. }
  253. else
  254. {
  255. // ILCreateFromPath sometimes fails when we're in disconnected
  256. // mode, so try the path instead.
  257. uFlags = SHCNF_PATH;
  258. pvItem = pszPath;
  259. }
  260. if (0 == nEvent)
  261. nEvent = SHCNE_UPDATEITEM;
  262. }
  263. else
  264. nEvent = 0;
  265. if (8 < cNoFlush++)
  266. bFlush = TRUE;
  267. if (bFlush)
  268. {
  269. uFlags |= (SHCNF_FLUSH | SHCNF_FLUSHNOWAIT);
  270. cNoFlush = 0;
  271. }
  272. SHChangeNotify(nEvent, uFlags, pvItem, NULL);
  273. if (pidlFile)
  274. SHFree(pidlFile);
  275. }
  276. //
  277. // Purpose: Get the path to the target file of a link
  278. //
  279. // Parameters: pszShortcut - name of link file
  280. // ppszTarget - target path returned here
  281. //
  282. //
  283. // Return: HRESULT
  284. // S_OK - target file returned
  285. // S_FALSE - target not returned
  286. // or failure code
  287. //
  288. // Notes: COM must be initialized before calling.
  289. // The function fails is the target is a folder.
  290. // *ppszTarget must be LocalFree'd by the caller.
  291. //
  292. HRESULT GetLinkTarget(LPCTSTR pszShortcut, LPTSTR *ppszTarget, DWORD *pdwAttr)
  293. {
  294. *ppszTarget = NULL;
  295. if (pdwAttr)
  296. *pdwAttr = 0;
  297. IShellLink *psl;
  298. HRESULT hr = LoadFromFile(CLSID_ShellLink, pszShortcut, IID_PPV_ARG(IShellLink, &psl));
  299. if (SUCCEEDED(hr))
  300. {
  301. // Get the pidl of the target
  302. LPITEMIDLIST pidlTarget;
  303. hr = psl->GetIDList(&pidlTarget);
  304. if (SUCCEEDED(hr))
  305. {
  306. hr = S_FALSE; // means no target returned
  307. TCHAR szTarget[MAX_PATH];
  308. DWORD dwAttr = SFGAO_FOLDER;
  309. if (SUCCEEDED(SHGetNameAndFlags(pidlTarget, SHGDN_FORPARSING, szTarget, ARRAYSIZE(szTarget), &dwAttr)))
  310. {
  311. if (!(dwAttr & SFGAO_FOLDER))
  312. {
  313. if (pdwAttr)
  314. {
  315. *pdwAttr = GetFileAttributes(szTarget);
  316. }
  317. hr = GetRemotePath(szTarget, ppszTarget);
  318. }
  319. }
  320. SHFree(pidlTarget);
  321. }
  322. psl->Release();
  323. }
  324. TraceLeaveResult(hr);
  325. }
  326. //*************************************************************
  327. //
  328. // _CSCEnumDatabase
  329. //
  330. // Purpose: Enumerate CSC database recursively
  331. //
  332. // Parameters: pszFolder - name of folder to begin enumeration
  333. // (can be NULL to enum shares)
  334. // bRecurse - TRUE to recurse into child folders
  335. // pfnCB - callback function called once for each child
  336. // lpContext - extra data passed to callback function
  337. //
  338. // Return: One of CSCPROC_RETURN_*
  339. //
  340. // Notes: Return CSCPROC_RETURN_SKIP from the callback to prevent
  341. // recursion into a child folder. CSCPROC_RETURN_ABORT
  342. // will terminate the entire operation (unwind all recursive
  343. // calls). CSCPROC_RETURN_CONTINUE will continue normally.
  344. // Other CSCPROC_RETURN_* values are treated as ABORT.
  345. //
  346. //*************************************************************
  347. #define PATH_BUFFER_SIZE 1024
  348. typedef struct
  349. {
  350. LPTSTR szPath;
  351. int cchPathBuffer;
  352. BOOL bRecurse;
  353. PFN_CSCENUMPROC pfnCB;
  354. LPARAM lpContext;
  355. } CSC_ENUM_CONTEXT, *PCSC_ENUM_CONTEXT;
  356. DWORD
  357. _CSCEnumDatabaseInternal(PCSC_ENUM_CONTEXT pContext)
  358. {
  359. DWORD dwResult = CSCPROC_RETURN_CONTINUE;
  360. HANDLE hFind;
  361. DWORD dwStatus = 0;
  362. DWORD dwPinCount = 0;
  363. DWORD dwHintFlags = 0;
  364. LPTSTR pszPath;
  365. int cchBuffer;
  366. LPTSTR pszFind = NULL;
  367. int cchDir = 0;
  368. WIN32_FIND_DATA fd;
  369. TraceEnter(TRACE_UTIL, "_CSCEnumDatabaseInternal");
  370. TraceAssert(pContext);
  371. TraceAssert(pContext->pfnCB);
  372. TraceAssert(pContext->szPath);
  373. TraceAssert(pContext->cchPathBuffer);
  374. pszPath = pContext->szPath;
  375. cchBuffer = pContext->cchPathBuffer;
  376. if (*pszPath)
  377. {
  378. PathAddBackslash(pszPath);
  379. cchDir = lstrlen(pszPath);
  380. TraceAssert(TEXT('\\') == pszPath[cchDir-1]);
  381. pszFind = pszPath;
  382. }
  383. // skips "." and ".."
  384. hFind = CacheFindFirst(pszFind,
  385. &fd,
  386. &dwStatus,
  387. &dwPinCount,
  388. &dwHintFlags,
  389. NULL);
  390. if (hFind != INVALID_HANDLE_VALUE)
  391. {
  392. do
  393. {
  394. int cchFile;
  395. ENUM_REASON eReason = ENUM_REASON_FILE;
  396. cchFile = lstrlen(fd.cFileName);
  397. if (cchFile >= cchBuffer - cchDir)
  398. {
  399. // Realloc the path buffer
  400. TraceMsg("Reallocating path buffer");
  401. cchBuffer += max(PATH_BUFFER_SIZE, cchFile + 1);
  402. pszPath = (LPTSTR)LocalReAlloc(pContext->szPath,
  403. cchBuffer * sizeof(TCHAR),
  404. LMEM_MOVEABLE);
  405. if (pszPath)
  406. {
  407. pContext->szPath = pszPath;
  408. pContext->cchPathBuffer = cchBuffer;
  409. }
  410. else
  411. {
  412. pszPath = pContext->szPath;
  413. cchBuffer = pContext->cchPathBuffer;
  414. TraceMsg("Unable to reallocate path buffer");
  415. Trace((pszPath));
  416. Trace((fd.cFileName));
  417. continue;
  418. }
  419. }
  420. // Build full path
  421. lstrcpyn(&pszPath[cchDir],
  422. fd.cFileName,
  423. cchBuffer - cchDir);
  424. cchFile = lstrlen(pszPath);
  425. if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) || !pszFind)
  426. eReason = ENUM_REASON_FOLDER_BEGIN;
  427. // Call the callback
  428. dwResult = (*pContext->pfnCB)(pszPath,
  429. eReason,
  430. dwStatus,
  431. dwHintFlags,
  432. dwPinCount,
  433. &fd,
  434. pContext->lpContext);
  435. // Recurse into folders
  436. if (CSCPROC_RETURN_CONTINUE == dwResult &&
  437. pContext->bRecurse &&
  438. ENUM_REASON_FOLDER_BEGIN == eReason)
  439. {
  440. dwResult = _CSCEnumDatabaseInternal(pContext);
  441. // Call the callback again
  442. pszPath[cchFile] = 0;
  443. dwResult = (*pContext->pfnCB)(pszPath,
  444. ENUM_REASON_FOLDER_END,
  445. 0, // dwStatus, // these have probably changed
  446. 0, // dwHintFlags,
  447. 0, // dwPinCount,
  448. &fd,
  449. pContext->lpContext);
  450. }
  451. if (CSCPROC_RETURN_SKIP == dwResult)
  452. dwResult = CSCPROC_RETURN_CONTINUE;
  453. if (CSCPROC_RETURN_CONTINUE != dwResult)
  454. break;
  455. } while (CacheFindNext(hFind,
  456. &fd,
  457. &dwStatus,
  458. &dwPinCount,
  459. &dwHintFlags,
  460. NULL));
  461. CSCFindClose(hFind);
  462. }
  463. TraceLeaveValue(dwResult);
  464. }
  465. DWORD
  466. _CSCEnumDatabase(LPCTSTR pszFolder,
  467. BOOL bRecurse,
  468. PFN_CSCENUMPROC pfnCB,
  469. LPARAM lpContext)
  470. {
  471. DWORD dwResult = CSCPROC_RETURN_CONTINUE;
  472. CSC_ENUM_CONTEXT ec;
  473. TraceEnter(TRACE_UTIL, "_CSCEnumDatabase");
  474. TraceAssert(pfnCB);
  475. if (!pfnCB)
  476. TraceLeaveValue(CSCPROC_RETURN_ABORT);
  477. // Allocate the single buffer used for the entire enumeration.
  478. // It will be reallocated later if necessary.
  479. ec.cchPathBuffer = PATH_BUFFER_SIZE;
  480. if (pszFolder)
  481. ec.cchPathBuffer *= ((lstrlen(pszFolder)/PATH_BUFFER_SIZE) + 1);
  482. ec.szPath = (LPTSTR)LocalAlloc(LMEM_FIXED, ec.cchPathBuffer*sizeof(TCHAR));
  483. if (!ec.szPath)
  484. TraceLeaveValue(CSCPROC_RETURN_ABORT);
  485. ec.szPath[0] = 0;
  486. // Assume pszFolder is valid a directory path or NULL
  487. if (pszFolder)
  488. lstrcpyn(ec.szPath, pszFolder, ec.cchPathBuffer);
  489. ec.bRecurse = bRecurse;
  490. ec.pfnCB = pfnCB;
  491. ec.lpContext = lpContext;
  492. dwResult = _CSCEnumDatabaseInternal(&ec);
  493. LocalFree(ec.szPath);
  494. TraceLeaveValue(dwResult);
  495. }
  496. //*************************************************************
  497. //
  498. // _Win32EnumFolder
  499. //
  500. // Purpose: Enumerate a directory recursively
  501. //
  502. // Parameters: pszFolder - name of folder to begin enumeration
  503. // bRecurse - TRUE to recurse into child folders
  504. // pfnCB - callback function called once for each child
  505. // lpContext - extra data passed to callback function
  506. //
  507. // Return: One of CSCPROC_RETURN_*
  508. //
  509. // Notes: Same as _CSCEnumDatabase except using FindFirstFile
  510. // instead of CSCFindFirstFile.
  511. //
  512. //*************************************************************
  513. typedef struct
  514. {
  515. LPTSTR szPath;
  516. int cchPathBuffer;
  517. BOOL bRecurse;
  518. PFN_WIN32ENUMPROC pfnCB;
  519. LPARAM lpContext;
  520. } W32_ENUM_CONTEXT, *PW32_ENUM_CONTEXT;
  521. DWORD
  522. _Win32EnumFolderInternal(PW32_ENUM_CONTEXT pContext)
  523. {
  524. DWORD dwResult = CSCPROC_RETURN_CONTINUE;
  525. HANDLE hFind;
  526. LPTSTR pszPath;
  527. int cchBuffer;
  528. int cchDir = 0;
  529. WIN32_FIND_DATA fd;
  530. TraceEnter(TRACE_UTIL, "_Win32EnumFolderInternal");
  531. TraceAssert(pContext);
  532. TraceAssert(pContext->pfnCB);
  533. TraceAssert(pContext->szPath && pContext->szPath[0]);
  534. TraceAssert(pContext->cchPathBuffer);
  535. pszPath = pContext->szPath;
  536. cchBuffer = pContext->cchPathBuffer;
  537. // Build wildcard path
  538. PathAddBackslash(pszPath);
  539. cchDir = lstrlen(pszPath);
  540. TraceAssert(TEXT('\\') == pszPath[cchDir-1]);
  541. pszPath[cchDir] = TEXT('*');
  542. pszPath[cchDir+1] = 0;
  543. hFind = FindFirstFile(pszPath, &fd);
  544. if (hFind != INVALID_HANDLE_VALUE)
  545. {
  546. do
  547. {
  548. int cchFile;
  549. ENUM_REASON eReason = ENUM_REASON_FILE;
  550. // skip "." and ".."
  551. if (PathIsDotOrDotDot(fd.cFileName))
  552. continue;
  553. cchFile = lstrlen(fd.cFileName);
  554. if (cchFile >= cchBuffer - cchDir)
  555. {
  556. // Realloc the path buffer
  557. TraceMsg("Reallocating path buffer");
  558. cchBuffer += max(PATH_BUFFER_SIZE, cchFile + 1);
  559. pszPath = (LPTSTR)LocalReAlloc(pContext->szPath,
  560. cchBuffer * sizeof(TCHAR),
  561. LMEM_MOVEABLE);
  562. if (pszPath)
  563. {
  564. pContext->szPath = pszPath;
  565. pContext->cchPathBuffer = cchBuffer;
  566. }
  567. else
  568. {
  569. pszPath = pContext->szPath;
  570. cchBuffer = pContext->cchPathBuffer;
  571. TraceMsg("Unable to reallocate path buffer");
  572. Trace((pszPath));
  573. Trace((fd.cFileName));
  574. continue;
  575. }
  576. }
  577. // Build full path
  578. lstrcpyn(&pszPath[cchDir],
  579. fd.cFileName,
  580. cchBuffer - cchDir);
  581. cchFile = lstrlen(pszPath);
  582. if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  583. eReason = ENUM_REASON_FOLDER_BEGIN;
  584. // Call the callback
  585. dwResult = (*pContext->pfnCB)(pszPath,
  586. eReason,
  587. &fd,
  588. pContext->lpContext);
  589. // Recurse into folders
  590. if (CSCPROC_RETURN_CONTINUE == dwResult &&
  591. pContext->bRecurse &&
  592. ENUM_REASON_FOLDER_BEGIN == eReason)
  593. {
  594. dwResult = _Win32EnumFolderInternal(pContext);
  595. // Call the callback again
  596. pszPath[cchFile] = 0;
  597. dwResult = (*pContext->pfnCB)(pszPath,
  598. ENUM_REASON_FOLDER_END,
  599. &fd,
  600. pContext->lpContext);
  601. }
  602. if (CSCPROC_RETURN_SKIP == dwResult)
  603. dwResult = CSCPROC_RETURN_CONTINUE;
  604. if (CSCPROC_RETURN_CONTINUE != dwResult)
  605. break;
  606. } while (FindNextFile(hFind, &fd));
  607. FindClose(hFind);
  608. }
  609. TraceLeaveValue(dwResult);
  610. }
  611. DWORD
  612. _Win32EnumFolder(LPCTSTR pszFolder,
  613. BOOL bRecurse,
  614. PFN_WIN32ENUMPROC pfnCB,
  615. LPARAM lpContext)
  616. {
  617. DWORD dwResult = CSCPROC_RETURN_CONTINUE;
  618. W32_ENUM_CONTEXT ec;
  619. TraceEnter(TRACE_UTIL, "_Win32EnumFolder");
  620. TraceAssert(pszFolder);
  621. TraceAssert(pfnCB);
  622. if (!pszFolder || !*pszFolder || !pfnCB)
  623. TraceLeaveValue(CSCPROC_RETURN_ABORT);
  624. // Allocate the single buffer used for the entire enumeration.
  625. // It will be reallocated later if necessary.
  626. ec.cchPathBuffer = ((lstrlen(pszFolder)/PATH_BUFFER_SIZE) + 1) * PATH_BUFFER_SIZE;
  627. ec.szPath = (LPTSTR)LocalAlloc(LMEM_FIXED, ec.cchPathBuffer*sizeof(TCHAR));
  628. if (!ec.szPath)
  629. TraceLeaveValue(CSCPROC_RETURN_ABORT);
  630. ec.szPath[0] = 0;
  631. // Assume pszFolder is valid a directory path
  632. lstrcpyn(ec.szPath, pszFolder, ec.cchPathBuffer);
  633. ec.bRecurse = bRecurse;
  634. ec.pfnCB = pfnCB;
  635. ec.lpContext = lpContext;
  636. dwResult = _Win32EnumFolderInternal(&ec);
  637. LocalFree(ec.szPath);
  638. TraceLeaveValue(dwResult);
  639. }
  640. CIDArray::~CIDArray()
  641. {
  642. DoRelease(m_psf);
  643. if (m_pIDA)
  644. {
  645. GlobalUnlock(m_Medium.hGlobal);
  646. m_pIDA = NULL;
  647. }
  648. ReleaseStgMedium(&m_Medium);
  649. }
  650. HRESULT CIDArray::Initialize(IDataObject *pdobj)
  651. {
  652. TraceAssert(NULL == m_pIDA);
  653. FORMATETC fe = { g_cfShellIDList, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
  654. HRESULT hr = pdobj->GetData(&fe, &m_Medium);
  655. if (SUCCEEDED(hr))
  656. {
  657. m_pIDA = (LPIDA)GlobalLock(m_Medium.hGlobal);
  658. if (m_pIDA)
  659. {
  660. LPCITEMIDLIST pidlFolder = (LPCITEMIDLIST)ByteOffset(m_pIDA, m_pIDA->aoffset[0]);
  661. hr = SHBindToObjectEx(NULL, pidlFolder, NULL, IID_PPV_ARG(IShellFolder, &m_psf));
  662. }
  663. else
  664. {
  665. hr = E_FAIL;
  666. }
  667. }
  668. return hr;
  669. }
  670. HRESULT CIDArray::GetItemPath(UINT iItem, LPTSTR pszPath, UINT cchPath, DWORD *pdwAttribs)
  671. {
  672. HRESULT hr = E_INVALIDARG;
  673. if (m_psf && m_pIDA && (iItem < m_pIDA->cidl))
  674. {
  675. LPCITEMIDLIST pidlChild, pidl = (LPCITEMIDLIST)ByteOffset(m_pIDA, m_pIDA->aoffset[iItem + 1]);
  676. IShellFolder *psf;
  677. hr = SHBindToFolderIDListParent(m_psf, pidl, IID_PPV_ARG(IShellFolder, &psf), &pidlChild);
  678. if (SUCCEEDED(hr))
  679. {
  680. if (pszPath)
  681. {
  682. hr = DisplayNameOf(psf, pidlChild, SHGDN_FORPARSING, pszPath, cchPath);
  683. if (SUCCEEDED(hr))
  684. {
  685. LPTSTR pszRemote;
  686. if (S_OK == GetRemotePath(pszPath, &pszRemote))
  687. {
  688. lstrcpyn(pszPath, pszRemote, cchPath);
  689. LocalFree(pszRemote);
  690. }
  691. }
  692. }
  693. if (SUCCEEDED(hr) && pdwAttribs)
  694. hr = psf->GetAttributesOf(1, &pidlChild, pdwAttribs);
  695. psf->Release();
  696. }
  697. }
  698. return hr;
  699. }
  700. HRESULT CIDArray::GetFolderPath(LPTSTR pszPath, UINT cchPath)
  701. {
  702. HRESULT hr = GetItemPath(0, pszPath, cchPath, NULL);
  703. if (SUCCEEDED(hr))
  704. {
  705. PathRemoveFileSpec(pszPath);
  706. }
  707. return hr;
  708. }
  709. //*************************************************************
  710. //
  711. // CCscFileHandle non-inline member functions.
  712. //
  713. //*************************************************************
  714. CCscFindHandle&
  715. CCscFindHandle::operator = (
  716. const CCscFindHandle& rhs
  717. )
  718. {
  719. if (this != &rhs)
  720. {
  721. Attach(rhs.Detach());
  722. }
  723. return *this;
  724. }
  725. void
  726. CCscFindHandle::Close(
  727. void
  728. )
  729. {
  730. if (m_bOwns && INVALID_HANDLE_VALUE != m_handle)
  731. {
  732. CSCFindClose(m_handle);
  733. }
  734. m_bOwns = false;
  735. m_handle = INVALID_HANDLE_VALUE;
  736. }
  737. //*************************************************************
  738. //
  739. // String formatting functions
  740. //
  741. //*************************************************************
  742. DWORD
  743. FormatStringID(LPTSTR *ppszResult, HINSTANCE hInstance, UINT idStr, ...)
  744. {
  745. DWORD dwResult;
  746. va_list args;
  747. va_start(args, idStr);
  748. dwResult = vFormatStringID(ppszResult, hInstance, idStr, &args);
  749. va_end(args);
  750. return dwResult;
  751. }
  752. DWORD
  753. FormatString(LPTSTR *ppszResult, LPCTSTR pszFormat, ...)
  754. {
  755. DWORD dwResult;
  756. va_list args;
  757. va_start(args, pszFormat);
  758. dwResult = vFormatString(ppszResult, pszFormat, &args);
  759. va_end(args);
  760. return dwResult;
  761. }
  762. DWORD
  763. vFormatStringID(LPTSTR *ppszResult, HINSTANCE hInstance, UINT idStr, va_list *pargs)
  764. {
  765. DWORD dwResult = 0;
  766. LPTSTR pszFormat = NULL;
  767. if (LoadStringAlloc(&pszFormat, hInstance, idStr))
  768. {
  769. dwResult = vFormatString(ppszResult, pszFormat, pargs);
  770. LocalFree(pszFormat);
  771. }
  772. return dwResult;
  773. }
  774. DWORD
  775. vFormatString(LPTSTR *ppszResult, LPCTSTR pszFormat, va_list *pargs)
  776. {
  777. return FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING,
  778. pszFormat,
  779. 0,
  780. 0,
  781. (LPTSTR)ppszResult,
  782. 1,
  783. pargs);
  784. }
  785. DWORD
  786. FormatSystemError(LPTSTR *ppszResult, DWORD dwSysError)
  787. {
  788. LPTSTR pszBuffer = NULL;
  789. DWORD dwResult = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
  790. FORMAT_MESSAGE_ALLOCATE_BUFFER,
  791. NULL,
  792. dwSysError,
  793. 0,
  794. (LPTSTR)&pszBuffer,
  795. 1,
  796. NULL);
  797. if (NULL != pszBuffer)
  798. {
  799. *ppszResult = pszBuffer;
  800. }
  801. return dwResult;
  802. }
  803. //
  804. // Center a window in it's parent.
  805. // If hwndParent is NULL, the window's parent is used.
  806. // If hwndParent is not NULL, hwnd is centered in it.
  807. // If hwndParent is NULL and hwnd doesn't have a parent, it is centered
  808. // on the desktop.
  809. //
  810. void
  811. CenterWindow(
  812. HWND hwnd,
  813. HWND hwndParent
  814. )
  815. {
  816. RECT rcScreen;
  817. if (NULL != hwnd)
  818. {
  819. rcScreen.left = rcScreen.top = 0;
  820. rcScreen.right = GetSystemMetrics(SM_CXSCREEN);
  821. rcScreen.bottom = GetSystemMetrics(SM_CYSCREEN);
  822. if (NULL == hwndParent)
  823. {
  824. hwndParent = GetParent(hwnd);
  825. if (NULL == hwndParent)
  826. hwndParent = GetDesktopWindow();
  827. }
  828. RECT rcWnd;
  829. RECT rcParent;
  830. GetWindowRect(hwnd, &rcWnd);
  831. GetWindowRect(hwndParent, &rcParent);
  832. INT cxWnd = rcWnd.right - rcWnd.left;
  833. INT cyWnd = rcWnd.bottom - rcWnd.top;
  834. INT cxParent = rcParent.right - rcParent.left;
  835. INT cyParent = rcParent.bottom - rcParent.top;
  836. POINT ptParentCtr;
  837. ptParentCtr.x = rcParent.left + (cxParent / 2);
  838. ptParentCtr.y = rcParent.top + (cyParent / 2);
  839. if ((ptParentCtr.x + (cxWnd / 2)) > rcScreen.right)
  840. {
  841. //
  842. // Window would run off the right edge of the screen.
  843. //
  844. rcWnd.left = rcScreen.right - cxWnd;
  845. }
  846. else if ((ptParentCtr.x - (cxWnd / 2)) < rcScreen.left)
  847. {
  848. //
  849. // Window would run off the left edge of the screen.
  850. //
  851. rcWnd.left = rcScreen.left;
  852. }
  853. else
  854. {
  855. rcWnd.left = ptParentCtr.x - (cxWnd / 2);
  856. }
  857. if ((ptParentCtr.y + (cyWnd / 2)) > rcScreen.bottom)
  858. {
  859. //
  860. // Window would run off the bottom edge of the screen.
  861. //
  862. rcWnd.top = rcScreen.bottom - cyWnd;
  863. }
  864. else if ((ptParentCtr.y - (cyWnd / 2)) < rcScreen.top)
  865. {
  866. //
  867. // Window would run off the top edge of the screen.
  868. //
  869. rcWnd.top = rcScreen.top;
  870. }
  871. else
  872. {
  873. rcWnd.top = ptParentCtr.y - (cyWnd / 2);
  874. }
  875. MoveWindow(hwnd, rcWnd.left, rcWnd.top, cxWnd, cyWnd, TRUE);
  876. }
  877. }
  878. //
  879. // We have some extra stuff to pass to the stats callback so we wrap the
  880. // CSCSHARESTATS in a larger structure.
  881. //
  882. typedef struct
  883. {
  884. CSCSHARESTATS ss; // The stats data.
  885. DWORD dwUnityFlagsReq; // SSUF_XXXX flags set by user (requested).
  886. DWORD dwUnityFlagsSum; // SSUF_XXXX flags set during enum (sum total).
  887. DWORD dwExcludeFlags; // SSEF_XXXX flags.
  888. bool bEnumAborted; // true if unity flags satisfied.
  889. } CSCSHARESTATS_CBKINFO, *PCSCSHARESTATS_CBKINFO;
  890. //
  891. // Called by CSCEnumForStats for each CSC item enumerated.
  892. //
  893. DWORD
  894. _CscShareStatisticsCallback(LPCTSTR lpszName,
  895. DWORD dwStatus,
  896. DWORD dwHintFlags,
  897. DWORD dwPinCount,
  898. WIN32_FIND_DATA *lpFind32,
  899. DWORD dwReason,
  900. DWORD dwParam1,
  901. DWORD dwParam2,
  902. DWORD_PTR dwContext)
  903. {
  904. DWORD dwResult = CSCPROC_RETURN_CONTINUE;
  905. if (CSCPROC_REASON_BEGIN != dwReason && // Not "start of data" notification.
  906. CSCPROC_REASON_END != dwReason && // Not "end of data" notification.
  907. 1 != dwParam2) // Not "share root" entry.
  908. {
  909. PCSCSHARESTATS_CBKINFO pssci = (PCSCSHARESTATS_CBKINFO)(dwContext);
  910. PCSCSHARESTATS pss = &(pssci->ss);
  911. const DWORD dwExcludeFlags = pssci->dwExcludeFlags;
  912. const DWORD dwUnityFlagsReq = pssci->dwUnityFlagsReq;
  913. const bool bIsDir = (0 == dwParam1);
  914. const bool bAccessUser = CscAccessUser(dwStatus);
  915. const bool bAccessGuest = CscAccessGuest(dwStatus);
  916. const bool bAccessOther = CscAccessOther(dwStatus);
  917. if (0 != dwExcludeFlags)
  918. {
  919. //
  920. // Caller want's to exclude some items from the enumeration.
  921. // If item is in "excluded" specification, return early.
  922. //
  923. if (0 != (dwExcludeFlags & (dwStatus & SSEF_CSCMASK)))
  924. {
  925. return dwResult;
  926. }
  927. if ((bIsDir && (dwExcludeFlags & SSEF_DIRECTORY)) ||
  928. (!bIsDir && (dwExcludeFlags & SSEF_FILE)))
  929. {
  930. return dwResult;
  931. }
  932. const struct
  933. {
  934. DWORD fExclude;
  935. bool bAccess;
  936. BYTE fMask;
  937. } rgExclAccess[] = {{ SSEF_NOACCUSER, bAccessUser, 0x01 },
  938. { SSEF_NOACCGUEST, bAccessGuest, 0x02 },
  939. { SSEF_NOACCOTHER, bAccessOther, 0x04 }};
  940. BYTE fExcludeMask = 0;
  941. BYTE fNoAccessMask = 0;
  942. for (int i = 0; i < ARRAYSIZE(rgExclAccess); i++)
  943. {
  944. if (dwExcludeFlags & rgExclAccess[i].fExclude)
  945. fExcludeMask |= rgExclAccess[i].fMask;
  946. if (!rgExclAccess[i].bAccess)
  947. fNoAccessMask |= rgExclAccess[i].fMask;
  948. }
  949. if (SSEF_NOACCAND & dwExcludeFlags)
  950. {
  951. //
  952. // Treat all access exclusion flags as a single unit.
  953. //
  954. if (fExcludeMask == fNoAccessMask)
  955. return dwResult;
  956. }
  957. else
  958. {
  959. //
  960. // Treat each access flag individually. Only one specified access
  961. // condition must be true to exclude this file.
  962. //
  963. if (fExcludeMask & fNoAccessMask)
  964. return dwResult;
  965. }
  966. }
  967. if (0 == (SSEF_DIRECTORY & dwExcludeFlags) || !bIsDir)
  968. {
  969. pss->cTotal++;
  970. pssci->dwUnityFlagsSum |= SSUF_TOTAL;
  971. if (0 != (dwHintFlags & (FLAG_CSC_HINT_PIN_USER | FLAG_CSC_HINT_PIN_ADMIN)))
  972. {
  973. pss->cPinned++;
  974. pssci->dwUnityFlagsSum |= SSUF_PINNED;
  975. }
  976. if (0 != (dwStatus & FLAG_CSCUI_COPY_STATUS_ALL_DIRTY))
  977. {
  978. //
  979. // If the current user doesn't have sufficient access
  980. // to merge offline changes, then someone else must have
  981. // modified the file, so don't count it for this user.
  982. //
  983. if (bIsDir || CscCanUserMergeFile(dwStatus))
  984. {
  985. pss->cModified++;
  986. pssci->dwUnityFlagsSum |= SSUF_MODIFIED;
  987. }
  988. }
  989. const struct
  990. {
  991. DWORD flag;
  992. int *pCount;
  993. bool bAccess;
  994. } rgUnity[] = {{ SSUF_ACCUSER, &pss->cAccessUser, bAccessUser },
  995. { SSUF_ACCGUEST, &pss->cAccessGuest, bAccessGuest },
  996. { SSUF_ACCOTHER, &pss->cAccessOther, bAccessOther }};
  997. DWORD fUnityMask = 0;
  998. DWORD fAccessMask = 0;
  999. for (int i = 0; i < ARRAYSIZE(rgUnity); i++)
  1000. {
  1001. if (dwUnityFlagsReq & rgUnity[i].flag)
  1002. fUnityMask |= rgUnity[i].flag;
  1003. if (rgUnity[i].bAccess)
  1004. {
  1005. (*rgUnity[i].pCount)++;
  1006. fAccessMask |= rgUnity[i].flag;
  1007. }
  1008. }
  1009. if (SSUF_ACCAND & dwUnityFlagsReq)
  1010. {
  1011. //
  1012. // Treat all access unity flags as a single unit.
  1013. // We only signal unity if all of the specified access
  1014. // unity conditions are true.
  1015. //
  1016. if (fUnityMask == fAccessMask)
  1017. pssci->dwUnityFlagsSum |= fUnityMask;
  1018. }
  1019. else
  1020. {
  1021. //
  1022. // Treat all access exclusion flags individually.
  1023. //
  1024. if (fUnityMask & fAccessMask)
  1025. {
  1026. if (SSUF_ACCOR & dwUnityFlagsReq)
  1027. pssci->dwUnityFlagsSum |= fUnityMask;
  1028. else
  1029. pssci->dwUnityFlagsSum |= fAccessMask;
  1030. }
  1031. }
  1032. if (bIsDir)
  1033. {
  1034. pss->cDirs++;
  1035. pssci->dwUnityFlagsSum |= SSUF_DIRS;
  1036. }
  1037. // Note the 'else': don't count dirs in the sparse total
  1038. else if (0 != (dwStatus & FLAG_CSC_COPY_STATUS_SPARSE))
  1039. {
  1040. pss->cSparse++;
  1041. pssci->dwUnityFlagsSum |= SSUF_SPARSE;
  1042. }
  1043. if (0 != dwUnityFlagsReq)
  1044. {
  1045. //
  1046. // Abort enumeration if all of the requested SSUF_XXXX unity flags
  1047. // have been set.
  1048. //
  1049. if (dwUnityFlagsReq == (dwUnityFlagsReq & pssci->dwUnityFlagsSum))
  1050. {
  1051. dwResult = CSCPROC_RETURN_ABORT;
  1052. pssci->bEnumAborted;
  1053. }
  1054. }
  1055. }
  1056. }
  1057. return dwResult;
  1058. }
  1059. //
  1060. // Enumerate all items for a given share and tally up the
  1061. // relevant information like file count, pinned count etc.
  1062. // Information is returned through *pss.
  1063. //
  1064. BOOL
  1065. _GetShareStatistics(
  1066. LPCTSTR pszShare,
  1067. PCSCGETSTATSINFO pi,
  1068. PCSCSHARESTATS pss
  1069. )
  1070. {
  1071. typedef BOOL (WINAPI * PFNENUMFORSTATS)(LPCTSTR, LPCSCPROC, DWORD_PTR);
  1072. CSCSHARESTATS_CBKINFO ssci;
  1073. BOOL bResult;
  1074. DWORD dwShareStatus = 0;
  1075. PFNENUMFORSTATS pfnEnumForStats = CSCEnumForStats;
  1076. ZeroMemory(&ssci, sizeof(ssci));
  1077. ssci.dwUnityFlagsReq = pi->dwUnityFlags;
  1078. ssci.dwExcludeFlags = pi->dwExcludeFlags;
  1079. if (pi->bAccessInfo ||
  1080. (pi->dwUnityFlags & (SSUF_ACCUSER | SSUF_ACCGUEST | SSUF_ACCOTHER)) ||
  1081. (pi->dwExcludeFlags & (SSEF_NOACCUSER | SSEF_NOACCGUEST | SSEF_NOACCOTHER)))
  1082. {
  1083. //
  1084. // If the enumeration requires access information, use the "ex" version
  1085. // of the EnumForStats CSC api. Only use it if necessary because gathering
  1086. // the access information has a perf cost.
  1087. //
  1088. pfnEnumForStats = CSCEnumForStatsEx;
  1089. }
  1090. pi->bEnumAborted = false;
  1091. bResult = (*pfnEnumForStats)(pszShare, _CscShareStatisticsCallback, (DWORD_PTR)&ssci);
  1092. *pss = ssci.ss;
  1093. if (CSCQueryFileStatus(pszShare, &dwShareStatus, NULL, NULL))
  1094. {
  1095. if (FLAG_CSC_SHARE_STATUS_FILES_OPEN & dwShareStatus)
  1096. {
  1097. pss->bOpenFiles = true;
  1098. }
  1099. if (FLAG_CSC_SHARE_STATUS_DISCONNECTED_OP & dwShareStatus)
  1100. {
  1101. pss->bOffline = true;
  1102. }
  1103. }
  1104. pi->bEnumAborted = ssci.bEnumAborted;
  1105. return bResult;
  1106. }
  1107. //
  1108. // Retrieve the statistics for the entire cache.
  1109. // This is a simple wrapper that calls _GetShareStatistics for each share
  1110. // in the cache then sums the results for the entire cache. It accepts
  1111. // the same unity and exclusion flags used by _GetShareStatistics.
  1112. //
  1113. BOOL
  1114. _GetCacheStatistics(
  1115. PCSCGETSTATSINFO pi,
  1116. PCSCCACHESTATS pcs
  1117. )
  1118. {
  1119. BOOL bResult = TRUE;
  1120. WIN32_FIND_DATA fd;
  1121. CSCSHARESTATS ss;
  1122. ZeroMemory(pcs, sizeof(*pcs));
  1123. pi->bEnumAborted = false;
  1124. CCscFindHandle hFind(CacheFindFirst(NULL, &fd, NULL, NULL, NULL, NULL));
  1125. if (hFind.IsValid())
  1126. {
  1127. do
  1128. {
  1129. pcs->cShares++;
  1130. if (bResult = _GetShareStatistics(fd.cFileName,
  1131. pi,
  1132. &ss))
  1133. {
  1134. pcs->cTotal += ss.cTotal;
  1135. pcs->cPinned += ss.cPinned;
  1136. pcs->cModified += ss.cModified;
  1137. pcs->cSparse += ss.cSparse;
  1138. pcs->cDirs += ss.cDirs;
  1139. pcs->cAccessUser += ss.cAccessUser;
  1140. pcs->cAccessGuest += ss.cAccessGuest;
  1141. pcs->cAccessOther += ss.cAccessOther;
  1142. pcs->cSharesOffline += int(ss.bOffline);
  1143. pcs->cSharesWithOpenFiles += int(ss.bOpenFiles);
  1144. }
  1145. }
  1146. while(bResult && !pi->bEnumAborted && CacheFindNext(hFind, &fd, NULL, NULL, NULL, NULL));
  1147. }
  1148. return bResult;
  1149. }
  1150. //
  1151. // Sets the proper exclusion flags to report only on files accessible by the
  1152. // logged on user. Otherwise it's the same as calling _GetShareStatistics.
  1153. //
  1154. BOOL
  1155. _GetShareStatisticsForUser(
  1156. LPCTSTR pszShare,
  1157. PCSCGETSTATSINFO pi,
  1158. PCSCSHARESTATS pss
  1159. )
  1160. {
  1161. pi->dwExcludeFlags |= SSEF_NOACCUSER | SSEF_NOACCGUEST | SSEF_NOACCAND;
  1162. return _GetShareStatistics(pszShare, pi, pss);
  1163. }
  1164. //
  1165. // Sets the proper exclusion flags to report only on files accessible by the
  1166. // logged on user. Otherwise it's the same as calling _GetCacheStatistics.
  1167. //
  1168. BOOL
  1169. _GetCacheStatisticsForUser(
  1170. PCSCGETSTATSINFO pi,
  1171. PCSCCACHESTATS pcs
  1172. )
  1173. {
  1174. pi->dwExcludeFlags |= SSEF_NOACCUSER | SSEF_NOACCGUEST | SSEF_NOACCAND;
  1175. return _GetCacheStatistics(pi, pcs);
  1176. }
  1177. //
  1178. // CSCUI version of reboot. Requires security goo.
  1179. // This code was pattered after that found in \shell\shell32\restart.c
  1180. // function CommonRestart().
  1181. //
  1182. DWORD
  1183. CSCUIRebootSystem(
  1184. void
  1185. )
  1186. {
  1187. TraceEnter(TRACE_UTIL, "CSCUIRebootSystem");
  1188. DWORD dwOldState, dwStatus, dwSecError;
  1189. DWORD dwRebootError = ERROR_SUCCESS;
  1190. SetLastError(0); // Be really safe about last error value!
  1191. dwStatus = Security_SetPrivilegeAttrib(SE_SHUTDOWN_NAME,
  1192. SE_PRIVILEGE_ENABLED,
  1193. &dwOldState);
  1194. dwSecError = GetLastError(); // ERROR_NOT_ALL_ASSIGNED sometimes
  1195. if (!ExitWindowsEx(EWX_REBOOT, 0))
  1196. {
  1197. dwRebootError = GetLastError();
  1198. Trace((TEXT("Error %d rebooting system"), dwRebootError));
  1199. }
  1200. if (NT_SUCCESS(dwStatus))
  1201. {
  1202. if (ERROR_SUCCESS == dwSecError)
  1203. {
  1204. Security_SetPrivilegeAttrib(SE_SHUTDOWN_NAME, dwOldState, NULL);
  1205. }
  1206. else
  1207. {
  1208. Trace((TEXT("Error %d setting SE_SHUTDOWN_NAME privilege"), dwSecError));
  1209. }
  1210. }
  1211. else
  1212. {
  1213. Trace((TEXT("Error %d setting SE_SHUTDOWN_NAME privilege"), dwStatus));
  1214. }
  1215. TraceLeaveResult(dwRebootError);
  1216. }
  1217. //
  1218. // Retrieve location, size and file/directory count information for the
  1219. // CSC cache. If CSC is disabled, information is gathered about the
  1220. // system volume. That's where the CSC agent will put the cache when
  1221. // one is created.
  1222. //
  1223. void
  1224. GetCscSpaceUsageInfo(
  1225. CSCSPACEUSAGEINFO *psui
  1226. )
  1227. {
  1228. ULARGE_INTEGER ulTotalBytes = {0, 0};
  1229. ULARGE_INTEGER ulUsedBytes = {0, 0};
  1230. ZeroMemory(psui, sizeof(*psui));
  1231. CSCGetSpaceUsage(psui->szVolume,
  1232. ARRAYSIZE(psui->szVolume),
  1233. &ulTotalBytes.HighPart,
  1234. &ulTotalBytes.LowPart,
  1235. &ulUsedBytes.HighPart,
  1236. &ulUsedBytes.LowPart,
  1237. &psui->dwNumFilesInCache,
  1238. &psui->dwNumDirsInCache);
  1239. if (0 == psui->szVolume[0])
  1240. {
  1241. //
  1242. // CSCGetSpaceUsage didn't give us a volume name. Probably because
  1243. // CSC hasn't been enabled on the system. Default to the system
  1244. // drive because that's what CSC uses anyway.
  1245. //
  1246. GetSystemDirectory(psui->szVolume, ARRAYSIZE(psui->szVolume));
  1247. psui->dwNumFilesInCache = 0;
  1248. psui->dwNumDirsInCache = 0;
  1249. }
  1250. PathStripToRoot(psui->szVolume);
  1251. DWORD spc = 0; // Sectors per cluster.
  1252. DWORD bps = 0; // Bytes per sector.
  1253. DWORD fc = 0; // Free clusters.
  1254. DWORD nc = 0; // Total clusters.
  1255. GetDiskFreeSpace(psui->szVolume, &spc, &bps, &fc, &nc);
  1256. psui->llBytesOnVolume = (LONGLONG)nc * (LONGLONG)spc * (LONGLONG)bps;
  1257. psui->llBytesTotalInCache = ulTotalBytes.QuadPart;
  1258. psui->llBytesUsedInCache = ulUsedBytes.QuadPart;
  1259. }
  1260. //-----------------------------------------------------------------------------
  1261. // This is code taken from shell32's utils.cpp file.
  1262. // We need the function SHSimpleIDListFromFindData() but it's not exported
  1263. // from shell32. Therefore, until it is, we just lifted the code.
  1264. // [brianau - 9/28/98]
  1265. //-----------------------------------------------------------------------------
  1266. class CFileSysBindData: public IFileSystemBindData
  1267. {
  1268. public:
  1269. CFileSysBindData();
  1270. // *** IUnknown methods ***
  1271. STDMETHODIMP QueryInterface(REFIID riid, void **ppvObj);
  1272. STDMETHODIMP_(ULONG) AddRef(void);
  1273. STDMETHODIMP_(ULONG) Release(void);
  1274. // IFileSystemBindData
  1275. STDMETHODIMP SetFindData(const WIN32_FIND_DATAW *pfd);
  1276. STDMETHODIMP GetFindData(WIN32_FIND_DATAW *pfd);
  1277. private:
  1278. ~CFileSysBindData();
  1279. LONG _cRef;
  1280. WIN32_FIND_DATAW _fd;
  1281. };
  1282. CFileSysBindData::CFileSysBindData() : _cRef(1)
  1283. {
  1284. ZeroMemory(&_fd, sizeof(_fd));
  1285. }
  1286. CFileSysBindData::~CFileSysBindData()
  1287. {
  1288. }
  1289. HRESULT CFileSysBindData::QueryInterface(REFIID riid, void **ppv)
  1290. {
  1291. static const QITAB qit[] = {
  1292. QITABENT(CFileSysBindData, IFileSystemBindData), // IID_IFileSystemBindData
  1293. { 0 },
  1294. };
  1295. return QISearch(this, qit, riid, ppv);
  1296. }
  1297. STDMETHODIMP_(ULONG) CFileSysBindData::AddRef(void)
  1298. {
  1299. return InterlockedIncrement(&_cRef);
  1300. }
  1301. STDMETHODIMP_(ULONG) CFileSysBindData::Release()
  1302. {
  1303. if (InterlockedDecrement(&_cRef))
  1304. return _cRef;
  1305. delete this;
  1306. return 0;
  1307. }
  1308. HRESULT CFileSysBindData::SetFindData(const WIN32_FIND_DATAW *pfd)
  1309. {
  1310. _fd = *pfd;
  1311. return S_OK;
  1312. }
  1313. HRESULT CFileSysBindData::GetFindData(WIN32_FIND_DATAW *pfd)
  1314. {
  1315. *pfd = _fd;
  1316. return S_OK;
  1317. }
  1318. HRESULT
  1319. SHCreateFileSysBindCtx(
  1320. const WIN32_FIND_DATA *pfd,
  1321. IBindCtx **ppbc
  1322. )
  1323. {
  1324. HRESULT hres;
  1325. IFileSystemBindData *pfsbd = new CFileSysBindData();
  1326. if (pfsbd)
  1327. {
  1328. if (pfd)
  1329. {
  1330. WIN32_FIND_DATAW fdw;
  1331. memcpy(&fdw, pfd, FIELD_OFFSET(WIN32_FIND_DATAW, cFileName));
  1332. SHTCharToUnicode(pfd->cFileName, fdw.cFileName, ARRAYSIZE(fdw.cFileName));
  1333. SHTCharToUnicode(pfd->cAlternateFileName, fdw.cAlternateFileName, ARRAYSIZE(fdw.cAlternateFileName));
  1334. pfsbd->SetFindData(&fdw);
  1335. }
  1336. hres = CreateBindCtx(0, ppbc);
  1337. if (SUCCEEDED(hres))
  1338. {
  1339. BIND_OPTS bo = {sizeof(bo)}; // Requires size filled in.
  1340. bo.grfMode = STGM_CREATE;
  1341. (*ppbc)->SetBindOptions(&bo);
  1342. (*ppbc)->RegisterObjectParam(STR_FILE_SYS_BIND_DATA, pfsbd);
  1343. }
  1344. pfsbd->Release();
  1345. }
  1346. else
  1347. {
  1348. *ppbc = NULL;
  1349. hres = E_OUTOFMEMORY;
  1350. }
  1351. return hres;
  1352. }
  1353. HRESULT
  1354. SHSimpleIDListFromFindData(
  1355. LPCTSTR pszPath,
  1356. const WIN32_FIND_DATA *pfd,
  1357. LPITEMIDLIST *ppidl
  1358. )
  1359. {
  1360. IShellFolder *psfDesktop;
  1361. HRESULT hres = SHGetDesktopFolder(&psfDesktop);
  1362. if (SUCCEEDED(hres))
  1363. {
  1364. IBindCtx *pbc;
  1365. hres = SHCreateFileSysBindCtx(pfd, &pbc);
  1366. if (SUCCEEDED(hres))
  1367. {
  1368. WCHAR wszPath[MAX_PATH];
  1369. SHTCharToUnicode(pszPath, wszPath, ARRAYSIZE(wszPath));
  1370. hres = psfDesktop->ParseDisplayName(NULL, pbc, wszPath, NULL, ppidl, NULL);
  1371. pbc->Release();
  1372. }
  1373. psfDesktop->Release();
  1374. }
  1375. if (FAILED(hres))
  1376. *ppidl = NULL;
  1377. return hres;
  1378. }
  1379. //
  1380. // Number of times a CSC API will be repeated if it fails.
  1381. // In particular, this is used for CSCDelete and CSCFillSparseFiles; both of
  1382. // which can fail on one call but succeed the next. This isn't designed
  1383. // behavior but it is reality. ShishirP knows about it and may be able to
  1384. // investigate later. [brianau - 4/2/98]
  1385. //
  1386. const int CSC_API_RETRIES = 3;
  1387. //
  1388. // Occasionally if a call to a CSC API fails with ERROR_ACCESS_DENIED,
  1389. // repeating the call will succeed.
  1390. // Here we wrap up the call to CSCDelete so that it is called multiple
  1391. // times in the case of these failures.
  1392. //
  1393. DWORD
  1394. CscDelete(
  1395. LPCTSTR pszPath
  1396. )
  1397. {
  1398. DWORD dwError = ERROR_SUCCESS;
  1399. int nRetries = CSC_API_RETRIES;
  1400. while(0 < nRetries--)
  1401. {
  1402. if (CSCDelete(pszPath))
  1403. return ERROR_SUCCESS;
  1404. dwError = GetLastError();
  1405. if (ERROR_ACCESS_DENIED != dwError)
  1406. return dwError;
  1407. }
  1408. if (ERROR_SUCCESS == dwError)
  1409. {
  1410. //
  1411. // Hack for some CSC APIs returning
  1412. // ERROR_SUCCESS even though they fail.
  1413. //
  1414. dwError = ERROR_GEN_FAILURE;
  1415. }
  1416. return dwError;
  1417. }
  1418. void
  1419. EnableDlgItems(
  1420. HWND hwndDlg,
  1421. const UINT* pCtlIds,
  1422. int cCtls,
  1423. bool bEnable
  1424. )
  1425. {
  1426. for (int i = 0; i < cCtls; i++)
  1427. {
  1428. EnableWindow(GetDlgItem(hwndDlg, *(pCtlIds + i)), bEnable);
  1429. }
  1430. }
  1431. void
  1432. ShowDlgItems(
  1433. HWND hwndDlg,
  1434. const UINT* pCtlIds,
  1435. int cCtls,
  1436. bool bShow
  1437. )
  1438. {
  1439. const int nCmdShow = bShow ? SW_NORMAL : SW_HIDE;
  1440. for (int i = 0; i < cCtls; i++)
  1441. {
  1442. ShowWindow(GetDlgItem(hwndDlg, *(pCtlIds + i)), nCmdShow);
  1443. }
  1444. }
  1445. //
  1446. // Wrapper around GetVolumeInformation that accounts for mounted
  1447. // volumes. This was borrowed from shell32\mulprsht.c
  1448. //
  1449. BOOL GetVolumeFlags(LPCTSTR pszPath, DWORD *pdwFlags)
  1450. {
  1451. TraceAssert(NULL != pszPath);
  1452. TraceAssert(NULL != pdwFlags);
  1453. TCHAR szRoot[MAX_PATH];
  1454. *pdwFlags = NULL;
  1455. //
  1456. // Is this a mount point, e.g. c:\ or c:\hostfolder\
  1457. //
  1458. if (!GetVolumePathName(pszPath, szRoot, ARRAYSIZE(szRoot)))
  1459. {
  1460. //
  1461. // No. Use path provided by caller.
  1462. //
  1463. lstrcpy(szRoot, pszPath);
  1464. PathStripToRoot(szRoot);
  1465. }
  1466. //
  1467. // GetVolumeInformation requires a trailing backslash.
  1468. //
  1469. PathAddBackslash(szRoot);
  1470. return GetVolumeInformation(szRoot, NULL, 0, NULL, NULL, pdwFlags, NULL, 0);
  1471. }
  1472. //
  1473. // Determine if the parent net share for a given UNC path has an open
  1474. // connection on the local machine.
  1475. //
  1476. // Returns:
  1477. //
  1478. // S_OK = There is an open connection to the share.
  1479. // S_FALSE = No open connection to the share.
  1480. // other = Some error code.
  1481. //
  1482. HRESULT
  1483. IsOpenConnectionPathUNC(
  1484. LPCTSTR pszPathUNC
  1485. )
  1486. {
  1487. TCHAR szShare[MAX_PATH * 2];
  1488. lstrcpyn(szShare, pszPathUNC, ARRAYSIZE(szShare));
  1489. PathStripToRoot(szShare);
  1490. if (PathIsUNCServerShare(szShare))
  1491. return IsOpenConnectionShare(szShare);
  1492. return S_FALSE;
  1493. }
  1494. //
  1495. // Determine if a net share has an open connection on the local machine.
  1496. //
  1497. // Returns:
  1498. //
  1499. // S_OK = There is an open connection to the share.
  1500. // S_FALSE = No open connection to the share.
  1501. // other = Some error code.
  1502. //
  1503. HRESULT
  1504. IsOpenConnectionShare(
  1505. LPCTSTR pszShare
  1506. )
  1507. {
  1508. DWORD dwStatus;
  1509. if (CSCQueryFileStatus(pszShare, &dwStatus, NULL, NULL))
  1510. {
  1511. if (FLAG_CSC_SHARE_STATUS_CONNECTED & dwStatus)
  1512. return S_OK;
  1513. }
  1514. return S_FALSE;
  1515. }
  1516. // With this version of CSCIsCSCEnabled, we can delay all extra dll loads
  1517. // (including cscdll.dll) until we actually see a net file/folder.
  1518. #include <devioctl.h>
  1519. #include <shdcom.h>
  1520. static TCHAR const c_szShadowDevice[] = TEXT("\\\\.\\shadow");
  1521. BOOL IsCSCEnabled(void)
  1522. {
  1523. BOOL bIsCSCEnabled = FALSE;
  1524. if (!IsOS(OS_PERSONAL))
  1525. {
  1526. SHADOWINFO sSI = {0};
  1527. ULONG ulBytesReturned;
  1528. HANDLE hShadowDB = CreateFile(c_szShadowDevice,
  1529. FILE_EXECUTE,
  1530. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1531. NULL,
  1532. OPEN_EXISTING,
  1533. 0,
  1534. NULL);
  1535. if (INVALID_HANDLE_VALUE == hShadowDB)
  1536. return FALSE;
  1537. sSI.uStatus = SHADOW_SWITCH_SHADOWING;
  1538. sSI.uOp = SHADOW_SWITCH_GET_STATE;
  1539. if (DeviceIoControl(hShadowDB,
  1540. IOCTL_SWITCHES,
  1541. (void *)(&sSI),
  1542. 0,
  1543. NULL,
  1544. 0,
  1545. &ulBytesReturned,
  1546. NULL))
  1547. {
  1548. bIsCSCEnabled = (sSI.uStatus & SHADOW_SWITCH_SHADOWING);
  1549. }
  1550. CloseHandle(hShadowDB);
  1551. }
  1552. return bIsCSCEnabled;
  1553. }
  1554. //
  1555. // The bit-masking used by this function is dependent upon the way
  1556. // Shishir defined the database status flags in cscapi.h
  1557. //
  1558. // FLAG_DATABASESTATUS_ENCRYPTION_MASK 0x00000006 (0000 0110)
  1559. // FLAG_DATABASESTATUS_UNENCRYPTED 0x00000000 (0000 0000)
  1560. // FLAG_DATABASESTATUS_PARTIALLY_UNENCRYPTED 0x00000004 (0000 0100)
  1561. // FLAG_DATABASESTATUS_ENCRYPTED 0x00000002 (0000 0010)
  1562. // FLAG_DATABASESTATUS_PARTIALLY_ENCRYPTED 0x00000006 (0000 0110)
  1563. //
  1564. // Things to note:
  1565. // 1. Bit 1 == encryption status.
  1566. // 2. Bit 2 == partial completion status.
  1567. //
  1568. //
  1569. // Returns:
  1570. // TRUE == Database is encrypted. May be fully or partially encrypted.
  1571. // FALSE == Database is not encrypted. May be fully or partially not encrypted.
  1572. //
  1573. // *pbPartial == Indicates if state is "partial" or not.
  1574. //
  1575. // Partial encryption means an encryption operation was started
  1576. // but not successfully completed. All new files created will be encrypted.
  1577. // Partial decryption means a decryption operation was started
  1578. // but not successfully completed. All new files created will be unencrypted.
  1579. //
  1580. BOOL IsCacheEncrypted(BOOL *pbPartial)
  1581. {
  1582. ULONG ulStatus;
  1583. ULONG ulErrors;
  1584. BOOL bEncrypted = FALSE;
  1585. if (CSCQueryDatabaseStatus(&ulStatus, &ulErrors))
  1586. {
  1587. ulStatus &= FLAG_DATABASESTATUS_ENCRYPTION_MASK;
  1588. bEncrypted = (0 != (FLAG_DATABASESTATUS_ENCRYPTED & ulStatus));
  1589. if (NULL != pbPartial)
  1590. {
  1591. const ULONG FLAGS_PARTIAL = (FLAG_DATABASESTATUS_PARTIALLY_ENCRYPTED & FLAG_DATABASESTATUS_PARTIALLY_UNENCRYPTED);
  1592. *pbPartial = (0 != (FLAGS_PARTIAL & ulStatus));
  1593. }
  1594. }
  1595. return bEncrypted;
  1596. }
  1597. bool
  1598. CscVolumeSupportsEncryption(
  1599. LPCTSTR pszPathIn // Path of CSC volume. Can be NULL.
  1600. )
  1601. {
  1602. TCHAR szPath[MAX_PATH]; // May need local copy to modify.
  1603. CSCSPACEUSAGEINFO sui;
  1604. LPTSTR psz;
  1605. DWORD dwVolFlags;
  1606. bool bSupportsEncryption = false;
  1607. if (NULL == pszPathIn)
  1608. {
  1609. //
  1610. // Caller didn't provide path of CSC volume.
  1611. // Get it from CSC.
  1612. //
  1613. sui.szVolume[0] = 0;
  1614. psz = sui.szVolume;
  1615. GetCscSpaceUsageInfo(&sui);
  1616. }
  1617. else
  1618. {
  1619. //
  1620. // Caller provided path of CSC volume.
  1621. //
  1622. lstrcpyn(szPath, pszPathIn, ARRAYSIZE(szPath));
  1623. psz = szPath;
  1624. }
  1625. TraceAssert(NULL != psz);
  1626. if (GetVolumeFlags(psz, &dwVolFlags))
  1627. {
  1628. if (0 != (FILE_SUPPORTS_ENCRYPTION & dwVolFlags))
  1629. {
  1630. bSupportsEncryption = true;
  1631. }
  1632. }
  1633. return bSupportsEncryption;
  1634. }
  1635. //
  1636. // Returns:
  1637. //
  1638. // NULL == Mutex is owned by another thread.
  1639. // non-NULL == Handle of mutex object. This thread now owns the mutex.
  1640. // Caller is responsible for releasing the mutex and closing
  1641. // the mutex handle.
  1642. //
  1643. // *pbAbandoned indicates if mutex was abandoned by its thread.
  1644. //
  1645. //
  1646. HANDLE
  1647. RequestNamedMutexOwnership(
  1648. LPCTSTR pszMutexName,
  1649. BOOL *pbAbandoned // [optional]
  1650. )
  1651. {
  1652. BOOL bAbandoned = FALSE;
  1653. HANDLE hMutex = CreateMutex(NULL, FALSE, pszMutexName);
  1654. if (NULL != hMutex)
  1655. {
  1656. //
  1657. // Whether we created or opened the mutex, wait on it
  1658. // to gain ownership.
  1659. //
  1660. switch(WaitForSingleObject(hMutex, 0))
  1661. {
  1662. case WAIT_ABANDONED:
  1663. bAbandoned = TRUE;
  1664. //
  1665. // Fall through...
  1666. //
  1667. case WAIT_OBJECT_0:
  1668. //
  1669. // Current thread now owns the mutex.
  1670. // We'll return the handle to the caller.
  1671. //
  1672. break;
  1673. case WAIT_TIMEOUT:
  1674. default:
  1675. //
  1676. // Couldn't gain ownership of the mutex.
  1677. // Close the handle.
  1678. //
  1679. CloseHandle(hMutex);
  1680. hMutex = NULL;
  1681. break;
  1682. }
  1683. }
  1684. if (NULL != pbAbandoned)
  1685. {
  1686. *pbAbandoned = bAbandoned;
  1687. }
  1688. return hMutex;
  1689. }
  1690. //
  1691. // Determine if a named mutex is currently owned by another thread
  1692. // or not. This function only determines ownership then immediately
  1693. // releases the mutex. If you need to determine ownership and want
  1694. // to retain ownership if previously unowned call
  1695. // RequestNamedMutexOwnership instead.
  1696. //
  1697. BOOL
  1698. IsNamedMutexOwned(
  1699. LPCTSTR pszMutexName,
  1700. BOOL *pbAbandoned
  1701. )
  1702. {
  1703. HANDLE hMutex = RequestNamedMutexOwnership(pszMutexName, pbAbandoned);
  1704. if (NULL != hMutex)
  1705. {
  1706. //
  1707. // Mutex was not owned (now owned by current thread).
  1708. // Since we're only interested in determining prior ownership
  1709. // we release it and close the handle.
  1710. //
  1711. ReleaseMutex(hMutex);
  1712. CloseHandle(hMutex);
  1713. return FALSE;
  1714. }
  1715. return TRUE;
  1716. }
  1717. BOOL IsSyncInProgress(void)
  1718. {
  1719. return IsNamedMutexOwned(c_szSyncInProgMutex, NULL);
  1720. }
  1721. BOOL IsPurgeInProgress(void)
  1722. {
  1723. return IsNamedMutexOwned(c_szPurgeInProgMutex, NULL);
  1724. }
  1725. BOOL IsEncryptionInProgress(void)
  1726. {
  1727. return IsNamedMutexOwned(c_szEncryptionInProgMutex, NULL);
  1728. }
  1729. //
  1730. // Requests ownership of the global cache encryption mutex.
  1731. //
  1732. // Returns:
  1733. // NULL == Mutex already owned by another thread.
  1734. // Non-NULL == Mutex now owned by current thread.
  1735. // Caller is responsible for releasing the mutex
  1736. // and closing the mutex handle.
  1737. //
  1738. HANDLE RequestPermissionToEncryptCache(void)
  1739. {
  1740. return RequestNamedMutexOwnership(c_szEncryptionInProgMutex, NULL);
  1741. }
  1742. //---------------------------------------------------------------
  1743. // DataObject helper functions.
  1744. // These are roughly taken from similar functions in
  1745. // shell\shell32\datautil.cpp
  1746. //---------------------------------------------------------------
  1747. HRESULT
  1748. DataObject_SetBlob(
  1749. IDataObject *pdtobj,
  1750. CLIPFORMAT cf,
  1751. LPCVOID pvBlob,
  1752. UINT cbBlob
  1753. )
  1754. {
  1755. HRESULT hr = E_OUTOFMEMORY;
  1756. void * pv = GlobalAlloc(GPTR, cbBlob);
  1757. if (pv)
  1758. {
  1759. CopyMemory(pv, pvBlob, cbBlob);
  1760. hr = DataObject_SetGlobal(pdtobj, cf, pv);
  1761. if (FAILED(hr))
  1762. GlobalFree((HGLOBAL)pv);
  1763. }
  1764. return hr;
  1765. }
  1766. HRESULT
  1767. DataObject_GetBlob(
  1768. IDataObject *pdtobj,
  1769. CLIPFORMAT cf,
  1770. void * pvBlob,
  1771. UINT cbBlob
  1772. )
  1773. {
  1774. STGMEDIUM medium = {0};
  1775. FORMATETC fmte = {cf, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  1776. HRESULT hr = pdtobj->GetData(&fmte, &medium);
  1777. if (SUCCEEDED(hr))
  1778. {
  1779. void * pv = GlobalLock(medium.hGlobal);
  1780. if (pv)
  1781. {
  1782. CopyMemory(pvBlob, pv, cbBlob);
  1783. GlobalUnlock(medium.hGlobal);
  1784. }
  1785. else
  1786. {
  1787. hr = E_UNEXPECTED;
  1788. }
  1789. ReleaseStgMedium(&medium);
  1790. }
  1791. return hr;
  1792. }
  1793. HRESULT
  1794. DataObject_SetGlobal(
  1795. IDataObject *pdtobj,
  1796. CLIPFORMAT cf,
  1797. HGLOBAL hGlobal
  1798. )
  1799. {
  1800. FORMATETC fmte = {cf, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  1801. STGMEDIUM medium;
  1802. medium.tymed = TYMED_HGLOBAL;
  1803. medium.hGlobal = hGlobal;
  1804. medium.pUnkForRelease = NULL;
  1805. return pdtobj->SetData(&fmte, &medium, TRUE);
  1806. }
  1807. HRESULT
  1808. DataObject_SetDWORD(
  1809. IDataObject *pdtobj,
  1810. CLIPFORMAT cf,
  1811. DWORD dw
  1812. )
  1813. {
  1814. return DataObject_SetBlob(pdtobj, cf, &dw, sizeof(dw));
  1815. }
  1816. HRESULT
  1817. DataObject_GetDWORD(
  1818. IDataObject *pdtobj,
  1819. CLIPFORMAT cf,
  1820. DWORD *pdwOut
  1821. )
  1822. {
  1823. return DataObject_GetBlob(pdtobj, cf, pdwOut, sizeof(DWORD));
  1824. }
  1825. HRESULT
  1826. SetGetLogicalPerformedDropEffect(
  1827. IDataObject *pdtobj,
  1828. DWORD *pdwEffect,
  1829. bool bSet
  1830. )
  1831. {
  1832. HRESULT hr = NOERROR;
  1833. static CLIPFORMAT cf;
  1834. if ((CLIPFORMAT)0 == cf)
  1835. cf = (CLIPFORMAT)RegisterClipboardFormat(CFSTR_LOGICALPERFORMEDDROPEFFECT);
  1836. if (bSet)
  1837. {
  1838. hr = DataObject_SetDWORD(pdtobj, cf, *pdwEffect);
  1839. }
  1840. else
  1841. {
  1842. *pdwEffect = DROPEFFECT_NONE;
  1843. DataObject_GetDWORD(pdtobj, cf, pdwEffect);
  1844. }
  1845. return hr;
  1846. }
  1847. DWORD
  1848. GetLogicalPerformedDropEffect(
  1849. IDataObject *pdtobj
  1850. )
  1851. {
  1852. DWORD dwEffect = DROPEFFECT_NONE;
  1853. SetGetLogicalPerformedDropEffect(pdtobj, &dwEffect, false);
  1854. return dwEffect;
  1855. }
  1856. HRESULT
  1857. SetLogicalPerformedDropEffect(
  1858. IDataObject *pdtobj,
  1859. DWORD dwEffect
  1860. )
  1861. {
  1862. return SetGetLogicalPerformedDropEffect(pdtobj, &dwEffect, true);
  1863. }
  1864. HRESULT
  1865. SetGetPreferredDropEffect(
  1866. IDataObject *pdtobj,
  1867. DWORD *pdwEffect,
  1868. bool bSet
  1869. )
  1870. {
  1871. HRESULT hr = NOERROR;
  1872. static CLIPFORMAT cf;
  1873. if ((CLIPFORMAT)0 == cf)
  1874. cf = (CLIPFORMAT)RegisterClipboardFormat(CFSTR_PREFERREDDROPEFFECT);
  1875. if (bSet)
  1876. {
  1877. hr = DataObject_SetDWORD(pdtobj, cf, *pdwEffect);
  1878. }
  1879. else
  1880. {
  1881. *pdwEffect = DROPEFFECT_NONE;
  1882. DataObject_GetDWORD(pdtobj, cf, pdwEffect);
  1883. }
  1884. return hr;
  1885. }
  1886. DWORD
  1887. GetPreferredDropEffect(
  1888. IDataObject *pdtobj
  1889. )
  1890. {
  1891. DWORD dwEffect = DROPEFFECT_NONE;
  1892. SetGetPreferredDropEffect(pdtobj, &dwEffect, false);
  1893. return dwEffect;
  1894. }
  1895. HRESULT
  1896. SetPreferredDropEffect(
  1897. IDataObject *pdtobj,
  1898. DWORD dwEffect
  1899. )
  1900. {
  1901. return SetGetPreferredDropEffect(pdtobj, &dwEffect, true);
  1902. }
  1903. //
  1904. // Wrap CSCFindFirstFile so we don't enumerate "." or "..".
  1905. // Wrapper also helps code readability.
  1906. //
  1907. HANDLE
  1908. CacheFindFirst(
  1909. LPCTSTR pszPath,
  1910. PSID psid,
  1911. WIN32_FIND_DATA *pfd,
  1912. DWORD *pdwStatus,
  1913. DWORD *pdwPinCount,
  1914. DWORD *pdwHintFlags,
  1915. FILETIME *pft
  1916. )
  1917. {
  1918. HANDLE hFind = CSCFindFirstFileForSid(pszPath,
  1919. psid,
  1920. pfd,
  1921. pdwStatus,
  1922. pdwPinCount,
  1923. pdwHintFlags,
  1924. pft);
  1925. while(INVALID_HANDLE_VALUE != hFind && PathIsDotOrDotDot(pfd->cFileName))
  1926. {
  1927. if (!CSCFindNextFile(hFind,
  1928. pfd,
  1929. pdwStatus,
  1930. pdwPinCount,
  1931. pdwHintFlags,
  1932. pft))
  1933. {
  1934. CSCFindClose(hFind);
  1935. hFind = INVALID_HANDLE_VALUE;
  1936. }
  1937. }
  1938. return hFind;
  1939. }
  1940. //
  1941. // Wrap CSCFindFirstFile so we don't enumerate "." or "..".
  1942. // Wrapper also helps code readability.
  1943. //
  1944. BOOL
  1945. CacheFindNext(
  1946. HANDLE hFind,
  1947. WIN32_FIND_DATA *pfd,
  1948. DWORD *pdwStatus,
  1949. DWORD *pdwPinCount,
  1950. DWORD *pdwHintFlags,
  1951. FILETIME *pft
  1952. )
  1953. {
  1954. BOOL bResult = FALSE;
  1955. do
  1956. {
  1957. bResult = CSCFindNextFile(hFind,
  1958. pfd,
  1959. pdwStatus,
  1960. pdwPinCount,
  1961. pdwHintFlags,
  1962. pft);
  1963. }
  1964. while(bResult && PathIsDotOrDotDot(pfd->cFileName));
  1965. return bResult;
  1966. }
  1967. //
  1968. // If there's a link to the Offline Files folder on the
  1969. // user's desktop, delete the link. This version checks a flag in the registry
  1970. // before enumerating all LNK's on the desktop. If the flag doesn't exist,
  1971. // we don't continue. This is a perf enhancement used at logon.
  1972. //
  1973. BOOL
  1974. DeleteOfflineFilesFolderLink_PerfSensitive(
  1975. HWND hwndParent
  1976. )
  1977. {
  1978. BOOL bResult = FALSE;
  1979. //
  1980. // Before enumerating links on the desktop, check to see if the user
  1981. // has created a link.
  1982. //
  1983. DWORD dwValue;
  1984. DWORD cbValue = sizeof(dwValue);
  1985. DWORD dwType;
  1986. DWORD dwResult = SHGetValue(HKEY_CURRENT_USER,
  1987. REGSTR_KEY_OFFLINEFILES,
  1988. REGSTR_VAL_FOLDERSHORTCUTCREATED,
  1989. &dwType,
  1990. &dwValue,
  1991. &cbValue);
  1992. if (ERROR_SUCCESS == dwResult)
  1993. {
  1994. //
  1995. // We don't care about the value or it's type.
  1996. // Presence/absence of the value is all that matters.
  1997. //
  1998. bResult = DeleteOfflineFilesFolderLink(hwndParent);
  1999. }
  2000. return bResult;
  2001. }
  2002. //
  2003. // This version of the "delete link" function does not check the
  2004. // flag in the registry. It finds the link file on the desktop and deletes it.
  2005. //
  2006. BOOL
  2007. DeleteOfflineFilesFolderLink(
  2008. HWND hwndParent
  2009. )
  2010. {
  2011. BOOL bResult = FALSE;
  2012. TCHAR szLinkPath[MAX_PATH];
  2013. if (SUCCEEDED(COfflineFilesFolder::IsLinkOnDesktop(hwndParent, szLinkPath, ARRAYSIZE(szLinkPath))))
  2014. {
  2015. bResult = DeleteFile(szLinkPath);
  2016. }
  2017. //
  2018. // Remove the "folder shortcut created" flag from the registry.
  2019. //
  2020. SHDeleteValue(HKEY_CURRENT_USER, REGSTR_KEY_OFFLINEFILES, REGSTR_VAL_FOLDERSHORTCUTCREATED);
  2021. return bResult;
  2022. }
  2023. //
  2024. // This was taken from shell\shell32\util.cpp.
  2025. //
  2026. BOOL ShowSuperHidden(void)
  2027. {
  2028. BOOL bRet = FALSE;
  2029. if (!SHRestricted(REST_DONTSHOWSUPERHIDDEN))
  2030. {
  2031. SHELLSTATE ss;
  2032. SHGetSetSettings(&ss, SSF_SHOWSUPERHIDDEN, FALSE);
  2033. bRet = ss.fShowSuperHidden;
  2034. }
  2035. return bRet;
  2036. }
  2037. BOOL ShowHidden(void)
  2038. {
  2039. SHELLSTATE ss;
  2040. SHGetSetSettings(&ss, SSF_SHOWALLOBJECTS, FALSE);
  2041. return ss.fShowAllObjects;
  2042. }
  2043. BOOL IsSyncMgrInitialized(void)
  2044. {
  2045. //
  2046. // Is this the first time this user has used run CSCUI?
  2047. //
  2048. DWORD dwValue = 0;
  2049. DWORD cbData = sizeof(dwValue);
  2050. DWORD dwType;
  2051. SHGetValue(HKEY_CURRENT_USER,
  2052. c_szCSCKey,
  2053. c_szSyncMgrInitialized,
  2054. &dwType,
  2055. (void *)&dwValue,
  2056. &cbData);
  2057. return (0 != dwValue);
  2058. }
  2059. void SetSyncMgrInitialized(void)
  2060. {
  2061. //
  2062. // Set the "initialized" flag so our logoff code in cscst.cpp doesn't
  2063. // try to re-register for sync-at-logon/logoff.
  2064. //
  2065. DWORD dwSyncMgrInitialized = 1;
  2066. SHSetValue(HKEY_CURRENT_USER,
  2067. c_szCSCKey,
  2068. c_szSyncMgrInitialized,
  2069. REG_DWORD,
  2070. &dwSyncMgrInitialized,
  2071. sizeof(dwSyncMgrInitialized));
  2072. }
  2073. //
  2074. // Return the HWND for a standard progress dialog.
  2075. //
  2076. HWND GetProgressDialogWindow(IProgressDialog *ppd)
  2077. {
  2078. HWND hwndProgress = NULL;
  2079. //
  2080. // Get the progress dialog's window handle. We'll use
  2081. // it as a parent window for error UI.
  2082. //
  2083. HRESULT hr = IUnknown_GetWindow(ppd, &hwndProgress);
  2084. return hwndProgress;
  2085. }
  2086. void
  2087. CAutoWaitCursor::Reset(
  2088. void
  2089. )
  2090. {
  2091. ShowCursor(FALSE);
  2092. if (NULL != m_hCursor)
  2093. SetCursor(m_hCursor);
  2094. m_hCursor = NULL;
  2095. }
  2096. //
  2097. // Expand all environment strings in a text string.
  2098. //
  2099. HRESULT
  2100. ExpandStringInPlace(
  2101. LPTSTR psz,
  2102. DWORD cch
  2103. )
  2104. {
  2105. HRESULT hr = E_OUTOFMEMORY;
  2106. LPTSTR pszCopy;
  2107. if (LocalAllocString(&pszCopy, psz))
  2108. {
  2109. DWORD cchExpanded = ExpandEnvironmentStrings(pszCopy, psz, cch);
  2110. if (0 == cchExpanded)
  2111. hr = HRESULT_FROM_WIN32(GetLastError());
  2112. else if (cchExpanded > cch)
  2113. hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
  2114. else
  2115. hr = S_OK;
  2116. LocalFreeString(&pszCopy);
  2117. }
  2118. if (FAILED(hr) && 0 < cch)
  2119. {
  2120. *psz = 0;
  2121. }
  2122. return hr;
  2123. }