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.

2408 lines
63 KiB

  1. /*++
  2. Microsoft Confidential
  3. Copyright (c) 1992-1997 Microsoft Corporation
  4. All rights reserved
  5. Module Name:
  6. virtual.c
  7. Abstract:
  8. Implements the Change Virtual Memory dialog of the System
  9. Control Panel Applet
  10. Notes:
  11. The virtual memory settings and the crash dump (core dump) settings
  12. are tightly-coupled. Therefore, virtual.c and virtual.h have some
  13. heavy dependencies on crashdmp.c and startup.h (and vice versa).
  14. Author:
  15. Byron Dazey 06-Jun-1992
  16. Revision History:
  17. 14-Apr-93 JonPa
  18. maintain paging path if != \pagefile.sys
  19. 15-Dec-93 JonPa
  20. added Crash Recovery dialog
  21. 02-Feb-1994 JonPa
  22. integrated crash recover and virtual memory settings
  23. 18-Sep-1995 Steve Cathcart
  24. split system.cpl out from NT3.51 main.cpl
  25. 12-Jan-1996 JonPa
  26. made part of the new SUR pagified system.cpl
  27. 15-Oct-1997 scotthal
  28. Split out CoreDump*() stuff into separate file
  29. 09-Jul-2000 SilviuC
  30. Allow very big page files if architecture supports it.
  31. Allow booting without a page file.
  32. Allow the system to scale the page file size based on RAM changes.
  33. --*/
  34. //==========================================================================
  35. // Include files
  36. //==========================================================================
  37. // NT base apis
  38. #include <nt.h>
  39. #include <ntrtl.h>
  40. #include <nturtl.h>
  41. #include <ntdddisk.h>
  42. #include <help.h>
  43. // Application specific
  44. #include "sysdm.h"
  45. //==========================================================================
  46. // External Data Declarations
  47. //==========================================================================
  48. extern HFONT hfontBold;
  49. //==========================================================================
  50. // Local Definitions
  51. //==========================================================================
  52. #define MAX_SIZE_LEN 8 // Max chars in the Swap File Size edit.
  53. #define MIN_FREESPACE 5 // Must have 5 meg free after swap file
  54. #define MIN_SUGGEST 22 // Always suggest at least 22 meg
  55. #define CCHMBSTRING 12 // Space for localizing the "MB" string.
  56. /*
  57. * Space for 26 pagefile info structures and 26 paths to pagefiles.
  58. */
  59. #define PAGEFILE_INFO_BUFFER_SIZE MAX_DRIVES * sizeof(SYSTEM_PAGEFILE_INFORMATION) + \
  60. MAX_DRIVES * MAX_PATH * sizeof(TCHAR)
  61. /*
  62. * Maximum length of volume info line in the listbox.
  63. * A: [ Vol_label ] %d - %d
  64. */
  65. #define MAX_VOL_LINE (3 + 1 + MAX_PATH + 2 + 10 + 3 + 10)
  66. /*
  67. * This amount will be added to the minimum page file size to determine
  68. * the maximum page file size if it is not explicitly specified.
  69. */
  70. #define MAXOVERMINFACTOR 50
  71. #define TABSTOP_VOL 22
  72. #define TABSTOP_SIZE 122
  73. /*
  74. * My privilege 'handle' structure
  75. */
  76. typedef struct {
  77. HANDLE hTok;
  78. TOKEN_PRIVILEGES tp;
  79. } PRIVDAT, *PPRIVDAT;
  80. //==========================================================================
  81. // Typedefs and Structs
  82. //==========================================================================
  83. // registry info for a page file (but not yet formatted).
  84. //Note: since this structure gets passed to FormatMessage, all fields must
  85. //be 4 bytes wide (or 8 bytes on Win64)
  86. typedef struct
  87. {
  88. LPTSTR pszName;
  89. DWORD_PTR nMin;
  90. DWORD_PTR nMax;
  91. DWORD_PTR chNull;
  92. } PAGEFILDESC;
  93. //==========================================================================
  94. // Global Data Declarations
  95. //==========================================================================
  96. HKEY ghkeyMemMgt = NULL;
  97. int gcrefMemMgt = 0;
  98. VCREG_RET gvcMemMgt = VCREG_ERROR;
  99. int gcrefPagingFiles = 0;
  100. TCHAR g_szSysDir[ MAX_PATH ];
  101. //==========================================================================
  102. // Local Data Declarations
  103. //==========================================================================
  104. /*
  105. * Virtual Memory Vars
  106. */
  107. // Registry Key and Value Names
  108. TCHAR szMemMan[] =
  109. TEXT("System\\CurrentControlSet\\Control\\Session Manager\\Memory Management");
  110. TCHAR szSessionManager[] = TEXT("System\\CurrentControlSet\\Control\\Session Manager");
  111. TCHAR szPendingRename[] = TEXT("PendingFileRenameOperations");
  112. TCHAR szRenameFunkyPrefix[] = TEXT("\\??\\");
  113. #ifndef VM_DBG
  114. TCHAR szPagingFiles[] = TEXT("PagingFiles");
  115. TCHAR szPagedPoolSize[] = TEXT("PagedPoolSize");
  116. #else
  117. // temp values for testing only!
  118. TCHAR szPagingFiles[] = TEXT("TestPagingFiles");
  119. TCHAR szPagedPoolSize[] = TEXT("TestPagedPoolSize");
  120. #endif
  121. /* Array of paging files. This is indexed by the drive letter (A: is 0). */
  122. PAGING_FILE apf[MAX_DRIVES];
  123. PAGING_FILE apfOriginal[MAX_DRIVES];
  124. // Other VM Vars
  125. TCHAR szPagefile[] = TEXT("x:\\pagefile.sys");
  126. TCHAR szNoPageFile[] = TEXT("TempPageFile");
  127. TCHAR szMB[CCHMBSTRING];
  128. DWORD dwFreeMB;
  129. DWORD cmTotalVM;
  130. DWORD cmRegSizeLim;
  131. DWORD cmPagedPoolLim;
  132. DWORD cmRegUsed;
  133. static DWORD cxLBExtent;
  134. static int cxExtra;
  135. //
  136. // Help IDs
  137. //
  138. DWORD aVirtualMemHelpIds[] = {
  139. IDC_STATIC, NO_HELP,
  140. IDD_VM_VOLUMES, NO_HELP,
  141. IDD_VM_DRIVE_HDR, (IDH_DLG_VIRTUALMEM + 0),
  142. IDD_VM_PF_SIZE_LABEL, (IDH_DLG_VIRTUALMEM + 1),
  143. IDD_VM_DRIVE_LABEL, (IDH_DLG_VIRTUALMEM + 2),
  144. IDD_VM_SF_DRIVE, (IDH_DLG_VIRTUALMEM + 2),
  145. IDD_VM_SPACE_LABEL, (IDH_DLG_VIRTUALMEM + 3),
  146. IDD_VM_SF_SPACE, (IDH_DLG_VIRTUALMEM + 3),
  147. IDD_VM_ST_INITSIZE, (IDH_DLG_VIRTUALMEM + 4),
  148. IDD_VM_SF_SIZE, (IDH_DLG_VIRTUALMEM + 4),
  149. IDD_VM_ST_MAXSIZE, (IDH_DLG_VIRTUALMEM + 5),
  150. IDD_VM_SF_SIZEMAX, (IDH_DLG_VIRTUALMEM + 5),
  151. IDD_VM_SF_SET, (IDH_DLG_VIRTUALMEM + 6),
  152. IDD_VM_MIN_LABEL, (IDH_DLG_VIRTUALMEM + 7),
  153. IDD_VM_MIN, (IDH_DLG_VIRTUALMEM + 7),
  154. IDD_VM_RECOMMEND_LABEL, (IDH_DLG_VIRTUALMEM + 8),
  155. IDD_VM_RECOMMEND, (IDH_DLG_VIRTUALMEM + 8),
  156. IDD_VM_ALLOCD_LABEL, (IDH_DLG_VIRTUALMEM + 9),
  157. IDD_VM_ALLOCD, (IDH_DLG_VIRTUALMEM + 9),
  158. IDD_VM_CUSTOMSIZE_RADIO,(IDH_DLG_VIRTUALMEM + 12),
  159. IDD_VM_RAMBASED_RADIO, (IDH_DLG_VIRTUALMEM + 13),
  160. IDD_VM_NOPAGING_RADIO, (IDH_DLG_VIRTUALMEM + 14),
  161. 0,0
  162. };
  163. #if 0
  164. Plan for splitting this into propert sheets:
  165. 1. Make the VM and CC registry keys globals that are inited
  166. to NULL (or INVALID_HANDLE_VALUE). Also make gvcVirt and
  167. vcCore to be globals (so we can tell how the reg was opened
  168. inside virtinit().)
  169. 1. Change all RegCloseKey's to VirtualCloseKey and CoreDumpCloseKey
  170. 2. Change VirtualOpenKey and CoreDumpOpenKey from macros to
  171. functions that return the global handles if they are already
  172. opened, or else opens them.
  173. 3. In the Perf and Startup pages, call VirtualOpenKey,
  174. CoreDumpOpenKey, and VirtualGetPageFiles.
  175. -- now we can call VirtualMemComputeAlloced() from the perf page
  176. -- we can also just execute the CrashDump code in the startup page
  177. 4. rewrite VirtInit to not try and open the keys again, but instesd
  178. use gvcVirt, vcCore, hkeyVM and kheyCC.
  179. 4. Write VirtualCloseKey and CoreDumpCloseKey as follows...
  180. 4.a If hkey == NULL return
  181. 4.b RegCloseKey(hkey)
  182. 4.c hkey = NULL
  183. 5. In the PSN_RESET and PSN_APPLY cases for Perf and Startup pages
  184. call VirtualCloseKey and CoreDumpCloseKey
  185. #endif
  186. //==========================================================================
  187. // Local Function Prototypes
  188. //==========================================================================
  189. static BOOL VirtualMemInit(HWND hDlg);
  190. static BOOL ParsePageFileDesc(LPTSTR *ppszDesc, INT *pnDrive,
  191. INT *pnMinFileSize, INT *pnMaxFileSize, LPTSTR *ppszName);
  192. static VOID VirtualMemBuildLBLine(LPTSTR pszBuf, INT iDrive);
  193. static INT GetMaxSpaceMB(INT iDrive);
  194. static VOID VirtualMemSelChange(HWND hDlg);
  195. static VOID VirtualMemUpdateAllocated(HWND hDlg);
  196. int VirtualMemComputeTotalMax( void );
  197. static BOOL VirtualMemSetNewSize(HWND hDlg);
  198. static UINT VMGetDriveType(LPCTSTR lpszDrive);
  199. void VirtualMemReconcileState();
  200. void GetAPrivilege( LPTSTR pszPrivilegeName, PPRIVDAT ppd );
  201. void ResetOldPrivilege( PPRIVDAT ppdOld );
  202. DWORD VirtualMemDeletePagefile( LPTSTR szPagefile );
  203. #define GetPageFilePrivilege( ppd ) \
  204. GetAPrivilege(SE_CREATE_PAGEFILE_NAME, ppd)
  205. #define GetRegistryQuotaPrivilege( ppd ) \
  206. GetAPrivilege(SE_INCREASE_QUOTA_NAME, ppd)
  207. //==========================================================================
  208. VCREG_RET VirtualOpenKey( void ) {
  209. DOUT("In VirtOpenKey" );
  210. if (gvcMemMgt == VCREG_ERROR) {
  211. gvcMemMgt = OpenRegKey( szMemMan, &ghkeyMemMgt );
  212. }
  213. if (gvcMemMgt != VCREG_ERROR)
  214. gcrefMemMgt++;
  215. DPRINTF((TEXT("SYSCPL.CPL: VirtOpenKey, cref=%d\n"), gcrefMemMgt ));
  216. return gvcMemMgt;
  217. }
  218. void VirtualCloseKey(void) {
  219. DOUT( "In VirtCloseKey" );
  220. if (gcrefMemMgt > 0) {
  221. gcrefMemMgt--;
  222. if (gcrefMemMgt == 0) {
  223. CloseRegKey( ghkeyMemMgt );
  224. gvcMemMgt = VCREG_ERROR;
  225. }
  226. }
  227. DPRINTF((TEXT("SYSCPL.CPL: VirtCloseKey, cref=%d\n"), gcrefMemMgt ));
  228. }
  229. LPTSTR SkipNonWhiteSpace( LPTSTR sz ) {
  230. while( *sz != TEXT('\0') && !IsWhiteSpace(*sz))
  231. sz++;
  232. return sz;
  233. }
  234. INT TranslateDlgItemInt( HWND hDlg, int id ) {
  235. /*
  236. * We can't just call GetDlgItemInt because the
  237. * string we are trying to translate looks like:
  238. * nnn (MB), and the '(MB)' would break GetDlgInt.
  239. */
  240. TCHAR szBuffer[256];
  241. int i = 0;
  242. if (GetDlgItemText(hDlg, id, szBuffer,
  243. sizeof(szBuffer) / sizeof(*szBuffer))) {
  244. i = StringToInt( szBuffer );
  245. }
  246. return i;
  247. }
  248. LPTSTR SZPageFileName (int i)
  249. {
  250. if (apf[i].pszPageFile != NULL) {
  251. return apf[i].pszPageFile;
  252. }
  253. szPagefile[0] = (TCHAR)(i + (int)TEXT('A'));
  254. return szPagefile;
  255. }
  256. LONG GetRegistryInt( HKEY hkey, LPTSTR pszValue, LONG lDefault ) {
  257. DWORD dwType;
  258. DWORD cbTemp;
  259. DWORD dwVal;
  260. cbTemp = sizeof(DWORD);
  261. if (RegQueryValueEx (hkey, pszValue, NULL,
  262. &dwType, (LPBYTE)&dwVal, &cbTemp) != ERROR_SUCCESS ||
  263. dwType != REG_DWORD || cbTemp != sizeof(DWORD)) {
  264. dwVal = (DWORD)lDefault;
  265. }
  266. return (LONG)dwVal;
  267. }
  268. BOOL SetRegistryInt( HKEY hkey, LPTSTR pszValue, LONG iValue ) {
  269. return RegSetValueEx(hkey, pszValue, 0L, REG_DWORD, (LPBYTE)&iValue,
  270. sizeof(iValue)) == ERROR_SUCCESS;
  271. }
  272. void VirtualCopyPageFiles( PAGING_FILE *apfDest, BOOL fFreeOld, PAGING_FILE *apfSrc, BOOL fCloneStrings ) {
  273. int i;
  274. for (i = 0; i < MAX_DRIVES; i++) {
  275. if (fFreeOld && apfDest[i].pszPageFile != NULL) {
  276. MemFree(apfDest[i].pszPageFile);
  277. }
  278. if (apfSrc != NULL) {
  279. apfDest[i] = apfSrc[i];
  280. if (fCloneStrings && apfDest[i].pszPageFile != NULL) {
  281. apfDest[i].pszPageFile = CloneString(apfDest[i].pszPageFile);
  282. }
  283. }
  284. }
  285. }
  286. /*
  287. * VirtualMemDlg
  288. *
  289. *
  290. *
  291. */
  292. INT_PTR
  293. APIENTRY
  294. VirtualMemDlg(
  295. HWND hDlg,
  296. UINT message,
  297. WPARAM wParam,
  298. LPARAM lParam
  299. )
  300. {
  301. static int fEdtCtlHasFocus = 0;
  302. switch (message)
  303. {
  304. case WM_INITDIALOG:
  305. VirtualMemInit(hDlg);
  306. return TRUE;
  307. case WM_COMMAND:
  308. switch (LOWORD(wParam))
  309. {
  310. case IDD_VM_VOLUMES:
  311. /*
  312. * Make edit control reflect the listbox selection.
  313. */
  314. if (HIWORD(wParam) == LBN_SELCHANGE)
  315. VirtualMemSelChange(hDlg);
  316. break;
  317. case IDD_VM_SF_SET:
  318. if (VirtualMemSetNewSize(hDlg))
  319. SetDefButton(hDlg, IDOK);
  320. break;
  321. case IDOK:
  322. {
  323. int iRet = VirtualMemPromptForReboot(hDlg);
  324. // RET_ERROR means the user told us not to overwrite an
  325. // existing file called pagefile.sys, so we shouldn't
  326. // end the dialog just yet.
  327. if (RET_ERROR == iRet) {
  328. break;
  329. }
  330. VirtualMemUpdateRegistry();
  331. VirtualMemReconcileState();
  332. VirtualCloseKey();
  333. #if 0
  334. CoreDumpCloseKey();
  335. #endif
  336. #if 0
  337. if (gfCoreDumpChanged)
  338. iRet |= RET_RECOVER_CHANGE;
  339. #endif
  340. //
  341. // get rid of backup copy of pagefile structs
  342. //
  343. VirtualCopyPageFiles( apfOriginal, TRUE, NULL, FALSE );
  344. EndDialog(hDlg, iRet);
  345. HourGlass(FALSE);
  346. break;
  347. }
  348. case IDCANCEL:
  349. //
  350. // get rid of changes and restore original values
  351. //
  352. VirtualCopyPageFiles( apf, TRUE, apfOriginal, FALSE );
  353. VirtualCloseKey();
  354. #if 0
  355. CoreDumpCloseKey();
  356. #endif
  357. EndDialog(hDlg, RET_NO_CHANGE);
  358. HourGlass(FALSE);
  359. break;
  360. case IDD_VM_SF_SIZE:
  361. case IDD_VM_SF_SIZEMAX:
  362. switch(HIWORD(wParam))
  363. {
  364. case EN_CHANGE:
  365. if (fEdtCtlHasFocus != 0)
  366. SetDefButton( hDlg, IDD_VM_SF_SET);
  367. break;
  368. case EN_SETFOCUS:
  369. fEdtCtlHasFocus++;
  370. break;
  371. case EN_KILLFOCUS:
  372. fEdtCtlHasFocus--;
  373. break;
  374. }
  375. break;
  376. case IDD_VM_NOPAGING_RADIO:
  377. case IDD_VM_RAMBASED_RADIO:
  378. if( HIWORD(wParam) == BN_CLICKED )
  379. {
  380. EnableWindow( GetDlgItem( hDlg, IDD_VM_SF_SIZE ), FALSE );
  381. EnableWindow( GetDlgItem( hDlg, IDD_VM_SF_SIZEMAX ), FALSE );
  382. }
  383. break;
  384. case IDD_VM_CUSTOMSIZE_RADIO:
  385. if( HIWORD(wParam) == BN_CLICKED )
  386. {
  387. EnableWindow( GetDlgItem( hDlg, IDD_VM_SF_SIZE ), TRUE );
  388. EnableWindow( GetDlgItem( hDlg, IDD_VM_SF_SIZEMAX ), TRUE );
  389. }
  390. break;
  391. default:
  392. break;
  393. }
  394. break;
  395. case WM_HELP: // F1
  396. WinHelp((HWND)((LPHELPINFO) lParam)->hItemHandle, HELP_FILE, HELP_WM_HELP,
  397. (DWORD_PTR) (LPSTR) aVirtualMemHelpIds);
  398. break;
  399. case WM_CONTEXTMENU: // right mouse click
  400. WinHelp((HWND) wParam, HELP_FILE, HELP_CONTEXTMENU,
  401. (DWORD_PTR) (LPSTR) aVirtualMemHelpIds);
  402. break;
  403. case WM_DESTROY:
  404. {
  405. VirtualFreePageFiles(apf);
  406. /*
  407. * The docs were not clear as to what a dialog box should return
  408. * for this message, so I am going to punt and let the defdlgproc
  409. * doit.
  410. */
  411. /* FALL THROUGH TO DEFAULT CASE! */
  412. }
  413. default:
  414. return FALSE;
  415. break;
  416. }
  417. return TRUE;
  418. }
  419. /*
  420. * UINT VMGetDriveType( LPCTSTR lpszDrive )
  421. *
  422. * Gets the drive type. This function differs from Win32's GetDriveType
  423. * in that it returns DRIVE_FIXED for lockable removable drives (like
  424. * bernolli boxes, etc).
  425. *
  426. * On IA64 we don't do this, however, requiring all pagefiles be on actual
  427. * fixed drives.
  428. */
  429. TCHAR szDevice[] = TEXT("\\Device");
  430. UINT VMGetDriveType( LPCTSTR lpszDrive ) {
  431. UINT i;
  432. TCHAR szDevName[MAX_PATH];
  433. // Check for subst drive
  434. if (QueryDosDevice( lpszDrive, szDevName, ARRAYSIZE( szDevName ) ) != 0) {
  435. // If drive does not start with '\Device', then it is not FIXED
  436. szDevName[ARRAYSIZE(szDevice) - 1] = '\0';
  437. if ( lstrcmpi(szDevName, szDevice) != 0 ) {
  438. return DRIVE_REMOTE;
  439. }
  440. }
  441. i = GetDriveType( lpszDrive );
  442. #ifndef _WIN64
  443. if ( i == DRIVE_REMOVABLE ) {
  444. TCHAR szNtDrive[20];
  445. DWORD cb;
  446. DISK_GEOMETRY dgMediaInfo;
  447. HANDLE hDisk;
  448. /*
  449. * 'Removable' drive. Check to see if it is a Floppy or lockable
  450. * drive.
  451. */
  452. cb = wsprintf( szNtDrive, TEXT("\\\\.\\%s"), lpszDrive );
  453. if ( cb != 0 && IsPathSep(szNtDrive[--cb]) ) {
  454. szNtDrive[cb] = TEXT('\0');
  455. }
  456. hDisk = CreateFile(
  457. szNtDrive,
  458. /* GENERIC_READ */ 0,
  459. FILE_SHARE_READ | FILE_SHARE_WRITE,
  460. NULL,
  461. OPEN_EXISTING,
  462. 0,
  463. NULL
  464. );
  465. if (hDisk != INVALID_HANDLE_VALUE ) {
  466. if (DeviceIoControl( hDisk, IOCTL_DISK_GET_MEDIA_TYPES, NULL,
  467. 0, &dgMediaInfo, sizeof(dgMediaInfo), &cb, NULL) == FALSE &&
  468. GetLastError() != ERROR_MORE_DATA) {
  469. /*
  470. * Drive is not a floppy
  471. */
  472. i = DRIVE_FIXED;
  473. }
  474. CloseHandle(hDisk);
  475. } else if (GetLastError() == ERROR_ACCESS_DENIED) {
  476. /*
  477. * Could not open the drive, either it is bad, or else we
  478. * don't have permission. Since everyone has permission
  479. * to open floppies, then this must be a bernoulli type device.
  480. */
  481. i = DRIVE_FIXED;
  482. }
  483. }
  484. #endif
  485. return i;
  486. }
  487. /*
  488. * BOOL VirtualGetPageFiles(PAGING_FILE *apf)
  489. *
  490. * Fills in the PAGING_FILE array from the values stored in the registry
  491. */
  492. BOOL VirtualGetPageFiles(PAGING_FILE *apf) {
  493. DWORD cbTemp;
  494. LPTSTR szTemp;
  495. DWORD dwType;
  496. INT nDrive;
  497. INT nMinFileSize;
  498. INT nMaxFileSize;
  499. LPTSTR psz;
  500. DWORD dwDriveMask;
  501. int i;
  502. static TCHAR szDir[] = TEXT("?:");
  503. DPRINTF((TEXT("SYSCPL: In VirtualGetPageFile, cref=%d\n"), gcrefPagingFiles));
  504. if (gcrefPagingFiles++ > 0) {
  505. // Paging files already loaded
  506. return TRUE;
  507. }
  508. dwDriveMask = GetLogicalDrives();
  509. for (i = 0; i < MAX_DRIVES; dwDriveMask >>= 1, i++)
  510. {
  511. apf[i].fCanHavePagefile = FALSE;
  512. apf[i].nMinFileSize = 0;
  513. apf[i].nMaxFileSize = 0;
  514. apf[i].nMinFileSizePrev = 0;
  515. apf[i].nMaxFileSizePrev = 0;
  516. apf[i].pszPageFile = NULL;
  517. if (dwDriveMask & 0x01)
  518. {
  519. szDir[0] = TEXT('A') + i;
  520. switch (VMGetDriveType(szDir))
  521. {
  522. case DRIVE_FIXED:
  523. apf[i].fCanHavePagefile = TRUE;
  524. break;
  525. default:
  526. break;
  527. }
  528. }
  529. }
  530. if (RegQueryValueEx (ghkeyMemMgt, szPagingFiles, NULL, &dwType,
  531. (LPBYTE) NULL, &cbTemp) != ERROR_SUCCESS)
  532. {
  533. // Could not get the current virtual memory settings size.
  534. return FALSE;
  535. }
  536. if ((szTemp = MemAlloc(LPTR, cbTemp)) == NULL)
  537. {
  538. // Could not alloc a buffer for the vmem settings
  539. return FALSE;
  540. }
  541. szTemp[0] = 0;
  542. if (RegQueryValueEx (ghkeyMemMgt, szPagingFiles, NULL, &dwType,
  543. (LPBYTE) szTemp, &cbTemp) != ERROR_SUCCESS)
  544. {
  545. // Could not read the current virtual memory settings.
  546. MemFree(szTemp);
  547. return FALSE;
  548. }
  549. psz = szTemp;
  550. while (*psz)
  551. {
  552. LPTSTR pszPageName;
  553. /*
  554. * If the parse works, and this drive can have a pagefile on it,
  555. * update the apf table. Note that this means that currently
  556. * specified pagefiles for invalid drives will be stripped out
  557. * of the registry if the user presses OK for this dialog.
  558. */
  559. if (ParsePageFileDesc(&psz, &nDrive, &nMinFileSize, &nMaxFileSize, &pszPageName))
  560. {
  561. if (apf[nDrive].fCanHavePagefile)
  562. {
  563. apf[nDrive].nMinFileSize =
  564. apf[nDrive].nMinFileSizePrev = nMinFileSize;
  565. apf[nDrive].nMaxFileSize =
  566. apf[nDrive].nMaxFileSizePrev = nMaxFileSize;
  567. apf[nDrive].pszPageFile = pszPageName;
  568. }
  569. }
  570. }
  571. MemFree(szTemp);
  572. return TRUE;
  573. }
  574. /*
  575. * VirtualFreePageFiles
  576. *
  577. * Frees data alloced by VirtualGetPageFiles
  578. *
  579. */
  580. void VirtualFreePageFiles(PAGING_FILE *apf) {
  581. int i;
  582. DPRINTF((TEXT("SYSCPL: In VirtualFreePageFile, cref=%d\n"), gcrefPagingFiles));
  583. if (gcrefPagingFiles > 0) {
  584. gcrefPagingFiles--;
  585. if (gcrefPagingFiles == 0) {
  586. for (i = 0; i < MAX_DRIVES; i++) {
  587. if (apf[i].pszPageFile != NULL)
  588. MemFree(apf[i].pszPageFile);
  589. }
  590. }
  591. }
  592. }
  593. /*
  594. * VirtualInitStructures()
  595. *
  596. * Calls VirtualGetPageFiles so other helpers can be called from the Perf Page.
  597. *
  598. * Returns:
  599. * TRUE if success, FALSE if failure
  600. */
  601. BOOL VirtualInitStructures( void ) {
  602. VCREG_RET vcVirt;
  603. BOOL fRet = FALSE;
  604. vcVirt = VirtualOpenKey();
  605. if (vcVirt != VCREG_ERROR)
  606. fRet = VirtualGetPageFiles( apf );
  607. LoadString(hInstance, IDS_SYSDM_MB, szMB, CCHMBSTRING);
  608. return fRet;
  609. }
  610. void VirtualFreeStructures( void ) {
  611. VirtualFreePageFiles(apf);
  612. VirtualCloseKey();
  613. }
  614. /*
  615. * LPTSTR BackslashTerm( LPTSTR pszPath )
  616. */
  617. LPTSTR BackslashTerm( LPTSTR pszPath )
  618. {
  619. LPTSTR pszEnd;
  620. pszEnd = pszPath + lstrlen( pszPath );
  621. //
  622. // Get the end of the source directory
  623. //
  624. switch( *CharPrev( pszPath, pszEnd ) )
  625. {
  626. case TEXT('\\'):
  627. case TEXT(':'):
  628. break;
  629. default:
  630. *pszEnd++ = TEXT( '\\' );
  631. *pszEnd = TEXT( '\0' );
  632. }
  633. return( pszEnd );
  634. }
  635. /*
  636. * VirtualMemInit
  637. *
  638. * Initializes the Virtual Memory dialog.
  639. *
  640. * Arguments:
  641. * HWND hDlg - Handle to the dialog window.
  642. *
  643. * Returns:
  644. * TRUE
  645. */
  646. static
  647. BOOL
  648. VirtualMemInit(
  649. HWND hDlg
  650. )
  651. {
  652. TCHAR szTemp[MAX_VOL_LINE];
  653. DWORD i;
  654. INT iItem;
  655. HWND hwndLB;
  656. INT aTabs[2];
  657. RECT rc;
  658. VCREG_RET vcVirt;
  659. SYSTEM_BASIC_INFORMATION BasicInfo;
  660. NTSTATUS status;
  661. unsigned __int64 TotalPhys;
  662. HourGlass(TRUE);
  663. //
  664. // Load the "MB" string.
  665. //
  666. LoadString(hInstance, IDS_SYSDM_MB, szMB, CCHMBSTRING);
  667. ////////////////////////////////////////////////////////////////////
  668. // List all drives
  669. ////////////////////////////////////////////////////////////////////
  670. vcVirt = VirtualOpenKey();
  671. if (vcVirt == VCREG_ERROR ) {
  672. // Error - cannot even get list of paging files from registry
  673. MsgBoxParam(hDlg, IDS_SYSDM_NOOPEN_VM_NOTUSER, IDS_SYSDM_TITLE, MB_ICONEXCLAMATION);
  674. EndDialog(hDlg, RET_NO_CHANGE);
  675. HourGlass(FALSE);
  676. if (ghkeyMemMgt != NULL)
  677. VirtualCloseKey();
  678. return FALSE;
  679. }
  680. /*
  681. * To change Virtual Memory size or Crash control, we need access
  682. * to both the CrashCtl key and the PagingFiles value in the MemMgr key
  683. */
  684. if (vcVirt == VCREG_READONLY ) {
  685. /*
  686. * Disable some fields, because they only have Read access.
  687. */
  688. EnableWindow(GetDlgItem(hDlg, IDD_VM_SF_SIZE), FALSE);
  689. EnableWindow(GetDlgItem(hDlg, IDD_VM_SF_SIZEMAX), FALSE);
  690. EnableWindow(GetDlgItem(hDlg, IDD_VM_ST_INITSIZE), FALSE);
  691. EnableWindow(GetDlgItem(hDlg, IDD_VM_ST_MAXSIZE), FALSE);
  692. EnableWindow(GetDlgItem(hDlg, IDD_VM_SF_SET), FALSE);
  693. }
  694. if (!VirtualGetPageFiles(apf)) {
  695. // Could not read the current virtual memory settings.
  696. MsgBoxParam(hDlg, IDS_SYSDM_CANNOTREAD, IDS_SYSDM_TITLE, MB_ICONEXCLAMATION);
  697. }
  698. //
  699. // Save a backup copy of the current pagefile structs
  700. //
  701. VirtualCopyPageFiles( apfOriginal, FALSE, apf, TRUE );
  702. hwndLB = GetDlgItem(hDlg, IDD_VM_VOLUMES);
  703. aTabs[0] = TABSTOP_VOL;
  704. aTabs[1] = TABSTOP_SIZE;
  705. SendMessage(hwndLB, LB_SETTABSTOPS, 2, (LPARAM)&aTabs);
  706. /*
  707. * Since SetGenLBWidth only counts tabs as one character, we must compute
  708. * the maximum extra space that the tab characters will expand to and
  709. * arbitrarily tack it onto the end of the string width.
  710. *
  711. * cxExtra = 1st Tab width + 1 default tab width (8 chrs) - strlen("d:\t\t");
  712. *
  713. * (I know the docs for LB_SETTABSTOPS says that a default tab == 2 dlg
  714. * units, but I have read the code, and it is really 8 chars)
  715. */
  716. rc.top = rc.left = 0;
  717. rc.bottom = 8;
  718. rc.right = TABSTOP_VOL + (4 * 8) - (4 * 4);
  719. MapDialogRect( hDlg, &rc );
  720. cxExtra = rc.right - rc.left;
  721. cxLBExtent = 0;
  722. for (i = 0; i < MAX_DRIVES; i++)
  723. {
  724. // Assume we don't have to create anything
  725. apf[i].fCreateFile = FALSE;
  726. if (apf[i].fCanHavePagefile)
  727. {
  728. VirtualMemBuildLBLine(szTemp, i);
  729. iItem = (INT)SendMessage(hwndLB, LB_ADDSTRING, 0, (LPARAM)szTemp);
  730. SendMessage(hwndLB, LB_SETITEMDATA, iItem, i);
  731. // SetGenLBWidth(hwndLB, szTemp, &cxLBExtent, hfontBold, cxExtra);
  732. cxLBExtent = SetLBWidthEx( hwndLB, szTemp, cxLBExtent, cxExtra);
  733. }
  734. }
  735. SendDlgItemMessage(hDlg, IDD_VM_SF_SIZE, EM_LIMITTEXT, MAX_SIZE_LEN, 0L);
  736. SendDlgItemMessage(hDlg, IDD_VM_SF_SIZEMAX, EM_LIMITTEXT, MAX_SIZE_LEN, 0L);
  737. /*
  738. * Get the total physical memory in the machine.
  739. */
  740. status = NtQuerySystemInformation(
  741. SystemBasicInformation,
  742. &BasicInfo,
  743. sizeof(BasicInfo),
  744. NULL
  745. );
  746. if (NT_SUCCESS(status)) {
  747. TotalPhys = (unsigned __int64) BasicInfo.NumberOfPhysicalPages * BasicInfo.PageSize;
  748. }
  749. else {
  750. TotalPhys = 0;
  751. }
  752. SetDlgItemMB(hDlg, IDD_VM_MIN, MIN_SWAPSIZE);
  753. // Recommended pagefile size is 1.5 * RAM size these days.
  754. // Nonintegral multiplication with unsigned __int64s is fun!
  755. // This will obviously fail if the machine has total RAM
  756. // greater than 13194139533312 MB (75% of a full 64-bit address
  757. // space). Hopefully by the time someone has such a beast we'll
  758. // have __int128s to hold the results of this calculation.
  759. TotalPhys >>= 20; // Bytes to MB
  760. TotalPhys *= 3; // This will always fit because of the operation above
  761. TotalPhys >>= 1; // x*3/2 == 1.5*x, more or less
  762. i = (DWORD) TotalPhys; // This cast actually causes the
  763. // algorithm to fail if the machine has
  764. // more than ~ 3.2 billion MB of RAM.
  765. // At that point, either the Win32 API has
  766. // to change to allow me to pass __int64s
  767. // as message params, or we have to start
  768. // reporting these stats in GB.
  769. SetDlgItemMB(hDlg, IDD_VM_RECOMMEND, max(i, MIN_SUGGEST));
  770. /*
  771. * Select the first drive in the listbox.
  772. */
  773. SendDlgItemMessage(hDlg, IDD_VM_VOLUMES, LB_SETCURSEL, 0, 0L);
  774. VirtualMemSelChange(hDlg);
  775. VirtualMemUpdateAllocated(hDlg);
  776. /*
  777. * Show RegQuota
  778. */
  779. cmTotalVM = VirtualMemComputeTotalMax();
  780. HourGlass(FALSE);
  781. return TRUE;
  782. }
  783. /*
  784. * ParseSDD
  785. */
  786. int ParseSDD( LPTSTR psz, LPTSTR szPath, INT *pnMinFileSize, INT *pnMaxFileSize) {
  787. int cMatched = 0;
  788. LPTSTR pszNext;
  789. psz = SkipWhiteSpace(psz);
  790. if (*psz) {
  791. int cch;
  792. cMatched++;
  793. pszNext = SkipNonWhiteSpace(psz);
  794. cch = (int)(pszNext - psz);
  795. CopyMemory( szPath, psz, sizeof(TCHAR) * cch );
  796. szPath[cch] = TEXT('\0');
  797. psz = SkipWhiteSpace(pszNext);
  798. if (*psz) {
  799. cMatched++;
  800. pszNext = SkipNonWhiteSpace(psz);
  801. *pnMinFileSize = StringToInt( psz );
  802. psz = SkipWhiteSpace(pszNext);
  803. if (*psz) {
  804. cMatched++;
  805. *pnMaxFileSize = StringToInt( psz );
  806. }
  807. }
  808. }
  809. return cMatched;
  810. }
  811. /*
  812. * ParsePageFileDesc
  813. *
  814. *
  815. *
  816. * Arguments:
  817. *
  818. * Returns:
  819. *
  820. */
  821. static
  822. BOOL
  823. ParsePageFileDesc(
  824. LPTSTR *ppszDesc,
  825. INT *pnDrive,
  826. INT *pnMinFileSize,
  827. INT *pnMaxFileSize,
  828. LPTSTR *ppstr
  829. )
  830. {
  831. LPTSTR psz;
  832. LPTSTR pszName = NULL;
  833. int cFields;
  834. TCHAR chDrive;
  835. TCHAR szPath[MAX_PATH];
  836. /*
  837. * Find the end of this REG_MULTI_SZ string and point to the next one
  838. */
  839. psz = *ppszDesc;
  840. *ppszDesc = psz + lstrlen(psz) + 1;
  841. /*
  842. * Parse the string from "filename minsize maxsize"
  843. */
  844. szPath[0] = TEXT('\0');
  845. *pnMinFileSize = 0;
  846. *pnMaxFileSize = 0;
  847. /* Try it without worrying about quotes */
  848. cFields = ParseSDD( psz, szPath, pnMinFileSize, pnMaxFileSize);
  849. if (cFields < 2)
  850. return FALSE;
  851. /*
  852. * Find the drive index
  853. */
  854. chDrive = (TCHAR)CharUpper((LPTSTR)*szPath);
  855. if (chDrive < TEXT('A') || chDrive > TEXT('Z'))
  856. return FALSE;
  857. *pnDrive = (INT)(chDrive - TEXT('A'));
  858. /* if the path != x:\pagefile.sys then save it */
  859. if (lstrcmpi(szPagefile + 1, szPath + 1) != 0)
  860. {
  861. pszName = CloneString(szPath);
  862. }
  863. *ppstr = pszName;
  864. if (cFields < 3)
  865. {
  866. INT nSpace;
  867. // don't call GetDriveSpace if the drive is invalid
  868. if (apf[*pnDrive].fCanHavePagefile)
  869. nSpace = GetMaxSpaceMB(*pnDrive);
  870. else
  871. nSpace = 0;
  872. *pnMaxFileSize = min(*pnMinFileSize + MAXOVERMINFACTOR, nSpace);
  873. }
  874. /*
  875. * If the page file size in the registry is zero it means this is
  876. * a RAM based page file.
  877. */
  878. if (*pnMinFileSize == 0) {
  879. apf[*pnDrive].fRamBasedPagefile = TRUE;
  880. }
  881. else {
  882. apf[*pnDrive].fRamBasedPagefile = FALSE;
  883. }
  884. return TRUE;
  885. }
  886. /*
  887. * VirtualMemBuildLBLine
  888. *
  889. *
  890. *
  891. */
  892. static
  893. VOID
  894. VirtualMemBuildLBLine(
  895. LPTSTR pszBuf,
  896. INT iDrive
  897. )
  898. {
  899. TCHAR szVolume[MAX_PATH];
  900. TCHAR szTemp[MAX_PATH];
  901. szTemp[0] = TEXT('A') + iDrive;
  902. szTemp[1] = TEXT(':');
  903. szTemp[2] = TEXT('\\');
  904. szTemp[3] = 0;
  905. *szVolume = 0;
  906. GetVolumeInformation(szTemp, szVolume, MAX_PATH,
  907. NULL, NULL, NULL, NULL, 0);
  908. szTemp[2] = TEXT('\t');
  909. lstrcpy(pszBuf, szTemp);
  910. if (*szVolume)
  911. {
  912. lstrcat(pszBuf, TEXT("["));
  913. lstrcat(pszBuf, szVolume);
  914. lstrcat(pszBuf, TEXT("]"));
  915. }
  916. if (apf[iDrive].fRamBasedPagefile)
  917. {
  918. if( LoadString( hInstance, 164, szTemp, ARRAYSIZE( szTemp ) ) > 0 )
  919. {
  920. lstrcat(pszBuf, szTemp);
  921. }
  922. }
  923. else if (apf[iDrive].nMinFileSize)
  924. {
  925. wsprintf(szTemp, TEXT("\t%d - %d"),
  926. apf[iDrive].nMinFileSize, apf[iDrive].nMaxFileSize);
  927. lstrcat(pszBuf, szTemp);
  928. }
  929. }
  930. /*
  931. * SetDlgItemMB
  932. *
  933. *
  934. */
  935. VOID SetDlgItemMB( HWND hDlg, INT idControl, DWORD dwMBValue ) {
  936. TCHAR szBuf[32];
  937. wsprintf(szBuf, TEXT("%d %s"), dwMBValue, szMB),
  938. SetDlgItemText(hDlg, idControl, szBuf);
  939. }
  940. /*
  941. * GetFreeSpaceMB
  942. *
  943. *
  944. *
  945. */
  946. DWORD
  947. GetFreeSpaceMB(
  948. INT iDrive
  949. )
  950. {
  951. TCHAR szDriveRoot[4];
  952. DWORD dwSectorsPerCluster;
  953. DWORD dwBytesPerSector;
  954. DWORD dwFreeClusters;
  955. DWORD dwClusters;
  956. DWORD iSpace;
  957. DWORD iSpaceExistingPagefile;
  958. HANDLE hff;
  959. WIN32_FIND_DATA ffd;
  960. szDriveRoot[0] = TEXT('A') + iDrive;
  961. szDriveRoot[1] = TEXT(':');
  962. szDriveRoot[2] = TEXT('\\');
  963. szDriveRoot[3] = (TCHAR) 0;
  964. if (!GetDiskFreeSpace(szDriveRoot, &dwSectorsPerCluster, &dwBytesPerSector,
  965. &dwFreeClusters, &dwClusters))
  966. return 0;
  967. iSpace = (INT)((dwSectorsPerCluster * dwFreeClusters) /
  968. (ONE_MEG / dwBytesPerSector));
  969. //
  970. // Be sure to include the size of any existing pagefile.
  971. // Because this space can be reused for a new paging file,
  972. // it is effectively "disk free space" as well. The
  973. // FindFirstFile api is safe to use, even if the pagefile
  974. // is in use, because it does not need to open the file
  975. // to get its size.
  976. //
  977. iSpaceExistingPagefile = 0;
  978. if ((hff = FindFirstFile(SZPageFileName(szDriveRoot[0] - TEXT('A')), &ffd)) !=
  979. INVALID_HANDLE_VALUE)
  980. {
  981. iSpaceExistingPagefile = (INT)(ffd.nFileSizeLow / ONE_MEG);
  982. FindClose(hff);
  983. }
  984. return iSpace + iSpaceExistingPagefile;
  985. }
  986. /*
  987. * GetMaxSpaceMB
  988. *
  989. *
  990. *
  991. */
  992. static
  993. INT
  994. GetMaxSpaceMB(
  995. INT iDrive
  996. )
  997. {
  998. TCHAR szDriveRoot[4];
  999. DWORD dwSectorsPerCluster;
  1000. DWORD dwBytesPerSector;
  1001. DWORD dwFreeClusters;
  1002. DWORD dwClusters;
  1003. INT iSpace;
  1004. szDriveRoot[0] = (TCHAR)(TEXT('A') + iDrive);
  1005. szDriveRoot[1] = TEXT(':');
  1006. szDriveRoot[2] = TEXT('\\');
  1007. szDriveRoot[3] = (TCHAR) 0;
  1008. if (!GetDiskFreeSpace(szDriveRoot, &dwSectorsPerCluster, &dwBytesPerSector,
  1009. &dwFreeClusters, &dwClusters))
  1010. return 0;
  1011. iSpace = (INT)((dwSectorsPerCluster * dwClusters) /
  1012. (ONE_MEG / dwBytesPerSector));
  1013. return iSpace;
  1014. }
  1015. /*
  1016. * VirtualMemSelChange
  1017. *
  1018. *
  1019. *
  1020. */
  1021. static
  1022. VOID
  1023. VirtualMemSelChange(
  1024. HWND hDlg
  1025. )
  1026. {
  1027. TCHAR szDriveRoot[4];
  1028. TCHAR szTemp[MAX_PATH];
  1029. TCHAR szVolume[MAX_PATH];
  1030. INT iSel;
  1031. INT iDrive;
  1032. INT nCrtRadioButtonId;
  1033. BOOL fEditsEnabled;
  1034. HWND hWndEdit;
  1035. if ((iSel = (INT)SendDlgItemMessage(
  1036. hDlg, IDD_VM_VOLUMES, LB_GETCURSEL, 0, 0)) == LB_ERR)
  1037. return;
  1038. iDrive = (INT)SendDlgItemMessage(hDlg, IDD_VM_VOLUMES,
  1039. LB_GETITEMDATA, iSel, 0);
  1040. szDriveRoot[0] = TEXT('A') + iDrive;
  1041. szDriveRoot[1] = TEXT(':');
  1042. szDriveRoot[2] = TEXT('\\');
  1043. szDriveRoot[3] = (TCHAR) 0;
  1044. *szVolume = (TCHAR) 0;
  1045. GetVolumeInformation(szDriveRoot, szVolume, MAX_PATH,
  1046. NULL, NULL, NULL, NULL, 0);
  1047. szTemp[0] = TEXT('A') + iDrive;
  1048. szTemp[1] = TEXT(':');
  1049. szTemp[2] = (TCHAR) 0;
  1050. if (*szVolume)
  1051. {
  1052. lstrcat(szTemp, TEXT(" ["));
  1053. lstrcat(szTemp, szVolume);
  1054. lstrcat(szTemp, TEXT("]"));
  1055. }
  1056. //LATER: should we also put up total drive size as well as free space?
  1057. SetDlgItemText(hDlg, IDD_VM_SF_DRIVE, szTemp);
  1058. SetDlgItemMB(hDlg, IDD_VM_SF_SPACE, GetFreeSpaceMB(iDrive));
  1059. if ( apf[iDrive].fRamBasedPagefile )
  1060. {
  1061. HWND hWndEdit;
  1062. //
  1063. // Paging file size based on RAM size
  1064. //
  1065. nCrtRadioButtonId = IDD_VM_RAMBASED_RADIO;
  1066. fEditsEnabled = FALSE;
  1067. }
  1068. else
  1069. {
  1070. if ( apf[iDrive].nMinFileSize != 0 )
  1071. {
  1072. //
  1073. // Custom size paging file
  1074. //
  1075. nCrtRadioButtonId = IDD_VM_CUSTOMSIZE_RADIO;
  1076. SetDlgItemInt(hDlg, IDD_VM_SF_SIZE, apf[iDrive].nMinFileSize, FALSE);
  1077. SetDlgItemInt(hDlg, IDD_VM_SF_SIZEMAX, apf[iDrive].nMaxFileSize, FALSE);
  1078. fEditsEnabled = TRUE;
  1079. }
  1080. else
  1081. {
  1082. //
  1083. // No paging file
  1084. //
  1085. nCrtRadioButtonId = IDD_VM_NOPAGING_RADIO;
  1086. SetDlgItemText(hDlg, IDD_VM_SF_SIZE, TEXT(""));
  1087. SetDlgItemText(hDlg, IDD_VM_SF_SIZEMAX, TEXT(""));
  1088. fEditsEnabled = FALSE;
  1089. }
  1090. }
  1091. //
  1092. // Select the appropriate radio button
  1093. //
  1094. CheckRadioButton(
  1095. hDlg,
  1096. IDD_VM_CUSTOMSIZE_RADIO,
  1097. IDD_VM_NOPAGING_RADIO,
  1098. nCrtRadioButtonId );
  1099. //
  1100. // Enable/disable the min & max size edit boxes
  1101. //
  1102. EnableWindow( GetDlgItem( hDlg, IDD_VM_SF_SIZE ), fEditsEnabled );
  1103. EnableWindow( GetDlgItem( hDlg, IDD_VM_SF_SIZEMAX ), fEditsEnabled );
  1104. }
  1105. /*
  1106. * VirtualMemUpdateAllocated
  1107. *
  1108. *
  1109. *
  1110. */
  1111. INT VirtualMemComputeAllocated( HWND hWnd , BOOL *pfTempPf)
  1112. {
  1113. BOOL fSuccess = FALSE;
  1114. static BOOL fWarned = FALSE;
  1115. ULONG ulPagefileSize = 0;
  1116. unsigned __int64 PagefileSize;
  1117. NTSTATUS result = ERROR_ACCESS_DENIED;
  1118. SYSTEM_INFO SysInfo;
  1119. PSYSTEM_PAGEFILE_INFORMATION pPagefileInfo = NULL;
  1120. PSYSTEM_PAGEFILE_INFORMATION pCurrentPagefile = NULL;
  1121. LONG lResult = ERROR_ACCESS_DENIED;
  1122. DWORD dwValueType = 0;
  1123. DWORD fTempPagefile = 0;
  1124. DWORD cbSize = sizeof(DWORD);
  1125. __try {
  1126. pCurrentPagefile = pPagefileInfo = (PSYSTEM_PAGEFILE_INFORMATION) MemAlloc(
  1127. LPTR,
  1128. PAGEFILE_INFO_BUFFER_SIZE
  1129. );
  1130. if (!pPagefileInfo) {
  1131. __leave;
  1132. } // if
  1133. // Get the page size in bytes
  1134. GetSystemInfo(&SysInfo);
  1135. // Get the sizes (in pages) of all of the pagefiles on the system
  1136. result = NtQuerySystemInformation(
  1137. SystemPageFileInformation,
  1138. pPagefileInfo,
  1139. PAGEFILE_INFO_BUFFER_SIZE,
  1140. NULL
  1141. );
  1142. if (ERROR_SUCCESS != result) {
  1143. __leave;
  1144. } // if
  1145. if (pfTempPf) {
  1146. // Check to see if the system created a temporary pagefile
  1147. lResult = RegQueryValueEx(
  1148. ghkeyMemMgt,
  1149. szNoPageFile,
  1150. NULL,
  1151. &dwValueType,
  1152. (LPBYTE) &fTempPagefile,
  1153. &cbSize
  1154. );
  1155. if ((ERROR_SUCCESS == lResult) && fTempPagefile) {
  1156. *pfTempPf = TRUE;
  1157. } // if (ERROR_SUCCESS...
  1158. else {
  1159. *pfTempPf = FALSE;
  1160. } // else
  1161. } // if (pfTempPf)
  1162. // Add up pagefile sizes
  1163. while (pCurrentPagefile->NextEntryOffset) {
  1164. ulPagefileSize += pCurrentPagefile->TotalSize;
  1165. ((LPBYTE) pCurrentPagefile) += pCurrentPagefile->NextEntryOffset;
  1166. } // while
  1167. ulPagefileSize += pCurrentPagefile->TotalSize;
  1168. // Convert pages to bytes
  1169. PagefileSize = (unsigned __int64) ulPagefileSize * SysInfo.dwPageSize;
  1170. // Convert bytes to MB
  1171. ulPagefileSize = (ULONG) (PagefileSize / ONE_MEG);
  1172. fSuccess = TRUE;
  1173. } // __try
  1174. __finally {
  1175. // If we failed to determine the pagefile size, then
  1176. // warn the user that the reported size is incorrect,
  1177. // once per applet invokation.
  1178. if (!fSuccess && !fWarned) {
  1179. MsgBoxParam(
  1180. hWnd,
  1181. IDS_SYSDM_DONTKNOWCURRENT,
  1182. IDS_SYSDM_TITLE,
  1183. MB_ICONERROR | MB_OK
  1184. );
  1185. fWarned = TRUE;
  1186. } // if
  1187. if (pPagefileInfo) {
  1188. MemFree((HLOCAL) pPagefileInfo);
  1189. } // if
  1190. } // __finally
  1191. return(ulPagefileSize);
  1192. }
  1193. static VOID VirtualMemUpdateAllocated(
  1194. HWND hDlg
  1195. )
  1196. {
  1197. SetDlgItemMB(hDlg, IDD_VM_ALLOCD, VirtualMemComputeAllocated(hDlg, NULL));
  1198. }
  1199. int VirtualMemComputeTotalMax( void ) {
  1200. INT nTotalAllocated;
  1201. INT i;
  1202. for (nTotalAllocated = 0, i = 0; i < MAX_DRIVES; i++)
  1203. {
  1204. nTotalAllocated += apf[i].nMaxFileSize;
  1205. }
  1206. return nTotalAllocated;
  1207. }
  1208. /*
  1209. * VirtualMemSetNewSize
  1210. *
  1211. *
  1212. *
  1213. */
  1214. static
  1215. BOOL
  1216. VirtualMemSetNewSize(
  1217. HWND hDlg
  1218. )
  1219. {
  1220. DWORD nSwapSize;
  1221. DWORD nSwapSizeMax;
  1222. BOOL fTranslated;
  1223. INT iSel;
  1224. INT iDrive = 2; // default to C
  1225. TCHAR szTemp[MAX_PATH];
  1226. DWORD nFreeSpace;
  1227. DWORD CrashDumpSizeInMbytes;
  1228. TCHAR Drive;
  1229. INT iBootDrive;
  1230. BOOL fRamBasedPagefile = FALSE;
  1231. //
  1232. // Initialize variables for crashdump.
  1233. //
  1234. if (GetSystemDrive (&Drive)) {
  1235. iBootDrive = tolower (Drive) - 'a';
  1236. } else {
  1237. iBootDrive = 0;
  1238. }
  1239. if ((iSel = (INT)SendDlgItemMessage(
  1240. hDlg, IDD_VM_VOLUMES, LB_GETCURSEL, 0, 0)) != LB_ERR)
  1241. {
  1242. if (LB_ERR ==
  1243. (iDrive = (INT)SendDlgItemMessage(hDlg, IDD_VM_VOLUMES,
  1244. LB_GETITEMDATA, iSel, 0)))
  1245. {
  1246. return FALSE; // failure!
  1247. }
  1248. }
  1249. CrashDumpSizeInMbytes =
  1250. (DWORD) ( CoreDumpGetRequiredFileSize (NULL) / ONE_MEG );
  1251. #if 0
  1252. CoreDumpGetValue(CD_LOG);
  1253. CoreDumpGetValue(CD_SEND);
  1254. CoreDumpGetValue(CD_WRITE);
  1255. if (acdfControls[CD_WRITE].u.fValue) {
  1256. nBootPF = -1;
  1257. } else if (acdfControls[CD_LOG].u.fValue ||
  1258. acdfControls[CD_SEND].u.fValue) {
  1259. nBootPF = MIN_SWAPSIZE;
  1260. }
  1261. if (nBootPF != 0) {
  1262. SYSTEM_BASIC_INFORMATION BasicInfo;
  1263. NTSTATUS status;
  1264. unsigned __int64 TotalPhys;
  1265. TCHAR szBootPath[MAX_PATH];
  1266. if (GetWindowsDirectory(szBootPath, MAX_PATH) == 0) {
  1267. iBootDrive = IDRV_DEF_BOOT;
  1268. } else {
  1269. iBootDrive = szBootPath[0];
  1270. if (iBootDrive > TEXT('Z'))
  1271. iBootDrive -= TEXT('a');
  1272. else {
  1273. iBootDrive -= TEXT('A');
  1274. }
  1275. }
  1276. if (nBootPF == -1) {
  1277. // Get the number of Meg in the system, rounding up
  1278. // (note that we round up a zero remainder)
  1279. status = NtQuerySystemInformation(
  1280. SystemBasicInformation,
  1281. &BasicInfo,
  1282. sizeof(BasicInfo),
  1283. NULL
  1284. );
  1285. if (NT_SUCCESS(status)) {
  1286. TotalPhys = (unsigned __int64) BasicInfo.NumberOfPhysicalPages * BasicInfo.PageSize;
  1287. }
  1288. else {
  1289. TotalPhys = 0;
  1290. }
  1291. nBootPF = (DWORD) ((TotalPhys / ONE_MEG) + 1);
  1292. }
  1293. }
  1294. #endif
  1295. if( IsDlgButtonChecked( hDlg, IDD_VM_NOPAGING_RADIO ) == BST_CHECKED )
  1296. {
  1297. //
  1298. // No paging file on this drive.
  1299. //
  1300. nSwapSize = 0;
  1301. nSwapSizeMax = 0;
  1302. fTranslated = TRUE;
  1303. }
  1304. else
  1305. {
  1306. if( IsDlgButtonChecked( hDlg, IDD_VM_RAMBASED_RADIO ) == BST_CHECKED )
  1307. {
  1308. MEMORYSTATUSEX MemoryInfo;
  1309. //
  1310. // User requested a RAM based page file. We will compute a page file
  1311. // size based on the RAM currently available so that we can benefit of
  1312. // all the verifications done below related to disk space available etc.
  1313. // The final page file specification written to the registry will contain
  1314. // zero sizes though because this is the way we signal that we
  1315. // want a RAM based page file.
  1316. //
  1317. ZeroMemory (&MemoryInfo, sizeof MemoryInfo);
  1318. MemoryInfo.dwLength = sizeof MemoryInfo;
  1319. if (GlobalMemoryStatusEx (&MemoryInfo))
  1320. {
  1321. fRamBasedPagefile = TRUE;
  1322. //
  1323. // We do not lose info because we first divide the RAM size to
  1324. // 1Mb and only after that we convert to a DWORD.
  1325. //
  1326. nSwapSize = (DWORD)(MemoryInfo.ullTotalPhys / 0x100000) + 12;
  1327. nSwapSizeMax = nSwapSize;
  1328. fTranslated = TRUE;
  1329. }
  1330. else
  1331. {
  1332. nSwapSize = 0;
  1333. nSwapSizeMax = 0;
  1334. fTranslated = TRUE;
  1335. }
  1336. }
  1337. else
  1338. {
  1339. //
  1340. // User requested a custom size paging file
  1341. //
  1342. nSwapSize = (INT)GetDlgItemInt(hDlg, IDD_VM_SF_SIZE,
  1343. &fTranslated, FALSE);
  1344. if (!fTranslated)
  1345. {
  1346. MsgBoxParam(hDlg, IDS_SYSDM_ENTERINITIALSIZE, IDS_SYSDM_TITLE, MB_ICONEXCLAMATION);
  1347. SetFocus(GetDlgItem(hDlg, IDD_VM_SF_SIZE));
  1348. return FALSE;
  1349. }
  1350. if ((nSwapSize < MIN_SWAPSIZE && nSwapSize != 0))
  1351. {
  1352. MsgBoxParam(hDlg, IDS_SYSDM_PAGEFILESIZE_START, IDS_SYSDM_TITLE, MB_ICONEXCLAMATION,
  1353. GetMaxPagefileSizeInMB(iDrive));
  1354. SetFocus(GetDlgItem(hDlg, IDD_VM_SF_SIZE));
  1355. return FALSE;
  1356. }
  1357. if (nSwapSize == 0)
  1358. {
  1359. nSwapSizeMax = 0;
  1360. }
  1361. else
  1362. {
  1363. nSwapSizeMax = (INT)GetDlgItemInt(hDlg, IDD_VM_SF_SIZEMAX,
  1364. &fTranslated, FALSE);
  1365. if (!fTranslated)
  1366. {
  1367. MsgBoxParam(hDlg, IDS_SYSDM_ENTERMAXIMUMSIZE, IDS_SYSDM_TITLE, MB_ICONEXCLAMATION,
  1368. GetMaxPagefileSizeInMB(iDrive));
  1369. SetFocus(GetDlgItem(hDlg, IDD_VM_SF_SIZEMAX));
  1370. return FALSE;
  1371. }
  1372. if (nSwapSizeMax < nSwapSize || nSwapSizeMax > GetMaxPagefileSizeInMB(iDrive))
  1373. {
  1374. MsgBoxParam(hDlg, IDS_SYSDM_PAGEFILESIZE_MAX, IDS_SYSDM_TITLE, MB_ICONEXCLAMATION,
  1375. GetMaxPagefileSizeInMB(iDrive));
  1376. SetFocus(GetDlgItem(hDlg, IDD_VM_SF_SIZEMAX));
  1377. return FALSE;
  1378. }
  1379. }
  1380. }
  1381. }
  1382. if (fTranslated && iSel != LB_ERR)
  1383. {
  1384. nFreeSpace = GetMaxSpaceMB(iDrive);
  1385. if (nSwapSizeMax > nFreeSpace)
  1386. {
  1387. MsgBoxParam(hDlg, IDS_SYSDM_PAGEFILESIZE_TOOSMALL_NAMED, IDS_SYSDM_TITLE, MB_ICONEXCLAMATION,
  1388. (TCHAR)(iDrive + TEXT('A')));
  1389. SetFocus(GetDlgItem(hDlg, IDD_VM_SF_SIZEMAX));
  1390. return FALSE;
  1391. }
  1392. nFreeSpace = GetFreeSpaceMB(iDrive);
  1393. if (nSwapSize > nFreeSpace)
  1394. {
  1395. MsgBoxParam(hDlg, IDS_SYSDM_PAGEFILESIZE_TOOSMALL, IDS_SYSDM_TITLE, MB_ICONEXCLAMATION);
  1396. SetFocus(GetDlgItem(hDlg, IDD_VM_SF_SIZE));
  1397. return FALSE;
  1398. }
  1399. if (nSwapSize != 0 && nFreeSpace - nSwapSize < MIN_FREESPACE)
  1400. {
  1401. MsgBoxParam(hDlg, IDS_SYSDM_NOTENOUGHSPACE_PAGE, IDS_SYSDM_TITLE, MB_ICONEXCLAMATION,
  1402. (int)MIN_FREESPACE);
  1403. SetFocus(GetDlgItem(hDlg, IDD_VM_SF_SIZE));
  1404. return FALSE;
  1405. }
  1406. if (nSwapSizeMax > nFreeSpace)
  1407. {
  1408. if (MsgBoxParam(hDlg, IDS_SYSDM_PAGEFILESIZE_TOOSMALL_GROW, IDS_SYSDM_TITLE, MB_ICONINFORMATION |
  1409. MB_OKCANCEL, (TCHAR)(iDrive + TEXT('A'))) == IDCANCEL)
  1410. {
  1411. SetFocus(GetDlgItem(hDlg, IDD_VM_SF_SIZEMAX));
  1412. return FALSE;
  1413. }
  1414. }
  1415. if (iDrive == iBootDrive &&
  1416. (ULONG64) nSwapSize < CrashDumpSizeInMbytes) {
  1417. DWORD Ret;
  1418. //
  1419. // The new boot drive page file size is less than we need for
  1420. // crashdump. The message notifies the user that the resultant
  1421. // dump file may be truncated.
  1422. //
  1423. // NOTE: DO NOT, turn off dumping at this point, because a valid
  1424. // dump could still be generated.
  1425. //
  1426. Ret = MsgBoxParam (hDlg,
  1427. IDS_SYSDM_DEBUGGING_MINIMUM,
  1428. IDS_SYSDM_TITLE,
  1429. MB_ICONEXCLAMATION | MB_YESNO,
  1430. (TCHAR) ( iBootDrive + TEXT ('A') ),
  1431. (DWORD) CrashDumpSizeInMbytes
  1432. );
  1433. if (Ret != IDYES) {
  1434. SetFocus(GetDlgItem(hDlg, IDD_VM_SF_SIZE));
  1435. return FALSE;
  1436. }
  1437. }
  1438. apf[iDrive].nMinFileSize = nSwapSize;
  1439. apf[iDrive].nMaxFileSize = nSwapSizeMax;
  1440. apf[iDrive].fRamBasedPagefile = fRamBasedPagefile;
  1441. // Remember if the page file does not exist so we can create it later
  1442. if (GetFileAttributes(SZPageFileName(iDrive)) == 0xFFFFFFFF &&
  1443. GetLastError() == ERROR_FILE_NOT_FOUND) {
  1444. apf[iDrive].fCreateFile = TRUE;
  1445. }
  1446. VirtualMemBuildLBLine(szTemp, iDrive);
  1447. SendDlgItemMessage(hDlg, IDD_VM_VOLUMES, LB_DELETESTRING, iSel, 0);
  1448. SendDlgItemMessage(hDlg, IDD_VM_VOLUMES, LB_INSERTSTRING, iSel,
  1449. (LPARAM)szTemp);
  1450. SendDlgItemMessage(hDlg, IDD_VM_VOLUMES, LB_SETITEMDATA, iSel,
  1451. (LPARAM)iDrive);
  1452. SendDlgItemMessage(hDlg, IDD_VM_VOLUMES, LB_SETCURSEL, iSel, 0L);
  1453. cxLBExtent = SetLBWidthEx(GetDlgItem(hDlg, IDD_VM_VOLUMES), szTemp, cxLBExtent, cxExtra);
  1454. if ( ( ! apf[iDrive].fRamBasedPagefile ) && ( apf[iDrive].nMinFileSize != 0 ) ) {
  1455. SetDlgItemInt(hDlg, IDD_VM_SF_SIZE, apf[iDrive].nMinFileSize, FALSE);
  1456. SetDlgItemInt(hDlg, IDD_VM_SF_SIZEMAX, apf[iDrive].nMaxFileSize, FALSE);
  1457. }
  1458. else {
  1459. SetDlgItemText(hDlg, IDD_VM_SF_SIZE, TEXT(""));
  1460. SetDlgItemText(hDlg, IDD_VM_SF_SIZEMAX, TEXT(""));
  1461. }
  1462. VirtualMemUpdateAllocated(hDlg);
  1463. SetFocus(GetDlgItem(hDlg, IDD_VM_VOLUMES));
  1464. }
  1465. return TRUE;
  1466. }
  1467. /*
  1468. * VirtualMemUpdateRegistry
  1469. *
  1470. *
  1471. *
  1472. */
  1473. BOOL
  1474. VirtualMemUpdateRegistry(
  1475. VOID
  1476. )
  1477. {
  1478. LPTSTR szBuf;
  1479. TCHAR szTmp[MAX_DRIVES * 22]; //max_drives * sizeof(fmt_string)
  1480. LONG i;
  1481. INT c;
  1482. int j;
  1483. PAGEFILDESC aparm[MAX_DRIVES];
  1484. static TCHAR szNULLs[] = TEXT("\0\0");
  1485. c = 0;
  1486. szTmp[0] = TEXT('\0');
  1487. szBuf = szTmp;
  1488. for (i = 0; i < MAX_DRIVES; i++)
  1489. {
  1490. /*
  1491. * Is this a RAM based page file or
  1492. * does this drive have a pagefile specified for it?
  1493. */
  1494. if (apf[i].fRamBasedPagefile) {
  1495. j = (c * 4);
  1496. aparm[c].pszName = CloneString(SZPageFileName(i));
  1497. aparm[c].nMin = 0;
  1498. aparm[c].nMax = 0;
  1499. aparm[c].chNull = (DWORD)TEXT('\0');
  1500. szBuf += wsprintf( szBuf, TEXT("%%%d!s! %%%d!d! %%%d!d!%%%d!c!"),
  1501. j+1, j+2, j+3, j+4);
  1502. c++;
  1503. }
  1504. else if (apf[i].nMinFileSize)
  1505. {
  1506. j = (c * 4);
  1507. aparm[c].pszName = CloneString(SZPageFileName(i));
  1508. aparm[c].nMin = apf[i].nMinFileSize;
  1509. aparm[c].nMax = apf[i].nMaxFileSize;
  1510. aparm[c].chNull = (DWORD)TEXT('\0');
  1511. szBuf += wsprintf( szBuf, TEXT("%%%d!s! %%%d!d! %%%d!d!%%%d!c!"),
  1512. j+1, j+2, j+3, j+4);
  1513. c++;
  1514. }
  1515. }
  1516. /*
  1517. * Alloc and fill in the page file registry string
  1518. */
  1519. //since FmtMsg returns 0 for error, it can not return a zero length string
  1520. //therefore, force string to be at least one space long.
  1521. if (szTmp[0] == TEXT('\0')) {
  1522. szBuf = szNULLs;
  1523. j = 1; //Length of string == 1 char (ZTerm null will be added later).
  1524. } else {
  1525. j = FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER |
  1526. FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_MAX_WIDTH_MASK |
  1527. FORMAT_MESSAGE_ARGUMENT_ARRAY,
  1528. szTmp, 0, 0, (LPTSTR)&szBuf, 1, (va_list *)&aparm);
  1529. }
  1530. for( i = 0; i < c; i++ )
  1531. MemFree(aparm[i].pszName);
  1532. if (j == 0)
  1533. return FALSE;
  1534. i = RegSetValueEx (ghkeyMemMgt, szPagingFiles, 0, REG_MULTI_SZ,
  1535. (LPBYTE)szBuf, SIZEOF(TCHAR) * (j+1));
  1536. // free the string now that it is safely stored in the registry
  1537. if (szBuf != szNULLs)
  1538. FmtFree(szBuf);
  1539. // if the string didn't get there, then return error
  1540. if (i != ERROR_SUCCESS)
  1541. return FALSE;
  1542. /*
  1543. * Now be sure that any previous pagefiles will be deleted on
  1544. * the next boot.
  1545. */
  1546. for (i = 0; i < MAX_DRIVES; i++)
  1547. {
  1548. /*
  1549. * Did this drive have a pagefile before, but does not have
  1550. * one now?
  1551. */
  1552. if (apf[i].nMinFileSizePrev != 0 && apf[i].nMinFileSize == 0)
  1553. {
  1554. //
  1555. // Hack workaround -- MoveFileEx() is broken
  1556. //
  1557. TCHAR szPagefilePath[MAX_PATH];
  1558. lstrcpy(szPagefilePath, szRenameFunkyPrefix);
  1559. lstrcat(szPagefilePath, SZPageFileName(i));
  1560. VirtualMemDeletePagefile(szPagefilePath);
  1561. // MoveFileEx(SZPageFileName(i), NULL, MOVEFILE_DELAY_UNTIL_REBOOT);
  1562. }
  1563. }
  1564. return TRUE;
  1565. }
  1566. void GetAPrivilege( LPTSTR szPrivilegeName, PPRIVDAT ppd ) {
  1567. HANDLE hTok;
  1568. LUID luid;
  1569. TOKEN_PRIVILEGES tpNew;
  1570. DWORD cb;
  1571. if (LookupPrivilegeValue( NULL, szPrivilegeName, &luid ) &&
  1572. OpenProcessToken(GetCurrentProcess(),
  1573. TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hTok)) {
  1574. tpNew.PrivilegeCount = 1;
  1575. tpNew.Privileges[0].Luid = luid;
  1576. tpNew.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  1577. if (!AdjustTokenPrivileges(hTok, FALSE, &tpNew, sizeof(ppd->tp),
  1578. &(ppd->tp), &cb)) {
  1579. GetLastError();
  1580. }
  1581. ppd->hTok = hTok;
  1582. } else {
  1583. ppd->hTok = NULL;
  1584. }
  1585. }
  1586. void ResetOldPrivilege( PPRIVDAT ppdOld ) {
  1587. if (ppdOld->hTok != NULL ) {
  1588. AdjustTokenPrivileges(ppdOld->hTok, FALSE, &(ppdOld->tp), 0, NULL,
  1589. NULL);
  1590. CloseHandle( ppdOld->hTok );
  1591. ppdOld->hTok = NULL;
  1592. }
  1593. }
  1594. /*
  1595. * VirtualMemReconcileState
  1596. *
  1597. * Reconciles the n*FileSizePrev fields of apf with the n*FileSize fields.
  1598. *
  1599. */
  1600. void
  1601. VirtualMemReconcileState(
  1602. )
  1603. {
  1604. INT i;
  1605. for (i = 0; i < MAX_DRIVES; i++) {
  1606. apf[i].nMinFileSizePrev = apf[i].nMinFileSize;
  1607. apf[i].nMaxFileSizePrev = apf[i].nMaxFileSize;
  1608. } // for
  1609. }
  1610. /*
  1611. * VirtualMemDeletePagefile
  1612. *
  1613. * Hack workaround -- MoveFileEx() is broken.
  1614. *
  1615. */
  1616. DWORD
  1617. VirtualMemDeletePagefile(
  1618. IN LPTSTR szPagefile
  1619. )
  1620. {
  1621. HKEY hKey;
  1622. BOOL fhKeyOpened = FALSE;
  1623. DWORD dwResult;
  1624. LONG lResult;
  1625. LPTSTR szBuffer = NULL;
  1626. LPTSTR szBufferEnd = NULL;
  1627. DWORD dwValueType;
  1628. DWORD cbRegistry;
  1629. DWORD cbBuffer;
  1630. DWORD cchPagefile;
  1631. DWORD dwRetVal = ERROR_SUCCESS;
  1632. __try {
  1633. cchPagefile = lstrlen(szPagefile) + 1;
  1634. lResult = RegOpenKeyEx(
  1635. HKEY_LOCAL_MACHINE,
  1636. szSessionManager,
  1637. 0L,
  1638. KEY_READ | KEY_WRITE,
  1639. &hKey
  1640. );
  1641. if (ERROR_SUCCESS != lResult) {
  1642. dwRetVal = lResult;
  1643. __leave;
  1644. } // if
  1645. //
  1646. // Find out of PendingFileRenameOperations exists, and,
  1647. // if it does, how big it is
  1648. //
  1649. lResult = RegQueryValueEx(
  1650. hKey,
  1651. szPendingRename,
  1652. 0L,
  1653. &dwValueType,
  1654. (LPBYTE) NULL,
  1655. &cbRegistry
  1656. );
  1657. if (ERROR_SUCCESS != lResult) {
  1658. //
  1659. // If the value doesn't exist, we still need to set
  1660. // it's size to one character so the formulas below (which are
  1661. // written for the "we're appending to an existing string"
  1662. // case) still work.
  1663. //
  1664. cbRegistry = sizeof(TCHAR);
  1665. } // if
  1666. //
  1667. // Buffer needs to hold the existing registry value
  1668. // plus the supplied pagefile path, plus two extra
  1669. // terminating NULL characters. However, we only have to add
  1670. // room for one extra character, because we'll be overwriting
  1671. // the terminating NULL character in the existing buffer.
  1672. //
  1673. cbBuffer = cbRegistry + ((cchPagefile + 1) * sizeof(TCHAR));
  1674. szBufferEnd = szBuffer = (LPTSTR) MemAlloc(LPTR, cbBuffer);
  1675. if (!szBuffer) {
  1676. dwRetVal = ERROR_NOT_ENOUGH_MEMORY;
  1677. __leave;
  1678. } // if
  1679. //
  1680. // Grab the existing value, if there is one
  1681. //
  1682. if (ERROR_SUCCESS == lResult) {
  1683. lResult = RegQueryValueEx(
  1684. hKey,
  1685. szPendingRename,
  1686. 0L,
  1687. &dwValueType,
  1688. (LPBYTE) szBuffer,
  1689. &cbRegistry
  1690. );
  1691. if (ERROR_SUCCESS != lResult) {
  1692. dwRetVal = ERROR_FILE_NOT_FOUND;
  1693. __leave;
  1694. } // if
  1695. //
  1696. // We'll start our scribbling right on the final
  1697. // terminating NULL character of the existing
  1698. // value.
  1699. //
  1700. szBufferEnd += (cbRegistry / sizeof(TCHAR)) - 1;
  1701. } // if
  1702. //
  1703. // Copy in the supplied pagefile path.
  1704. //
  1705. lstrcpy(szBufferEnd, szPagefile);
  1706. //
  1707. // Add the final two terminating NULL characters
  1708. // required for REG_MULTI_SZ-ness. Yes, those indeces
  1709. // are correct--when cchPagfile was calculated above,
  1710. // we added one for its own terminating NULL character.
  1711. //
  1712. szBufferEnd[cchPagefile] = TEXT('\0');
  1713. szBufferEnd[cchPagefile + 1] = TEXT('\0');
  1714. dwValueType = REG_MULTI_SZ;
  1715. lResult = RegSetValueEx(
  1716. hKey,
  1717. szPendingRename,
  1718. 0L,
  1719. dwValueType,
  1720. (CONST BYTE *) szBuffer,
  1721. cbBuffer
  1722. );
  1723. if (ERROR_SUCCESS != lResult) {
  1724. dwRetVal = lResult;
  1725. } // if
  1726. } // __try
  1727. __finally {
  1728. if (fhKeyOpened) {
  1729. RegCloseKey(hKey);
  1730. } // if
  1731. if (szBuffer) {
  1732. MemFree((HLOCAL) szBuffer);
  1733. } // if
  1734. } // __finally
  1735. return dwRetVal;
  1736. }
  1737. /*
  1738. * VirtualMemCreatePagefileFromIndex
  1739. *
  1740. *
  1741. */
  1742. NTSTATUS
  1743. VirtualMemCreatePagefileFromIndex(
  1744. IN INT i
  1745. )
  1746. {
  1747. UNICODE_STRING us;
  1748. LARGE_INTEGER liMin, liMax;
  1749. NTSTATUS status;
  1750. WCHAR wszPath[MAX_PATH*2];
  1751. TCHAR szDrive[3];
  1752. DWORD cch;
  1753. HourGlass(TRUE);
  1754. // convert path drive letter to an NT device path
  1755. wsprintf(szDrive, TEXT("%c:"), (TCHAR)(i + (int)TEXT('A')));
  1756. cch = QueryDosDevice( szDrive, wszPath, sizeof(wszPath) /
  1757. sizeof(TCHAR));
  1758. if (cch != 0) {
  1759. // Concat the filename only (skip 'd:') to the nt device
  1760. // path, and convert it to a UNICODE_STRING
  1761. lstrcat( wszPath, SZPageFileName(i) + 2 );
  1762. RtlInitUnicodeString( &us, wszPath );
  1763. liMin.QuadPart = (LONGLONG)(apf[i].nMinFileSize * ONE_MEG);
  1764. liMax.QuadPart = (LONGLONG)(apf[i].nMaxFileSize * ONE_MEG);
  1765. status = NtCreatePagingFile ( &us, &liMin, &liMax, 0L );
  1766. }
  1767. else
  1768. {
  1769. status = STATUS_NO_SUCH_DEVICE;
  1770. }
  1771. HourGlass(FALSE);
  1772. return status;
  1773. }
  1774. /*
  1775. * VirtualMemUpdateListboxFromIndex
  1776. *
  1777. */
  1778. void
  1779. VirtualMemUpdateListboxFromIndex(
  1780. HWND hDlg,
  1781. INT i
  1782. )
  1783. {
  1784. int j, cLBEntries, iTemp;
  1785. int iLBEntry = -1;
  1786. TCHAR szTemp[MAX_PATH];
  1787. cLBEntries = (int)SendDlgItemMessage(
  1788. (HWND) hDlg,
  1789. (int) IDD_VM_VOLUMES,
  1790. (UINT) LB_GETCOUNT,
  1791. (WPARAM) 0,
  1792. (LPARAM) 0
  1793. );
  1794. if (LB_ERR != cLBEntries) {
  1795. // Loop through all the listbox entries, looking for the one
  1796. // that corresponds to the drive index we were supplied.
  1797. for (j = 0; j < cLBEntries; j++) {
  1798. iTemp = (int)SendDlgItemMessage(
  1799. (HWND) hDlg,
  1800. (int) IDD_VM_VOLUMES,
  1801. (UINT) LB_GETITEMDATA,
  1802. (WPARAM) j,
  1803. (LPARAM) 0
  1804. );
  1805. if (iTemp == i) {
  1806. iLBEntry = j;
  1807. break;
  1808. } // if
  1809. } // for
  1810. if (-1 != iLBEntry) {
  1811. // Found the desired entry, so update it.
  1812. VirtualMemBuildLBLine(szTemp, i);
  1813. SendDlgItemMessage(
  1814. hDlg,
  1815. IDD_VM_VOLUMES,
  1816. LB_DELETESTRING,
  1817. (WPARAM) iLBEntry,
  1818. 0
  1819. );
  1820. SendDlgItemMessage(
  1821. hDlg,
  1822. IDD_VM_VOLUMES,
  1823. LB_INSERTSTRING,
  1824. (WPARAM) iLBEntry,
  1825. (LPARAM) szTemp
  1826. );
  1827. SendDlgItemMessage(
  1828. hDlg,
  1829. IDD_VM_VOLUMES,
  1830. LB_SETITEMDATA,
  1831. (WPARAM) iLBEntry,
  1832. (LPARAM) i
  1833. );
  1834. SendDlgItemMessage(
  1835. hDlg,
  1836. IDD_VM_VOLUMES,
  1837. LB_SETCURSEL,
  1838. (WPARAM) iLBEntry,
  1839. 0
  1840. );
  1841. if (apf[i].nMinFileSize) {
  1842. SetDlgItemInt(hDlg, IDD_VM_SF_SIZE, apf[i].nMinFileSize, FALSE);
  1843. SetDlgItemInt(hDlg, IDD_VM_SF_SIZEMAX, apf[i].nMaxFileSize, FALSE);
  1844. }
  1845. else {
  1846. SetDlgItemText(hDlg, IDD_VM_SF_SIZE, TEXT(""));
  1847. SetDlgItemText(hDlg, IDD_VM_SF_SIZEMAX, TEXT(""));
  1848. }
  1849. VirtualMemUpdateAllocated(hDlg);
  1850. } // if (-1 != iLBEntry)
  1851. } // if (LB_ERR...
  1852. return;
  1853. }
  1854. /*
  1855. * VirtualMemPromptForReboot
  1856. *
  1857. *
  1858. *
  1859. */
  1860. int
  1861. VirtualMemPromptForReboot(
  1862. HWND hDlg
  1863. )
  1864. {
  1865. INT i, result;
  1866. int iReboot = RET_NO_CHANGE;
  1867. int iThisDrv;
  1868. UNICODE_STRING us;
  1869. LARGE_INTEGER liMin, liMax;
  1870. NTSTATUS status;
  1871. TCHAR szDrive[3];
  1872. PRIVDAT pdOld;
  1873. GetPageFilePrivilege( &pdOld );
  1874. // Have to make two passes through the list of pagefiles.
  1875. // The first checks to see if files called "pagefile.sys" exist
  1876. // on any of the drives that will be getting new pagefiles.
  1877. // If there are existing files called "pagefile.sys" and the user
  1878. // doesn't want any one of them to be overwritten, we bail out.
  1879. // The second pass through the list does the actual work of
  1880. // creating the pagefiles.
  1881. for (i = 0; i < MAX_DRIVES; i++) {
  1882. //
  1883. // Did something change?
  1884. //
  1885. if (apf[i].nMinFileSize != apf[i].nMinFileSizePrev ||
  1886. apf[i].nMaxFileSize != apf[i].nMaxFileSizePrev ||
  1887. apf[i].fCreateFile ) {
  1888. // Assume we have permission to nuke existing files called pagefile.sys
  1889. // (we'll confirm the assumption later)
  1890. result = IDYES;
  1891. if (0 != apf[i].nMinFileSize) { // Pagefile wanted for this drive
  1892. if (0 == apf[i].nMinFileSizePrev) { // There wasn't one there before
  1893. if (!(((GetFileAttributes(SZPageFileName(i)) == 0xFFFFFFFF)) || (GetLastError() == ERROR_FILE_NOT_FOUND))) {
  1894. // A file named pagefile.sys exists on the drive
  1895. // We need to confirm that we can overwrite it
  1896. result = MsgBoxParam(
  1897. hDlg,
  1898. IDS_SYSDM_OVERWRITE,
  1899. IDS_SYSDM_TITLE,
  1900. MB_ICONQUESTION | MB_YESNO,
  1901. SZPageFileName(i)
  1902. );
  1903. } // if (!((GetFileAttributes...
  1904. } // if (0 == apf[i].nMinFileSizePrev)
  1905. if (IDYES != result) {
  1906. // User doesn't want us overwriting an existing
  1907. // file called pagefile.sys, so back out the changes
  1908. apf[i].nMinFileSize = apf[i].nMinFileSizePrev;
  1909. apf[i].nMaxFileSize = apf[i].nMaxFileSizePrev;
  1910. apf[i].fCreateFile = FALSE;
  1911. // Update the listbox
  1912. VirtualMemUpdateListboxFromIndex(hDlg, i);
  1913. SetFocus(GetDlgItem(hDlg, IDD_VM_VOLUMES));
  1914. // Bail, telling the DlgProc not to end the dialog
  1915. iReboot = RET_ERROR;
  1916. goto bailout;
  1917. } // if (IDYES != result)
  1918. } // if (0 != apf[i].nMinFileSize)
  1919. } // if
  1920. } // for
  1921. for (i = 0; i < MAX_DRIVES; i++)
  1922. {
  1923. //
  1924. // Did something change?
  1925. //
  1926. if (apf[i].nMinFileSize != apf[i].nMinFileSizePrev ||
  1927. apf[i].nMaxFileSize != apf[i].nMaxFileSizePrev ||
  1928. apf[i].fCreateFile ) {
  1929. /*
  1930. * If we are strictly creating a *new* page file, or *enlarging*
  1931. * the minimum or maximum size of an existing page file, then
  1932. * we can try do it on the fly. If no errors are returned by
  1933. * the system then no reboot will be required.
  1934. */
  1935. // assume we will have to reboot
  1936. iThisDrv = RET_VIRTUAL_CHANGE;
  1937. /*
  1938. * IF we are creating a new page file
  1939. */
  1940. if ((0 != apf[i].nMinFileSize) && (0 == apf[i].nMinFileSizePrev)) {
  1941. status = VirtualMemCreatePagefileFromIndex(i);
  1942. if (NT_SUCCESS(status)) {
  1943. // made it on the fly, no need to reboot for this drive!
  1944. iThisDrv = RET_CHANGE_NO_REBOOT;
  1945. }
  1946. }
  1947. /*
  1948. * If we're enlarging the minimum or maximum size of an existing
  1949. * page file, we can try to do it on the fly
  1950. */
  1951. else if ((apf[i].nMinFileSize != 0) &&
  1952. ((apf[i].nMinFileSize > apf[i].nMinFileSizePrev) ||
  1953. (apf[i].nMaxFileSize > apf[i].nMaxFileSizePrev))) {
  1954. status = VirtualMemCreatePagefileFromIndex(i);
  1955. if (NT_SUCCESS(status)) {
  1956. iThisDrv = RET_CHANGE_NO_REBOOT;
  1957. }
  1958. } /* else if */
  1959. // if this drive has changed, we must reboot
  1960. if (RET_VIRTUAL_CHANGE == iThisDrv)
  1961. {
  1962. iReboot |= RET_VIRTUAL_CHANGE;
  1963. }
  1964. }
  1965. }
  1966. bailout:
  1967. ResetOldPrivilege( &pdOld );
  1968. //
  1969. // If Nothing changed, then change our IDOK to IDCANCEL so System.cpl will
  1970. // know not to reboot.
  1971. //
  1972. return iReboot;
  1973. }