Міністерство освіти і науки, молоді та спорту України
Національний університет «Львівська політехніка»
Кафедра ЕОМ
Курсова Робота
з предмету «Системне програмне забезпечення»
на тему «Розробка профайлера для ОС Windows»
АНОТАЦІЯ
Метою даної курсової роботи є дослідження методів профілювання і створення профайлера для для операційної системи Windows, що аналізує роботу процесів в ОП. Даний профайлер призначений для статистичного збору інформації про під час виконання процесу.
Також в даній роботі розглянуті питання вибору оптимального методу профілювання і обґрунтування методу використаного в даній роботі.
Проведене тестування роботи програми і отримано звіт про роботу процесів локального комп’ютера.
ЗМІСТ
ВСТУП 4
1. Огляд поставленої задачі 5
1.1 Аналіз важливості використання профайлерів 5
1.2 Аналіз існуючих методів та засобів профілювання 5
1.3 Поняття процесів та потоків 6
2. Аналіз завдання 7
2.1 Вибір мови програмування та середовища розробки 7
2.2 Вибір та розробка структур даних 7
2.3 Функції Win API та функції користувача 9
3. Розробка компонент програмної реалізації 11
3.1 Опис алгоритму роботи програми 11
3.2 Розробка інтерфейсу користувача 15
4. Використання профайлера 18
4.1 Інсрукції користувача 18
4.2 Результати тестування 18
ВИСНОВКИ 20
СПИСОК ЛІТЕРАТУРИ 21
ДОДАТОК 1 Завдання на проектування 22
ДОДАТОК 2 Схема загальної структури програми 23
ДОДАТОК 3 Код програми 24
ВСТУП
Профілювання є важливим для ефективної розробки програмних продуктів. Головною метою профілювання (аналізу продуктивності) - визначити які частини програми оптимізувати, для покращення використання пам'яті або швидкодії. Профілювання є джерелом інформації про функціонування процесів операційної системи і розподіл ресурсів комп’ютера між процесами. Використання профайлерів життєво необхідне в процесі планування продуктивності.
Інструменти програмного аналізу критично важливі для розуміння поведінки програми. Комп'ютерним архітекторам потрібні такі інструменти, щоб оцінити, як програми виконуватимуться на новій архітектурі. Авторам програмного забезпечення потрібні інструменти, аби проаналізувати їх програми і ідентифікувати критичні частини коду. Автори компіляторів часто використовують такі інструменти, аби з'ясувати, як добре виконується їх планування інструкцій або алгоритм передбачення, що відлагоджується.
1. Огляд поставленої задачі
1.1 Аналіз важливості використання профайлерів
Аналіз продуктивності, або профілювання при розробці програмного забезпечення це – дослідження поведінки програми, використовуючи інформацію, зібрану в результаті дії програми (тобто форма динамічного аналізу програми, в протилежність статичному аналізу коду). Звичайна мета аналізу продуктивності - визначити які частини програми оптимізувати, для покращення використання пам'яті або швидкості.
Для послідовних програм, профайлу зазвичай досить, але проблеми продуктивності в паралельних програмах (очікуючи повідомлень або проблем синхронізації) часто залежать від взаємозв'язку часу подій, тому вимагають повного запису, щоб зрозуміти проблему.
1.2 Аналіз існуючих методів та засобів профілювання
На даний момент існує доволі широкий спектр методів та засобів побудови профайлерів. Існують такі типи профайлерів:
За способом виводу:
Профайлери, які виводять список подій;
Профайлери, що будують граф викликів;
За способом збору даних:
Базуються, на подіях певної мови програмування. Мови Java, .NET, Python, Ruby мають вбудовані засоби профілювання;
Статистичні – здійснюють вибірку даних через певний інтервал. Наприклад: AMD Code Analyst, Apple Inc. Shark, Intel VTune;
Інтерпретаційні – вибірка даних здійснюється у потрібному місці коду
Інструментальні – модифікують програму при виконанні для збору даних. Наприклад gprof, Dynlnst, Valgrind, ATOM;
Супервізори – по-суті віртуальні машини, які імітують виконання програм і виконують профілювання: SIMMON, OLIVER.
Очевидно, що таке велике різноманіття типів профайлерів диктоване необхідністю комплексного підходу до оцінки і підвищення продуктивності програмних продуктів.
1.3 Поняття процесів та потоків
Під процесом розуміють абстракцію ОС, яка об'єднує все необхідне для виконання однієї програми в певний момент часу, тобто процес представляє собою певний об’єкт ОС. Процесом називають сукупність одного або декількох потоків і захищеного адресного простору, у якому ці потоки виконуються.
Потоком (потік керування, нитка, thread) називають набір послідовно виконуваних команд процесора, які використовують загальний адресний простір процесу. Оскільки в системі може одночасно бути багато потоків, завданням ОС є організація перемикання процесора між ними і планування їхнього виконання. У багатопроцесорних системах код окремих потоків може виконуватися на окремих процесорах.
У більшості сучасних ОС (таких, як лінія Windows XP, сучасні версії UNIX) може бути багато процесів, а в адресному просторі кожного процесу – багато потоків. Ці системи підтримують багато-потоковість або реалізують модель потоків. Процес у такій системі називають багато-потоковим процесом.
2. Аналіз завдання
2.1 Вибір мови програмування та середовища розробки
Для реалізації курсової роботи була вибрана мова програмування С++. Вона найкраще підходить для вирішення системних задач для операційної системи Windows, оскільки забезпечує високу швидкодію і ступінь взаємодії з операційною системою. С++ підтримує процедурне, об’єктно-орієнтоване, узагальнене програмування.
Середовище програмування – Microsoft Visual Studio 2010. Тип проекту CLR Windows Forms Application – забезпечує підтримку бібліотек .NET, які в даній роботі викристовуються для побудови графічного інтерфейсу. Бібліотеки .NET надають величезний набір класів «на всі випадки життя»: списки, масиви, графічний інтерфейс і т. д.
.NET — крос - платформена технологія, в цей час існує реалізація для платформи Microsoft Windows, FreeBSD (від Microsoft) і варіант технології для ОС Linux в проекті Mono (в рамках угоди між Microsoft та Novell), DotGNU.
Тобто тут поєднується проста, швидка побудова графічного інтерфейсу і потужні системні можливості С++. Ці фактори дозволять створити програмне забезпечення для найбільш різноманітних потреб, хоча і потребують додаткового встановлення бібліотек .NET framework.
2.2 Вибір та розробка структур даних
Для реалізації курсової роботи я використав класи, списки, структури, функції. Класами представлено графічний інтерфейс, профілюючий потік, клас обробки подій профілювання.
Клас Form1 – успадковується від класу Form .NET і реалізує головне вікно програми. В конструкторі міститься виклик методу, що виконує додавання користувацьких елементів інтерфейсу в форму і їх початкову ініціалізацію, також вона містить дочірні форми ChooseProc для вибору процесу зі списку існуючих та StartProc для запуску нового процесу на виконання. Також тут міститься області для виводу графіків профілювання.
PicProc – область для виведення графіків використання процесорного часу, що використовується системою та процесом, що профілюється.
PicMem – область для виведення графіків використання пам’яті системою та процесом зокрема
lstEvents – список подій профілювання. Тут відображається інформація, що отримується за допомою класу Debuger та функцій Debug API зокрема.
DebugEvents, PerfInf – класи потоків .NET відповідають дочірнім потокам, призначення яких відслідкувування подій профілювання та збір статистичної інформації про роботу системи та процесу, що профілюється
Клас Debuger призначений для обробки подій профілювання і підключення, відключення та запуск процесу для профілювання. Також у ньому виконується головний цикл обробки подій профілювання. Він забезчує:
Запуск процесу на виконання з параметрами, підключення процесу по ID
Обробку подій профілювання і запис результатів в буфер
Коректне відключення процесу, що профілюється
Виконання головного циклу відслідковування подій в процесі, що профілюється
Клас BufferInfo призначений для взаємодії головного потоку програми та потоків, що відповідають за збір даних про роботу процесу. Також у ньому знаходяться буфери обміну куди допоміжні потоки записують інформацію про роботу процесу, що профілюється. Він забезчує:
взаємодію між потоками;
збереження історії про роботу процесу, що профілюється
інші додаткові налаштування
Існують також допоміжні функції, що забезпечують надання привілегій профайлеру, а також запуск потоку обробки подій профілювання, отримання інформації про стан системи.
Класи, що забезпечують користувацький інтерфейс базуються на основі класів .NET framework. Їх задача представити інформацію профілювання в зручному для користувача вигляді.
2.3 Функції Win API та функції користувача
Windows API (Application Programming Interfaces) — загальне найменування для цілого набору базових функцій інтерфейсів програмування застосунків операційних систем сімейств Windows корпорації Майкрософт. Є найпрямішим способом взаємодії застосунків з Windows. Для створення програм, що використовують Windows API, Майкрософт випускає SDK, який називається Platform SDK і містить документацію, набір бібліотек, утиліт і інших інструментальних засобів.
Одним з методів побудови профайлерів є використання вбудованих засобів операйної системи, що представляють набір функцій інтерфейсу прикладного рівня для профілювання роботи процесів операційної системи. В операційній системі Windows для цього існує набір функцій Debug API. В даній роботі вони призначені для збору статистичної інформації про роботу процесу, проте ними можна здійснювати не тільки статистичний збір інформації, але й змінювати її контекст. Тобто, наприклад, ними можливо замінити адреси модулів процесу при їх підключенні.
Дві функції, WaitForDebugEvent і ContinueDebugEvent, використовуються спеціально для обробки подій в процесі, що профілюють. Ці функції дозволяють профайлеру чекати на появу подій, зупиняти виконання процесу, який профілюють, обробляти кожну конкретну подію, і при закінченні обробки продовжувати виконання процесу. Для того, щоб під’єднати процес до профайлера використовується функція DebugActiveProcess. Для того щоб від’єднати процес використовується функція DebugActiveProcessStop.
Для збору інформації про використання процесорного часу та пам’яті використовуються такі функції Win API:
GlobalMemoryStatusEx, GetProcessMemoryInfo – ці функції повертають інформацію необхідну для обчислення використання пам’яті системою і процесом зокрема;
GetSystemTimes, GetProcessTimes – функції, які повертають дані необхідні для обчислення використання ЦП;
Для надання привілегій процесу використовується функція EnablePrivileges, яка дозволяє йому робити профілювання ситемних процесів.
StartEx, AttchEx – функції відповідають за запуск обробки подій профілювання;
TakeInf – функція відповідає за знаття показників використання ЦП та пам’яті системою та процесом, що профілюється.
3. Розробка компонент програмної реалізації
Програма «Профайлер» це багатомодульна програма оформлена у вигляді CLR C++ проекту. При проектуванні було розділено на модулі (класи) логічні та графічні компоненти. Використано об’єктно-орієнтований та функціональний підхід побудови проекту. Проект складається з *.срр та *.h файлів, тому модуль може складатися з кількох файлів водночас.
Програмний проект побудований у вигляді багато-потокової програми. Спрощена структура проекту зображена на Рис. 3.1. Головний потік відповідає за побудову графічного інтерфейсу і команди користувача. Допоміжний потік DebugEvents відслідковує події профілювання і відповідно обробляє їх. Інший допоміжний потік PerInf вимірює використання процесорного часу та пам’яті процесом та системою через певний інтервал. Обмін даними між допоміжними потоками та головним потоком відбувається через буфер (клас який містить список інформації про події профілювання, використання ЦП та пам’яті, команди керування допоміжними потоками).
Рис 3.1 Спрощена структура програми.
Детальніша структура проекту подана в додатках (Додаток 2. Схема загальної структури програми)
3.1 Опис алгоритму роботи програми
З рис. 3.1 програму можна поділити на три частини. Тобто слід конкретно описати роботу потоків програми і механізм взаємодії між ними.
Потік DebugEvents
Рис 3.2 Алгоритм роботи потоку DebugEvents
На рис. 3.2 зображено алгоритм виконання потоку DebugEvents. Запуск потоку може відбуватися двома способами:
Потік запускає новий процес і відразу підключає його.
Потік підключає вже запущений процес.
Після того, як процес підключено починається головний цикл потоку, в якому і відбувається обробка подій профілювання. Функція WaitForDebugEvent чекає настання ооднієї з нижчеперечислених подій. Очікування буде тривати доти доки не настане подія, або не мине певний час(тайм-аут). При виникненні події всі потоки процесу, що профілюється зупиняються. Далі буде запущено відповідну функцію-обробник. Насамкінець функція ContinueDebugEvent продовжить виконання зупиненого процесу. При закінченні тайм-ауту відбувається перехід на початок головного циклу і перевірка чи немає команди завершення потоку. Це зроблено для того, щоб потік не очікував на подію вічно і міг коректно завершитись. В даному потоці забезпечується перехоплення таких подій:
CREATE_PROCESS_DEBUG_EVENT виникає перед ініціалізацією процесу, який ми відслідковуємо, або при підключенні до нього. Дана подія забезпечує вивід інформації про процес та головний потік процесу;
EXIT_PROCESS_DEBUG_EVENT виникає при завершенні процесу. Забезпечує інформацію про процес та код завершення процесу;
CREATE_THREAD_DEBUG_EVENT виникає при створенні потоку в процесі. Дає інформацію про новий потік, а також інформацію про батьківський потік;
EXIT_THREAD_DEBUG_EVENT виникає при завершенні потоку в процесі. Дає код завершення потоку;
LOAD_DLL_DEBUG_EVENT виникає коли процес підключає модуль до свого адресного простору. Дає інформацію про розміщення модуля в адресному просторі процесу;
UNLOAD_DLL_DEBUG_EVENT виникає, коли процес від’єднує модуль від свого адресного простору;
EXCEPTION_DEBUG_EVENT виникає при виключній ситуації в процесі.
Дані про події заносяться в буфер (додаток 2) необхідний для того, щоб виводити інформацію у вигляді графіків.
Потік PerfInf
Рис 3.3 Алгоритм роботи потоку PerfInf
На рис. 3.3 зображено алгоритм виконання потоку PerfInf відповідального за збір інформації про використання ЦП та пам’яті. Основою алгоритму є зчитування даних в циклі, що виконується доки є змінна керування рівна true. В головному циклі потік зчитує інформацію про використання системних ресурсів (памяті та процесорного часу). Далі обчислюється використання пам’яті та процесорного часу системою та процесом зокрема. Ці дані заносяться в буфер ( додаток 2) необхідний для того, щоб виводити інформацію у вигляді графіків. Після виконання обчислень потік зупиняється на певний інтервал і продовжує роботу для оновлених даних про процес.
Обчислення даних використання системних ресурсів відбувається за допомогою наступних функцій і формул.
GlobalMemoryStatusEx – повертає структуру MEMORYSTATUSEX з якої беремо необхідну інформацію для обчислення проценту використання пам’яті.
Процент використання=
Загальна пам’ять−Доступна пам’ять
Загальна пам’ять
∙100% ;
GetProcessMemoryInfo – ця функція повертає структуру PPROCESS_MEMORY_COUNTERS, що містить інформацію про використання пам’яті конкретним процесом. Процент використання обчислюється з наступною формулою.
Процент використання=
Пам’ять зайнята процесом
Загальна пам’ять
∙100% ;
GetSystemTimes – повертає значення типу LPFILETIME, які визначають час роботи системи в режимі ядра, в режимі користувача та час простою.
час користувача =Час режиму користувача−Останній час режиму користувача ;
час ядра =Час режиму ядра−Останній час режиму ядра ;
час простою =Час простою системи−Останній час простою системи ;
Процент використання=
час користувача + часядра − час простою
час ядра + час користувача
∙100% ;
GetProcessTimes – повертає значення типу LPFILETIME, які визначають час роботи системи в режимі ядра та в режимі користувача конкретного процесу.
час процесу =Час режиму користувача процесу+Час режиму ядра процесу;
Процент використання=
час процесу – попередній час процесу
час ядра + час користувача
∙100% ;
3.2 Розробка інтерфейсу користувача
Головне вікно профайлер складається з головного меню (№ 1) та чотирьох додаткових панелей.
Панель № 2 – відображення загальної інформації про процес.
Панель № 3 – відображення інформації про події профілювання.
Панель № 4 – відображення нрафіків використання процесорного часу.
Панель № 5 – відображення нрафіків використання пам’яті.
/
Рис 3.4 Головне вікно профайлера
Голвне меню профайлера (рис. 3.5) складається з трьох пунктів. Можна профілювати існуючий процес, запустити новий чи вийти з програми.
/
Рис 3.5 Головне меню профайлера
/
Рис 3.6 Форма вибору процесу для профілювання.
На рис. 3.6 зображена форма вибору процесу для профілювання зі списку запущених. Вибір процесу здійснюються подвійним кліком миші. Можна оновити список процесів відповідною кнопкою. Вибравши процес натискаємо кнопку ОК.
/
Рис 3.7 Вікно запуску нового процесу
На рис. 3.7 зображено вікно запуску нового процесу. Для зпуску процесу не обхідно ввести ім’я виконавчого файлу та параметри запуску. Ім’я виконавчого файлу можна вибрати кнопкою огляд... Заповнивши необхідні поля тиснемо кнопку ОК.
Після вибору чи запуску процесу результати профілювання відображатимуться в головному вікні програми.
4.Використання профайлера
4.1 Інсрукції користувачу
Проект був розроблений в середовищі Microsoft Visual Studio з використанням бібліотек .NET
Для використання даного профайлера у користувача на локальному комп’ютері повинна бути встановлена бібліотека .net framework 4.0.
Також користувачу потрібно скопіювати файл kursec.exe на свій локальний комп’ютер.
Профайлер використовує специфічні АРІ функції, тому він працюватиме на операційній системі Windows Xp SP1 і пізнішій.
4.2 Результати тестування
Нехай нам потрібно проаналізувати процес explorer. На рисунках 4.1, 4.2 показано послідовність старту профілювання, можна вибрати існуючий процес рис. 4.3, або запустити новий з потрібними параметрами рис. 4.2.
/
Рис 4.1 Головне вікно програми
/
Рис 4.2 Вікно вибору процесу
Після запуску події (рис. 4.4) профілювання відображаються в лівій частині клієнтської області програми. В правій верхній частині відображається поточна інформація про процес. В нижній правій частині відображається графік використання оперативної пам’яті системою (оранжевий графік) і процесом (голубий графік).
/
Рис 4.4 Результати профілювання
ВИСНОВКИ
В процесі виконання курсової роботи було виконано наступне:
Ознайомлення з різноманітними методами та засобами профілювання. Дослідження вбудованих засобів профілювання в операційної системи Windows, ознайомлення з функціями ОС Windows для зняття показників продуктивності
Cтворено та протестовано профайлер операційної системи Windows призначений для дослідження поведінки процесів.
Дана курсова робота носить навчальний характер, тому багато можливих функцій не було реалізовано, як наприклад точки переривання, можливість зміни контексту подій профілювання. Проте дана програма наглядно демонструє використання функцій профілювання, а також має простий та зрозумілий користувацький інтерфейс.
СПИСОК ЛІТЕРАТУРИ
Randy Kath – «The Debugging Application Programming Interface» [Електронний ресурс]: Microsoft Developer Network Technology Group – 1992 р. Режим доступу: http://msdn.microsoft.com/en-us/library/ms809754.aspx - Назва з екрану.
Xu, Jack. Practical C# Charts and Graphics – Advanced Chart and Graphics Programming for Real-World .NET Applications / Jack Xu. – 1st ed. p.cm. ISBN 978-0-9793725-0-6
Гордеев А. В., Молчанов А. Ю., Системное программное обеспечение. – СПб.: Питер, 2001. – 736с.
Bock Jason, «CIL Programming: Under the Hood of .NET», 2002, Apress.
Шефферд Дж. Программирование на Microsoft Visual C++ .NET – Русская редакция; СПБ: Питер 2007 – 928 с.
Шилдт Г. - C# 4.0 полное руководство – 2011 р.
ДОДАТОК 1. Завдання на проектування.
Дослідити виконання процесів в ОС Windows.
Розробити профайлер для ОС Windows, що аналізує системну інформацію (детально), зокрема процеси.
Профайлер призначений для аналізу поведінки процесів в ОС Windows.
Профайлер повинен надавати дані про використання процесора та оперативної пам’яті в реальному часі за допомогою графіків.
ДОДАТОК 2. Схема загальної структури програми
ДОДАТОК 3. Код програми
Файл stdafx.h
// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
#pragma once
// TODO: reference additional headers your program requires here
#ifndef stdafx_H
#define stdafx_H
#include <Windows.h>
#include <stdio.h>
#include <tchar.h>
#include <strsafe.h>
#include <psapi.h>
#include <iostream>
#include <string.h>
#include <dbghelp.h>
#include <crtdbg.h>
#include <stdlib.h>
#include <process.h>
#include <map>
#include <list>
#include <deque>
#pragma comment(lib, "psapi")
#pragma comment(lib, "advapi32")
#define BUFSIZE 512
using namespace std;
typedef std::basic_string<TCHAR> TString;
wchar_t* CMS(System::String^ managedString);
class BufferInfo
{
public:
BufferInfo()
{
IsRunning = false;
TimeOut = 30;
Count = 300;
EventStrings = new list<TString>();
CPUglobalUsage = new deque<double>();
CPUprocUsage = new deque<double>();
MemoryGlobalUsage = new deque<double>();
MemoryProcUsage = new deque<double>();
}
DWORD ProcId;
TString FileName;
TString CmdLine;
bool IsRunning;
list<TString>* EventStrings;
deque<double>* CPUglobalUsage;
deque<double>* CPUprocUsage;
deque<double>* MemoryGlobalUsage;
deque<double>* MemoryProcUsage;
int TimeOut;
int Count;
};
#endif
Файл stdafx.cpp
// stdafx.cpp : source file that includes just the standard includes
// kursec.pch will be the pre-compiled header
// stdafx.obj will contain the pre-compiled type information
#include "stdafx.h"
#include "Debugger.h"
BufferInfo msg ;
wchar_t* CMS(System::String^ managedString)
{
wchar_t* str;
System::Text::StringBuilder^ bld = gcnew System::Text::StringBuilder(managedString);
wchar_t* outString = new wchar_t[512];
int i;
for( i = 0; i < bld->Length; i++)
outString[i] = (wchar_t)bld[i];
outString[i] = 0;
return outString;
}
Файл Debugger.h
#include "stdafx.h"
class CDebug
{
public:
CDebug();
~CDebug();
void MainLoop();
bool StartProcess(const TString& FileName,const TString& CmdLine);
bool AttachProcess(DWORD ProcId);
bool GetFileNameFromHandle(HANDLE hFile, TString& FileName);
list<TString> m_Buffer;
protected:
virtual void OnCreateThreadEvent(DEBUG_EVENT DebugEvent);
virtual void OnExitThreadEvent(DEBUG_EVENT DebugEvent);
virtual void OnLoadModuleEvent(DEBUG_EVENT DebugEvent);
virtual void OnUnloadModuleEvent(DEBUG_EVENT DebugEvent);
virtual void OnCreateProcessEvent(DEBUG_EVENT DebugEvent);
virtual void OnExitProcessEvent(DEBUG_EVENT DebugEvent);
virtual void OnExceptionEvent(DEBUG_EVENT DebugEvent);
HANDLE m_hProcess;
std::map<LPVOID, TString> m_Modules;
};
Файл Debugger.cpp
#include "stdafx.h"
#include "Debugger.h"
extern BufferInfo msg;
void CDebug::OnLoadModuleEvent(DEBUG_EVENT DebugEvent)
{
TString ModuleName = L"<невідомий>";
GetFileNameFromHandle(DebugEvent.u.LoadDll.hFile,ModuleName);
m_Modules[DebugEvent.u.LoadDll.lpBaseOfDll] = ModuleName;
msg.EventStrings->push_front(CMS(System::String::Format("Завантажено модуль: 0x{0:X} файл: {1}",
(unsigned)DebugEvent.u.LoadDll.lpBaseOfDll,
gcnew System::String(ModuleName.c_str()))));
}
void CDebug::OnUnloadModuleEvent(DEBUG_EVENT DebugEvent)
{
TString ModuleName = m_Modules[DebugEvent.u.UnloadDll.lpBaseOfDll];
msg.EventStrings->push_front(CMS(System::String::Format("Вивантажено модуль: 0x{0,-8:X} файл: {1}",
(unsigned)DebugEvent.u.LoadDll.lpBaseOfDll,
gcnew System::String(ModuleName.c_str()))));
m_Modules[DebugEvent.u.UnloadDll.lpBaseOfDll].erase();
}
bool CDebug::AttachProcess(DWORD ProcId)
{
DebugActiveProcess( ProcId ) ;
m_hProcess = OpenProcess(PROCESS_ALL_ACCESS,false,ProcId);
if(m_hProcess == INVALID_HANDLE_VALUE || m_hProcess == NULL)
{
return false;
}
return true;
}
bool CDebug::StartProcess(const TString& FileName, const TString& CmdLine)
{
LPCTSTR lpFileName = FileName.empty() ? 0 : FileName.c_str();
LPTSTR lpCmdLine = 0;
bool IsOk;
if( CmdLine.length() > 0 )
{
lpCmdLine = (LPTSTR)_alloca( ( CmdLine.length() + 1 ) * sizeof(TCHAR) );
_tcscpy( lpCmdLine, CmdLine.c_str() );
}
STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi = { NULL, NULL, 0, 0 };
if( !CreateProcess( lpFileName, lpCmdLine, NULL, NULL, FALSE,
CREATE_NEW_CONSOLE | DEBUG_ONLY_THIS_PROCESS , NULL, NULL, &si, &pi ) )
{
return false;
}
msg.ProcId = pi.dwProcessId;
IsOk = AttachProcess(pi.dwProcessId);
if( pi.hProcess != NULL )
CloseHandle( pi.hProcess );
if( pi.hThread != NULL )
CloseHandle( pi.hThread );
return IsOk;
}
CDebug::CDebug()
{}
CDebug::~CDebug()
{
if (m_hProcess != NULL && m_hProcess != INVALID_HANDLE_VALUE)
{
CloseHandle(m_hProcess);
}
}
void CDebug::OnCreateThreadEvent(DEBUG_EVENT DebugEvent)
{
msg.EventStrings->push_front(CMS(System::String::Format("Створено потік: 0x{0:X} адреса:0x{1:X}",
(unsigned)GetThreadId(DebugEvent.u.CreateThread.hThread),
(unsigned)DebugEvent.u.CreateThread.lpStartAddress)->PadRight(8, '0')));
}
void CDebug::OnExitThreadEvent(DEBUG_EVENT DebugEvent)
{
msg.EventStrings->push_front(CMS(System::String::Format("Завершення потоку: 0x{0:X} код завершення: 0x{1:X} ({1})",
(unsigned)DebugEvent.dwThreadId,
(unsigned)DebugEvent.u.ExitThread.dwExitCode)->PadLeft(8, '0')));
}
void CDebug::OnCreateProcessEvent(DEBUG_EVENT DebugEvent)
{
msg.EventStrings->push_front(CMS(System::String::Format("Створено процес Id: 0x{0:X} ({0})",
(unsigned)DebugEvent.dwProcessId)));
}
void CDebug::OnExitProcessEvent(DEBUG_EVENT DebugEvent)
{
msg.EventStrings->push_front(CMS(System::String::Format("Завершення процесу id: 0x{0:X} ({0}) код завершення: 0x{1:X} ({1})",
(unsigned)DebugEvent.dwProcessId,
(unsigned)DebugEvent.u.ExitProcess.dwExitCode)));
}
void CDebug::OnExceptionEvent(DEBUG_EVENT DebugEvent)
{
EXCEPTION_DEBUG_INFO Info = DebugEvent.u.Exception;
msg.EventStrings->push_front(CMS(System::String::Format("{0} виключення в потоці: 0x{1:X}",
Info.dwFirstChance ? "First-chance" : "Second-chance",
(unsigned)DebugEvent.dwThreadId)));
}
bool CDebug::GetFileNameFromHandle(HANDLE hFile, TString& FileName)
{
BOOL bSuccess = FALSE;
TCHAR pszFilename[MAX_PATH+1];
HANDLE hFileMap;
FileName = L"";
// Get the file size.
DWORD dwFileSizeHi = 0;
DWORD dwFileSizeLo = GetFileSize(hFile, &dwFileSizeHi);
if( dwFileSizeLo == 0 && dwFileSizeHi == 0 )
{
return FALSE;
}
// Create a file mapping object.
hFileMap = CreateFileMapping(hFile,
NULL,
PAGE_READONLY,
0,
1,
NULL);
if (hFileMap)
{
// Create a file mapping to get the file name.
void* pMem = MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 1);
if (pMem)
{
if (GetMappedFileName (GetCurrentProcess(),
pMem,
pszFilename,
MAX_PATH))
{
// Translate path with device name to drive letters.
TCHAR szTemp[BUFSIZE];
szTemp[0] = '\0';
if (GetLogicalDriveStrings(BUFSIZE-1, szTemp))
{
TCHAR szName[MAX_PATH];
TCHAR szDrive[3] = TEXT(" :");
BOOL bFound = FALSE;
TCHAR* p = szTemp;
do
{
// Copy the drive letter to the template string
*szDrive = *p;
// Look up each device name
if (QueryDosDevice(szDrive, szName, MAX_PATH))
{
size_t uNameLen = _tcslen(szName);
if (uNameLen < MAX_PATH)
{
bFound = _tcsnicmp(pszFilename,
szName,
uNameLen) == 0
&& *(pszFilename + uNameLen) == _T('\\');
if (bFound)
{
// Reconstruct pszFilename using szTempFile
// Replace device path with DOS path
TCHAR szTempFile[MAX_PATH];
//wsprintf(szTempFile,L"%s%S",szDrive,pszFilename + uNameLen);
int i = 0;
for(i = 0; i < MAX_PATH && szDrive[i] != 0; i++)
{
szTempFile[i] = szDrive[i];
}
//i = 0;
for(int j = 0; j < MAX_PATH && pszFilename[j + uNameLen] != 0;j++, i++)
{