Характеристика Win32

Введение



Последние 10 лет Windows – самая популярная (91,02%[1]) операционная система на рынке персональных компьютеров. Операционные системы Windows работают на платформах x86, AMD64, IA-64. Существовали также версии для DEC Alpha, MIPSи PowerPC.

Семейство Windows NT:

Операционные системы этого семейства работали на процессорах с архитектурой IA-32 и некоторых RISC-процессорах: Alpha, MIPS, Power PC (до версии 2000, которая вышла только в версии для IA-32). Windows NT являются полностью 32-битными операционными системами, и, в отличие от версий 1.0–3.x и 9x, не нуждаются в поддержке со стороны MS-DOS.

Windows NT 3.1 (1993)

Windows NT 3.5 (1994)

Windows NT 3.51 (1995)

Windows NT 4.0 (1996)

Windows 2000 (2000) – Windows NT 5.0

Windows XP (2001) – Windows NT 5.1

Windows XP 64-bit Edition (2006) – Windows NT 5.2

Windows Server 2003 (2003) – Windows NT 5.2

Windows Vista (2006) – Windows NT 6.0

Windows Home Server (2007)

Windows Server 2008

Windows 7 (2009) – Windows NT 7.0 (Актуальная версия – 6.1)

В основу семейства Windows NT положено разделение адресных пространств между процессами. Каждый процесс имеет возможность работать с выделенной ему памятью. Однако он не имеет прав для записи в память других процессов, драйверов и системного кода.

Семейство Windows NT относится к операционным системам с вытесняющей многозадачностью, а не к операционным системам реального времени. Разделение процессорного времени между потоками происходит по принципу «карусели». Ядро операционной системы выделяет квант времени (в Windows 2000 квант равен примерно 20 мс) каждому из потоков по очереди при условии, что все потоки имеют одинаковый приоритет. Поток может отказаться от выделенного ему кванта времени. В этом случае, система перехватывает у него управление (даже если выделенный квант времени не закончен) и передаёт управление другому потоку. При передаче управления другому потоку система сохраняет состояние всех регистров процессора в особой структуре в оперативной памяти. Эта структура называется контекстом потока. Сохранение контекста потока достаточно для последующего возобновления его работы.

API (Application Programming Interface – интерфейс прикладных программ) – это множество функций, организованных, обычно, в виде DLL. Функции API позволяют организовать интерфейс между прикладной программой и средой, в которой работает эта программа. Вызов функций API позволяет программе получать доступ к ресурсам среды и управлять ее работой. Как правило, API задает стандарт взаимодействия среды и прикладной программы.

Win32 – это название интерфейса, ориентированного на 32-х разрядные приложения и реализованного на таких известных платформах как Windows 95, Windows 98, Windows NT, Windows CE. Функции, составляющие этот интерфейс, позволяют прикладной программе получать доступ к ресурсам операционной системы и управлять ее работой. Более ранние версии Windows используют интерфейс, известный как Win16. Конечно, не все функции, составляющие интерфейс Win32, реализованы в полной мере на всех платформах, так что вызов одной и той же функции под NT приведет к определенному результату, а под Windows 95 работает как вызов заглушки. Любое из приложений, работающее в среде Windows, прямо или косвенно вызывает функции, входящие в Win32 API.

Функции, составляющие Win32 интерфейс, организованы в виде нескольких динамически подключаемых библиотек (DLL) и исполняемых файлов.

API функции не обязательно входят в состав Win32 интерфейса. Например, MAPI интерфейс (Messaging Application Programming Interface) составляют функции, предназначенные для обработки сообщений электронной почты, TAPI (Telephone API) – функции работы с телефонными сообщениями. MAPI, TAPI, также как и Win32 это некоторый набор функций, задающий определенный стандарт взаимодействия

Функции, образующие API, обычно, организованы в виде DLL – динамически подключаемых библиотеках. Одно из достоинств DLL состоит в том, что, сколько бы приложений (процессов) не работало с функциями одной и той же DLL, код DLLсуществует в единственном экземпляре.






1. Теоретическая часть



Возможности Win32 для нахождения списка запущенных процессов

программа алгоритм библиотека пользователь

Win32 предоставляет несколько способов перечисления запущенных процессов. К сожалению, нет единого способа, который бы работал на всех Win32-платформах. Программистам приходится комбинировать несколько методов в одной программе, чтобы она работала на всех версиях Windows.

Рассмотрим следующие методы:

С помощью библиотеки Process Status Helper (PSAPI)

С помощью ToolHelp32 API

С помощью недокументированной функции ZwQuerySystemInformation

Через счетчики производительности

С использованием интерфейсов Windows Management Instrumentation

Функции интерфейса сокетов



Использование библиотеки Process Status Helper



Библиотека Process Status Helper, известная также под названием PSAPI, предоставляет набор функций, позволяющих получить информацию о процессах и драйверах устройств. Библиотека поставляется в составе Windows 2000/XP и доступна в качестве устанавливаемой компоненты для Windows NT 4.0.

Для перечисления процессов библиотека предоставляет функцию EnumProcesses, которая возвращает массив идентификаторов запущенных процессов. Ниже приведен текст функции EnumProcesses_PsApi, реализующей перечисление процессов с помощью PSAPI.

Функция EnumProcesses не позволяет узнать, сколько места нужно для того, чтобы принять весь массив идентификаторов. Поэтому мы вызываем ее в цикле, увеличивая размер буфера, до тех пор, пока размер возвращенного массива не будет меньше размера буфера.

Поскольку мы хотим помимо идентификаторов процессов получить и имена процессов, мы должны проделать дополнительную работу. Для каждого процесса мы сначала получаем его описатель (handle) c помощью функции OpenProcess и затем используем функцию ЕnumProcessModules, которая возвращает список модулей, загруженных в адресное пространство процесса. Первым модулем в списке всегда является модуль, соответсвующий EXE-файлу программы. Наконец, мы вызываем функцию GetModuleFileNameEx (которая также является частью PSAPI), чтобы получить путь к EXE-файлу по описателю модуля. Мы используем имя EXE-файла без пути в качестве имени процесса.

Нужно обратить внимание на специальную обработку для двух процессов. Мы вынуждены обрабатывать отдельно процесс бездействия системы (Idle) с идентификатором 0, и системный процесс (System), который имеет идентификатор 2 на Windows NT 4 и 8 – на Windows 2000/XP, потому что OpenProcess не позволяет открыть описатель для этих процессов, возвращая код ошибки ERROR_ACCESS_DENIED.



Использование ToolHelp32 API



Корпорация Microsoft добавила набор функций под названием ToolHelp API в Windows 3.1, чтобы позволить сторонним разработчикам получить доступ к системной информации, которая ранее была доступна только программистам Microsoft. При создании Windows 95, эти функции перекочевали в новую систему под названием ToolHelp32 API. Операционная система Windows NT c cамого создания содержала средства для получения подобной информации под названием «данные производительности». Интерфейс для доступа к данным производительности был крайне запутанным и неудобным (справедливости ради надо отметить, что начиная с Windows NT 4.0, Microsoft предоставляет библиотеку Performance Data Helper, значительно облегчающую получение данных производительности; мы воспользуемся этой библиотекой при реализации соответствующего метода перечисления процессов). Говорят, команда Windows NT долгое время сопротивлялась включению ToolHelp32 API в систему, тем не менее, начиная с Windows 2000, ToolHelp32 API присутствует и в этой операционной системе.

Используя ToolHelp32 API, мы сначала создаем моментальный снимок (snapshot) списка процессов с помощью функции CreateToolhelp32Snapshot, а затем проходим по списку используя функции Process32First и Process32Next. Структура PROCESSENTRY32, заполняемая этими функциями, содержит всю необходимую информацию. Ниже приведен код функции EnumProcesses_ToolHelp, реализующей перечисление процессов с помощью ToolHelp32.



Использование функции ZwQuerySystemInformation



В данной курсовой использовался этот метод.

Несмотря на наличие документированного способа получения списка процессов в Windows NT с помощью данных производительности, Windows NT Task Manager никогда не использовал этот интерфейс. Вместо этого он использовал недокументированную функцию ZwQuerySystemInformation, экспортируемую из NTDLL.DLL, которая позволяет получить доступ к самой разнообразной системной информации и списку процессов в том числе.

Функция ZwQuerySystemInformation имеет следующий прототип [2]:






																NTSYSAPI

																NTSTATUS

																NTAPI

																ZwQuerySystemInformation (

																IN SYSTEM_INFORMATION_CLASS SystemInformationClass,

																IN OUT PVOID SystemInformation,

																IN ULONG SystemInformationLength,

																OUT PULONG ReturnLength

																);



где

SystemInformationClass – задает тип получаемой информации, нас интересует SystemProcessesAndThreadsInformation;

SystemInformation – указатель на буфер, принимающий запрошенную информацию;

SystemInformationLength – задает длину приемного буфера в байтах;

ReturnLength – указатель на переменную, в которую заносится количество байтов, записанных в выходной буфер

Формат информации о процессах и потоках описывается структурой SYSTEM_PROCESSES, которая содержит почти всю информацию, отображаемую Task Manager. Ниже привeден код функции EnumProcesses_NtApi, реализующей перечисление процессов с использованием функции ZwQuerySystemInformation.

При вызове ZwQuerySystemInformation трудно заранее определить, какой размер выходного буфера будет достаточным, поэтому мы начинам с буфера размером 32K и увеличиваем его по необходимости.



Использование cчетчиков производительности



Как уже отмечалось, операционная система Windows NT с самого создания содержала интерфейс для получения разнообразной информации о системе в виде счетчиков производительности. Этот интерфейс является, скажем, далеко не интуитивным. Для получения той или иной информации нужно прочитать из ключа реестра HKEY_PERFORMANCE_DATA значение со специально сформированным именем. В результате возвращается набор глубоко вложенных структур, многие из которых переменного размера, и разбор этих данных требует определенной усидчивости.

Ситуация изменилась в лучшую сторону с появлением в Windows NT 4.0 библиотеки Performance Data Helper (PDH), которая предоставляет более удобный интерфейс к данным производительности. Эта библиотека, однако, не входила в комплект поставки Windows NT 4.0, она распространялась в составе Microsoft Platform SDK. В Windows 2000 PDH.DLL присутствует по умолчанию.

Подробное рассмотрение данных производительности выходит за рамки данной статьи, отметим лишь, что система подсчета производительности в Windows NT определяет понятие объекта, для которого осуществляется подсчет производительности. Примерами объектов являются процессор и жесткий диск. Каждый объект может иметь один или более экземпляров, и для каждого объекта существует свой набор счетчиков производительности. Наша задача состоит в перечислении всех экземпляров объекта с именем «Process» и получении для каждого из них значения счетчика с именем «ID Process».



Использование Windows Management Instrumentation



Windows Management Instrumentation (WMI) является реализацией Mircrosoft для так называемой технологии Web-Based Enterprise Management (WBEM). WBEM определяет унифицированную архитектуру, которая позволяет получать данные от различных источников, построенных с помощью различных технологий и платформ, и единообразно представлять эти данные. WBEM основана на схеме общей информационной модели (Common Information Model, CIM), которая является индустриальным стандартом, управляемым Distributed Management Task Force (DMTF). WMI поставляется в составе Windows 2000, но также может быть установлен на Windows 95/98/Me и Windows NT 4.0

Поскольку WMI основана на технологии COM, это избавляет от необходимости явно загружать требуемые библиотеки, как это делалось в предыдущих примерах. Этот же факт требует инициализации библиотеки COM прежде чем будет вызвана функция перечисления процессов. В приложении, созданном с использованием MFC, это можно сделать с помощью функции AfxOleInit, в остальных случаях следует пользоваться функциями CoInitialize или CoInitializeEx.

Кроме того, использование WMI требует инициализации безопасности COM с помощью функции CoInitializeSecurity

Заметим, что как и метод с использованием счетчиков производительности, этот метод позволяет перечислить процессы на другом компьютере, для чего нужно указать имя компьютера в вызове IWbemLocator: ConnectServer.






2. Описание программы



2.1 Описание алгоритма



Программа была написана на Microsoft Visual Studio 2005, на языке С++, с использованием библиотек классов MFC, и функций Win32API.

При запуске программы открывается окно:





Рисунок 2.1 – Окно программы



Сразу отображается список запущенных процес сов, построенный с помощью функциии EnumProcesses_NtApi, реализующей перечисление процессов с использованием функции ZwQuerySystemInformation.

Определение времени запуска процесса осуществляется с помощью функции CreateTime_str.

При нажатии левой кнопкой мыши на поля «ID» или «Name» осуществляется сортировка при помощи функции CMainFrame: OnList_ColumnClick, и функции сортировки CMainFrame: SortCallback.




Рисунок 2.2 – Пример сортировки по названию



С помощью кнопки Exit программа закрывается.






3. Инструкция пользователя



3.1 Назначение продукта



Эта программа предназначена для частного пользования, для определения процессов, запущенных на компьютере, и времени их запуска.



3.2 Системные требования



Рекомендованные системные требования для компьютера:

Процессор: Intel Pentium III 0.8Ггц или выше;

ОЗУ: 128 Мб;

ПЗУ: 10 МБ;

Видео адаптер: Поддерживающий Directx 6.0 и выше;

ОС: Windows XP и выше



3.3 Запуск программы



Клиентское приложение состоит из файла «pview.exe». При запуске этого файла открывается окно. Автоматически загружается список запущенных приложений. При нажатии левой кнопкой мыши на «ID», список процессов, сортируется по коду. При нажатии левой кнопкой мыши на «Name», список сортируется по названию. Сортировать можно как по возрастанию, так и по убыванию.

В строке меню находится кнопка «Exit», при нажатии на которую, программа закроется.






Выводы



В ходе выполнения данного курсового проекта была разработана программа на языке высокого уровня Visual C++. А также изучены возможности данного языка.

Систематизированы и закреплены практические навыки использования ПК, программного обеспечения, существующих средств обслуживания системных программистов, а также теоретические знания по основным разделам курса «Операционные системы». Основное внимание уделено изучению современных операционных систем.

В ходе выполнения курсовой работы были использованы не только учебные средства, но и исходники различных программ.

Получены практические навыки работы в среде Microsoft Visual Studio.






Список литературы



1. Дейтел Х. Дейтел П. Как программировать на С++. «Бином» – Моква, 2004. – 1018 с.

2. Бондарев М.Ф. Липанов А.В. Путятин Е.П. Синельникова Т.Ф. Системное программирование в современных операционных системах «Компания СМИТ» – Харьков, 2005. – 432 с.

3. Холзнер С. Visual С++. «Питер» – Санкт Петербург, 2006. – 580 с.

4. Павловская Т.А. С/С++. Программирование на языке высокого уровня – СПб: Издательство «Питер», 2001. –464 с.

5. Саймон Р. Microsoft Windows API. Справочник системного программиста. «Dia Soft» – Киев, 2004. – 1216 с.

6. http://rsdn.ru/

7. http://www.source-code.ru

8. http://www.codeguru.com



	


Приложение



Тексты файлов программы



enumproc.cpp



#include «stdafx.h»

#include «enumproc.h»



#include <tlhelp32.h>

#include <pdh.h>

#include <pdhmsg.h>



#include <comdef.h>

#include «SshWbemHelpers.h»

 // Some definitions from NTDDK and other sources

 // 



typedef LONG	NTSTATUS;

typedef LONG	KPRIORITY;



#define NT_SUCCESS(Status) ((NTSTATUS) (Status) >= 0)



#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS) 0xC0000004L)



#define SystemProcessesAndThreadsInformation	5



typedef struct _CLIENT_ID {

DWORD	 UniqueProcess;

DWORD	 UniqueThread;

} CLIENT_ID;



typedef struct _UNICODE_STRING {

USHORT	 Length;

USHORT	 MaximumLength;

PWSTR	 Buffer;

} UNICODE_STRING;



typedef struct _VM_COUNTERS {

SIZE_T	 PeakVirtualSize;

SIZE_T	 VirtualSize;

ULONG	 PageFaultCount;

SIZE_T	 PeakWorkingSetSize;

SIZE_T	 WorkingSetSize;

SIZE_T	 QuotaPeakPagedPoolUsage;

SIZE_T	 QuotaPagedPoolUsage;

SIZE_T	 QuotaPeakNonPagedPoolUsage;

SIZE_T	 QuotaNonPagedPoolUsage;

SIZE_T	 PagefileUsage;

SIZE_T	 PeakPagefileUsage;

} VM_COUNTERS;



typedef struct _SYSTEM_THREADS {

LARGE_INTEGER KernelTime;

LARGE_INTEGER UserTime;

LARGE_INTEGER CreateTime;

ULONG			WaitTime;

PVOID			StartAddress;

CLIENT_ID	 ClientId;

KPRIORITY	 Priority;

KPRIORITY	 BasePriority;

ULONG			ContextSwitchCount;

LONG			State;

LONG			WaitReason;

} SYSTEM_THREADS, * PSYSTEM_THREADS;



 // Note that the size of the SYSTEM_PROCESSES structure is different on

 // NT 4 and Win2K, but we don't care about it, since we don't access neither

 // IoCounters member nor Threads array



typedef struct _SYSTEM_PROCESSES {

ULONG			NextEntryDelta;

ULONG			ThreadCount;

ULONG			Reserved1 [6];

LARGE_INTEGER CreateTime;

LARGE_INTEGER UserTime;

LARGE_INTEGER KernelTime;

UNICODE_STRING ProcessName;

KPRIORITY	 BasePriority;

ULONG			ProcessId;

ULONG			InheritedFromProcessId;

ULONG			HandleCount;

ULONG			Reserved2 [2];

VM_COUNTERS	 VmCounters;

#if _WIN32_WINNT >= 0x500

IO_COUNTERS	 IoCounters;

#endif

SYSTEM_THREADS Threads[1];

} SYSTEM_PROCESSES, * PSYSTEM_PROCESSES;

 // –

 // EnumProcesses_NtApi



BOOL

WINAPI

EnumProcesses_NtApi (

IN LPCTSTR pszMachineName,

IN PFNENUMPROC pfnEnumProc,

IN LPARAM lParam

)

{

_UNUSED(pszMachineName);



_ASSERTE (pfnEnumProc!= NULL);

_ASSERTE (pszMachineName == NULL);



HINSTANCE hNtDll;

NTSTATUS (WINAPI * _ZwQuerySystemInformation) (UINT, PVOID, ULONG, PULONG);



 // get handle to NTDLL.DLL

hNtDll = GetModuleHandle (_T(«ntdll.dll»));

_ASSERTE (hNtDll!= NULL);



 // find the address of ZwQuerySystemInformation

*(FARPROC *)&_ZwQuerySystemInformation =

GetProcAddress (hNtDll, «ZwQuerySystemInformation»);

if (_ZwQuerySystemInformation == NULL)

return SetLastError (ERROR_PROC_NOT_FOUND), FALSE;



 // obtain a handle to the default process heap

HANDLE hHeap = GetProcessHeap();

FILETIME Local_CreateTime, MyCreateTime;

SYSTEMTIME System_CreateTime;

char CreateTime_str[55];



NTSTATUS Status;

ULONG cbBuffer = 0x8000;

PVOID pBuffer = NULL;





do

{

pBuffer = HeapAlloc (hHeap, 0, cbBuffer);

if (pBuffer == NULL)

return SetLastError (ERROR_NOT_ENOUGH_MEMORY), FALSE;



Status = _ZwQuerySystemInformation (

SystemProcessesAndThreadsInformation,

pBuffer, cbBuffer, NULL);



if (Status == STATUS_INFO_LENGTH_MISMATCH)

{

HeapFree (hHeap, 0, pBuffer);

cbBuffer *= 2;

}

else if (! NT_SUCCESS(Status))

{

HeapFree (hHeap, 0, pBuffer);

return SetLastError(Status), FALSE;

}

}

while (Status == STATUS_INFO_LENGTH_MISMATCH);



PSYSTEM_PROCESSES pProcesses = (PSYSTEM_PROCESSES) pBuffer;



for (;)

{

PCWSTR pszProcessName = pProcesses->ProcessName. Buffer;



MyCreateTime.dwHighDateTime = pProcesses->CreateTime. HighPart;

MyCreateTime.dwLowDateTime = pProcesses->CreateTime. LowPart;

if (MyCreateTime.dwLowDateTime!= 0 && MyCreateTime.dwHighDateTime!= 0)

{

FileTimeToLocalFileTime (&MyCreateTime,&Local_CreateTime);

FileTimeToSystemTime (&Local_CreateTime,&System_CreateTime);

sprintf (CreateTime_str, «%02u:%02u:%02u:%03u\0», System_CreateTime.wHour, System_CreateTime.wMinute, System_CreateTime.wSecond, System_CreateTime.wMilliseconds);

}

else

{

sprintf (CreateTime_str, «00:00:00:000\0»);

}

if (pszProcessName == NULL)

pszProcessName = L «Idle»;



#ifdef _UNICODE



if (! pfnEnumProc (pProcesses->ProcessId, pszProcessName, CreateTime_str, lParam))

break;



#else



CHAR szProcessName [MAX_PATH];

WideCharToMultiByte (CP_ACP, 0, pszProcessName, -1,

szProcessName, MAX_PATH, NULL, NULL);



if (! pfnEnumProc (pProcesses->ProcessId, szProcessName, CreateTime_str, lParam))

break;



#endif

if (pProcesses->NextEntryDelta == 0)

break;



 // find the address of the next process structure

pProcesses = (PSYSTEM_PROCESSES) (((LPBYTE) pProcesses)

+ pProcesses->NextEntryDelta);

}



HeapFree (hHeap, 0, pBuffer);

return TRUE;

}



mainfrm.cpp

#include «stdafx.h»

#include «pview.h»

#include «mainfrm.h»

#include «enumproc.h»

#include «secedit.h»



BEGIN_MESSAGE_MAP (CMainFrame, CFrameWnd)



ON_WM_CONTEXTMENU()

ON_WM_CREATE()

ON_WM_DESTROY()

ON_WM_SETFOCUS()

ON_COMMAND (ID_VIEW_REFRESH, OnViewRefresh)

ON_COMMAND (ID_VIEW_APPLICATIONS, OnViewApplications)

ON_UPDATE_COMMAND_UI (ID_VIEW_APPLICATIONS, OnViewApplications_Update)

ON_COMMAND (ID_VIEW_PROCESSES, OnViewProcesses)

ON_UPDATE_COMMAND_UI (ID_VIEW_PROCESSES, OnViewProcesses_Update)

ON_COMMAND (ID_OPTIONS_ENUMPROC_TOOLHELP, OnOptionsEnumprocToolhelp)

ON_UPDATE_COMMAND_UI (ID_OPTIONS_ENUMPROC_TOOLHELP, OnOptionsEnumprocToolhelp_Update)

ON_COMMAND (ID_OPTIONS_ENUMPROC_NTAPI, OnOptionsEnumprocNtapi)

ON_UPDATE_COMMAND_UI (ID_OPTIONS_ENUMPROC_NTAPI, OnOptionsEnumprocNtapi_Update)

ON_COMMAND (ID_OPTIONS_ENUMPROC_PERFDATA, OnOptionsEnumprocPerfdata)

ON_UPDATE_COMMAND_UI (ID_OPTIONS_ENUMPROC_PERFDATA, OnOptionsEnumprocPerfdata_Update)

ON_UPDATE_COMMAND_UI (ID_OPTIONS_DEBUG, OnOptionsDebug_Update)

ON_COMMAND (ID_OPTIONS_DEBUG, OnOptionsDebug)

ON_COMMAND (ID_OPTIONS_ENUMPROC_WMI, OnOptionsEnumprocWmi)

ON_UPDATE_COMMAND_UI (ID_OPTIONS_ENUMPROC_WMI, OnOptionsEnumprocWmi_Update)

ON_WM_TIMER()

ON_COMMAND (ID_ACTION_SECURITY, OnActionSecurity)

ON_UPDATE_COMMAND_UI (ID_ACTION_SECURITY, OnActionSecurity_Update)

ON_WM_SYSCOLORCHANGE()

ON_NOTIFY (LVN_COLUMNCLICK, AFX_IDW_PANE_FIRST, OnList_ColumnClick)

ON_NOTIFY (LVN_DELETEITEM, AFX_IDW_PANE_FIRST, OnList_DeleteItem)

ON_COMMAND (ID_ABOUT, &CMainFrame: OnAbout)

END_MESSAGE_MAP()



 // –

 // CMainFrame

CMainFrame:CMainFrame()

{

m_bProcesses = -1;

m_nSortOrder = -1;

m_nAppsSortOrder = -1;

m_bShow16Bit = FALSE;

m_hVdmDbg = NULL;

m_pfnVDMEnumTaskWOWEx = NULL;

m_pfnVDMTerminateTaskWOW = NULL;

m_hPDH = NULL;

m_hPSAPI = NULL;

m_bWmiAvailable = NULL;

m_nRefreshPeriod = UPDATE_PERIOD_NORMAL;

m_bSedAvailable = FALSE;

 //m_pfnIsAppHung = IsAppHung_SMTO;

m_dwWaitStart = 0;



m_osvi.dwOSVersionInfoSize = sizeof (m_osvi);

_VERIFY (GetVersionEx(&m_osvi));

}



 // –

 // ~CMainFrame

CMainFrame:~CMainFrame()

{

}



 // –

 // PreCreateWindow

BOOL

CMainFrame: PreCreateWindow (

CREATESTRUCT& cs

)

{

if (! CFrameWnd: PreCreateWindow(cs))

return FALSE;



cs.dwExStyle &= ~WS_EX_CLIENTEDGE;

cs.lpszClass = AfxRegisterWndClass (0, NULL, NULL,

AfxGetApp()->LoadIcon (IDR_MAINFRAME));



return TRUE;

}



 // –



void

CMainFrame: OnContextMenu (

CWnd * pWnd,

CPoint point

)

{

if (pWnd!= &m_wndView)

return;



int nSel = m_wndView. GetNextItem (-1, LVNI_SELECTED);

if (nSel == -1)

return;



if (point.x == -1 && point.y == -1)

{

RECT rect;

m_wndView. GetItemRect (nSel, &rect, LVIR_BOUNDS);

m_wndView. ClientToScreen(&rect);



point.x = rect.left + 1;

point.y = rect.bottom + 1;

}



CMenu menu;

int nMenu = m_bProcesses? 0: 1;



menu. GetSubMenu(nMenu)->TrackPopupMenu (TPM_LEFTALIGN|TPM_LEFTBUTTON,

point.x, point.y, this);

}



 // –

 // OnCreate

int

CMainFrame: OnCreate (

CREATESTRUCT * pCreateStruct

)

{

OnSysColorChange();



RECT rcEmpty;

SetRectEmpty(&rcEmpty);



if (CFrameWnd: OnCreate(pCreateStruct) == -1)

return -1;



 // create status bar

UINT nInd = ID_SEPARATOR;





if (! m_ImageList. Create (16, 16, ILC_COLOR32|ILC_MASK, 16, 16))

return -1;



 // insert the default application icon into the image list

m_ImageList. Add (LoadIcon(NULL, IDI_APPLICATION));



if (m_osvi.dwPlatformId == VER_PLATFORM_WIN32_NT)

{

m_hVdmDbg = LoadLibrary (_T(«vdmdbg.dll»));

if (m_hVdmDbg!= NULL)

{

m_pfnVDMEnumTaskWOWEx =

(VDMENUMTASKWOWEXPROC) GetProcAddress (m_hVdmDbg,

«VDMEnumTaskWOWEx»);

m_pfnVDMTerminateTaskWOW =

(VDMTERMINATETASKINWOWPROC) GetProcAddress (m_hVdmDbg,

«VDMTerminateTaskWOW»);

}

}



m_hPSAPI = LoadLibrary (_T(«psapi.dll»));

m_hPDH = LoadLibrary (_T(«pdh.dll»));



IWbemLocator * pLocator = NULL;

HRESULT hRes = CoCreateInstance (__uuidof(WbemLocator), NULL,

CLSCTX_INPROC_SERVER,

__uuidof(IWbemLocator),

(PVOID *)&pLocator);

if (SUCCEEDED(hRes))

{

pLocator->Release();

m_bWmiAvailable = TRUE;

}

else

{

m_bWmiAvailable = FALSE;

}



m_bSedAvailable = CProcessSecInfo: IsDaclEditorAvailable();



m_nEnumProcMethod = (int) g_theApp. GetProfileInt (_T(«Settings»),

_T («EnumProcessesMethod»), ENUMPROCESSES_INVALID);



if (m_nEnumProcMethod == ENUMPROCESSES_PERFDATA &&

m_hPDH == NULL)

m_nEnumProcMethod = ENUMPROCESSES_INVALID;



if (m_nEnumProcMethod == ENUMPROCESSES_WMI &&

! m_bWmiAvailable)

m_nEnumProcMethod = ENUMPROCESSES_INVALID;



if (m_nEnumProcMethod == ENUMPROCESSES_INVALID)

{

if (m_osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)

m_nEnumProcMethod = ENUMPROCESSES_TOOLHELP;

else

m_nEnumProcMethod = ENUMPROCESSES_NTAPI;

}



int bProcesses = (int) g_theApp. GetProfileInt (_T(«Settings»),			_T («ProcessesMode»), 1);

m_nSortOrder = (int) g_theApp. GetProfileInt (_T(«Settings»),

_T («ProcessesSortOrder»), -1);

m_nAppsSortOrder = (int) g_theApp. GetProfileInt (_T(«Settings»),

_T («ApplicationsSortOrder»), -1);

m_bShow16Bit = (BOOL) g_theApp. GetProfileInt (_T(«Settings»),

_T («Show16Bit»), FALSE);



if (m_pfnVDMEnumTaskWOWEx == NULL ||

m_pfnVDMTerminateTaskWOW == NULL)

m_bShow16Bit = FALSE;



m_nRefreshPeriod = g_theApp. GetProfileInt (_T(«Settings»),			_T («UpdateSpeed»), UPDATE_PERIOD_NORMAL);



if (m_nRefreshPeriod!= UPDATE_PERIOD_PAUSED)

SetTimer (1, m_nRefreshPeriod, NULL);



int bHung = (int) g_theApp. GetProfileInt (_T(«Settings»),_T («IsAppHung»), 0);



PBYTE pData = NULL;

UINT cbData = 0;

int * pnValues = NULL;



if (g_theApp. GetProfileBinary (_T(«Settings»), _T («ListView»),

&pData, &cbData))

{

if (cbData == 8 * sizeof(int))

{

pnValues = (int *) pData;

m_nProcColWidth[0] = pnValues[0];

m_nProcColWidth[1] = pnValues[1];

m_nAppsColWidth[0] = pnValues[2];

m_nAppsColWidth[1] = pnValues[3];

m_nProcColOrder[0] = pnValues[4];

m_nProcColOrder[1] = pnValues[5];

m_nAppsColOrder[0] = pnValues[6];

m_nAppsColOrder[1] = pnValues[7];

}

delete[] pData;

}



if (pnValues == NULL)

{

m_nProcColWidth[0] = LVSCW_AUTOSIZE_USEHEADER;

m_nProcColWidth[1] = LVSCW_AUTOSIZE_USEHEADER;

m_nAppsColWidth[0] = LVSCW_AUTOSIZE_USEHEADER;

m_nAppsColWidth[1] = LVSCW_AUTOSIZE_USEHEADER;

m_nProcColOrder[0] = 0;

m_nProcColOrder[1] = 1;

m_nAppsColOrder[0] = 0;

m_nAppsColOrder[1] = 1;

}



if (bProcesses)

OnViewProcesses();

else

OnViewApplications();

return 0;

}



 // –

 // OnDestroy

void

CMainFrame: OnDestroy()

{

SaveViewSettings();



g_theApp. WriteProfileInt (_T(«Settings»), _T («EnumProcessesMethod»),

m_nEnumProcMethod);

g_theApp. WriteProfileInt (_T(«Settings»), _T («ProcessesMode»),

m_bProcesses);

g_theApp. WriteProfileInt (_T(«Settings»), _T («ProcessesSortOrder»),

m_nSortOrder);

g_theApp. WriteProfileInt (_T(«Settings»), _T («ApplicationsSortOrder»),

m_nAppsSortOrder);

g_theApp. WriteProfileInt (_T(«Settings»), _T («Show16Bit»),

m_bShow16Bit);

g_theApp. WriteProfileInt (_T(«Settings»), _T («UpdateSpeed»),

m_nRefreshPeriod);



int nValues[8];

nValues[0] = m_nProcColWidth[0];

nValues[1] = m_nProcColWidth[1];

nValues[2] = m_nAppsColWidth[0];

nValues[3] = m_nAppsColWidth[1];

nValues[4] = m_nProcColOrder[0];

nValues[5] = m_nProcColOrder[1];

nValues[6] = m_nAppsColOrder[0];

nValues[7] = m_nAppsColOrder[1];



g_theApp. WriteProfileBinary (_T(«Settings»), _T («ListView»),

(LPBYTE) nValues, sizeof(nValues));



if (m_hVdmDbg!= NULL)

_VERIFY (FreeLibrary(m_hVdmDbg));



m_hVdmDbg = NULL;

m_pfnVDMEnumTaskWOWEx = NULL;

m_pfnVDMTerminateTaskWOW = NULL;



if (m_hPSAPI!= NULL)

_VERIFY (FreeLibrary(m_hPSAPI));



if (m_hPDH!= NULL)

_VERIFY (FreeLibrary(m_hPDH));



CFrameWnd: OnDestroy();

}



 // –

 // OnSetFocus

void

CMainFrame: OnSetFocus (

CWnd * pOldWnd

)

{

_UNUSED(pOldWnd);



 // forward focus to the view window

m_wndView. SetFocus();

}



 // –

 // OnSysColorChange

void CMainFrame: OnSysColorChange()

{

CFrameWnd: OnSysColorChange();



if (m_bmSortUp.m_hObject!= NULL)

_VERIFY (m_bmSortUp. DeleteObject());

if (m_bmSortDown.m_hObject!= NULL)

_VERIFY (m_bmSortDown. DeleteObject());



_VERIFY (m_bmSortUp. LoadMappedBitmap (IDB_SORT_UP));

_VERIFY (m_bmSortDown. LoadMappedBitmap (IDB_SORT_DOWN));		

}



 // –

 // OnTimer

void

CMainFrame: OnTimer (

UINT nIDEvent

)

{

_UNUSED(nIDEvent);



_ASSERTE (nIDEvent == 1);



OnViewRefresh();

}





 // –

 // OnActionSecurity

void

CMainFrame: OnActionSecurity()

{

int nSel = m_wndView. GetNextItem (-1, LVNI_SELECTED);	_ASSERTE (nSel!= -1);



CItemData * pData = (CItemData *) m_wndView. GetItemData(nSel);

_ASSERTE (_CrtIsValidHeapPointer(pData));



CProcessSecInfo SecInfo;



if (! SecInfo. EditDacl (m_hWnd, pData->dwProcessId, pData->strName))

AfxThrowOleException (HRESULT_FROM_WIN32 (GetLastError()));

}



 // –

 // OnActionSecurity_Update

void

CMainFrame: OnActionSecurity_Update (CCmdUI * pCmdUI)

{

BOOL bEnable = FALSE;

if (m_bProcesses && m_bSedAvailable && m_strMachineName. IsEmpty())

{

int nSel = m_wndView. GetNextItem (-1, LVNI_SELECTED);

if (nSel!= -1)

{CItemData * pData = (CItemData *) m_wndView. GetItemData(nSel);

_ASSERTE (_CrtIsValidHeapPointer(pData));



Enable = pData->dwProcessId!= 0 && pData->dwWowTaskId == 0;

}

}



pCmdUI->Enable(bEnable);

}

 // –

 // OnViewApplications

void

CMainFrame: OnViewApplications()

{

if (m_bProcesses!= 0)

{

if (:IsWindow (m_wndView.m_hWnd))

{

SaveViewSettings();

m_wndView. DestroyWindow();

}

DWORD dwStyle;



 // create a view to occupy the client area of the frame

dwStyle = WS_CHILD|WS_VISIBLE|LVS_REPORT|LVS_SHAREIMAGELISTS|

LVS_SHOWSELALWAYS|LVS_SINGLESEL;



RECT rcClient;

GetClientRect(&rcClient);



m_wndView. Create (dwStyle, rcClient, this, AFX_IDW_PANE_FIRST);

m_wndView. ModifyStyleEx (0, WS_EX_CLIENTEDGE);

m_wndView. SetExtendedStyle (LVS_EX_FULLROWSELECT|LVS_EX_HEADERDRAGDROP);



m_wndView. SetImageList (&m_ImageList, LVSIL_SMALL);

RecalcLayout();

m_strMachineName. Empty();



 // remove any colums currently in the list

while (m_wndView. DeleteColumn(0));



TCHAR szColumn[256];

 // add two colums to the list control

AfxLoadString (IDS_APPS_TASK, szColumn, countof(szColumn));

m_wndView. InsertColumn (0, szColumn);

AfxLoadString (IDS_APPS_STATUS, szColumn, countof(szColumn));

m_wndView. InsertColumn (1, szColumn);

m_bProcesses = 0;

m_wndView. SetRedraw(FALSE);

m_wndView. SetColumnWidth (0, m_nAppsColWidth[0]);

m_wndView. SetColumnWidth (1, m_nAppsColWidth[1]);

m_wndView. SetColumnOrderArray (2, m_nAppsColOrder);

OnViewRefresh();

}

}



 // –

 // OnViewApplications_Update

void

CMainFrame: OnViewApplications_Update (CCmdUI * pCmdUI)

{

_ASSERTE (pCmdUI!= NULL);

pCmdUI->SetRadio (! m_bProcesses);

}



 // –

 // OnViewProcesses

void

CMainFrame: OnViewProcesses()

{

if (m_bProcesses!= 1)

{

if (:IsWindow (m_wndView.m_hWnd))

{

SaveViewSettings();

m_wndView. DestroyWindow();

}



DWORD dwStyle;

 // create a view to occupy the client area of the frame

dwStyle = WS_CHILD|WS_VISIBLE|LVS_REPORT|LVS_SHAREIMAGELISTS|

LVS_SHOWSELALWAYS|LVS_SINGLESEL;

RECT rcClient;

GetClientRect(&rcClient);

m_wndView. Create (dwStyle, rcClient, this, AFX_IDW_PANE_FIRST);

m_wndView. ModifyStyleEx (0, WS_EX_CLIENTEDGE);

m_wndView. SetExtendedStyle (LVS_EX_FULLROWSELECT|LVS_EX_HEADERDRAGDROP);

RecalcLayout();

TCHAR szColumn[256];





 // add two colums to the list control

AfxLoadString (IDS_PROCESSES_ID, szColumn, countof(szColumn));

m_wndView. InsertColumn (0, szColumn);



AfxLoadString (IDS_PROCESSES_NAME, szColumn, countof(szColumn));

m_wndView. InsertColumn (1, szColumn);



AfxLoadString (IDS_PROCESSES_time, szColumn, countof(szColumn));

m_wndView. InsertColumn (2, szColumn);

m_bProcesses = 1;

m_wndView. SetRedraw(FALSE);

m_wndView. SetColumnWidth (0, 103);

m_wndView. SetColumnWidth (1, 103);

m_wndView. SetColumnWidth (2, 103);

m_wndView. SetColumnOrderArray (2, m_nProcColOrder);



OnViewRefresh();

}

}



 // –

 // OnViewProcesses_Update

void CMainFrame: OnViewProcesses_Update (

CCmdUI * pCmdUI

)

{

_ASSERTE (pCmdUI!= NULL);



pCmdUI->SetRadio (m_bProcesses);

}





 // –

 // OnViewRefresh

 // 

 // Handles View|Refresh menu command. Refreshes the currently displayed

 // information.



void

CMainFrame: OnViewRefresh()

{

int i;

if (m_nRefreshPeriod == UPDATE_PERIOD_PAUSED)

AfxGetApp()->BeginWaitCursor();



m_wndView. SetRedraw(FALSE);



 // mark all items

int nCount = m_wndView. GetItemCount();

for (i = 0; i < nCount; i++)

{

CItemData * pData = (CItemData *) m_wndView. GetItemData(i);

_ASSERTE (pData!= NULL);

pData->bDelete = TRUE;

}



try

{

if (m_bProcesses)

ListProcesses();

}

catch (CException * pe)

{

if (m_nRefreshPeriod!= UPDATE_PERIOD_PAUSED)

{

KillTimer(1);

m_nRefreshPeriod = UPDATE_PERIOD_PAUSED;

}



pe->ReportError();

pe->Delete();

}



 // walk through the list and delete items which are still marked

nCount = m_wndView. GetItemCount();

for (i = nCount – 1; i >= 0; i–)

{

CItemData * pData = (CItemData *) m_wndView. GetItemData(i);

_ASSERTE (pData!= NULL);



if (pData->bDelete)

m_wndView. DeleteItem(i);

}



m_wndView. SetRedraw(TRUE);



TCHAR szFormat[256];

TCHAR szTitle[256];



if (m_strMachineName. IsEmpty())

AfxLoadString (IDS_TITLE_LOCAL, szFormat, countof(szFormat));

else

AfxLoadString (IDS_TITLE_REMOTE, szFormat, countof(szFormat));



wsprintf (szTitle, szFormat, (LPCTSTR) m_strMachineName);

SetWindowText(szTitle);



if (m_nRefreshPeriod == UPDATE_PERIOD_PAUSED)

AfxGetApp()->EndWaitCursor();

}



 // –

 // OnViewSpeedPaused_Update

void

CMainFrame: OnViewSpeedPaused_Update (

CCmdUI * pCmdUI

)

{

_ASSERTE (pCmdUI!= NULL);



pCmdUI->SetRadio (m_nRefreshPeriod == UPDATE_PERIOD_PAUSED);

}





 // –

void

CMainFrame: OnOptionsEnumprocToolhelp()

{

m_nEnumProcMethod = ENUMPROCESSES_TOOLHELP;

OnViewRefresh();

}

 // –

 // OnOptionsEnumprocToolhelp_Update

void CMainFrame: OnOptionsEnumprocToolhelp_Update (CCmdUI* pCmdUI)

{

_ASSERTE (pCmdUI!= NULL);



BOOL bEnable = (m_osvi.dwPlatformId == VER_PLATFORM_WIN32_NT &&

m_osvi.dwMajorVersion >= 5) || m_osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS;



pCmdUI->Enable (bEnable && m_strMachineName. IsEmpty());

pCmdUI->SetRadio (m_nEnumProcMethod == ENUMPROCESSES_TOOLHELP);

}

 // –

 // OnOptionsEnumprocNtapi

void CMainFrame: OnOptionsEnumprocNtapi()

{

m_nEnumProcMethod = ENUMPROCESSES_NTAPI;

OnViewRefresh();

}

 // –

 // OnOptionsEnumprocNtapi_Update

void

CMainFrame: OnOptionsEnumprocNtapi_Update (

CCmdUI * pCmdUI

)

{

_ASSERTE (pCmdUI!= NULL);



pCmdUI->Enable (m_osvi.dwPlatformId == VER_PLATFORM_WIN32_NT &&

m_strMachineName. IsEmpty());

pCmdUI->SetRadio (m_nEnumProcMethod == ENUMPROCESSES_NTAPI);

}

 // –

 // OnOptionsEnumprocPerfdata

void CMainFrame: OnOptionsEnumprocPerfdata()

{

m_nEnumProcMethod = ENUMPROCESSES_PERFDATA;

OnViewRefresh();

}

 // –

 // OnOptionsEnumprocPerfdata_Update

void

CMainFrame: OnOptionsEnumprocPerfdata_Update (

CCmdUI * pCmdUI

)

{

_ASSERTE (pCmdUI!= NULL);



pCmdUI->Enable (m_hPDH!= NULL);

pCmdUI->SetRadio (m_nEnumProcMethod == ENUMPROCESSES_PERFDATA);

}

 // –

 // OnOptionsEnumprocWmi

void

CMainFrame: OnOptionsEnumprocWmi()

{

m_nEnumProcMethod = ENUMPROCESSES_WMI;

OnViewRefresh();

}



 // –

 // OnOptionsEnumprocWmi_Update

void

CMainFrame: OnOptionsEnumprocWmi_Update (

CCmdUI * pCmdUI

)

{

_ASSERTE (pCmdUI!= NULL);



pCmdUI->Enable (m_bWmiAvailable!= NULL);

pCmdUI->SetRadio (m_nEnumProcMethod == ENUMPROCESSES_WMI);	

}



 // –

 // OnOptionsDebug

void

CMainFrame: OnOptionsDebug()

{

TOKEN_PRIVILEGES tkp;

tkp. PrivilegeCount = 1;



LookupPrivilegeValue (NULL, SE_DEBUG_NAME, &tkp. Privileges[0].Luid);





HANDLE hToken;

if (OpenProcessToken (GetCurrentProcess(), ЕOKEN_QUERY|TOKEN_ADJUST_PRIVILEGES,&hToken))

{

AdjustTokenPrivileges (hToken, FALSE, &tkp, sizeof(tkp), NULL, NULL);

CloseHandle(hToken);

}



OnViewRefresh();

}

 // –

 // OnOptionsDebug_Update

void

CMainFrame: OnOptionsDebug_Update (CCmdUI* pCmdUI)

{

_ASSERTE (pCmdUI!= NULL);



LUID Luid;

LookupPrivilegeValue (NULL, SE_DEBUG_NAME, &Luid);

if (m_osvi.dwPlatformId == VER_PLATFORM_WIN32_NT)

{}

else

pCmdUI->Enable(FALSE);

}

 // –

 // OnList_ColumnClick

void

CMainFrame: OnList_ColumnClick (

NMHDR * pNMHDR,

LRESULT * pResult

)

{

_UNUSED(pResult);



_ASSERTE (pNMHDR!= NULL);

_ASSERTE (pResult!= NULL);



NMLISTVIEW * pnmlv = (NMLISTVIEW *) pNMHDR;



if (m_bProcesses)

{

if (pnmlv->iSubItem == abs (m_nSortOrder) – 1)

m_nSortOrder = – m_nSortOrder;

else

m_nSortOrder = – (pnmlv->iSubItem + 1);



m_wndView. SortItems (SortCallback, m_nSortOrder);

SetSortMark (m_nSortOrder);

}

else

{

if (pnmlv->iSubItem == abs (m_nAppsSortOrder) – 1)

m_nAppsSortOrder = – m_nAppsSortOrder;

else

m_nAppsSortOrder = – (pnmlv->iSubItem + 1);



m_wndView. SortItems (AppsSortCallback, m_nAppsSortOrder);

SetSortMark (m_nAppsSortOrder);

}

}



 // –

 // OnList_DeleteItem

void

CMainFrame: OnList_DeleteItem (NMHDR * pNMHDR, LRESULT * pResult)

{

_UNUSED(pResult);



_ASSERTE (pNMHDR!= NULL);

_ASSERTE (pResult!= NULL);



NMLISTVIEW * pnmlv = (NMLISTVIEW *) pNMHDR;

CItemData * pData = (CItemData *) m_wndView. GetItemData (pnmlv->iItem);



_ASSERTE (pData!= NULL);



delete pData;

}

 // –

 // SaveViewSettings

void

CMainFrame: SaveViewSettings()

{

if (m_bProcesses)

{

m_nProcColWidth[0] = m_wndView. GetColumnWidth(0);

m_nProcColWidth[1] = m_wndView. GetColumnWidth(1);

m_nProcColWidth[2] = m_wndView. GetColumnWidth(2);

m_wndView. GetColumnOrderArray (m_nProcColOrder, 2);

}

else

{

m_nAppsColWidth[0] = m_wndView. GetColumnWidth(0);

m_nAppsColWidth[1] = m_wndView. GetColumnWidth(1);

m_wndView. GetColumnOrderArray (m_nAppsColOrder, 2);

}

}

 // –

 // SetSortMark

void

CMainFrame: SetSortMark (int nOrder)

{

int nSubItem = abs(nOrder) – 1;	



CHeaderCtrl& hdr = *m_wndView. GetHeaderCtrl();



int nCount = hdr. GetItemCount();

for (int i = 0; i < nCount; i++)

{

HDITEM hdi;

hdi.mask = HDI_FORMAT;



_VERIFY (hdr. GetItem (i, &hdi));



if (i!= nSubItem)

{

hdi.fmt &= ~(HDF_BITMAP|HDF_BITMAP_ON_RIGHT);

}

else

{

hdi.mask |= HDI_BITMAP;

hdi.fmt |= HDF_BITMAP|HDF_BITMAP_ON_RIGHT;

hdi.hbm = (nOrder > 0)? m_bmSortDown: m_bmSortUp;

}



_VERIFY (hdr. SetItem (i, &hdi));

}

}

 // –

 // SortCallback

int

CALLBACK

CMainFrame: SortCallback (LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)

{

CItemData * pData1 = (CItemData *) lParam1;

CItemData * pData2 = (CItemData *) lParam2;

_ASSERTE (_CrtIsValidHeapPointer(pData1));

_ASSERTE (_CrtIsValidHeapPointer(pData2));



int nRes;



switch (abs(lParamSort))

{

 // sort on process identifiers

case 1:

nRes = (int) pData2->dwProcessId – (int) pData1->dwProcessId;

break;

 // sort on process names

case 2:

nRes = lstrcmpi (pData2->strName, pData1->strName);

break;



default:

_ASSERTE(0);

__assume(0);

}

if (lParamSort < 0)

nRes = – nRes;



if (nRes == 0)

nRes = (int) pData1->dwWowTaskId – (int) pData2->dwWowTaskId;



return nRes;

}

 // –

 // AppsSortCallback

int

CALLBACK

CMainFrame: AppsSortCallback (LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)

{

CItemData * pData1 = (CItemData *) lParam1;

CItemData * pData2 = (CItemData *) lParam2;



_ASSERTE (_CrtIsValidHeapPointer(pData1));

_ASSERTE (_CrtIsValidHeapPointer(pData2));



int nRes;



switch (abs(lParamSort))

{

 // sort on application names

case 1:

nRes = lstrcmpi (pData2->strName, pData1->strName);

break;



 // sort on application status

case 2:

if (pData1->bRunning &&! pData2->bRunning)

nRes = 1;

else if (! pData1->bRunning && pData2->bRunning)

nRes = -1;

else

nRes = lstrcmpi (pData2->strName, pData1->strName);

break;



default:

_ASSERTE(0);

__assume(0);

}



if (lParamSort < 0)

nRes = – nRes;



return nRes;

}



 // –

 // ListProcesses

void

CMainFrame: ListProcesses()

{

PFNENUMPROCESSES pfnEnumProc = NULL;



 // select enumeration function to use

switch (m_nEnumProcMethod)

{

case ENUMPROCESSES_TOOLHELP:

pfnEnumProc = EnumProcesses_ToolHelp;

break;

case ENUMPROCESSES_NTAPI:

pfnEnumProc = EnumProcesses_NtApi;

break;

case ENUMPROCESSES_PERFDATA:

pfnEnumProc = EnumProcesses_PerfData;

break;

case ENUMPROCESSES_WMI:

pfnEnumProc = EnumProcesses_Wmi;

break;

default:

_ASSERTE(0);

__assume(0);

}

_ASSERTE (pfnEnumProc!= NULL);

LPCTSTR pszMachineName = NULL;

if (! m_strMachineName. IsEmpty())

pszMachineName = m_strMachineName;



 // call process enumeration function

if (! pfnEnumProc (pszMachineName, EnumProcessCallback, (LPARAM) this))

AfxThrowOleException (HRESULT_FROM_WIN32 (GetLastError()));



m_wndView. SortItems (SortCallback, m_nSortOrder);

SetSortMark (m_nSortOrder);

}

 // –

 // EnumProcessCallback

BOOL

CALLBACK

CMainFrame: EnumProcessCallback (

DWORD dwProcessId,

LPCTSTR pszName,

char CreateTime_str[55],

LPARAM lParam

)

{

int nItem;

CMainFrame * pFrame = (CMainFrame *) lParam;

ASSERT_VALID(pFrame);

CListCtrl& wndView = pFrame->m_wndView;

CItemData * pData;

BOOL bFound = FALSE;

TCHAR szID[64];

wsprintf (szID, _T («%u (0x % X)»), dwProcessId, dwProcessId);



 // try to find the corresponding item in the list

int nCount = wndView. GetItemCount();

for (nItem = 0; nItem < nCount; nItem++)

{

pData = (CItemData *) wndView. GetItemData(nItem);

if (pData->dwProcessId == dwProcessId &&

pData->dwWowTaskId == 0 &&

pData->strName == pszName)

{

pData->bDelete = FALSE;

bFound = TRUE;

break;

}

}

if (! bFound)

{

pData = new CItemData (dwProcessId, DWORD(0));



nItem = wndView. InsertItem (LVIF_TEXT|LVIF_PARAM, nCount, szID,

0, 0, -1, (LPARAM) pData);

if (nItem == -1)

{

delete pData;

return TRUE;

}



TCHAR szUnavailable[256];

if (pszName == NULL)

{

AfxLoadString (IDS_NAME_UNAVAILABLE, szUnavailable, countof(szUnavailable));

pszName = szUnavailable;

}

pData->strName = pszName;

wndView. SetItemText (nItem, 1, pszName);

wndView. SetItemText (nItem, 2, CreateTime_str);

}

if (pFrame->m_bShow16Bit &&

(lstrcmpi (pszName, _T («NTVDM.EXE»)) == 0 ||

lstrcmpi (pszName, _T («NTVDM»)) == 0))

{

_ASSERTE (pFrame->m_pfnVDMEnumTaskWOWEx!= NULL);

pFrame->m_dwProcessId = dwProcessId;

}

return TRUE;

}

void CMainFrame: OnAbout()

{

DestroyWindow();

}