#c #winapi #virtualquery
#c #winapi #virtualquery
Вопрос:
Я пытаюсь отобразить информацию о виртуальной памяти каждого процесса в системе:
#include <windows.h>
#include <conio.h>
#include <tlhelp32.h>
#include <iostream>
using namespace std;
void main() {
HANDLE CONST hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
PROCESSENTRY32 proc;
TCHAR Buffer[1024];
TCHAR Buffer2[1024];
DWORD temp;
HANDLE CONST hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (INVALID_HANDLE_VALUE == hSnap)
{
return;
}
proc.dwSize = sizeof(PROCESSENTRY32);
Process32First(hSnap, amp;proc);
do {
MEMORY_BASIC_INFORMATION mbi = {};
wsprintf(Buffer, L" %s %d n ", proc.szExeFile, proc.th32ProcessID);
WriteConsole(hStdOut, Buffer, lstrlen(Buffer), amp;temp, NULL);
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, proc.th32ProcessID);
VirtualQueryEx(hProcess, 0, amp;mbi, sizeof(MEMORY_BASIC_INFORMATION));
printf("Alloc = %p, base = %p , size = %d, type = %d, state = %pn", mbi.AllocationBase, mbi.BaseAddress, mbi.RegionSize, mbi.Type,mbi.State);
} while (Process32Next(hSnap, amp;proc));
CloseHandle(hSnap);
}
Вывод выглядит следующим образом:
Я получаю базовый адрес и выделяю значение, равное 0000000, и набираю 0, как мне получить нормальные значения? Я имею в виду, что размер и состояние, похоже, в порядке, но остальное «0000000», я не знаю, в чем проблема
Комментарии:
1. Попробуйте проверить возвращаемое значение каждой функции, которая предшествует ей, и сравнить их с документацией. Скорее всего, проблема не в том, где вы думаете.
2. Ваша строка формата printf не соответствует типам ваших параметров. Предпочитаю
std::cout
вместо этого.3. Обратите внимание на предупреждения компилятора, при компиляции вашего кода я получаю три разных предупреждения для этого вызова printf. Все это связано с неправильными типами для строки формата. Но, как я уже сказал, самый простой способ — использовать
std::cout
.4. cout не работает
5. @DussyPestroyer Пожалуйста, уточните, не удается ли скомпилировать? Если да, то какую ошибку она генерирует? Или он просто ничего не пишет? (кроме того, отмечайте людей в своих ответах. Таким образом, тот, с кем вы разговариваете, получает уведомление)
Ответ №1:
В настоящее время вы извлекаете информацию только о первом блоке памяти для каждого процесса. Процесс обычно будет иметь много блоков памяти, а не только один (от тысяч до десятков тысяч было бы довольно типично).
Вот некоторый код, который извлекает и распечатывает статус каждого блока данных в указанном процессе.
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <iostream>
#include <string>
unsigned long show_module(MEMORY_BASIC_INFORMATION info) {
unsigned long usage = 0;
std::cout << info.BaseAddress << "(" << info.RegionSize / 1024 << ")t";
switch (info.State) {
case MEM_COMMIT:
std::cout << "Committed";
break;
case MEM_RESERVE:
std::cout << "Reserved";
break;
case MEM_FREE:
std::cout << "Free";
break;
}
std::cout << "t";
switch (info.Type) {
case MEM_IMAGE:
std::cout << "Code Module";
break;
case MEM_MAPPED:
std::cout << "Mapped ";
break;
case MEM_PRIVATE:
std::cout << "Private ";
}
std::cout << "t";
int guard = 0, nocache = 0;
if ( info.AllocationProtect amp; PAGE_NOCACHE)
nocache = 1;
if ( info.AllocationProtect amp; PAGE_GUARD )
guard = 1;
info.AllocationProtect amp;= ~(PAGE_GUARD | PAGE_NOCACHE);
if ((info.State == MEM_COMMIT) amp;amp; (info.AllocationProtect == PAGE_READWRITE || info.AllocationProtect == PAGE_READONLY))
usage = info.RegionSize;
switch (info.AllocationProtect) {
case PAGE_READONLY:
std::cout << "Read Only";
break;
case PAGE_READWRITE:
std::cout << "Read/Write";
break;
case PAGE_WRITECOPY:
std::cout << "Copy on Write";
break;
case PAGE_EXECUTE:
std::cout << "Execute only";
break;
case PAGE_EXECUTE_READ:
std::cout << "Execute/Read";
break;
case PAGE_EXECUTE_READWRITE:
std::cout << "Execute/Read/Write";
break;
case PAGE_EXECUTE_WRITECOPY:
std::cout << "COW Executable";
break;
}
if (guard)
std::cout << "tguard page";
if (nocache)
std::cout << "tnon-cacheable";
std::cout << "n";
return usage;
}
unsigned long show_modules(HANDLE process) {
unsigned long usage = 0;
unsigned char* p = NULL;
MEMORY_BASIC_INFORMATION info;
for ( p = NULL;
VirtualQueryEx(process, p, amp;info, sizeof(info)) == sizeof(info);
p = info.RegionSize )
{
usage = show_module(info);
}
return usage;
}
int main(int argc, char **argv) {
int pid;
if (argc != 2) {
std::cerr << "Usage: " << argv[0] << " <process ID>n";
return EXIT_FAILURE;
}
pid = std::stoi(argv[1]);
HANDLE process = OpenProcess(
PROCESS_VM_READ | PROCESS_QUERY_INFORMATION,
false,
pid);
unsigned long mem_used = show_modules(process);
std::cout << "Total memory used: " << mem_used / 10224 << "KBn";
}
Чтобы дать представление о результате, вот первые несколько строк вывода из процесса в моей системе:
0000000000000000(64) Free
0000000000010000(64) Committed Mapped Read/Write
0000000000020000(4) Committed Mapped Read Only
0000000000021000(60) Free
0000000000030000(4) Committed Private
0000000000031000(60) Reserved Private
Но имейте в виду: вы, вероятно, получите намного больше выходных данных, чем для большинства типичных процессов. Этот конкретный процесс (Thunderbird) выдал в общей сложности 3686 строк вывода. Быстрый тест с Chrome (с использованием пары гигабайт памяти) выдает более 46 000 строк вывода (т. Е. Более 46 000 отдельных блоков памяти, отслеживаемых системой для него).
Если вы собираетесь что-то печатать для каждого процесса в системе, вы, вероятно, захотите немного обобщить данные (но, не зная, зачем вам это нужно, трудно догадаться, какого результата вы, вероятно, хотите).
Комментарии:
1. немного более правильное использование
p = (PBYTE)info.BaseAddress info.RegionSize;
, потомуRegionSize
что изBaseAddress
и когда-нибудь (редко) может бытьp != BaseAddress
. аreturn usage;
также опечатка