// Copyright (c) 1997-1999 Microsoft Corporation #include "precomp.h" #ifdef EXT_DEBUG #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif // Application specific #include "sysdm.h" #include "VirtualMemDlg.h" #include "..\common\util.h" #include #include "helpid.h" #include "shlwapi.h" #include "common.h" #define RET_ERROR (-1) #define RET_NO_CHANGE 0x00 #define RET_VIRTUAL_CHANGE 0x01 #define RET_RECOVER_CHANGE 0x02 #define RET_CHANGE_NO_REBOOT 0x04 #define RET_CONTINUE 0x08 #define RET_BREAK 0x10 #define RET_VIRT_AND_RECOVER (RET_VIRTUAL_CHANGE | RET_RECOVER_CHANGE) //========================================================================== // Local Definitions //========================================================================== #define MAX_SIZE_LEN 8 // Max chars in the Swap File Size edit. #define MAX_DRIVES 26 // Max number of drives. #define MIN_SWAPSIZE 2 // Min swap file size (see note below). #define MIN_FREESPACE 5 // Must have 5 meg free after swap file #define MIN_SUGGEST 22 // Always suggest at least 22 meg #define ONE_MEG 1048576 //New consts for Win Server 2003 #define MAX_SWAPSIZE_X86 (4 * 1024) // 4 Gb (number stored in megabytes) #define MAX_SWAPSIZE_X86_PAE (16 * 1024 * 1024) // 16 Tb #define MAX_SWAPSIZE_IA64 (32 * 1024 * 1024) // 32 Tb #define MAX_SWAPSIZE_AMD64 (16 * 1024 * 1024) // 16 Tb #define MIN_FREESPACE_STR _T("5") // equal their manifests. #define TABSTOP_VOL 22 #define TABSTOP_SIZE 122 TCHAR gszPageFileSettings[] = _T("Win32_PageFileSetting"); TCHAR gszPageFileUsage[] = _T("Win32_PageFileUsage"); TCHAR gszLogicalFile[] = _T("CIM_LogicalFile"); TCHAR gszAllocatedBaseSize[] = _T("AllocatedBaseSize"); TCHAR gszFileSize[] = _T("FileSize"); TCHAR gszInitialSize[] = _T("InitialSize"); TCHAR gszMaximumSize[] = _T("MaximumSize"); TCHAR gszName[] = _T("Name"); TCHAR gszPFNameFormat[] = _T("%s\\\\pagefile.sys"); // My privilege 'handle' structure typedef struct { HANDLE hTok; TOKEN_PRIVILEGES tp; } PRIVDAT, *PPRIVDAT; DWORD aVirtualMemHelpIds[] = { IDD_VM_VOLUMES, -1, IDD_VM_DRIVE_HDR, (IDH_DLG_VIRTUALMEM + 0), IDD_VM_PF_SIZE_LABEL, (IDH_DLG_VIRTUALMEM + 1), IDD_VM_DRIVE_LABEL, (IDH_DLG_VIRTUALMEM + 2), IDD_VM_SF_DRIVE, (IDH_DLG_VIRTUALMEM + 2), IDD_VM_SPACE_LABEL, (IDH_DLG_VIRTUALMEM + 3), IDD_VM_SF_SPACE, (IDH_DLG_VIRTUALMEM + 3), IDD_VM_ST_INITSIZE, (IDH_DLG_VIRTUALMEM + 4), IDD_VM_SF_SIZE, (IDH_DLG_VIRTUALMEM + 4), IDD_VM_ST_MAXSIZE, (IDH_DLG_VIRTUALMEM + 5), IDD_VM_SF_SIZEMAX, (IDH_DLG_VIRTUALMEM + 5), IDD_VM_SF_SET, (IDH_DLG_VIRTUALMEM + 6), IDD_VM_MIN_LABEL, (IDH_DLG_VIRTUALMEM + 7), IDD_VM_MIN, (IDH_DLG_VIRTUALMEM + 7), IDD_VM_RECOMMEND_LABEL, (IDH_DLG_VIRTUALMEM + 8), IDD_VM_RECOMMEND, (IDH_DLG_VIRTUALMEM + 8), IDD_VM_ALLOCD_LABEL, (IDH_DLG_VIRTUALMEM + 9), IDD_VM_ALLOCD, (IDH_DLG_VIRTUALMEM + 9), IDD_VM_CUSTOMSIZE_RADIO,(IDH_DLG_VIRTUALMEM + 12), //IDH_PERFOPT_ADVTAB_VIRTUALMEM_CUSTOM in sysdm.h IDD_VM_RAMBASED_RADIO, (IDH_DLG_VIRTUALMEM + 13), //IDH_PERFOPT_ADVTAB_VIRTUALMEM_SYSMANAGED in sysdm.h IDD_VM_NOPAGING_RADIO, (IDH_DLG_VIRTUALMEM + 14), //IDH_PERFOPT_ADVTAB_VIRTUALMEM_NOFILE in sysdm.h 0,0 }; //========================================================================== // Typedefs and Structs //========================================================================== // registry info for a page file (but not yet formatted). //Note: since this structure gets passed to FormatMessage, all fields must //be 4 bytes wide. typedef struct { LPTSTR pszName; DWORD nMin; DWORD nMax; DWORD chNull; } PAGEFILDESC; //========================================================================== // Global Data Declarations //========================================================================== //TCHAR m_szSysHelp[] = TEXT("sysdm.hlp"); //TCHAR g_szSysDir[ MAX_PATH ]; //UINT g_wHelpMessage; //========================================================================== // Local Data Declarations //========================================================================== // Other VM Vars BOOL gfCoreDumpChanged; DWORD cmTotalVM; //========================================================================== // Local Function Prototypes //========================================================================== HRESULT QueryInstanceProperties( const TCHAR * pszClass, const TCHAR * pszRequestedProperties, const TCHAR * pszKeyPropertyName, const TCHAR * pszKeyPropertyValue, CWbemServices &Services, IWbemClassObject ** ppcoInst); //-------------------------------------------------------------- INT_PTR CALLBACK StaticVirtDlgProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam) { // if this is the initDlg msg... if(message == WM_INITDIALOG) { // transfer the 'this' ptr to the extraBytes. SetWindowLongPtr(hwndDlg, DWLP_USER, lParam); } // DWL_USER is the 'this' ptr. VirtualMemDlg *me = (VirtualMemDlg *)GetWindowLongPtr(hwndDlg, DWLP_USER); if(me != NULL) { // call into the DlgProc() that has some context. return me->DlgProc(hwndDlg, message, wParam, lParam); } else { return FALSE; } } //-------------------------------------------------------------- VirtualMemDlg::VirtualMemDlg(WbemServiceThread *serviceThread) : WBEMPageHelper(serviceThread) { IWbemClassObject *pInst = NULL; // this is initialized properly in Init() m_VMWriteAccess = FALSE; m_pgEnumSettings = NULL; m_pgEnumUsage = NULL; m_cxLBExtent = 0; if((pInst = FirstInstanceOf("Win32_LogicalMemoryConfiguration")) != NULL) { m_memory = pInst; } if((pInst = FirstInstanceOf("Win32_Registry")) != NULL) { m_registry = pInst; } if((pInst = FirstInstanceOf("Win32_OSRecoveryConfiguration")) != NULL) { m_recovery = pInst; } } //-------------------------------------------------------------- VirtualMemDlg::~VirtualMemDlg() { if(m_pgEnumSettings != NULL) { m_pgEnumSettings->Release(); m_pgEnumSettings = NULL; } if(m_pgEnumUsage != NULL) { m_pgEnumUsage->Release(); m_pgEnumUsage = NULL; } } //-------------------------------------------------------------- int VirtualMemDlg::DoModal(HWND hDlg) { return (int) DialogBoxParam(HINST_THISDLL, (LPTSTR) MAKEINTRESOURCE(DLG_VIRTUALMEM), hDlg, StaticVirtDlgProc, (LPARAM)this); } //-------------------------------------------------------------- int TranslateDlgItemInt( HWND hDlg, int id ) { /* * We can't just call GetDlgItemInt because the * string we are trying to translate looks like: * nnn (MB), and the '(MB)' would break GetDlgInt. */ TCHAR szBuffer[256] = {0}; int i = 0; if (GetDlgItemText(hDlg, id, szBuffer, sizeof(szBuffer) / sizeof(*szBuffer))) { _stscanf(szBuffer, _T("%d"), &i); } return i; } //---------------------------------------------------- bool VirtualMemDlg::DlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { static int fEdtCtlHasFocus = 0; m_hDlg = hDlg; switch (message) { case WM_INITDIALOG: Init(hDlg); return TRUE; case WM_COMMAND: switch (LOWORD(wParam)) { case IDD_VM_VOLUMES: // Make edit control reflect the listbox selection. if (HIWORD(wParam) == LBN_SELCHANGE) SelChange(hDlg); break; case IDD_VM_SF_SET: if (SetNewSize(hDlg)) { ::EnableWindow(::GetDlgItem(hDlg, IDD_VM_SF_SET), FALSE); SetDefButton(hDlg, IDOK); } break; case IDOK: { int iRet = UpdateWBEM(); // iRet |= PromptForReboot(hDlg); if (iRet & RET_CHANGE_NO_REBOOT) { // We created a pagefile, turn off temp page file flag DWORD dwRegData; dwRegData = 0; } else { // reboot required, warn user & set global flag MsgBoxParam(m_hDlg, IDS_MUST_REBOOT, IDS_SYS_CHANGE_CAPTION, MB_OK | MB_ICONINFORMATION, NULL, NULL); g_fRebootRequired = true; } if (gfCoreDumpChanged) iRet |= RET_RECOVER_CHANGE; EndDialog(hDlg, iRet ); HourGlass(FALSE); break; } case IDCANCEL: // get rid of changes and restore original values. EndDialog(hDlg, RET_NO_CHANGE); HourGlass(FALSE); break; case IDD_HELP: break; case IDD_VM_SF_SIZE: case IDD_VM_SF_SIZEMAX: switch(HIWORD(wParam)) { case EN_CHANGE: if ((fEdtCtlHasFocus != 0) && m_VMWriteAccess) { ::EnableWindow(::GetDlgItem(hDlg, IDD_VM_SF_SET), TRUE); SetDefButton( hDlg, IDD_VM_SF_SET); } break; case EN_SETFOCUS: fEdtCtlHasFocus++; break; case EN_KILLFOCUS: fEdtCtlHasFocus--; break; } break; case IDD_VM_NOPAGING_RADIO: case IDD_VM_RAMBASED_RADIO: if( HIWORD(wParam) == BN_CLICKED ) { EnableWindow( GetDlgItem( hDlg, IDD_VM_SF_SIZE ), FALSE ); EnableWindow( GetDlgItem( hDlg, IDD_VM_SF_SIZEMAX ), FALSE ); if (m_VMWriteAccess) { ::EnableWindow(::GetDlgItem(hDlg, IDD_VM_SF_SET), TRUE); SetDefButton( hDlg, IDD_VM_SF_SET); } } break; case IDD_VM_CUSTOMSIZE_RADIO: if( HIWORD(wParam) == BN_CLICKED ) { EnableWindow( GetDlgItem( hDlg, IDD_VM_SF_SIZE ), TRUE ); EnableWindow( GetDlgItem( hDlg, IDD_VM_SF_SIZEMAX ), TRUE ); if (m_VMWriteAccess) { ::EnableWindow(::GetDlgItem(hDlg, IDD_VM_SF_SET), TRUE); SetDefButton( hDlg, IDD_VM_SF_SET); } } break; default: break; } break; case WM_DESTROY: { PAGING_FILE *pgVal = NULL; HWND lbHWND = GetDlgItem(m_hDlg, IDD_VM_VOLUMES); int last = ListBox_GetCount(lbHWND); // zero-based loop. for(int x = 0; x < last; x++) { pgVal = (PAGING_FILE *)ListBox_GetItemData(lbHWND, x); delete pgVal; } } break; case WM_HELP: // F1 ::WinHelp((HWND)((LPHELPINFO)lParam)->hItemHandle, L"sysdm.hlp", HELP_WM_HELP, (ULONG_PTR)(LPSTR)aVirtualMemHelpIds); break; case WM_CONTEXTMENU: // right mouse click WinHelp((HWND) wParam, HELP_FILE, HELP_CONTEXTMENU, (ULONG_PTR)(LPSTR) aVirtualMemHelpIds); break; default: return FALSE; break; } return TRUE; } //--------------------------------------------------------------- TCHAR szCrashControl[] = TEXT("System\\CurrentControlSet\\Control\\CrashControl"); TCHAR szMemMan[] = TEXT("System\\CurrentControlSet\\Control\\Session Manager\\Memory Management"); TCHAR szRegSizeLim[] = TEXT("System\\CurrentControlSet\\Control"); BOOL VirtualMemDlg::Init(HWND hDlg) { INT i; HWND hwndLB; INT aTabs[2]; RECT rc; DWORD dwTotalPhys = 0; HourGlass(TRUE); // g_wHelpMessage = RegisterWindowMessage( TEXT( "ShellHelp" ) ); if(m_pgEnumUsage == NULL) { // Error - cannot even get list of paging files from WBEM MsgBoxParam(hDlg, SYSTEM+11, IDS_TITLE, MB_ICONEXCLAMATION); EndDialog(hDlg, RET_NO_CHANGE); HourGlass(FALSE); return FALSE; } BOOL vcVirtRO = TRUE, vcCoreRO = TRUE; RemoteRegWriteable(szCrashControl, vcCoreRO); RemoteRegWriteable(szMemMan, vcVirtRO); // EXCUSE: I wanted to preserve as much of the original logic but its // writability was reversed from my util so I do this wierd thing to // flip it back. vcCoreRO = !vcCoreRO; vcVirtRO = !vcVirtRO; // To change Virtual Memory size or Crash control, we need access // to both the CrashCtl key and the PagingFiles value in the MemMgr key if(vcVirtRO || vcCoreRO) { // Disable some fields, because they only have Read access. EnableWindow(GetDlgItem(hDlg, IDD_VM_CUSTOMSIZE_RADIO), FALSE); EnableWindow(GetDlgItem(hDlg, IDD_VM_RAMBASED_RADIO), FALSE); EnableWindow(GetDlgItem(hDlg, IDD_VM_NOPAGING_RADIO), FALSE); EnableWindow(GetDlgItem(hDlg, IDD_VM_SF_SIZE), FALSE); EnableWindow(GetDlgItem(hDlg, IDD_VM_SF_SIZEMAX), FALSE); EnableWindow(GetDlgItem(hDlg, IDD_VM_ST_INITSIZE), FALSE); EnableWindow(GetDlgItem(hDlg, IDD_VM_ST_MAXSIZE), FALSE); EnableWindow(GetDlgItem(hDlg, IDD_VM_SF_SET), FALSE); m_VMWriteAccess = FALSE; } else m_VMWriteAccess = TRUE; hwndLB = GetDlgItem(hDlg, IDD_VM_VOLUMES); aTabs[0] = TABSTOP_VOL; aTabs[1] = TABSTOP_SIZE; SendMessage(hwndLB, LB_SETTABSTOPS, 2, (LPARAM)&aTabs); // Since SetGenLBWidth only counts tabs as one character, we must compute // the maximum extra space that the tab characters will expand to and // arbitrarily tack it onto the end of the string width. // // cxExtra = 1st Tab width + 1 default tab width (8 chrs) - strlen("d:\t\t"); // // (I know the docs for LB_SETTABSTOPS says that a default tab == 2 dlg // units, but I have read the code, and it is really 8 chars) rc.top = rc.left = 0; rc.bottom = 8; rc.right = TABSTOP_VOL + (4 * 8) - (4 * 4); MapDialogRect( hDlg, &rc ); m_cxExtra = rc.right - rc.left; // List all drives LoadVolumeList(); SendDlgItemMessage(hDlg, IDD_VM_SF_SIZE, EM_LIMITTEXT, MAX_SIZE_LEN, 0L); SendDlgItemMessage(hDlg, IDD_VM_SF_SIZEMAX, EM_LIMITTEXT, MAX_SIZE_LEN, 0L); // Get the total physical memory in the machine. dwTotalPhys = m_memory.GetLong("TotalPhysicalMemory"); SetDlgItemMB(hDlg, IDD_VM_MIN, MIN_SWAPSIZE); // convert to KBs for the calculation. dwTotalPhys /= 1024; dwTotalPhys *= 3; dwTotalPhys >>=1; // x*3/2 == 1.5*x more or less. i = (DWORD)dwTotalPhys; SetDlgItemMB(hDlg, IDD_VM_RECOMMEND, max(i, MIN_SUGGEST)); // Select the first drive in the listbox. SendDlgItemMessage(hDlg, IDD_VM_VOLUMES, LB_SETCURSEL, 0, 0L); SelChange(hDlg); //since the data is already loaded into the listbox, we use this lightweight // way of calculating. SetDlgItemMB(hDlg, IDD_VM_ALLOCD, RecomputeAllocated()); // Show RegQuota cmTotalVM = ComputeTotalMax(); HourGlass(FALSE); return TRUE; } //------------------------------------------------------------------- int VirtualMemDlg::ComputeTotalMax( void ) { INT nTotalAllocated = 0; INT i; HWND VolHWND = GetDlgItem(m_hDlg, IDD_VM_VOLUMES); int cItems = ListBox_GetCount(VolHWND); for(i = 0; i < cItems; i++) { PAGING_FILE *pgVal = (PAGING_FILE *)ListBox_GetItemData(VolHWND, i); nTotalAllocated += pgVal->nMaxFileSize; } return nTotalAllocated; } //-------------------------------------------------------- void VirtualMemDlg::BuildLBLine(LPTSTR pszBuf, const PAGING_FILE *pgVal) { // // Build a string according to the following format: // // C: [ Vol_label ] %d - %d // TCHAR szVolume[MAX_PATH] = {0}; TCHAR szTemp[MAX_PATH] = {0}; if (pgVal->name != NULL) { lstrcpy(pszBuf, pgVal->name); } else { *pszBuf = _T('\0'); } lstrcat(pszBuf, _T("\t")); if (pgVal->volume != NULL && *pgVal->volume) { lstrcat(pszBuf, _T("[")); lstrcat(pszBuf, pgVal->volume); lstrcat(pszBuf, _T("]")); } if (!pgVal->fRamBasedPagefile && pgVal->nMinFileSize) { // // Drive has a page file with specific settings. // wsprintf(szTemp, _T("\t%d - %d"), pgVal->nMinFileSize, pgVal->nMaxFileSize); lstrcat(pszBuf, szTemp); } else { // // Either the page file size is derived from the RAM size or the // drive doesn't have a page file. // // In either case, do nothing else. // } } //-------------------------------------------------------------- void VirtualMemDlg::SelChange(HWND hDlg) { TCHAR szTemp[MAX_PATH] = {0}; INT iSel; INT nCrtRadioButtonId; PAGING_FILE *iDrive; BOOL fEditsEnabled; // where are we pointing now. if ((iSel = (INT)SendDlgItemMessage(hDlg, IDD_VM_VOLUMES, LB_GETCURSEL, 0, 0)) == LB_ERR) { return; } // get its data. iDrive = (PAGING_FILE *)SendDlgItemMessage(hDlg, IDD_VM_VOLUMES, LB_GETITEMDATA, iSel, 0); TCHAR volBuf[40] = {0}; if(_tcslen(iDrive->volume) != 0) { _tcscpy(volBuf, _T("[")); _tcscat(volBuf, iDrive->volume); _tcscat(volBuf, _T("]")); } wsprintf(szTemp, _T("%s %s"), iDrive->name, volBuf); //LATER: should we also put up total drive size as well as free space? SetDlgItemText(hDlg, IDD_VM_SF_DRIVE, szTemp); if ( iDrive->fRamBasedPagefile ) { // // Paging file size based on RAM size // nCrtRadioButtonId = IDD_VM_RAMBASED_RADIO; fEditsEnabled = FALSE; } else { if ( iDrive->nMinFileSize ) { // // Custom size paging file // nCrtRadioButtonId = IDD_VM_CUSTOMSIZE_RADIO; SetDlgItemInt(hDlg, IDD_VM_SF_SIZE, iDrive->nMinFileSize, FALSE); SetDlgItemInt(hDlg, IDD_VM_SF_SIZEMAX, iDrive->nMaxFileSize, FALSE); fEditsEnabled = TRUE; } else { // // No paging file // nCrtRadioButtonId = IDD_VM_NOPAGING_RADIO; SetDlgItemText(hDlg, IDD_VM_SF_SIZE, TEXT("")); SetDlgItemText(hDlg, IDD_VM_SF_SIZEMAX, TEXT("")); fEditsEnabled = FALSE; // // If the allocated size is zero, then this is a volume which // had a page file previously but does not now. In this case, // there is no settings/usage information in the repository. // Since the pagefile.sys file size is considered free space // in the free space size computation, then it needs to be // obtained here. // if ( iDrive->nAllocatedFileSize == 0 ) { // // Fetch x:\pagefile.sys file size. // CWbemClassObject LogicalFile; IWbemClassObject * pcoInst; HRESULT hr; wsprintf(szTemp, gszPFNameFormat, iDrive->name); hr = QueryInstanceProperties(gszLogicalFile, gszFileSize, gszName, szTemp, m_WbemServices, &pcoInst); LogicalFile = pcoInst; if (SUCCEEDED(hr)) { iDrive->nAllocatedFileSize = (LogicalFile.GetLong(gszFileSize) / ONE_MEG); } } } } // // Set 'Space Available'. // SetDlgItemMB(hDlg, IDD_VM_SF_SPACE, iDrive->freeSpace + iDrive->nAllocatedFileSize); // // Select the appropriate radio button // CheckRadioButton( hDlg, IDD_VM_CUSTOMSIZE_RADIO, IDD_VM_NOPAGING_RADIO, nCrtRadioButtonId ); // // Enable/disable the min & max size edit boxes (if user has write access !) // if (m_VMWriteAccess) { EnableWindow( GetDlgItem( hDlg, IDD_VM_SF_SIZE ), fEditsEnabled ); EnableWindow( GetDlgItem( hDlg, IDD_VM_SF_SIZEMAX ), fEditsEnabled ); } } //-------------------------------------------------------------- bool VirtualMemDlg::EnsureEnumerator(const bstr_t bstrClass) { HRESULT hr = S_OK; // // This code used to retain/cache these interface ptrs and call // CreateInstanceEnum once. But the logic was commented out for // some reason with a comment that it was expensive to cache the // interfaces, although the data member was set each time with no // call to Release!). // if (lstrcmpi(gszPageFileSettings, bstrClass) == 0) { IEnumWbemClassObject * pgEnumSettings = NULL; hr = m_WbemServices.CreateInstanceEnum(bstrClass, WBEM_FLAG_SHALLOW, &pgEnumSettings); if (SUCCEEDED(hr)) { if (m_pgEnumSettings != NULL) { m_pgEnumSettings->Release(); } m_pgEnumSettings = pgEnumSettings; } } else if (lstrcmpi(gszPageFileUsage, bstrClass) == 0) { IEnumWbemClassObject * pgEnumUsage = NULL; hr = m_WbemServices.CreateInstanceEnum(bstrClass, WBEM_FLAG_SHALLOW, &pgEnumUsage); if (SUCCEEDED(hr)) { if (m_pgEnumUsage != NULL) { m_pgEnumUsage->Release(); } m_pgEnumUsage = pgEnumUsage; } } else { // Do nothing. } return (SUCCEEDED(hr)); } //-------------------------------------------------------------- void VirtualMemDlg::LoadVolumeList(void) { IEnumWbemClassObject *diskEnum = NULL; IWbemClassObject *pInst = NULL; CWbemClassObject newInst; DWORD uReturned = 0; HRESULT hr = 0; bstr_t sNameProp(gszName); bstr_t sVolumeProp("VolumeName"); bstr_t sFileSystemProp("FileSystem"); bstr_t sDriveTypeProp("DriveType"); bstr_t sFreeProp("FreeSpace"); bstr_t sSizeProp("Size"), temp; long driveType; __int64 temp64 = 0; variant_t pVal; int idx; TCHAR volumeLine[100] = {0}; PAGING_FILE *pgVar; HWND VolHWND = GetDlgItem(m_hDlg, IDD_VM_VOLUMES); // walk the disks. if(hr = m_WbemServices.ExecQuery(bstr_t("Select __PATH, DriveType from Win32_LogicalDisk"), 0, &diskEnum) == S_OK) { TCHAR bootLtr[2] = {0}; if((pInst = FirstInstanceOf("Win32_OperatingSystem")) != NULL) { CWbemClassObject os = pInst; bstr_t temp = os.GetString(L"SystemDirectory"); _tcsncpy(bootLtr, temp, 1); m_PAEEnabled = os.GetBool(L"PAEEnabled"); } // get the first and only instance. while(SUCCEEDED(diskEnum->Next(-1, 1, &pInst, &uReturned)) && (uReturned != 0)) { // get the DriveType. if ((pInst->Get(sDriveTypeProp, 0L, &pVal, NULL, NULL) == S_OK)) { // look at the DriveType to see if this drive can have a swapfile. driveType = pVal; if(driveType == DRIVE_FIXED) { // it can so get the expensive properties now. // NOTE: This releases pInst; cuz you EXCHANGED // it for a better one. newInst = ExchangeInstance(&pInst); // extract. pgVar = new PAGING_FILE; pgVar->name = CloneString(newInst.GetString(sNameProp)); pgVar->volume = CloneString(newInst.GetString(sVolumeProp)); pgVar->filesystem = CloneString(newInst.GetString(sFileSystemProp)); if(bootLtr[0] == pgVar->name[0]) { pgVar->bootDrive = true; } temp64 = 0; temp = newInst.GetString(sFreeProp); _stscanf(temp, _T("%I64d"), &temp64); pgVar->freeSpace = (ULONG)(temp64 / ONE_MEG); temp64 = 0; temp = newInst.GetString(sSizeProp); _stscanf(temp, _T("%I64d"), &temp64); pgVar->totalSize = (ULONG)(temp64 / ONE_MEG); // match with a Win32_PageFileSettings if possible. FindSwapfile(pgVar); // add it to the listbox. BuildLBLine(volumeLine, pgVar); idx = ListBox_AddString(VolHWND, volumeLine); int nRet = ListBox_SetItemData(VolHWND, idx, pgVar); if(nRet == LB_ERR) { MessageBox(NULL,_T("Error"),_T("Error"),MB_OK); } m_cxLBExtent = SetLBWidthEx(VolHWND, volumeLine, m_cxLBExtent, m_cxExtra); } //endif drive can have swapfile. } //endif get the cheap variable. // in case it wasn't exchanged, release it now. if(pInst) { pInst->Release(); pInst = NULL; } } // endwhile Enum diskEnum->Release(); } //endif CreateInstanceEnum() SUCCEEDED (one way or another :) } //--------------------------------------------------------------- void VirtualMemDlg::FindSwapfile(PAGING_FILE *pgVar) { IWbemClassObject *pInst = NULL; CWbemClassObject PFSettings; CWbemClassObject PFUsage; DWORD uReturned = 0; HRESULT hr = 0; bstr_t sNameProp(gszName); bstr_t sMaxProp(gszMaximumSize); bstr_t sInitProp(gszInitialSize); bstr_t sPathProp("__PATH"); bstr_t sAllocSize(gszAllocatedBaseSize); variant_t pVal, pVal1, pVal2, pVal3; bstr_t bName; // do we have one? if(EnsureEnumerator(gszPageFileSettings)) { m_pgEnumSettings->Reset(); // walk through the pagefiles... while((hr = m_pgEnumSettings->Next(-1, 1, &pInst, &uReturned) == S_OK) && (uReturned != 0)) { PFSettings = pInst; // trying to match the drive letter. bName = PFSettings.GetString(sNameProp); if(_wcsnicmp((wchar_t *)bName, pgVar->name, 1) == 0) { // letter matched; get some details. pgVar->nMinFileSize = pgVar->nMinFileSizePrev = PFSettings.GetLong(sInitProp); // // If the page file InitialSize property is zero, it is an // indication that the page file size is to be computed based // on RAM size. // pgVar->fRamBasedPagefile = (pgVar->nMinFileSize ? FALSE : TRUE); pgVar->nMaxFileSize = pgVar->nMaxFileSizePrev = PFSettings.GetLong(sMaxProp); pgVar->objPath = CloneString(PFSettings.GetString(sPathProp)); pgVar->pszPageFile = CloneString(bName); // // Fetch the Win32_PageFileUsage.AllocatedBaseSize property. // TCHAR szTemp[sizeof(gszPFNameFormat) / sizeof(TCHAR)]; wsprintf(szTemp, gszPFNameFormat, pgVar->name); IWbemClassObject * pcoInst; hr = QueryInstanceProperties(gszPageFileUsage, gszAllocatedBaseSize, gszName, szTemp, m_WbemServices, &pcoInst); PFUsage = pcoInst; if (SUCCEEDED(hr)) { pgVar->nAllocatedFileSize = PFUsage.GetLong(sAllocSize); } else { pgVar->nAllocatedFileSize = 0; } // found the one and only-- cleanup early and bail out. pInst->Release(); break; // while() } //endif match the drive letter. // in case that BREAK didn't jump over the endwhile() pInst->Release(); } // endwhile envEnum // NOTE: The BREAK jumps here. Duplicate any cleanup from before the // endwhile. } //endif CreateInstanceEnum() SUCCEEDED one way or another :) } //-------------------------------------------------------------- // this version calculates based on pre-existing wbem data. bool VirtualMemDlg::ComputeAllocated(unsigned long *value) { bool retval = false; IWbemClassObject *pgInst = NULL; DWORD uReturned = 0; bstr_t sAllocSize(gszAllocatedBaseSize); variant_t pVal, pVal1; // do we have one? if(EnsureEnumerator(gszPageFileUsage)) { m_pgEnumUsage->Reset(); // get the first and only instance. while(SUCCEEDED(m_pgEnumUsage->Next(-1, 1, &pgInst, &uReturned)) && (uReturned != 0)) { // get the variables. if((pgInst->Get(sAllocSize, 0L, &pVal1, NULL, NULL) == S_OK) && (pVal1.vt == VT_I4)) { *value += pVal1.ulVal; } //endif get the variable. pgInst->Release(); } // endwhile envEnum retval = true; } //endif CreateInstanceEnum() SUCCEEDED (one way or another :) return retval; } //-------------------------------------------------------------- // this version calculates based on the listbox. unsigned long VirtualMemDlg::RecomputeAllocated(void) { unsigned long nTotalAllocated = 0; PAGING_FILE *pgVal = NULL; HWND lbHWND = GetDlgItem(m_hDlg, IDD_VM_VOLUMES); int last = ListBox_GetCount(lbHWND); // zero-based loop. for(int x = 0; x < last; x++) { pgVal = (PAGING_FILE *)ListBox_GetItemData(lbHWND, x); if ( pgVal->fRamBasedPagefile || pgVal->nMinFileSize ) { // // Add in only pagefiles in use. // nTotalAllocated += pgVal->nAllocatedFileSize; } } return nTotalAllocated; } //-------------------------------------------------------------- void VirtualMemDlg::GetRecoveryFlags(bool &bWrite, bool &bLog, bool &bSend) { if((bool)m_recovery) { bWrite = m_recovery.GetBool("WriteDebugInfo"); bLog = m_recovery.GetBool("WriteToSystemLog"); bSend = m_recovery.GetBool("SendAdminAlert"); } else { bWrite = bLog = bSend = false; } } //-------------------------------------------------------------- /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!! IMPORTANT !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/ /* THIS FUNCTION IS A REPLICA OF THE FUNCTION in \\depot\shell\cpls\system\util.c */ /* OFCOURSE WITH A BIT OF MODIFICATION FOR USING WMI */ /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/ DWORD VirtualMemDlg::GetMaxPagefileSizeInMB( PAGING_FILE *iDrive // drive to check on ) { #if defined(_AMD64_) return MAX_SWAPSIZE_AMD64; #elif defined(_X86_) if (m_PAEEnabled && !(_wcsnicmp(iDrive->filesystem, L"NTFS",4))) { return MAX_SWAPSIZE_X86_PAE; } else { return MAX_SWAPSIZE_X86; } #elif defined(_IA64_) return MAX_SWAPSIZE_IA64; #else return 0; #endif } //-------------------------------------------------------------- /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!! IMPORTANT !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/ /* THIS FUNCTION IS A REPLICA OF THE FUNCTION in \\depot\shell\cpls\system\virtual.c */ /* OFCOURSE WITH A BIT OF MODIFICATION FOR USING WMI */ /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/ bool VirtualMemDlg::SetNewSize(HWND hDlg) { ULONG nSwapSize; ULONG nSwapSizeMax; BOOL fTranslated; INT iSel; PAGING_FILE *iDrive; TCHAR szTemp[MAX_PATH] = {0}; ULONG nBootPF = 0; bool fRamBasedPagefile = FALSE; // get the item's data. if ((iSel = (INT)SendDlgItemMessage( hDlg, IDD_VM_VOLUMES, LB_GETCURSEL,0, 0)) != LB_ERR) { if ((LRESULT)(iDrive = (PAGING_FILE *)SendDlgItemMessage(hDlg, IDD_VM_VOLUMES, LB_GETITEMDATA, iSel, 0)) == LB_ERR) { return FALSE; //failure ! } } // Initialize variables for crashdump. // nBootPF == crash dump size required. // bool bWrite = false, bLog = false, bSend = false; GetRecoveryFlags(bWrite, bLog, bSend); if (bWrite) { nBootPF = -1; } else if (bLog || bSend) { nBootPF = MIN_SWAPSIZE; } if (nBootPF == -1) { nBootPF = ((DWORD)m_memory.GetLong("TotalPhysicalMemory") / 1024); } if ( IsDlgButtonChecked( hDlg, IDD_VM_NOPAGING_RADIO ) == BST_CHECKED ) { // // No paging file on this drive. // nSwapSize = 0; nSwapSizeMax = 0; fTranslated = TRUE; } else { if ( IsDlgButtonChecked( hDlg, IDD_VM_RAMBASED_RADIO ) == BST_CHECKED ) { MEMORYSTATUSEX MemoryInfo; // // User requested a RAM based page file. We will compute a page // file size based on the RAM currently available so that we can // benefit of all the verifications done below related to disk // space available etc. // // The final page file specification written to the registry will // contain zero sizes though because this is the way we signal // that we want a RAM based page file. // ZeroMemory (&MemoryInfo, sizeof MemoryInfo); MemoryInfo.dwLength = sizeof MemoryInfo; if (GlobalMemoryStatusEx (&MemoryInfo)) { fRamBasedPagefile = TRUE; // // We do not lose info because we first divide the RAM size to // 1Mb and only after that we convert to a DWORD. // nSwapSize = (DWORD)(MemoryInfo.ullTotalPhys / 0x100000) + 12; nSwapSizeMax = nSwapSize; fTranslated = TRUE; } else { nSwapSize = 0; nSwapSizeMax = 0; fTranslated = TRUE; } } else { // // User requested a custom size page file. // nSwapSize = (ULONG)GetDlgItemInt(hDlg, IDD_VM_SF_SIZE, &fTranslated, FALSE); // was it an integer? if (!fTranslated) { // need a valid integer for initial size. MsgBoxParam(hDlg, SYSTEM+37, IDS_TITLE, MB_ICONEXCLAMATION); SetFocus(GetDlgItem(hDlg, IDD_VM_SF_SIZE)); return FALSE; } // was it in range > 2MB if ((nSwapSize < MIN_SWAPSIZE && nSwapSize != 0)) { // initial value out of range. MsgBoxParam(hDlg, SYSTEM+13, IDS_TITLE, MB_ICONEXCLAMATION); SetFocus(GetDlgItem(hDlg, IDD_VM_SF_SIZE)); return FALSE; } // deleting swapfile? if (nSwapSize == 0) { nSwapSizeMax = 0; } else // adding/changing. { nSwapSizeMax = (ULONG)GetDlgItemInt(hDlg, IDD_VM_SF_SIZEMAX, &fTranslated, FALSE); // was it an integer? if (!fTranslated) { // need an integer. MsgBoxParam(hDlg, SYSTEM+38, IDS_TITLE, MB_ICONEXCLAMATION); SetFocus(GetDlgItem(hDlg, IDD_VM_SF_SIZEMAX)); return FALSE; } // in range? if (nSwapSizeMax < nSwapSize || nSwapSizeMax > GetMaxPagefileSizeInMB(iDrive)) { TCHAR strTemp[16]; MsgBoxParam(hDlg, SYSTEM+14, IDS_TITLE, MB_ICONEXCLAMATION, _ultow(GetMaxPagefileSizeInMB(iDrive), strTemp, 10)); SetFocus(GetDlgItem(hDlg, IDD_VM_SF_SIZEMAX)); return FALSE; } } } } // if we have integers and the listbox has a good focus... if (fTranslated && iSel != LB_ERR) { // will it fit? if (nSwapSizeMax > iDrive->totalSize) { // nope. MsgBoxParam(hDlg, SYSTEM+16, IDS_TITLE, MB_ICONEXCLAMATION, iDrive->name); SetFocus(GetDlgItem(hDlg, IDD_VM_SF_SIZEMAX)); return FALSE; } //Actual FreeSpace is freespace in the disk + page file size. ULONG freeSpace = iDrive->freeSpace + iDrive->nAllocatedFileSize; // room to spare?? if (nSwapSize > freeSpace) { // nope. MsgBoxParam(hDlg, SYSTEM+15, IDS_TITLE, MB_ICONEXCLAMATION); SetFocus(GetDlgItem(hDlg, IDD_VM_SF_SIZE)); return FALSE; } // don't hog the last 5MB. if (nSwapSize != 0 && freeSpace - nSwapSize < MIN_FREESPACE) { MsgBoxParam(hDlg, SYSTEM+26, IDS_TITLE, MB_ICONEXCLAMATION, MIN_FREESPACE_STR); SetFocus(GetDlgItem(hDlg, IDD_VM_SF_SIZE)); return FALSE; } // max too big, should I just use all the space anyway. if (nSwapSizeMax > freeSpace) { if (MsgBoxParam(hDlg, SYSTEM+20, IDS_TITLE, MB_ICONINFORMATION | MB_OKCANCEL, iDrive->name) == IDCANCEL) { SetFocus(GetDlgItem(hDlg, IDD_VM_SF_SIZEMAX)); return FALSE; } } // enough room for core dumps?? if (iDrive->bootDrive && nSwapSize < nBootPF) { // The new boot drive page file size is less than we need for // crash control. Inform the user. if (MsgBoxParam(hDlg, SYSTEM+29, IDS_TITLE, MB_ICONEXCLAMATION |MB_YESNO, iDrive->name, _itow(nBootPF, szTemp, 10)) != IDYES) { SetFocus(GetDlgItem(hDlg, IDD_VM_SF_SIZE)); return FALSE; } } iDrive->nMinFileSize = nSwapSize; iDrive->nMaxFileSize = nSwapSizeMax; iDrive->fRamBasedPagefile = fRamBasedPagefile; BuildLBLine(szTemp, iDrive); SendDlgItemMessage(hDlg, IDD_VM_VOLUMES, LB_DELETESTRING, iSel, 0); SendDlgItemMessage(hDlg, IDD_VM_VOLUMES, LB_INSERTSTRING, iSel, (LPARAM)szTemp); SendDlgItemMessage(hDlg, IDD_VM_VOLUMES, LB_SETITEMDATA, iSel, (LPARAM)iDrive); SendDlgItemMessage(hDlg, IDD_VM_VOLUMES, LB_SETCURSEL, iSel, 0L); m_cxLBExtent = SetLBWidthEx(GetDlgItem(hDlg, IDD_VM_VOLUMES), szTemp, m_cxLBExtent, m_cxExtra); if (!iDrive->fRamBasedPagefile && iDrive->nMinFileSize) { SetDlgItemInt(hDlg, IDD_VM_SF_SIZE, iDrive->nMinFileSize, FALSE); SetDlgItemInt(hDlg, IDD_VM_SF_SIZEMAX, iDrive->nMaxFileSize, FALSE); } else { SetDlgItemText(hDlg, IDD_VM_SF_SIZE, _T("")); SetDlgItemText(hDlg, IDD_VM_SF_SIZEMAX, _T("")); } SetDlgItemMB(hDlg, IDD_VM_ALLOCD, RecomputeAllocated()); SetFocus(GetDlgItem(hDlg, IDD_VM_VOLUMES)); } return true; } //-------------------------------------------------------------- int VirtualMemDlg::UpdateWBEM(void) { int iRet = RET_NO_CHANGE; bool bRebootRequired = false; CWbemClassObject inst; bstr_t sNameProp(gszName); bstr_t sMaxProp(gszMaximumSize); bstr_t sInitProp(gszInitialSize); HRESULT hr = 0; PAGING_FILE *pgVal = NULL; HWND lbHWND = GetDlgItem(m_hDlg, IDD_VM_VOLUMES); int last = ListBox_GetCount(lbHWND); BOOL fNewPFInstance; #ifdef NTONLY BOOL fCreatePFPrivEnabled = FALSE; #endif // NTONLY // MAINTAINERS NOTE: // the iRet value gets *overwritten* each time through the loop // it looks to me like the flags should be OR'd together instead // but it's way too scary to change it at this late date... for(int x = 0; x < last; x++) { // get it's state structure. pgVal = (PAGING_FILE *)ListBox_GetItemData(lbHWND, x); // // Should assert objPath != NULL && *pgVal->objPath != 0. // Do NOT assume when objPath is non-NULL that objPath // is a non-empty string. // fNewPFInstance = (pgVal->objPath == NULL || !*pgVal->objPath); if (!fNewPFInstance) { // // Instance doesn't yet exist, of course, if no object path. // inst = m_WbemServices.GetObject(pgVal->objPath); } // // This condition evaluates pagefile previous/current state. // Evaluate to true if: // 1. (MINprev != MINcur or MAXprev != MAXcur) - Simple case // where the values changed. // 2. (RAMBasedPagefile == TRUE) - Important special case from // custom to RAM-based AND all min/max prev/cur values // coincidentally equal. // 3. (MINcur == 0) - Another special case from RAM-based to no // pagefile. In this case, min/max prev/cur values are all // zero and the RAM-Based pagefile flag is FALSE. // if ((pgVal->nMinFileSizePrev != pgVal->nMinFileSize || pgVal->nMaxFileSizePrev != pgVal->nMaxFileSize) || pgVal->fRamBasedPagefile || pgVal->nMinFileSize == 0) { // reboot required if a page file has *shrunk* in size if (pgVal->nMaxFileSizePrev > pgVal->nMaxFileSize) bRebootRequired = true; if (pgVal->nMinFileSize != 0 || pgVal->fRamBasedPagefile) { // // Custom or RAM-based. Note, the RAM-based pagefile flag // check seems redundant but it is important for error cases // in the SetSize code. // // Create the instance if it does not exist. // BOOL fCreate = FALSE, fModified = FALSE; if (inst.IsNull()) { inst = m_WbemServices.CreateInstance( gszPageFileSettings); } // // Now write out changes. Sigh, too close to RC1 to rewrite // this existing code. // if(!inst.IsNull()) { if (fNewPFInstance) // Write name at creation time only. { BOOL fRet = TRUE; #ifdef NTONLY if (!fCreatePFPrivEnabled) { // // Pagefile creation requires pagefile creation // privilege. // // Aargh! No return code to check here... // m_WbemServices.SetPriv(SE_CREATE_PAGEFILE_NAME); fCreatePFPrivEnabled = TRUE; } #endif // NTONLY if (fRet) { TCHAR temp[30] = {0}; wsprintf(temp, _T("%s\\pagefile.sys"), pgVal->name); hr = inst.Put(sNameProp, _bstr_t(temp)); if (SUCCEEDED(hr)) { fModified = TRUE; } } } // // Write zeros for min/max values when the page file // size is to be computed based on RAM size. // if (pgVal->nMinFileSizePrev != pgVal->nMinFileSize) { hr = inst.Put(sInitProp, (pgVal->fRamBasedPagefile ? 0 : (long)pgVal->nMinFileSize)); if (SUCCEEDED(hr)) { fModified = TRUE; } } if (pgVal->nMaxFileSizePrev != pgVal->nMaxFileSize) { hr = inst.Put(sMaxProp, (pgVal->fRamBasedPagefile ? 0 : (long)pgVal->nMaxFileSize)); if (SUCCEEDED(hr)) { fModified = TRUE; } } if (fModified) { hr = m_WbemServices.PutInstance( inst, WBEM_FLAG_CREATE_OR_UPDATE, EOAC_STATIC_CLOAKING); } if(FAILED(hr)) { CHString errorDescription; CHString errorMessage; TCHAR formatString[1024]; ::LoadString(HINST_THISDLL,IDS_ERR_PAGECREATE, formatString, 1024); TCHAR errorHeading[20]; ::LoadString(HINST_THISDLL,IDS_ERR_HEADING, errorHeading, 20); ErrorLookup(hr, errorDescription); errorMessage.Format(formatString, errorDescription); ::MessageBox(m_hDlg,errorMessage,errorHeading,MB_OK); } else { if (fModified) { iRet = RET_VIRTUAL_CHANGE; } } } } else { // // No paging file. Delete the instance. // if (!inst.IsNull() && !fNewPFInstance && pgVal->objPath != NULL) // 3rd condition insures // extra safety. { hr = m_WbemServices.DeleteInstance(pgVal->objPath); // I'm taking it on faith that we can only get here // if we *deleted* a page file... if (hr != WBEM_E_NOT_FOUND) bRebootRequired = true; if (SUCCEEDED(hr)) { iRet = RET_VIRTUAL_CHANGE; } } } } } // endfor #ifdef NTONLY if (fCreatePFPrivEnabled) { m_WbemServices.ClearPriv(); } #endif // NTONLY if (!bRebootRequired) iRet |= RET_CHANGE_NO_REBOOT; return iRet; } //-------------------------------------------------------------- int VirtualMemDlg::PromptForReboot(HWND hDlg) { int iReboot = RET_NO_CHANGE; /* int i; int iThisDrv; WCHAR us; LARGE_INTEGER liMin, liMax; NTSTATUS status; WCHAR wszPath[MAX_PATH*2]; TCHAR szDrive[3] = {0}; PRIVDAT pdOld; GetPageFilePrivilege( &pdOld ); for (i = 0; i < MAX_DRIVES; i++) { // Did something change? if (apf[i].nMinFileSize != apf[i].nMinFileSizePrev || apf[i].nMaxFileSize != apf[i].nMaxFileSizePrev || apf[i].fCreateFile ) { // If we are strictly creating a *new* page file, then // we can do it on the fly, otherwise we have to reboot. // assume we will have to reboot iThisDrv = RET_VIRTUAL_CHANGE; // IF we are not deleting a page file // - AND - // The Page file does not exist // - OR - // (This is a New page file AND We are allowed to erase the // old, unused pagefile that exists there now) if (apf[i].nMinFileSize != 0 && ((GetFileAttributes(SZPageFileName(i)) == 0xFFFFFFFF && GetLastError() == ERROR_FILE_NOT_FOUND) || (apf[i].nMinFileSizePrev == 0 && MsgBoxParam(hDlg, SYSTEM+25, IDS_TITLE, MB_ICONQUESTION | MB_YESNO, SZPageFileName(i)) == IDYES)) ) { DWORD cch; // Create the page file on the fly so JVert and MGlass will // stop bugging me! HourGlass(TRUE); // convert path drive letter to an NT device path wsprintf(szDrive, TEXT("%c:"), (TCHAR)(i + (int)TEXT('A'))); cch = QueryDosDevice( szDrive, wszPath, sizeof(wszPath) / sizeof(TCHAR)); if (cch != 0) { // Concat the filename only (skip 'd:') to the nt device // path, and convert it to a UNICODE_STRING lstrcat( wszPath, SZPageFileName(i) + 2 ); RtlInitUnicodeString( &us, wszPath ); liMin.QuadPart = (LONGLONG)(apf[i].nMinFileSize * ONE_MEG); liMax.QuadPart = (LONGLONG)(apf[i].nMaxFileSize * ONE_MEG); status = NtCreatePagingFile ( &us, &liMin, &liMax, 0L ); if (NT_SUCCESS(status)) { // made it on the fly, no need to reboot for this drive! iThisDrv = RET_CHANGE_NO_REBOOT; } } HourGlass(FALSE); } iReboot |= iThisDrv; } } ResetOldPrivilege( &pdOld ); // If Nothing changed, then change our IDOK to IDCANCEL so System.cpl will // know not to reboot. */ return iReboot; } /************************************************************************ * * * Function: QueryInstanceProperties * * * * Description: Returns requested object properties associated with * * the instance matching the key property value/name. * * * * Arguments: pszClass -- Object class. * * pszRequestedProperties -- Space-separated property * * names or *. * * pszKeyPropertyName -- Specific instance key * * property name. * * pszKeyPropertyValue -- Key property value. * * Services -- Wbem services. * * ppcoInstEnum -- Returned instance. * * * * Returns: HRESULT * * * ***********************************************************************/ #define QUERY_INSTANCEPROPERTY _T("SELECT %s FROM %s WHERE %s=\"%s\"") HRESULT QueryInstanceProperties( const TCHAR * pszClass, const TCHAR * pszRequestedProperties, const TCHAR * pszKeyPropertyName, const TCHAR * pszKeyPropertyValue, CWbemServices &Services, IWbemClassObject ** ppcoInst) { TCHAR * pszQuery; BSTR bstrQuery; HRESULT hr; *ppcoInst = NULL; // Dislike multiple allocations of bstr_t. // pszQuery = new TCHAR[(sizeof(QUERY_INSTANCEPROPERTY) / sizeof(TCHAR)) + lstrlen(pszClass) + lstrlen(pszRequestedProperties) + lstrlen(pszKeyPropertyName) + // No +1 ala lstrlen(pszKeyPropertyValue)]; // sizeof. if (pszQuery == NULL) { return ERROR_NOT_ENOUGH_MEMORY; } wsprintf(pszQuery, QUERY_INSTANCEPROPERTY, pszRequestedProperties, pszClass, pszKeyPropertyName, pszKeyPropertyValue); // Sigh, must create a bstr. // bstrQuery = SysAllocString(pszQuery); delete pszQuery; if (bstrQuery == NULL) { return ERROR_NOT_ENOUGH_MEMORY; } IEnumWbemClassObject * pecoInstEnum; hr = Services.ExecQuery(bstrQuery, 0, &pecoInstEnum); SysFreeString(bstrQuery); if (SUCCEEDED(hr)) { DWORD uReturned = 0; hr = pecoInstEnum->Next(-1, 1, ppcoInst, &uReturned); pecoInstEnum->Release(); } return hr; }