Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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