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.

796 lines
25 KiB

  1. /*++
  2. Microsoft Windows
  3. Copyright (C) Microsoft Corporation, 1981 - 1998
  4. Module Name:
  5. utils.cxx
  6. Abstract:
  7. Author:
  8. Rahul Thombre (RahulTh) 4/8/1998
  9. Revision History:
  10. 4/8/1998 RahulTh
  11. Created this module.
  12. --*/
  13. #include "precomp.hxx"
  14. BOOL IsSpecialDescendant (const long nID, UINT* parentID /*= NULL*/)
  15. {
  16. BOOL fRetVal;
  17. int prntID = -1;
  18. switch (nID)
  19. {
  20. case IDS_MYPICS:
  21. prntID = IDS_MYDOCS;
  22. break;
  23. case IDS_PROGRAMS:
  24. prntID = IDS_STARTMENU;
  25. break;
  26. case IDS_STARTUP:
  27. prntID = IDS_PROGRAMS;
  28. break;
  29. default:
  30. prntID = -1;
  31. break;
  32. }
  33. if (fRetVal = (-1 != prntID))
  34. {
  35. if (parentID)
  36. *parentID = prntID;
  37. }
  38. return fRetVal;
  39. }
  40. //this is a helper function for ConvertOldStyleSection(...) which is used
  41. //to convert Beta3 style ini files to Win2K style ini files.
  42. void SplitRHS (CString& szValue, unsigned long & flags, CString& szPath)
  43. {
  44. int index;
  45. int iRetVal;
  46. //take some precautions
  47. szValue.TrimRight();
  48. szValue.TrimLeft();
  49. szPath.Empty();
  50. flags = 0;
  51. if (szValue.IsEmpty())
  52. return;
  53. //if we are here, szValue at least contains the flags
  54. iRetVal = swscanf ((LPCTSTR)szValue, TEXT("%x"), &flags);
  55. ASSERT((iRetVal != 0) && (iRetVal != EOF));
  56. //check if there is a path too.
  57. index = szValue.Find(' '); //we will find a space only if there is a path too.
  58. if (-1 != index) //there is a path too.
  59. {
  60. szPath = szValue.Mid (index + 1);
  61. szPath.TrimLeft();
  62. szPath.TrimRight();
  63. ASSERT (!szPath.IsEmpty());
  64. }
  65. }
  66. //////////////////////////////////////////////////////////////////////////
  67. // Given a full path name, this routine extracts its display name, viz.
  68. // the part of which follows the final \. If there are no \'s in the
  69. // full name, then it sets the display name to the full name
  70. //////////////////////////////////////////////////////////////////////////
  71. void ExtractDisplayName (const CString& szFullname, CString& szDisplayname)
  72. {
  73. CString szName;
  74. szName = szFullname;
  75. //first get rid of any trailing spaces; this might happen in cases
  76. //where one is trying to create a shortcut to a network drive and
  77. //when resolved to a UNC path, it yields a path ending in a slash
  78. //reverse the string so that any trailing slashes will now be at the
  79. //head of the string
  80. szName.MakeReverse();
  81. //get rid of the leading slashes and spaces of the reversed string
  82. szName = szName.Mid ((szName.SpanIncluding(TEXT("\\ "))).GetLength());
  83. //reverse the string again and we will have a string without
  84. //any trailing '\' or ' '
  85. szName.MakeReverse();
  86. //with the trailing '\' and spaces removed, we can go about the
  87. //business of getting the display name
  88. //if \ cannot be found, ReverseFind returns -1 which gives 0 on adding
  89. //1, therefore szDisplayname gets the entire name if no \ is found.
  90. szDisplayname = szName.Mid (szName.ReverseFind('\\') + 1);
  91. }
  92. //+--------------------------------------------------------------------------
  93. //
  94. // Function: SplitProfileString
  95. //
  96. // Synopsis: This function takes in a string of the type key=value and
  97. // extracts the key and the value from it.
  98. //
  99. // Arguments: [in] szPair : the key value pair
  100. // [out] szKey : the key
  101. // [out] szValue : the value
  102. //
  103. // Returns: S_OK : if everything goes well.
  104. // E_FAIL: if the '=' sign cannot be found
  105. //
  106. // History: 9/28/1998 RahulTh created
  107. //
  108. // Notes:
  109. //
  110. //---------------------------------------------------------------------------
  111. HRESULT SplitProfileString (CString szPair, CString& szKey, CString& szValue)
  112. {
  113. int nEqPos;
  114. nEqPos = szPair.Find ('=');
  115. if (-1 == nEqPos)
  116. return E_FAIL;
  117. szKey = szPair.Left(nEqPos);
  118. szKey.TrimLeft();
  119. szKey.TrimRight();
  120. szValue = szPair.Mid (nEqPos + 1);
  121. szValue.TrimLeft();
  122. szValue.TrimRight();
  123. return S_OK;
  124. }
  125. //+--------------------------------------------------------------------------
  126. //
  127. // Function: ConvertOldStyleSection
  128. //
  129. // Synopsis: this function looks at an ini file and if does not have the
  130. // new ini file format, it reads the old redirect section and
  131. // transforms it into the new ini file format which supports
  132. // scaleability
  133. //
  134. // Arguments: [in] szGPTPath : the directory where the ini file resides
  135. // [in] pScope : pointer to the scope pane
  136. //
  137. // Returns: S_OK if it was successful
  138. // an error code if it fails
  139. //
  140. // History: 9/28/1998 RahulTh created
  141. //
  142. // Notes: This function exists primarily for backward compatibility
  143. // with Win2K betas. Might be okay to remove it.
  144. //
  145. //---------------------------------------------------------------------------
  146. HRESULT ConvertOldStyleSection (
  147. const CString& szGPTPath
  148. )
  149. {
  150. AFX_MANAGE_STATE (AfxGetStaticModuleState());
  151. CString szIniFile;
  152. TCHAR* lpszSection;
  153. TCHAR* szEntry;
  154. DWORD cbSize = 1024;
  155. DWORD cbCopied;
  156. CString SectionEntry;
  157. CString Key;
  158. CString Dir;
  159. CString Value;
  160. CString Path;
  161. CString szStartMenu;
  162. CString szPrograms;
  163. CString szStartup;
  164. ULONG flags;
  165. DWORD Status;
  166. BOOL bStatus;
  167. HRESULT hr = S_OK;
  168. const TCHAR szEveryOne[] = TEXT("s-1-1-0");
  169. //derive the full path of the ini file.
  170. szIniFile.LoadString (IDS_INIFILE);
  171. szIniFile = szGPTPath + '\\' + szIniFile;
  172. //create an empty section
  173. lpszSection = new TCHAR [cbSize];
  174. lpszSection[0] = lpszSection[1] = '\0';
  175. switch (CheckIniFormat (szIniFile))
  176. {
  177. case S_OK:
  178. //this section has already been converted
  179. goto ConOldStlSec_CleanupAndQuit;
  180. case S_FALSE:
  181. break; //has the Redirect section but not the FolderStatus
  182. //section, so there is processing to do.
  183. case REGDB_E_KEYMISSING:
  184. //this means that the function has neither the FolderStatus section
  185. //nor the Redirect section, so we just create an empty FolderStatus
  186. //section to make processing simpler in future.
  187. //ignore any errors here because they don't really cause any harm
  188. //however, make sure that the file is pre-created in unicode so that
  189. //the WritePrivateProfile* functions don't puke in ANSI
  190. PrecreateUnicodeIniFile ((LPCTSTR)szIniFile);
  191. WritePrivateProfileSection (TEXT("FolderStatus"),
  192. lpszSection,
  193. (LPCTSTR) szIniFile);
  194. hr = S_OK;
  195. goto ConOldStlSec_CleanupAndQuit;
  196. }
  197. //this means that we need to convert the section ourselves
  198. //first load the redirect section
  199. do
  200. {
  201. cbCopied = GetPrivateProfileSection (TEXT("Redirect"),
  202. lpszSection,
  203. cbSize,
  204. (LPCTSTR) szIniFile
  205. );
  206. if (cbSize - 2 == cbCopied)
  207. {
  208. delete [] lpszSection;
  209. cbSize *= 2;
  210. lpszSection = new TCHAR [cbSize];
  211. continue;
  212. }
  213. //the section has been successfully loaded if we are here.
  214. break;
  215. } while (TRUE);
  216. //start the conversion process:
  217. for (szEntry = lpszSection; *szEntry; szEntry += (lstrlen(szEntry) + 1))
  218. {
  219. SectionEntry = szEntry;
  220. if (FAILED(hr = SplitProfileString (SectionEntry, Key, Value)))
  221. goto ConOldStlSec_CleanupAndQuit;
  222. SplitRHS (Value, flags, Path);
  223. Path.TrimLeft();
  224. Path.TrimRight();
  225. if (Path.IsEmpty())
  226. Path = TEXT("%USERPROFILE%") + ('\\' + Key); //we used the relative paths for keys in the old style section
  227. ExtractDisplayName (Key, Dir);
  228. //set the new flags or modify the existing flags to reflect new behavior
  229. szStartMenu.LoadString (IDS_STARTMENU);
  230. szPrograms.LoadString (IDS_PROGRAMS);
  231. szStartup.LoadString (IDS_STARTUP);
  232. if (Dir.CompareNoCase (szStartMenu) && //it is not the start menu and
  233. Dir.CompareNoCase (szPrograms) && //it is not programs and
  234. Dir.CompareNoCase (szStartup)) //it is not the startup folder
  235. {
  236. flags |= REDIR_SETACLS; //apply acls. this was the default behavior earlier, but not any more
  237. }
  238. else //it is one of start menu/programs/startup
  239. {
  240. //move contents is not allowed for start menu and its descendants
  241. flags &= ~REDIR_MOVE_CONTENTS;
  242. }
  243. if ((flags & REDIR_DONT_CARE) && (flags & REDIR_FOLLOW_PARENT))
  244. {
  245. //if both flags were present, this implies they are linked together
  246. //in the new format, in order to express this, only follow_parent
  247. //is required
  248. flags &= ~REDIR_DONT_CARE;
  249. }
  250. Value.Format (TEXT("%x"), flags);
  251. bStatus = WritePrivateProfileString (TEXT("FolderStatus"),
  252. Dir,
  253. Value,
  254. (LPCTSTR)szIniFile
  255. );
  256. if (bStatus && (!(flags & REDIR_DONT_CARE)) && (!(flags & REDIR_FOLLOW_PARENT)))
  257. bStatus = WritePrivateProfileString ((LPCTSTR) Dir,
  258. szEveryOne,
  259. (LPCTSTR) Path,
  260. (LPCTSTR) szIniFile
  261. );
  262. if (!bStatus)
  263. {
  264. Status = GetLastError();
  265. hr = HRESULT_FROM_WIN32 (Status);
  266. goto ConOldStlSec_CleanupAndQuit;
  267. }
  268. }
  269. ConOldStlSec_CleanupAndQuit:
  270. delete [] lpszSection;
  271. return hr;
  272. }
  273. //+--------------------------------------------------------------------------
  274. //
  275. // Function: GetFolderIndex
  276. //
  277. // Synopsis: given the name of a folder, this function returns its index
  278. // in the array of CFileInfo objects in the scope pane
  279. //
  280. // Arguments: [in] szName : name of the folder
  281. //
  282. // Returns: the index of the folder or -1 if the name is invalid
  283. //
  284. // History: 9/28/1998 RahulTh created
  285. //
  286. // Notes:
  287. //
  288. //---------------------------------------------------------------------------
  289. LONG GetFolderIndex (const CString& szName)
  290. {
  291. LONG i;
  292. CString szBuiltinFolder;
  293. for (i = IDS_DIRS_START; i < IDS_DIRS_END; i++)
  294. {
  295. szBuiltinFolder.LoadString (i);
  296. if (szName.CompareNoCase((LPCTSTR)szBuiltinFolder))
  297. break;
  298. }
  299. return GETINDEX (i);
  300. }
  301. //+--------------------------------------------------------------------------
  302. //
  303. // Function: CheckIniFormat
  304. //
  305. // Synopsis: this function examines the sections of an ini file to see
  306. // if it supports the new ini file format (that allows for
  307. // scaleability)
  308. //
  309. // Arguments: [in] szIniFile : the full path of the ini file
  310. //
  311. // Returns: S_OK : if it finds the FolderStatus section
  312. // S_FALSE : if it does not find the FolderStatus section but
  313. // finds the Redirect section
  314. // REGDB_E_KEYMISSING : if it finds neither the FolderStatus
  315. // section nor the Redirect section
  316. //
  317. // History: 9/28/1998 RahulTh created
  318. //
  319. // Notes: this function exists for backward compatibility with Win2K
  320. // Betas. Might be okay to get rid of this eventually.
  321. //
  322. //---------------------------------------------------------------------------
  323. HRESULT CheckIniFormat (LPCTSTR szIniFile)
  324. {
  325. DWORD cchSize = 1024;
  326. DWORD cchCopied;
  327. TCHAR* lpszNames;
  328. TCHAR* szSectionName;
  329. BOOL fHasFolderStatus = FALSE;
  330. BOOL fHasRedirect = FALSE;
  331. do
  332. {
  333. lpszNames = (TCHAR*) LocalAlloc( LPTR, cchSize * sizeof(TCHAR) );
  334. if (! lpszNames)
  335. return E_OUTOFMEMORY;
  336. *lpszNames = L'\0';
  337. cchCopied = GetPrivateProfileSectionNames (lpszNames, cchSize, szIniFile);
  338. if (cchSize - 2 == cchCopied) //the buffer was not enough.
  339. {
  340. LocalFree( lpszNames );
  341. cchSize *= 2; //increase the buffer size
  342. continue;
  343. }
  344. break; //if we are here, we are done.
  345. } while (TRUE);
  346. for (szSectionName = lpszNames;
  347. *szSectionName;
  348. szSectionName += (lstrlen(szSectionName) + 1))
  349. {
  350. if (CompareString(LOCALE_INVARIANT, NORM_IGNORECASE, szSectionName, -1, TEXT("FolderStatus"), -1) == CSTR_EQUAL)
  351. {
  352. fHasFolderStatus = TRUE;
  353. continue;
  354. }
  355. if (CompareString(LOCALE_INVARIANT, NORM_IGNORECASE, szSectionName, -1, TEXT("Redirect"), -1) == CSTR_EQUAL)
  356. {
  357. fHasRedirect = TRUE;
  358. continue;
  359. }
  360. }
  361. //cleanup dynamically allocated memory before quitting
  362. LocalFree( lpszNames );
  363. if (fHasFolderStatus)
  364. return S_OK;
  365. //if we are here, the file does not have the FolderStatus section
  366. if (fHasRedirect)
  367. return S_FALSE;
  368. //if we are here, then the file has neither the folder status section
  369. //nor the Redirect section
  370. return REGDB_E_KEYMISSING;
  371. }
  372. //+--------------------------------------------------------------------------
  373. //
  374. // Function: GetIntfromUnicodeString
  375. //
  376. // Synopsis: converts a unicode string into an integer
  377. //
  378. // Arguments: [in] szNum : the number represented as a unicode string
  379. // [in] Base : the base in which the resultant int is desired
  380. // [out] pValue : pointer to the integer representation of the
  381. // number
  382. //
  383. // Returns: STATUS_SUCCESS if successful.
  384. // or some other error code
  385. //
  386. // History: 9/29/1998 RahulTh created
  387. //
  388. // Notes:
  389. //
  390. //---------------------------------------------------------------------------
  391. NTSTATUS GetIntFromUnicodeString (const WCHAR* szNum, ULONG Base, PULONG pValue)
  392. {
  393. CString StrNum;
  394. UNICODE_STRING StringW;
  395. size_t len;
  396. NTSTATUS Status;
  397. StrNum = szNum;
  398. len = StrNum.GetLength();
  399. StringW.Length = len * sizeof(WCHAR);
  400. StringW.MaximumLength = sizeof(WCHAR) * (len + 1);
  401. StringW.Buffer = StrNum.GetBuffer(len);
  402. Status = RtlUnicodeStringToInteger (&StringW, Base, pValue);
  403. return Status;
  404. }
  405. //+--------------------------------------------------------------------------
  406. //
  407. // Function: GetUNCPath
  408. //
  409. // Synopsis: this function tries to retrieve the UNC path of an item
  410. // given its PIDL
  411. //
  412. // Arguments: [in] lpszPath : the full path to the selected file.
  413. // [out] szUNC : the UNC path of the item
  414. //
  415. // Returns: NO_ERROR if the conversion was successful.
  416. // other error codes if not...
  417. //
  418. // History: 10/1/1998 RahulTh created
  419. // 4/12/1999 RahulTh added error code. changed params.
  420. // (item id list is no longer passed in)
  421. //
  422. // Notes: if this function is unsuccessful, then szUNC will contain an
  423. // empty string
  424. //
  425. //---------------------------------------------------------------------------
  426. DWORD GetUNCPath (LPCTSTR lpszPath, CString& szUNC)
  427. {
  428. TCHAR* lpszUNCName;
  429. UNIVERSAL_NAME_INFO* pUNCInfo;
  430. DWORD lBufferSize;
  431. DWORD retVal = NO_ERROR;
  432. szUNC.Empty(); //precautionary measures
  433. //we have a path, now we shall try to get a UNC path
  434. lpszUNCName = new TCHAR[MAX_PATH];
  435. pUNCInfo = (UNIVERSAL_NAME_INFO*)lpszUNCName;
  436. lBufferSize = MAX_PATH * sizeof(TCHAR);
  437. retVal = WNetGetUniversalName (lpszPath,
  438. UNIVERSAL_NAME_INFO_LEVEL,
  439. (LPVOID)pUNCInfo,
  440. &lBufferSize);
  441. if (ERROR_MORE_DATA == retVal) //MAX_PATH was insufficient to hold the UNC path
  442. {
  443. delete [] lpszUNCName;
  444. lpszUNCName = new TCHAR[lBufferSize/(sizeof(TCHAR)) + 1];
  445. pUNCInfo = (UNIVERSAL_NAME_INFO*)lpszUNCName;
  446. retVal = WNetGetUniversalName (lpszPath,
  447. UNIVERSAL_NAME_INFO_LEVEL,
  448. (LPVOID)pUNCInfo,
  449. &lBufferSize);
  450. }
  451. //at this point we may or may not have a UNC path.
  452. //if we do, we return that, or we return whatever we already have
  453. if (NO_ERROR == retVal)
  454. szUNC = pUNCInfo->lpUniversalName;
  455. delete [] lpszUNCName;
  456. return retVal;
  457. }
  458. //+--------------------------------------------------------------------------
  459. //
  460. // Function: BrowseCallbackProc
  461. //
  462. // Synopsis: the callback function for SHBrowseForFolder
  463. //
  464. // Arguments: see Platform SDK
  465. //
  466. // Returns: see Platform SDK
  467. //
  468. // History: 4/9/1999 RahulTh created
  469. //
  470. // Notes:
  471. //
  472. //---------------------------------------------------------------------------
  473. int CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg,
  474. LPARAM lParam, LPARAM lpData
  475. )
  476. {
  477. CString * pszData;
  478. CString szStart;
  479. int index;
  480. LPITEMIDLIST lpidl = NULL;
  481. TCHAR lpszPath [MAX_PATH];
  482. pszData = (CString *) lpData;
  483. switch (uMsg)
  484. {
  485. case BFFM_INITIALIZED:
  486. if (pszData)
  487. {
  488. szStart = *pszData;
  489. szStart.TrimRight();
  490. szStart.TrimLeft();
  491. if (! szStart.IsEmpty())
  492. {
  493. index = szStart.ReverseFind (L'\\');
  494. if (-1 != index && index > 1)
  495. szStart = szStart.Left (index);
  496. SendMessage (hwnd, BFFM_SETSELECTION, TRUE,
  497. (LPARAM)(LPCTSTR)szStart);
  498. }
  499. }
  500. break;
  501. case BFFM_SELCHANGED:
  502. //we need to check if we can get the full path to the selected folder.
  503. //e.g. if the full path exceeds MAX_PATH, we cannot obtain the path
  504. //from the item id list. if we cannot get the path, we should not
  505. //enable the OK button. So, over here, as a precaution, we first
  506. //disable the OK button. We will enable it only after we get the path.
  507. SendMessage (hwnd, BFFM_ENABLEOK, FALSE, FALSE);
  508. if (SHGetPathFromIDList((LPCITEMIDLIST)lParam, lpszPath))
  509. {
  510. //set the path into the data member and enable the OK button
  511. if (lpData)
  512. {
  513. SendMessage (hwnd, BFFM_ENABLEOK, TRUE, TRUE);
  514. *((CString *) lpData) = lpszPath;
  515. }
  516. }
  517. break;
  518. default:
  519. break;
  520. }
  521. return 0;
  522. }
  523. //+--------------------------------------------------------------------------
  524. //
  525. // Function: PrecreateUnicodeIniFile
  526. //
  527. // Synopsis: The WritePrivateProfile* functions do not write in unicode
  528. // unless the file already exists in unicode format. Therefore,
  529. // this function is used to precreate a unicode file so that
  530. // the WritePrivateProfile* functions can preserve the unicodeness.
  531. //
  532. // Arguments: [in] lpszFilePath : the full path of the ini file.
  533. //
  534. // Returns: ERROR_SUCCESS if successful.
  535. // an error code otherwise.
  536. //
  537. // History: 7/9/1999 RahulTh created
  538. //
  539. // Notes:
  540. //
  541. //---------------------------------------------------------------------------
  542. DWORD PrecreateUnicodeIniFile (LPCTSTR lpszFilePath)
  543. {
  544. HANDLE hFile;
  545. WIN32_FILE_ATTRIBUTE_DATA fad;
  546. DWORD Status = ERROR_ALREADY_EXISTS;
  547. DWORD dwWritten;
  548. if (!GetFileAttributesEx (lpszFilePath, GetFileExInfoStandard, &fad))
  549. {
  550. if (ERROR_FILE_NOT_FOUND == (Status = GetLastError()))
  551. {
  552. hFile = CreateFile(lpszFilePath, GENERIC_WRITE, 0, NULL,
  553. CREATE_NEW, FILE_ATTRIBUTE_HIDDEN, NULL);
  554. if (hFile != INVALID_HANDLE_VALUE)
  555. {
  556. //add the unicode marker to the beginning of the file
  557. //so that APIs know for sure that it is a unicode file.
  558. WriteFile(hFile, L"\xfeff\r\n", 3 * sizeof(WCHAR),
  559. &dwWritten, NULL);
  560. //add some unicode characters to the file.
  561. WriteFile(hFile, L" \r\n", 7 * sizeof(WCHAR),
  562. &dwWritten, NULL);
  563. CloseHandle(hFile);
  564. Status = ERROR_SUCCESS;
  565. }
  566. else
  567. {
  568. Status = GetLastError();
  569. }
  570. }
  571. }
  572. return Status;
  573. }
  574. //+--------------------------------------------------------------------------
  575. //
  576. // Function: IsValidPrefix
  577. //
  578. // Synopsis: Given a path, this function determines if it is a valid prefix
  579. //
  580. // Arguments: [in] pathType : the type of the path
  581. // [in] pwszPath : the supplied path
  582. //
  583. // Returns: TRUE: if the prefix is valid.
  584. // FALSE: otherwise
  585. //
  586. // History: 3/14/2000 RahulTh created
  587. //
  588. // Notes: A valid prefix is either a non-unc path or a UNC path which
  589. // has at least the server and the share component. It must also
  590. // be a non-empty path.
  591. //
  592. //---------------------------------------------------------------------------
  593. BOOL IsValidPrefix (UINT pathType, LPCTSTR pwszPath)
  594. {
  595. CString szPath;
  596. const WCHAR * pwszProcessedPath;
  597. if (! pwszPath || L'\0' == *pwszPath)
  598. return FALSE;
  599. szPath = pwszPath;
  600. szPath.TrimLeft();
  601. szPath.TrimRight();
  602. szPath.TrimRight(L'\\');
  603. pwszProcessedPath = (LPCTSTR) szPath;
  604. if (PathIsUNC ((LPCTSTR) szPath))
  605. {
  606. // Make sure it has both the server and the share component
  607. if (lstrlen (pwszProcessedPath) <= 2 ||
  608. L'\\' != pwszProcessedPath[0] ||
  609. L'\\' != pwszProcessedPath[1] ||
  610. NULL == wcschr (&pwszProcessedPath[2], L'\\'))
  611. {
  612. return FALSE;
  613. }
  614. }
  615. //
  616. // If we are here, we just need to make sure that the path does not contain
  617. // any environment variables -- if it is not IDS_SPECIFIC_PATH
  618. //
  619. if (pathType != IDS_SPECIFIC_PATH &&
  620. NULL != wcschr(pwszProcessedPath, L'%'))
  621. {
  622. return FALSE;
  623. }
  624. // If we make it up to here, then the path is a valid prefix.
  625. return TRUE;
  626. }
  627. //+--------------------------------------------------------------------------
  628. //
  629. // Function: AlwaysShowMyPicsNode
  630. //
  631. // Synopsis: In WindowsXP, we now show the MyPics node in the scope pane
  632. // only if My Pics does not follow My Docs. However, if required
  633. // this MyPics can always be made visible by setting a reg. value
  634. // under HKLM\Software\Policies\Microsoft\Windows\System called
  635. // FRAlwaysShowMyPicsNode. This is a DWORD value and if set to
  636. // non-zero, the MyPics node will always be displayed.
  637. //
  638. // Arguments: none.
  639. //
  640. // Returns: TRUE : if the value was found in the registry and was non-zero.
  641. // FALSE : otherwise.
  642. //
  643. // History: 4/10/2001 RahulTh created
  644. //
  645. // Notes: Note: In case of errors, the default value of FALSE is returned.
  646. //
  647. //---------------------------------------------------------------------------
  648. BOOL AlwaysShowMyPicsNode (void)
  649. {
  650. BOOL bAlwaysShowMyPics = FALSE;
  651. DWORD dwValue = 0;
  652. DWORD dwType = REG_DWORD;
  653. DWORD dwSize = sizeof(DWORD);
  654. HKEY hKey = NULL;
  655. if (ERROR_SUCCESS != RegOpenKey (HKEY_LOCAL_MACHINE,
  656. TEXT("Software\\Policies\\Microsoft\\Windows\\System"),
  657. &hKey)
  658. )
  659. {
  660. return bAlwaysShowMyPics;
  661. }
  662. if (ERROR_SUCCESS == RegQueryValueEx (hKey,
  663. TEXT("FRAlwaysShowMyPicsNode"),
  664. NULL,
  665. &dwType,
  666. (LPBYTE)(&dwValue),
  667. &dwSize)
  668. )
  669. {
  670. if (REG_DWORD == dwType && dwValue)
  671. bAlwaysShowMyPics = TRUE;
  672. }
  673. RegCloseKey(hKey);
  674. return bAlwaysShowMyPics;
  675. }
  676. //+--------------------------------------------------------------------------
  677. //
  678. // Function: CreateThemedPropertyPage
  679. //
  680. // Synopsis: Helper function to make sure that property pages put up
  681. // by the snap-in are themed.
  682. //
  683. // Arguments:
  684. //
  685. // Returns:
  686. //
  687. // History: 4/20/2001 RahulTh created
  688. //
  689. // Notes:
  690. //
  691. //---------------------------------------------------------------------------
  692. HPROPSHEETPAGE CreateThemedPropertySheetPage(AFX_OLDPROPSHEETPAGE* psp)
  693. {
  694. PROPSHEETPAGE_V3 sp_v3 = {0};
  695. CopyMemory (&sp_v3, psp, psp->dwSize);
  696. sp_v3.dwSize = sizeof(sp_v3);
  697. return (::CreatePropertySheetPage (&sp_v3));
  698. }