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

2467 lines
70 KiB

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