Издание четвертое windows ® для профессионалов создание эффективных Win32-приложений с учетом специфики 64-разрядной версии Windows


Г ЛАВА 13Архитектура памяти в WindowsТаблица 13-4



Pdf просмотр
страница35/68
Дата28.11.2016
Размер3.57 Mb.
Просмотров12465
Скачиваний0
1   ...   31   32   33   34   35   36   37   38   ...   68
Г ЛАВА 13
Архитектура памяти в Windows
Таблица 13-4.
продолжение
Базовый
Атрибут(ы)
адрес
Тип
Размер
Блоки защиты
Описание
80015000
Private
4096 1
80015000
Private
4096
RW
80016000
Private
4096 1
80016000
Private
4096
RW
80017000
Private
4096 1
80017000
Private
4096
RW
85620000
Free
9773056 85F72000
Private
151552 1
85F72000
Private
151552
R
85F97000
Private
327680 1
85F97000
Private
327680
R
85FE7000
Free
22052864 874EF000
Private
4194304 1
874EF000
Reserve
4194304 878EF000
Free
679219200
B00B0000
Private
880640 3
B00B0000
Private
233472
R
B00E9000
Private
20480
RW
B00EE000
Private
626688
R
B0187000
Free
177311744
BAAA0000
Private
315392 7
BAAA0000
Private
4096
R
BAAA1000
Private
4096
RW
BAAA2000
Private
241664
R
BAADD000
Private
4096
RW
BAADE000
Private
4096
R
BAADF000
Private
32768
RW
BAAE7000
Private
24576
R
BAAED000
Free
86978560
BFDE0000
Private
20480 1
BFDE0000
Private
20480
R
BFDE5000
Free
45056
BFDF0000
Private
65536 3
BFDF0000
Private
40960
R
BFDFA000
Private
4096
RW
BFDFB000
Private
20480
R
BFE00000
Free
131072
BFE20000
Private
16384 3
BFE20000
Private
8192
R
BFE22000
Private
4096
RW
BFE23000
Private
4096
R
BFE24000
Free
245760
BFE60000
Private
24576 3

336
Ч АС Т Ь I I I
УПРАВЛЕНИЕ ПАМЯТЬЮ
Таблица 13-4.
продолжение
Базовый
Атрибут(ы)
адрес
Тип
Размер
Блоки защиты
Описание
BFE60000
Private
8192
R
BFE62000
Private
4096
RW
BFE63000
Private
12288
R
BFE66000
Free
40960
BFE70000
Private
24576 3
BFE70000
Private
8192
R
BFE72000
Private
4096
RW
BFE73000
Private
12288
R
BFE76000
Free
40960
BFE80000
Private
65536 3
C:\WINDOWS\SYSTEM\ADVAPI32.DLL
BFE80000
Private
49152
R
BFE8C000
Private
4096
RW
BFE8D000
Private
12288
R
BFE90000
Private
573440 3
BFE90000
Private
425984
R
BFEF8000
Private
4096
RW
BFEF9000
Private
143360
R
BFF1C000
Free
16384
BFF20000
Private
155648 5
C:\WINDOWS\SYSTEM\GDI32.DLL
BFF20000
Private
126976
R
BFF3F000
Private
8192
RW
BFF41000
Private
4096
R
BFF42000
Private
4096
RW
BFF43000
Private
12288
R
BFF46000
Free
40960
BFF50000
Private
69632 3
C:\WINDOWS\SYSTEM\USER32.DLL
BFF50000
Private
53248
R
BFF5D000
Private
4096
RW
BFF5E000
Private
12288
R
BFF61000
Free
61440
BFF70000
Private
585728 Главное отличие двух карт адресного пространства в том, что под управлением 98 информации получаешь значительно меньше. Например, о регионах и блоках можно узнать лишь, свободные они, резервные или закрытые. Распознать тип физической памяти Mapped или Image нельзя Windows 98 не позволяет получить дополнительную информацию, по которой можно было бы судить, что с регионом связан проецируемый в память файл или образ исполняемого файла.

337
Г ЛАВА 13
Архитектура памяти в Наверное, Вы заметили, что размер большинства регионов кратен 64 Кб (это значение определяется гранулярностью выделения памяти. Если размеры блоков, составляющих регион, не дают в сумме величины, кратной 64 Кб, тов конце региона часто появляется резервный блок адресного пространства. Его размер выбирается системой так, чтобы довести общий объем региона до величины, кратной 64 Кб. Например,
регион, который начинается с адреса 0x00530000, включает в себя два блока четы рехкилобайтовый блок переданной памяти и резервный блок, занимающий 60 Кб адресного пространства.
Заметьте также, что на последней карте не встречаются атрибуты защиты, разрешающие исполнение или копирование при записи, поскольку Windows 98 не поддерживает их. Кроме того, она не поддерживает и флаги атрибутов защиты (PAGE_GUARD,
PAGE_WRITECOMBINE и PAGE_NOCACHE). Из за этого программе VMMap приходится использовать более сложный метод, чтобы определить, не выделен ли данный регион под стек потока.
И последнее. В Windows 98 (в отличие от Windows 2000) можно исследовать регион адресного пространства 0x80000000–0xBFFFFFFF. Это раздел, в котором находится адресное пространство, общее для всех 32 разрядных приложений. По карте видно, что в него загружены четыре системные DLL, и поэтому они доступны любому процессу.
Выравнивание данных
Здесь мы отвлечемся от виртуального адресного пространства процесса и обсудим такую важную тему, как выравнивание данных. Кстати, выравнивание данных — не столько часть архитектуры памяти в операционной системе, сколько часть архитектуры процессора.
Процессоры работают эффективнее, когда имеют дело с правильно выровненными данными. Например, значение типа WORD всегда должно начинаться счетного адреса, кратного 2, значение типа DWORD — счетного адреса, кратного 4, и т. д. При попытке считать невыровненные данные процессор сделает одно из двух либо возбудит исключение, либо считает их в несколько приемов.
Вот фрагмент кода, обращающийся к невыровненным данным SomeFunc(PVOID pvDataBuffer) {
// первый байт в буфере содержит значение типа BYTE
char c = * (PBYTE) pvDataBuffer;
// увеличиваем указатель для перехода за этот байт pvDataBuffer = (PVOID)((PBYTE) pvDataBuffer + 1);
// байты 2 5 в буфере содержат значение типа DWORD
DWORD dw = * (DWORD *) pvDataBuffer;
// на процессорах Alpha предыдущая строка приведет к исключению из за некорректного выравнивания данных
M
}
Очевидно, что быстродействие программы снизится, если процессору придется обращаться к памяти в несколько приемов. В лучшем случае система потратит на доступ к невыровненному значению в 2 раза больше времени, чем на доступ к выров

338
Ч АС Т Ь I I I
УПРАВЛЕНИЕ ПАМЯТЬЮ
ненному! Так что, если Вы хотите оптимизировать работу своей программы, позаботьтесь о правильном выравнивании данных.
Рассмотрим, как справляется с выравниванием данных процессор типа
x86. Такой процессор в регистре EFLAGS содержит специальный битовый флаг, называемый флагом AC (alignment check). По умолчанию, при первой подаче питания на процессор он сброшен. Когда этот флаг равен 0, процессор автоматически выполняет инструкции, необходимые для успешного доступа к невыровненным данным. Однако, если этот флаг установлен (равен 1), то при каждой попытке доступа к невыровненным данным процессор инициирует прерывание INT 17h. Версия Windows 2000 для процессоров типа
x86 и Windows 98 никогда не изменяют этот битовый флаг процессора. Поэтому в программе, работающей на процессоре типа
x86, исключения, связанные с попыткой доступа к невыровненным данным, никогда не возникают.
Теперь обратим внимание на процессор Alpha. Он не умеет оперировать с невы ровненными данными. Когда происходит попытка доступа к таким данным, этот процессор уведомляет операционную систему. Далее Windows 2000 решает, что делать генерировать соответствующее исключение или самой устранить возникшую проблему, выдав процессору дополнительные инструкции. По умолчанию Windows установленная на компьютере с процессором Alpha, сама исправляет все ошибки обращения к невыровненным данным. Однако Вы можете изменить ее поведение. При загрузке Windows 2000 проверяет раздел реестра В этом разделе может присутствовать параметр Если его нет (что чаще всего и бывает, Windows 2000 сама исправляет ошибки, связанные с доступом к невыровненным данным. Но, если он есть, система учитывает его значение. При его нулевом значении система действует также, как ив отсутствие этого параметра. Если же он равен 1, система не исправляет такие ошибки, а генерирует исключения. Никогда не модифицируйте этот параметр в реестре без особой необходимости, потому что иначе некоторые приложения будут вызывать исключения из за доступа к невыровненным данными аварийно завершаться.
Чтобы упростить изменение этого параметра реестра, с Microsoft Visual C++ для платформы Alpha поставляется утилита AXPAlign.exe. Она используется так, как показано ниже AXP alignment fault exception control
Usage: axpalign [option]
Options:
/enable to enable alignment fault exceptions.
/disable to disable alignment fault exceptions.
/show to display the current alignment exception setting.
Enable alignment fault В этом режиме любое обращение к невыровненным данным приведет к исключению.
Приложение может быть закрыто. В своем коде Вы можете найти источник ошибок, связанных с выравниванием данных, с помощью отладчика.
Действие этого параметра распространяется на все выполняемые процессы,
и использовать его следует с осторожностью, так как в старых приложениях могут возникать необрабатываемые ими исключения.
Заметьте, что SetErrorMode(SEM_NOALIGNMENTFAULTEXCEPT) позволяет подавить генерацию таких исключений даже в этом режиме.

339
Г ЛАВА 13
Архитектура памяти в Windows
Disable alignment fault Этот режим действует по умолчанию в Windows NT for Alpha AXP версий 3.1 и Операционная система сама исправляет любые ошибки, связанные с доступом к невыровненным данным (если таковые ошибки возникают, и приложения или отладчики их не замечают. Если программа часто обращается к невыровненным данным,
производительность системы может заметно снизиться. Для наблюдения за частотой появления таких ошибок можно использовать Perfmon или Эта утилита просто модифицирует нужный параметр реестра или показывает его текущее значение. Изменив значение этого параметра, перезагрузите компьютер, чтобы изменения вступили в силу.
Но, даже не пользуясь утилитой AXPAlign, Вы все равно можете заставить систему молча исправлять ошибки обращения к невыровненным данным во всех потоках
Вашего процесса. Для этого один из потоков должен вызвать функцию
SetErrorMode:
UINT SetErrorMode(UINT В данном случае Вам нужен флаг SEM_NOALIGNMENTFAULTEXCEPT. Когда он установлен, система автоматически исправляет ошибки обращения к невыровненным данным, а когда он сброшен, система вместо этого генерирует соответствующие исключения. Заметьте, что изменение этого флага влияет на потоки только того процесса, из которого была вызвана функция
SetErrorMode. Иначе говоря, его модификация не отражается на потоках других процессов. Также учтите, что любые флаги режимов обработки ошибок наследуются всеми дочерними процессами. Поэтому перед вызовом функции
CreateProcess Вам может понадобиться временно сбросить этот флаг.
SetErrorMode можно вызывать с флагом SEM_NOALIGNMENTFAULTEXCEPT независимо оттого, на какой платформе выполняется Ваше приложение. Но результаты ее вызова не всегда одинаковы. На платформе
x86 сбросить этот флаг просто нельзя, а на платформе Alpha его разрешается сбросить, только если параметр EnableAlign mentFaultExceptions в реестре равен Для наблюдения за частотой возникновения ошибок, связанных с доступом к не выровненным данным, в Windows 2000 можно использовать Performance подключаемый к MMC. Наследующей иллюстрации показано диалоговое окно Add
Counters, которое позволяет добавить нужный показатель в Performance Monitor.

340
Ч АС Т Ь I I I
УПРАВЛЕНИЕ ПАМЯТЬЮ
Этот показатель сообщает, сколько разв секунду процессор уведомляет операционную систему о доступе к невыровненным данным. На компьютере с процессором типа
x86 он всегда равен 0. Это связано стем, что такой процессор сам справляется с проблемами обращения к невыровненным данными не уведомляет об этом операционную систему. А поскольку он обходится без помощи со стороны операционной системы, падение производительности при частом доступе к невыровненным данным не столь значительно, как на процессорах, требующих стой же целью участия операционной системы.
Как видите, простого вызова
SetErrorMode вполне достаточно для того, чтобы Ваше приложение работало корректно. Но это решение явно не самое эффективное. Так, в
Alpha Architecture Reference Manual, опубликованном Digital Press, утверждается, что системный код, автоматически устраняющий ошибки обращения к невыровненным данным, может снизить быстродействие враз Издержки слишком велики. К счастью, есть более эффективное решение этой проблемы.
Компилятор Microsoft C/C++ для процессоров Alpha поддерживает ключевое слово. Этот модификатор используется также, как const или volatile, но применим лишь для переменных указателей. Когда Вы обращаетесь к данным через не выровненный указатель (unaligned pointer), компилятор генерирует код, исходя из того, что данные скорее всего не выровнены, и вставляет дополнительные машинные инструкции, необходимые для доступа к таким данным. Ниже показан тот же фрагмент кода, что ив начале разделано с использованием ключевого слова
__unaligned.
VOID SomeFunc(PVOID pvDataBuffer) {
// первый байт в буфере содержит значение типа BYTE
char c = * (PBYTE) pvDataBuffer;
// увеличиваем указатель для перехода за этот байт pvDataBuffer = (PVOID)((PBYTE) pvDataBuffer + 1);
// байты 2 5 в буфере содержат значение типа DWORD
DWORD dw = * (__unaligned DWORD *) pvDataBuffer;
// Предыдущая строка заставит компилятор сгенерировать дополнительные машинные инструкции, которые позволят считать значение типа DWORD
// в несколько приемов. При этом исключение из за попытки доступа к невыровненным данным не возникнет.
M
}
При компиляции следующей строки на процессоре Alpha, генерируется 7 машинных инструкций dw = * (__unaligned DWORD *) Но если я уберу ключевое слово
__unaligned, то получу всего 3 машинные инструкции. Как видите, модификатор
__unaligned на процессорах Alpha приводит к увеличению числа генерируемых машинных инструкций более чем в 2 раза. Но инструкции, добавляемые компилятором, все равно намного эффективнее, чем перехват процессором попыток доступа к невыровненным данными исправление таких ошибок операционной системой.
И последнее. Ключевое слово
__unaligned на процессорах типа x86 компилятором C/C++ не поддерживается. На этих процессорах оно просто ненужно. Но это

341
Г ЛАВА 13
Архитектура памяти в Windows означает, что версия компилятора для процессоров
x86, встретив в исходном коде ключевое слово
__unaligned, сообщит об ошибке. Поэтому, если Вы хотите создать единую базу исходного кода приложения для обеих процессорных платформ, используйте вместо
__unaligned макрос UNALIGNED. Он определен в файле WinNT.h так defined(_M_MRX000) || defined(_M_ALPHA) || defined(_M_IA64)
#define UNALIGNED __unaligned
#if defined(_WIN64)
#define UNALIGNED64 __unaligned
#else
#define UNALIGNED64
#endif
#else
#define UNALIGNED
#define UNALIGNED64
#endif

342
Г ЛАВА 4
Исследование виртуальной памяти
В
предыдущей главе мы выяснили, как система управляет виртуальной памятью, как процесс получает свое адресное пространство и что оно собой представляет. А сейчас мы перейдем от теории к практике и рассмотрим некоторые Windows функции,
сообщающие о состоянии системной памяти и виртуального адресного пространства в томили ином процессе.
Системная информация
Многие параметры операционной системы (размер страницы, гранулярность выделения памяти и др) зависят от используемого в компьютере процессора. Поэтому нельзя жестко зашивать их значения в исходный код программ. Эту информацию надо считывать в момент инициализации процесса с помощью функции
GetSystemInfo:
VOID GetSystemInfo(LPSYSTEM_INFO Вы должны передать в
GetSystemInfo адрес структуры SYSTEM_INFO, и функция инициализирует элементы этой структуры struct _SYSTEM_INFO {
union {
DWORD dwOemId; // не используйте этот элемент, он устарел struct {
WORD wProcessorArchitecture;
WORD wReserved;
};
};
DWORD dwPageSize;
LPVOID lpMinimumApplicationAddress;
LPVOID lpMaximumApplicationAddress;
DWORD_PTR dwActiveProcessorMask;
DWORD dwNumberOfProcessors;
DWORD dwProcessorType;
DWORD dwAllocationGranularity;
WORD wProcessorLevel;
WORD wProcessorRevision;
} SYSTEM_INFO, При загрузке система определяет значения элементов этой структуры для конкретной системы их значения постоянны. Функция
GetSystemInfo предусмотрена специально для того, чтобы и приложения могли получать эту информацию. Из всех элементов структуры лишь четыре имеют отношение к памяти. Они описаны в следующей таблице.

343
Г ЛАВА 14
Исследование виртуальной памяти
Элемент
Описание
dwPageSize
Размер страницы памяти. На процессорах
x86 это значение равно, а на процессорах Alpha — 8192 байтам.
lpMinimumApplicationAddress
Минимальный адрес памяти доступного адресного пространства для каждого процесса. В Windows 98 это значение равно 194 304, или 0x00400000, поскольку нижние 4 Мб адресного пространства каждого процесса недоступны. В Windows это значение равно 65 536, или 0x00010000, так как в этой системе резервируются лишь первые 64 Кб адресного пространства каждого процесса.
lpMaximumApplicationAddress
Максимальный адрес памяти доступного адресного пространства, отведенного в личное пользование каждому процессу.
В Windows 98 этот адрес равен 2 147 483 647, или так как верхние 2 Гб занимают общие файлы, проецируемые в память, и разделяемый код операционной системы.
В Windows 2000 этот адрес соответствует началу раздела для кода и данных режима ядра за вычетом 64 Кб.
dwAllocationGranularity
Гранулярность резервирования регионов адресного пространства. На момент написания книги это значение составляет 64 Кб для всех платформ Остальные элементы этой структуры показаны в таблице ниже.
Элемент
Описание
dwOemId
Устарел; больше не используется
wReserved
Зарезервирован на будущее пока не используется
dwNumberOfProcessors
Число процессоров в компьютере
dwActiveProcessorMask
Битовая маска, которая сообщает, какие процессоры активны
(выполняют потоки)
dwProcessorType
Используется только в Windows 98; сообщает тип процессора,
например Intel 386, 486 или Pentium
wProcessorArchitecture
Используется только в Windows 2000; сообщает тип архитектуры процессора, например Intel, Alpha, 64 разрядный Intel или разрядный Alpha
wProcessorLevel
Используется только в Windows 2000; сообщает дополнительные подробности об архитектуре процессора, например Intel
Pentium Pro или Pentium II
wProcessorRevision
Используется только в Windows 2000; сообщает дополнительные подробности об уровне данной архитектуры процессора
Программа-пример SysInfo
Эта программа, «14 SysInfo.exe» (см. листинг на рис. 14 1), весьма проста она вызывает функцию
GetSystemInfo и выводит на экран информацию, возвращенную в структуре. Файлы исходного кода и ресурсов этой программы находятся в каталоге 14 SysInfo на компакт диске, прилагаемом к книге. Диалоговые окна с результатами выполнения программы SysInfo на разных процессорных платформах показаны ниже.

344
Ч АС Т Ь I I I
УПРАВЛЕНИЕ ПАМЯТЬЮ
Windows 98 на процессоре x86
32 разрядная Windows 2000 на процессоре x86
32 разрядная Windows 2000
64 разрядная Windows 2000 на процессоре Alpha
на процессоре Alpha
SysInfo.cpp
/******************************************************************************
Модуль: Автор Copyright (c) 2000, Джеффри Рихтер (Jeffrey Richter)
******************************************************************************/
#include "..\CmnHdr.h"
/* см. приложение А */
#include
#include
#include
#include "Resource.h"
///////////////////////////////////////////////////////////////////////////////
// устанавливаем TRUE, если программа выполняется в Windows 9x
BOOL g_fWin9xIsHost = FALSE;
///////////////////////////////////////////////////////////////////////////////
// эта функция принимает число и преобразует его в строку вставляя в нужных местах запятые BigNumToString(LONG lNum, PTSTR szBuf) {
TCHAR szNum[100];
Рис. 14-1.
Программа-пример SysInfo

345
Г ЛАВА 14
Исследование виртуальной памяти
Рис. 14-1.
продолжение
wsprintf(szNum, TEXT("%d"), lNum);
NUMBERFMT nf;
nf.NumDigits = 0;
nf.LeadingZero = FALSE;
nf.Grouping = 3;
nf.lpDecimalSep = TEXT(".");
nf.lpThousandSep = TEXT(",");
nf.NegativeOrder = 0;
GetNumberFormat(LOCALE_USER_DEFAULT, 0, szNum, &nf, szBuf, 100);
return(szBuf);
}
///////////////////////////////////////////////////////////////////////////////
void ShowCPUInfo(HWND hwnd, WORD wProcessorArchitecture, WORD wProcessorLevel,
WORD wProcessorRevision) {
TCHAR szCPUArch[64]
= TEXT("(unknown)");
TCHAR szCPULevel[64] = TEXT("(unknown)");
TCHAR szCPURev[64] = TEXT("(unknown)");
switch (wProcessorArchitecture) {
case PROCESSOR_ARCHITECTURE_INTEL:
lstrcpy(szCPUArch, TEXT("Intel"));
switch (wProcessorLevel) {
case 3: case 4:
wsprintf(szCPULevel, TEXT("80%c86"), wProcessorLevel + '0');
if (!g_fWin9xIsHost)
wsprintf(szCPURev, TEXT("%c%d"),
HIBYTE(wProcessorRevision) + TEXT('A'), LOBYTE(wProcessorRevision));
break;
case 5:
wsprintf(szCPULevel, TEXT("Pentium"));
if (!g_fWin9xIsHost)
wsprintf(szCPURev, TEXT("Model %d, Stepping %d"),
HIBYTE(wProcessorRevision), LOBYTE(wProcessorRevision));
break;
case 6:
wsprintf(szCPULevel, TEXT("Pentium Pro or Pentium II"));
if (!g_fWin9xIsHost)
wsprintf(szCPURev, TEXT("Model %d, Stepping %d"),
HIBYTE(wProcessorRevision), LOBYTE(wProcessorRevision));
break;
}
break;
case PROCESSOR_ARCHITECTURE_ALPHA:
lstrcpy(szCPUArch, TEXT("Alpha"));
wsprintf(szCPULevel, TEXT("%d"), wProcessorLevel);
см. след. стр.

346
Ч АС Т Ь I I I
УПРАВЛЕНИЕ ПАМЯТЬЮ
Рис. 14-1.
продолжение
wsprintf(szCPURev, TEXT("Model %c, Pass %d"),
HIBYTE(wProcessorRevision) + TEXT('A'), LOBYTE(wProcessorRevision));
break;
case PROCESSOR_ARCHITECTURE_IA64:
lstrcpy(szCPUArch, TEXT("IA 64"));
wsprintf(szCPULevel, TEXT("%d"), wProcessorLevel);
wsprintf(szCPURev, TEXT("Model %c, Pass %d"),
HIBYTE(wProcessorRevision) + TEXT('A'), LOBYTE(wProcessorRevision));
break;
case PROCESSOR_ARCHITECTURE_ALPHA64:
lstrcpy(szCPUArch, TEXT("Alpha64"));
wsprintf(szCPULevel, TEXT("%d"), wProcessorLevel);
wsprintf(szCPURev, TEXT("Model %c, Pass %d"),
HIBYTE(wProcessorRevision) + TEXT('A'), LOBYTE(wProcessorRevision));
break;
case PROCESSOR_ARCHITECTURE_UNKNOWN:
default:
wsprintf(szCPUArch, TEXT("Unknown"));
break;
}
SetDlgItemText(hwnd, IDC_PROCARCH,
szCPUArch);
SetDlgItemText(hwnd, IDC_PROCLEVEL, szCPULevel);
SetDlgItemText(hwnd, IDC_PROCREV, szCPURev);
}
///////////////////////////////////////////////////////////////////////////////
BOOL Dlg_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam) {
chSETDLGICONS(hwnd, IDI_SYSINFO);
SYSTEM_INFO sinf;
GetSystemInfo(&sinf);
if (g_fWin9xIsHost) {
sinf.wProcessorLevel = (WORD) (sinf.dwProcessorType / 100);
}
ShowCPUInfo(hwnd, sinf.wProcessorArchitecture,
sinf.wProcessorLevel, sinf.wProcessorRevision);
TCHAR szBuf[50];
SetDlgItemText(hwnd, IDC_PAGESIZE, BigNumToString(sinf.dwPageSize, szBuf));
_stprintf(szBuf, TEXT("%p"), sinf.lpMinimumApplicationAddress);
SetDlgItemText(hwnd, IDC_MINAPPADDR, szBuf);
_stprintf(szBuf, TEXT("%p"), sinf.lpMaximumApplicationAddress);
SetDlgItemText(hwnd, IDC_MAXAPPADDR, szBuf);
1   ...   31   32   33   34   35   36   37   38   ...   68


База данных защищена авторским правом ©nethash.ru 2019
обратиться к администрации

войти | регистрация
    Главная страница


загрузить материал