//=====================================================================
//TITLE:
// 获取WinCE进程的内存信息
//AUTHOR:
// norains
//DATE:
// Wednesday 3- February-2010
//Environment:
// WINDOWS CE 5.0
//=====================================================================
获取WinCE下的进程的内存信息并不困难,完全可以借助微软自带的Remote工具,比如:Remote Process Viewer,Remote Heap Walker等等。如果是日常的调试,不做别的特殊用途,那么这些完全够用了。但如果你不满足于此,而是非常渴望知道如何在自己的程序也能获取系统的进程相关信息,那么你可以继续往下阅读。:)
首先我们需要做的是,先获取当前活动的进程。因为我们无法保证每次的进程数目都是相同的,所以为了简便,我们直接将STL的vector作为缓存进行数据的保存。
故,我们的函数会如下:
- BOOL GetAllProcInfo(std::vector<PROCESSENTRY32> &vtProcInfo)
- {
- vtProcInfo.clear();
- return EnumProcInfo(EnumAllProcessProc,&vtProcInfo);
- }
该函数并没有做任何实质的事情,只是将保存的缓存清空,然后再调用EnumProcInfo函数。
EnumProcInfo函数用来枚举系统中的进程信息,其实现如下:
- BOOL EnumProcInfo(PROC_EMUN_PROC pProcFunc,VOID *pParam)
- {
- BOOL bRes = FALSE;
- HANDLE hSnapshot = INVALID_HANDLE_VALUE;
- static const DWORD TH32CS_SNAPNOHEAPS = 0x40000000;
- __try
- {
- if(pProcFunc == NULL)
- {
- __leave;
- }
- hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS | TH32CS_SNAPNOHEAPS, 0);
- if (hSnapshot == INVALID_HANDLE_VALUE)
- {
- __leave;
- }
- PROCESSENTRY32 processEntry;
- processEntry.dwSize = sizeof(PROCESSENTRY32);
- if(Process32First(hSnapshot, &processEntry) == FALSE)
- {
- __leave;
- }
- if((*pProcFunc)(processEntry,pParam) == FALSE)
- {
- bRes = TRUE;
- __leave;
- }
- while (Process32Next(hSnapshot, &processEntry) != FALSE)
- {
- if((*pProcFunc)(processEntry,pParam) == FALSE)
- {
- break;
- }
- }
- bRes = TRUE;
- }
- __finally
- {
- if (hSnapshot != INVALID_HANDLE_VALUE)
- {
- CloseToolhelp32Snapshot(hSnapshot);
- hSnapshot = NULL;
- }
- }
- return bRes;
- }
看起来很复杂,其实原理很简单。
首先我们看一下其形参,pProcFunc保存的是回调函数地址,当搜索到系统的进程时,会调用该地址指向的函数,然后再将pParam形参传递过去。
了解形参之后,我们再往下看。
CreateToolhelp32Snapshot用来创建一个搜索快照的句柄,我们根据此句柄来获取系统当前的进程信息。和微软的其它枚举函数类似,第一次查找调用的是XXXFirst,接下来就是就是XXXNext。
这样,通过GetAllProcInfo就能获取系统当前的进程信息。
获得了当前进程信息,我们可以干的事情就多了。那么,我们接下来先做点什么呢?我们就先获取一下HeapList吧。
为了方便,我们也定义了一个函数,用来获取HeapList:
- BOOL GetHeapList(DWORD dwProcID,std::vector<HEAPLIST32> &vtHeapList)
- {
- BOOL bRes = FALSE;
- HANDLE hSnapShot = INVALID_HANDLE_VALUE;
- __try
- {
- vtHeapList.clear();
- hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPHEAPLIST, dwProcID);
- if(hSnapShot == INVALID_HANDLE_VALUE)
- {
- __leave;
- }
- HEAPLIST32 heapList;
- heapList.dwSize = sizeof(HEAPLIST32);
- //Begin to find the heap list
- if(Heap32ListFirst(hSnapShot,&heapList) == FALSE)
- {
- __leave;
- }
- vtHeapList.push_back(heapList);
- while(Heap32ListNext(hSnapShot, &heapList) != FALSE)
- {
- vtHeapList.push_back(heapList);
- }
- bRes = TRUE;
- }
- __finally
- {
- if(hSnapShot != INVALID_HANDLE_VALUE)
- {
- CloseToolhelp32Snapshot(hSnapShot);
- }
- }
- return bRes;
- }
结构和思维其实和列举进程信息的相同,在此不再赘述。不过这里唯一需要提一下的是该函数的形参:dwProcID。
可能大家无法从GetAllProcInfo看出和dwProcID有什么联系,其实GetAllProcInfo函数返回的数值中,有个th32ProcessID就是和此相关。
如果用代码标示,我们可以这样书写:
- std::vector<PROCESSENTRY32> vtProcInfo;
- GetAllProcInfo(vtProcInfo);
- std::vector<HEAPLIST32> vtHeapList;
- GetHeapList(vtProcInfo[0].th32ProcessID,vtHeapList);
既然能获得了HeapList,我们就再接再厉,来获取HeapEntry信息:
- BOOLGetHeapEntry(DWORD dwProcID,const HEAPLIST32 &heapList,std::vector<HEAPENTRY32> &vtHeapEntry)
- {
- BOOL bRes = FALSE;
- HANDLE hSnapShot = INVALID_HANDLE_VALUE;
- __try
- {
- vtHeapEntry.clear();
- hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPHEAPLIST, dwProcID);
- if(hSnapShot == INVALID_HANDLE_VALUE)
- {
- __leave;
- }
- HEAPENTRY32 heapEntry = {0};
- heapEntry.dwSize = sizeof(HEAPENTRY32);
- //Begin to find the heap entry
- if(Heap32First(hSnapShot, &heapEntry, heapList.th32ProcessID, heapList.th32HeapID) == FALSE)
- {
- __leave;
- }
- vtHeapEntry.push_back(heapEntry);
- while(Heap32Next(hSnapShot, &heapEntry) != FALSE)
- {
- vtHeapEntry.push_back(heapEntry);
- }
- bRes = TRUE;
- }
- __finally
- {
- if(hSnapShot != INVALID_HANDLE_VALUE)
- {
- CloseToolhelp32Snapshot(hSnapShot);
- }
- }
- return bRes;
- }
获取HeapEntry信息后,我们还可以做一件事情,就是统计Heap的大小。我们也可以将其作为一个函数:
- DWORD GetHeapSize(const std::vector<HEAPENTRY32> &vtHeapEntry)
- {
- DWORD dwSize = 0;
- for(std::vector<HEAPENTRY32>::const_iterator iter = vtHeapEntry.begin(); iter != vtHeapEntry.end(); ++ iter)
- {
- dwSize += iter->dwBlockSize;
- }
- return dwSize;
- }
基本上,关于Heap的信息,我们先暂时讨论到这里。接下来,我们来根据如上的函数,用来统计空闲内存,提交内存和保留内存的大小。
为了方便函数的书写,我们先定义一个结构体,分别用来存储这三种类型内存:
- struct RegionSize
- {
- DWORD dwFree;
- DWORD dwReserve;
- DWORD dwCommit;
- };
然后我们的函数如下形式:
- BOOL GetRegionSizeFromMemoryBase(DWORD dwAddressBase,RegionSize &RegionSize)
- {
- DWORD dwStartAddress = dwAddressBase;
- DWORD dwEndAddress = dwStartAddress + 0x40000000;
- DWORD dwAddress = dwStartAddress;
- if(dwAddress >= dwEndAddress)
- {
- return FALSE;
- }
- memset(&RegionSize,0,sizeof(RegionSize));
- while (dwAddress < dwEndAddress)
- {
- MEMORY_BASIC_INFORMATION memoryInfo;
- SIZE_T rv = ::VirtualQuery((LPVOID)dwAddress, &memoryInfo, sizeof(memoryInfo));
- if (rv != 0)
- {
- if (memoryInfo.State == MEM_COMMIT)
- {
- RegionSize.dwCommit += memoryInfo.RegionSize;
- }
- if (memoryInfo.State == MEM_RESERVE)
- {
- RegionSize.dwReserve += memoryInfo.RegionSize;
- }
- if (memoryInfo.State == MEM_FREE)
- {
- RegionSize.dwFree += memoryInfo.RegionSize;
- }
- dwAddress += memoryInfo.RegionSize;
- }
- else
- {
- break;
- }
- }
- return TRUE;
- }
GetRegionSizeFromMemoryBase函数的dwAddressBase形参数值,我们可以使用从GetProcessEntry获得信息的th32MemoryBase字段。
GetRegionSizeFromMemoryBase函数的思维也非常简单,无非就是根据State的数值类型,然后累加不同的数值而已。
有了如上的函数,我们就能简单方便地获取WinCE系统进程的相关内存信息了。