Форум системного администратора

Объявление

Форум системного администратора рад приветствовать Вас. Наша основная цель заключается в качественном обмене опытом в сфере высоких технологий. Спешите зарегистрироваться и вступить в наше сообщество IT-специалистов. Администрация сайта была бы очень признательна, если бы вы заходили на рекламу: вам это ничего не стоит, а нам хоть какие-то начисления:)
Администрация.

Информация о пользователе

Привет, Гость! Войдите или зарегистрируйтесь.


Вы здесь » Форум системного администратора » С++ » Статьи про С++


Статьи про С++

Сообщений 1 страница 5 из 5

1

Обзор C++Builder 2007
Судьба продуктов семейства C++Builder – всегда оставаться в тени своего «старшего брата», ориентированного на Object Pascal. Среда разработки CodeGear C++Builder (C++Builder 2007) была представлена общественности три месяца спустя после выхода Delphi 2007, и список внесенных в нее изменений почти совпадает со списком новшеств последней версии Delphi. Впрочем, язык C++ (который, в отличие от Object Pascal, не является почти безраздельной вотчиной Borland/CodeGear) оказывает и собственное влияние на эволюцию C++ IDE. Таким образом, все новые функции и возможности, которые мы встретим в C++Builder 2007, можно разделить на две категории – новшества, унаследованные от Delphi 2007, и новшества, связанные со спецификой C++.

http://symmetrica.net/uploads/images/cgcb0.jpg

На первый взгляд
Заставку Delphi 2007 украшает безмятежный лик Аполлона Дельфийского – символ Delphi на протяжении многих лет. Символом C++Builder долгое время был строительный кран, а теперь на заставке программы изображена голова Юпитера, что, судя по всему, отражает мысль разработчиков о сходстве, а, возможно, и превосходстве C++Builder над Delphi. В обзорах Delphi 2007 некоторые писали, что новая среда загружается быстрее предшественницы. Ничего подобного я про C++Builder 2007 сказать не могу. Среда C++Builder 2007, конечно, загружается быстрее, чем BDS 2006, но не быстрее (или, по крайней мере, не на много быстрее), чем запущенная отдельно C++Builder 2006. Интерфейс оболочки IDE выполнен в том же стиле, в котором он выполняется со времен Delphi 8, а вот функциональная организация интерфейса претерпела небольшие изменения.

Много численные элементы окна Project Options сгруппированы более рационально. Например, все опции, связанные с совместимостью с другими версиями и средами разработки на C++, теперь объединены в две группы настроек проекта: General Compatibility и C++ Compatibility. Появились и новые окна настроек C++, о которых будет сказано ниже. Симпатичное окошко File Browser (команда View|FileBorowser), реализованное ранее в Delphi 2007, позволяет выполнять различные операции с файлами, не покидая оболочку IDE.

http://symmetrica.net/uploads/images/cgcb1.jpg

Новшества, унаследованные от Delphi 2007
Как и Delphi 2007, новая среда C++Builder поддерживает систему MSBuild, грозящую стать стандартным средством сборки на платформе Microsoft Windows. Интеграция поддержки MSBuild, в свою очередь, привела к необходимости переработать многие компоненты системы сборки C++Builder 2007. Файлы проектов теперь получили расширение cbproj, а их новый XML-синтаксис соответствует формату MSBuild. Попробуем собрать простой проект с помощью MSBuild. Создайте проект приложения C++Builder и сохраните его на диске. Если вы просто откроете окно консоли и наберете в ней

msbuild

скорее всего, ничего не случится. Хотя утилита MSBuild уже установлена в вашей системе, переменные окружения, необходимые для ее запуска, не настроены. Чтобы не настраивать их вручную, воспользуйтесь консолью RAD Studio Command Prompt, в которой все необходимые переменные уже настроены. Ярлык RAD Studio Command Prompt расположен в группе CodeGear RAD Studio меню «Все программы» меню кнопки «Пуск». Запустите  консоль RAD Studio и скомандуйте:

msbuild myproject.cbproj

где myproject.cbproj – имя проекта C++Builder 2007.

В результате экран консоли заполнится сообщениями, как это бывает при сборке проектов с помощью make-файлов и, если все прошло удачно, в конце ваша программа будет собрана.

Разумеется, ничто не мешает вам собирать проекты C++Builder по старинке, с помощью команды меню Project|Build.

Как и Delphi 2007, новый C++Builder позволяет создавать «события сборки» - наборы команд, которые могут быть выполнены на определенных этапах сборки (раньше можно было создавать специальные наборы команд только для выполнения  перед началом сборки и после ее окончания).

Вслед за Delphi в C++Builder 2007 обновилась подсистема dbExpress (которая теперь именуется DBX framework). Все драйверы DBX написаны на Delphi и эта же среда может использоваться для написания новых драйверов. Новая модель драйверов DBX позволяет создавать делегированные драйверы, которые играют роль прослойки между приложением и драйвером BDX. Делегированные драйверы могут использоваться для отладки и мониторинга приложений баз данных. Их также можно задействовать  для реализации дополнительной функциональности в BDX. Одно из применений делегированных драйверов – создание потокобезопасных интерфейсов BDX, в которых делегированный драйвер берет на себя функции синхронизации обращений из разных потоков. Наконец-то была реализована поддержка Unicode в драйверах для Oracle, Interbase, и MySQL.

По-моему, ни один новый релиз Delphi/Borland C++Builder не обходился без добавления новых компонентов VCL. Не стал исключением и CodeGear C++Builder 2007. В палитру VCL были добавлены компоненты, реализующие диалоговые окна Windows Vista - TFileOpenDialog, TFileSaveDialog, TTaskDialog (в общей сложности в VCL добавлено 18 новых классов). Значительно усовершенствован интерфейс менеджера памяти (для работы с ним добавлено десять функций и переменных).

Отметим еще одну маленькую, но приятную мелочь – в окне Project Manager теперь можно выбрать сразу несколько файлов для дальнейших операций над ними.

Наконец-то вариант среды разработки для C++ обзавелся полноценными средствами блочного тестирования (Unit testing), которые ранее были реализованы в Delphi. В C++ IDE встроена версия Borland Together с ограниченной функциональностью (вариант Together для C++Builder 2007 позволяет создавать диаграммы кода и генерировать документацию).

Собственные новшества C++Builder 2007
Как уже отмечалось, в новой версии C++Builder значительно усовершенствована система сборки. Однако новшества этой системы в C++Builder не ограничиваются тем, что было реализовано в Delphi. У среды C++ всегда была своя специфика механизма сборки, связанная, в частности, с конфигурациями. Помимо стандартных конфигураций Debug и Release в C++Builder 2007 введена базовая конфигурация сборки Base (нечто подобное давно уже существует в Microsoft Visual C++). Базовая конфигурация содержит настройки проекта, которые наследуются по умолчанию всеми создаваемыми конфигурациями (в новых конфигурациях унаследованные настройки, естественно, могут быть изменены). Специальный флажок Merge  позволяет использовать в текущей конфигурации настройки из базовой конфигурации, не меняя самих текущих настроек. Как и в Delphi 2007, в C++Builder 2007 появилась возможность создавать именованные наборы настроек (named option sets). Именованные наборы настроек создаются независимо от проектов и сохраняются в специальных файлах. Создав именованный набор настроек, вы можете затем применить его к любой конфигурации настроек любого проекта.

В соответствии с требованиями системы MSBuild порядок сборки проекта теперь определяется расширениями файлов (раньше он определялся структурой проекта). Согласно новым правилам сначала компилируются файлы .pas, затем файлы .c/.cpp, затем файлы .asm, и, наконец, файлы .rc. Однако порядок расположения файлов в каталогах также влияет на порядок сборки (сначала собираются все файлы в одном каталоге, затем – в другом, и т.д.). Для того чтобы совместить старое и новое, разработчики из CodeGear пошли на оригинальный шаг: файлы проекта можно группировать в виртуальные каталоги. Фактически виртуальные каталоги позволяют определять произвольный порядок сборки файлов, не нарушая ни физической структуры проекта, ни правил MSBuild.

Расширены возможности Web-служб C++Builder 2007, в частности интерфейсы Web-служб могут теперь содержать необязательные элементы.

Помимо всего прочего C++Builder 2007 может компилировать пакеты времени разработки, содержащие Delphi-код (аналогичная возможность для пакетов времени выполнения, была, разумеется, урезана специально, чтобы разработчики не могли использовать C++Builder 2007 как две IDE «в одном флаконе»).

Итоги
В общем и целом C++Builder 2007 производит впечатление классической, IDE в традиционно добротном стиле Borland/CodeGear, с достойным для очередного релиза набором новшеств. Однако после тщательного знакомства с новой средой разработки возникает и легкое чувство досады. Последним версиям продуктов Borland/CodeGear не хватает того, что отличало ранние версии – новаторства. Да что там говорить о новаторстве, если средства разработки Delphi и C++ до сих пор не освоили поддержку Unicode и, судя по всему, не освоят эту, далеко не новую, технологию в обозримом будущем. Подводя итоги можно сказать, что разработки CodeGear по-прежнему добротны и, безусловно, найдут свою нишу, но в то же время, современная CodeGear, это, скорее компания, стремящаяся остаться наплаву, нежели смело прокладывающая новые пути.

0

2

История развития 64-битных программных систем не нова и составляет уже более десятилетия [1]. В 1991 году был выпушен первый 64-битный микропроцессор MIPS R4000 [2, 3]. С тех пор в форумах и статьях возникали дискуссии посвященные переносу программ на 64-битные системы. Началось обсуждения проблем связанных с разработкой 64-битных программ на языке Си. Обсуждались вопросы, какая модель данных лучше, что такое long long и многое другое. Вот, например, интересная подборка сообщений [4] из новостной группы comp.lang.c, посвященная использованию типа long long в языке Си, что в свою очередь было связано с появлением 64-битных систем.

Одним из наиболее распространенных и чувствительных к изменению размерности типов данных является язык Си. Из-за его низкоуровневых свойств, следует постоянно контролировать корректность программы на этом языке, переносимой на новую платформу. Естественно, что при появлении 64-битных систем разработчики по всему миру вновь столкнулись с задачами обеспечения совместимости старого исходного кода с новыми системами. Одним из косвенных свидетельств сложности проблем миграции является большое количество моделей данных, которые постоянно следует учитывать. Модель данных - это соотношение размеров базовых типов в языке программирования. На рисунке 1 показаны размерность типов в различных моделях данных, на которые мы в дальнейшем будем ссылаться.

Рисунок 1. Модели данных.

Существующие публикации и инструменты в сфере верификации 64-битных приложений
Конечно, это был не первый этап смены разрядности. Достаточно вспомнить переход с 16-битных систем на 32-битные. Естественно накопленный опыт оказал свое положительное воздействие на этапе перехода на 64-битные системы.

Но переход на 64-битные системы, имел свои нюансы, в результате чего появилась серий исследований и публикаций по данным вопросам, например [5, 6, 7].

В основном авторами того времени, выделялись ошибки, следующих типов:

Упаковка указателей в типы меньшей размерности. Например, помещение указателя в тип int на системе с моделью данных LP64 приведет к обрезанию значения указателя и невозможности его использовать в дальнейшем.
Использование магических констант. Опасность заключается в использовании таких чисел как 4, 32, 0x80000000 и ряда других вместо специализированных констант или использования оператора sizeof().
Некорректные операции сдвига, не учитывающих увеличение размерности ряда типов.
Использование некорректных объединений или структур без учета выравнивания на системах с различной разрядностью.
Ошибки работы с битовыми полями.
Некорректные арифметические выражения. Пример:
int x = 100000, y = 100000, z = 100000;
long long s = x * y * x;

Рассматривались и некоторые другие более редкие ошибки, но основные перечислены в списке.

На основе проведенных исследований вопроса верификации 64-битного кода были предложены решения, обеспечивающих диагностику опасных конструкций. Например, такую проверку реализовали в статических анализаторах Gimpel Software PC-Lint (http://www.gimpel.com) и Parasoft C++test (http://www.parasoft.com).

Возникает вопрос, если 64-битные системы существуют так давно, существуют статьи, посвященные данной тематике и даже программные инструменты обеспечивающий контроль опасных конструкций в коде, так стоит ли возвращаться к этому вопросу?

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

Существующая информационная поддержка и инструменты в области разработки 64-битных технологий устарели и нуждаются в существенной переработке. Но Вы возразите, что в Интернете можно найти множество современных статей (2005-2007г), посвященных вопросам разработки 64-битных приложений на языке Си/Си++. К сожалению, на практике они являются не более чем пересказом старых статей, применительно к новой 64-битной версии Windows, без учета ее специфики и произошедших изменений технологий.

Неосвещенные проблемы разработки 64-битных программ.
Но начнем по порядку. Авторы новых статей не учитывают, огромный объем памяти, который стал доступен современным приложениям. Конечно, указатели были 64-битными еще в стародавние времена, но вот использовать таким программам массивы размером в несколько гигабайт не доводилось. В результате, как в старых, так и в новых статьях выпал целый пласт ошибок, связанный с ошибками индексации больших массивов. Практически невозможно найти в статьях описание ошибки, подобной следующей:

for (int x = 0; x != width; ++x)
  for (int y = 0; y != height; ++y)
  for (int z = 0; z != depth; ++z)
      BigArray[z * width * height + y * width + x] = InitValue;
В этом примере, выражение "z * width * height + y * width + x" используемое для адресации имеет тип int, а, следовательно, данный код будет некорректен на массивах, содержащих более 2 GB элементов. На 64-битных системах для безопасной индексации к большим массивам следует использовать типы ptrdiff_t, size_t или производные от них. Отсутствие описания такого вида ошибки в статьях объясняется очень просто. Во времена их написания, машины с объемом памяти, позволяющей хранить такие массивы, были практически не доступны. Сейчас же это становится рядовой задачей в программировании и с большим удивлением можно наблюдать, как код верой и правдой служивший многие годы, вдруг перестает корректно работать при работе с большими массивами данных на 64-битных системах.

Другой пласт практически неосвященных проблем, представлен ошибками, связанными с возможностями и особенностями языка Си++. Почему так произошло, тоже достаточно объяснимо. Во время внедрения первых 64-битных систем, язык Си++ для них не существовал или он был не распространен. По этому практически все статьи посвящены проблемам в области языка Си. Современные авторы заменили название Си на Си/Си++, но нового ничего не добавили.

Но отсутствие в статьях описания ошибок специфичных для Си++ не означает, что их нет. Существуют ошибки, проявляющие себя при переносе программ на 64-битные системы. Они связанны с виртуальными функциями, исключениями, перегруженными функциями и так далее. Более подробно с такими ошибками можно ознакомиться в статье [8]. Приведем простой пример, связанный с использованием виртуальных функций.

class CWinApp {
  ...
  virtual void WinHelp(DWORD_PTR dwData, UINT nCmd);
  };
  class CSampleApp : public CWinApp {
  ...
  virtual void WinHelp(DWORD dwData, UINT nCmd);
  };
Проследим жизненный цикл разработки некоторого приложения. Пусть первоначально оно разрабатывалось под Microsoft Visual C++ 6.0. когда, функция WinHelp в классе CWinApp имела следующий прототип:

virtual void WinHelp(DWORD dwData, UINT nCmd = HELP_CONTEXT);
Совершенно верно было осуществить перекрытие виртуальной функции в классе CSampleApp, как показано в примере. Затем проект был перенесен в Microsoft Visual C++ 2005, где прототип функции в классе CWinApp претерпел изменения, заключающиеся в смене типа DWORD на тип DWORD_PTR. На 32-битной системе программа продолжит совершенно корректно работать, так как здесь типы DWORD и DWORD_PTR совпадают. Неприятности проявят себя при компиляции данного кода под 64-битную платформу. Получатся две функции с одинаковыми именами, но с различными параметрами, в результате чего перестанет вызываться пользовательский код.

Помимо особенностей разработки 64-битных программ с точки зрения языка Си++, существуют и другие тонкие моменты. Например, особенности связанные с архитектурой 64-битной версии Windows. Хочется заранее предупредить разработчиков о потенциальных проблемах и порекомендовать уделить большее внимание тестированию 64-битного программного обеспечения [9].

Теперь вернемся к методам верификации исходного кода программы с использованием статических анализаторов. Я думаю, вы уже угадали, что здесь тоже не все так хорошо как кажется. Не смотря на заявленную поддержку диагностирования особенностей 64-битного кода, эта поддержка на данный момент не удовлетворяет необходимым требованием. Причина заключена в том, что диагностические правила были созданы по все тем же статьям, не учитывающим специфику языка Си++ или обработку больших массивов данных, превышающих 2 GB.

Для Windows разработчиков дело обстоит еще несколько хуже. Основные статические анализаторы рассчитаны на диагностику 64-битных ошибок для модели данных LP64, в то время, как в Windows используется модель данных LLP64 [10]. Обусловлено это тем, что 64-битные версии Windows молоды, а ранее 64-битные системы были представлены Unix подобными системами с моделью данных LP64.

В качестве примера, рассмотрим диагностическое сообщение 3264bit_IntToLongPointerCast (port-10), генерируемое анализатором Parasoft C++test.

int *intPointer;
long *longPointer;
longPointer = (long *)intPointer; //-ERR port-10
C++test предполагает, что с точки зрения модели LP64, данная конструкция будет некорректна. Но в рамках модели данных принятых в Windows данная конструкция будет безопасна.

Рекомендации по верификации 64-битных программ
Хорошо, скажите Вы, проблемы разработки 64-битных версий программ действительно актуальны. Но как найти все эти ошибки?

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

Ознакомьте Ваших коллег, связанных с разработкой 64-битых приложений со следующими статьями: [7, 8, 9, 10, 11, 12, 13, 14, 15].
Ознакомьте Ваших коллег с методологией статического анализа кода: [16, 17, 18]. Статическая верификация кода один из лучших способов поиска такого рода ошибок. Она позволяет убедиться в работоспособности даже тех частей кода, работу которых на больших объемах данных сложно смоделировать в реальности, например при использовании методологии юнит-тестов.
Разработчикам будет полезно познакомиться со статическими анализаторами, такими как Parasoft C++test (wwwparasoft.com), Gimpel Software PC-lint (wwwgimpel.com), Abraxas Software CodeCheck (wwwabxsoft.com).
Для разработчиков Windows приложений особенно будет полезно познакомиться со специализированным статическим анализатором Viva64 (http://www.viva64.com), рассчитанным на модель данных LLP64 [19].
Усовершенствуйте систему юнит-тестирования, включив в набор тестов обработку больших массивов данных. Более подробно с необходимостью тестирования на большом объеме данных, можно познакомиться в [9], а также узнать, как лучше организовать такое тестирование.
Провести тщательно ручное тестирование перенесенного кода на реальных больших задачах, использующих возможности 64-битных систем. Смена архитектуры слишком существенное изменение, чтобы полностью положиться на автоматизированные системы тестирования.

0

3

Работа с процессами в С/С++. Основные приемы
Работа с процессами. Основные приемы. Данная статья рассказывает о работе с процессами, модулями, кучами и потоками при помощи билиотеки TOOLHELP Процессы, потоки, модули, кучи, toolhelp, tlhelp. Хабибуллин Тимур aka Kergan Автор: Тимур Хабибуллин aka Kergan Данная статья рассказывает о работе с процессами, модулями, кучами и потоками при помощи билиотеки TOOLHELP Работа с процессами - основа, без которой заниматься системным программированием так же бессмысленно, как без знания структуры PE-файлов или организации памяти. Поэтому я поднимаю эту тему вновь и расскажу о работе с процессами посредством функций TOOLHELP. Язык программирования: я выбрал C (без плюсиков, т.к. работы с классами в этой статье не будет - после прочтения вы сможете их без труда составить сами) по многим причинам и в первую очередь из-за его низкоуровнего взаимодействия с памятью...записал-считал, все просто и понятно. Перечислить запущенные в системе процессы можно по-разному, я привык пользоваться функциями TOOLHELP. Общая последовательность действий при работе с этой библиотекой: делаем "снимок" (Snapshot) системной информации, которая нам необходима, потом бегаем по процессам (а также модулям и кучам). Поэтому начнем с простого - перечислим все процессы.
//Перечисление процессов
int EnumerateProcs(void)
{
//создаем "снимок" информации о процессах
//первый параметр функции - константа, определяющая,
//какую информацию нам нужно "снять", а второй -
//идентификатор процесса, к которому относится эта
//информация. В данном случае это 0 т.к. мы делаем
//снимок всех процессов
HANDLE pSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

bool bIsok = false;
//Структура, в которую будут записаны данные процесса
PROCESSENTRY32 ProcEntry;
//установим ее размер, это необходимое действие
ProcEntry.dwSize = sizeof(ProcEntry);
//теперь определим первый процесс
//первый параметр функции - хэндл "снимка" информации
//второй - адрес структуры PROCESSENTRY32
//true - в случае удачи, false - в случае неудачи
bIsok = Process32First(pSnap, &ProcEntry);
//здесь можно было вставить роскошный цикл for(....) но это
//не совсем удобочитаемо
//так что цикл while
while(bIsok)
{
    //печатаем имя процесса, его идентификатор
    //теперь, когда у нас есть структура ProcEntry
    //То, какую информацию вы из нее возьмете, зависит
    //только от задачи ))
    printf("%s  %un", ProcEntry.szExeFile, ProcEntry.th32ProcessID);
    bIsok = Process32Next(pSnap, &ProcEntry);
}
//чистим память!
CloseHandle(pSnap);
return 1;
}

Вуаля, список всех процессов, аки в диспетчере задач. Теперь мы сделаем кое-что, чего в диспетчере нет! В адресном пространстве каждого процесса (в области памяти, выделенной ему системой) находятся различные библиотеки, которые, собственно, состовляют ПРИЛОЖЕНИЕ. Это и Kernel32 и GDI и еще множество различных. Наша задача - их все пересчитать и переписать! Для этого действа напишем небольшую функцию.
//Перечисление модулей процесса
int EnumerateModules(DWORD PID)
{
//Входной параметр - идентификатор процесса, чьи модули мы собираемся
//перечислять. Во первых создадим snapshot информации о модулях
//теперь нам нужна информация о конкретном процессе - процессе
//с идентификатором PID
HANDLE pMdlSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, PID);

bool bIsok = false;

//структура с информацией о модуле
MODULEENTRY32 MdlEntry;
//зададим размер
MdlEntry.dwSize = sizeof(MODULEENTRY32);
//и найдем первый модуль
bIsok = Module32First(pMdlSnap, &MdlEntry);
//и далее, как и с процессами
while(bIsok)
{
    //печатаем имя модуля
    printf(" %s n", MdlEntry.szModule);
    //и переходим к следующему
    bIsok = Module32Next(pMdlSnap, &MdlEntry);
}
//чистим память!
CloseHandle(pMdlSnap);
return 1;
}

А теперь немного притормозим и посмотрим, какую еще информацию о процессах и модулях мы получаем:
typedef struct tagPROCESSENTRY32 {
DWORD dwSize;//Рамер структуры
DWORD cntUsage; //Число ссылк на процесс. Процесс уничтожается,
//когда число ссылок становится 0
DWORD th32ProcessID;
//Идентификатор процесса - необходим
        //во многих функциях
DWORD th32DefaultHeapID;
//Идентификатор основной кучи - имеет
           
//смысл только в функциях toolhelp
DWORD th32ModuleID;
//идентификатор модуля - имеет
           
//смысл только в функциях toolhelp
DWORD cntThreads;//Число потоков
DWORD th32ParentProcessID;
//Идентификатор родителя - возвращается
           
//Даже если родителя уже нет
LONG pcPriClassBase;
//приоритет по умолчанию всех //создаваемых процессом потоков
DWORD dwFlags;   
//Зарезервировано
CHAR  szExeFile[MAX_PATH];
//Собственно имя процесса
} PROCESSENTRY32,*PPROCESSENTRY32,*LPPROCESSENTRY32;

typedef struct tagMODULEENTRY32 {
DWORD dwSize;   
//размер структуры
DWORD th32ModuleID;
//идентификатор модуля
DWORD th32ProcessID;
//идентификатор процесса, к которому относится
           
//модуль
DWORD GlblcntUsage;   
//общее число ссылок на этот модуль
DWORD ProccntUsage;   
//число ссылко в контексте процесса,
       
//по идентификатору которого был создан
       
//снэпшот. Если равен 65535 - модуль подгружен
       
//неявно
BYTE *modBaseAddr;    //адрес модуля в контексте процесса
DWORD modBaseSize;    //размер проекции
HMODULE hModule;    //ссылка на модуль
char szModule[MAX_MODULE_NAME32 + 1]; //Имя модуля
char szExePath[MAX_PATH];    //Полный путь к модулю
} MODULEENTRY32,*PMODULEENTRY32,*LPMODULEENTRY32;

Обратите внмание: ссылка на модуль (параметр hModule) - это первый байт ДОС-заголовка! Таким образом, мы получаем возможность работать с проекцией при некотором знании структуры PE-файлов. В частности мы можем прочиатать таблицу импорта, и, как правило, - даже переписать ее (это используется при перехвате АПИ). Параметр szExePath имеет свой "заскок" - иногда полный путь к модулю возвращается со странными вставками и, например, всесто "c:windowssystem32advapi32.dll" я иногда получаю "c:x86_proc_winsyspathadvapi32.dll". Как правило для системных задач средней сложности (перехват апи, или, наоборот, перехват стелсов) всего вышеописанного хватает. Но на этом возможности toolhelp не исчерпываются и теперь мы побегаем по потокам! Работа с потоками несколько отличается от работы с модулями - даже если мы сделаем снимок, задав идентификатор какого-либо процесса, функция Thread32Next не остановится, пока не пробежится по ВСЕМ потокам в системе. Поэтому мы должны проверять, к какому процессу принадлежит поток - благо, в структуре THREADENTRY32 есть член th32OwnerProcessID - идентификатор породившего поток процесса. Таким образом:
int EnumerateThreads(DWORD PID)
{
//Начнем с создания снимка
HANDLE pThreadSnap =  CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, PID);

bool bIsok = false;
//Структура, описывающая поток
THREADENTRY32 ThrdEntry;
//ставим размер
ThrdEntry.dwSize = sizeof(THREADENTRY32);
//Берем первый поток
bIsok = Thread32First(pThreadSnap, &ThrdEntry);
//и бегаем по всем потокам...
while (bIsok)
{
    //проверяем, тому ли процессу принадлежит поток
    if (ThrdEntry.th32OwnerProcessID == PID)
    {
    //Если да, то выводим некотурую информацию...
    //Хоть она никому нафиг не нужна :о)
printf("%u  %un", ThrdEntry.th32OwnerProcessID, ThrdEntry.th32ThreadID);
    }
    bIsok = Thread32Next(pThreadSnap, &ThrdEntry);
}
//не забываем чистить память
CloseHandle(pThreadSnap);
return 1;
}

Ну вот, у нас есть потоки. Что еще осталось? Правильно, остались кучи. Здесь тоже все очень просто:
int EnumerateHeaps(DWORD PID)
{
//Первый параметр - идентификатор процесса
//а второй - основная куча
//Теперь делаем снимок, чтоб перечислить кучки...
HANDLE pSnapHeaps = CreateToolhelp32Snapshot(TH32CS_SNAPHEAPLIST, PID);
bool bIsok = false;
bool bIsokHeap = false;
//Структура, в которую будут записываться данные списка кучи
HEAPLIST32 HpLst;
//Структура, в которую будут записываться данные
//непосредствнно БЛОКОВ КУЧИ
HEAPENTRY32 HpEntry;
//Ставим размеры...
HpLst.dwSize = sizeof(HEAPLIST32);
HpEntry.dwSize = sizeof(HEAPENTRY32);
bIsok = Heap32ListFirst(pSnapHeaps, &HpLst);
while (bIsok)
{
    //Теперь перечисляем блоки кучи
    //этот код я привел, чтобы стало ясно
    //как получить данные по блокам
    //но он жрет много времени
    //так что я его закомментирую - если вам интересно
    //можете погонять...
    /*bIsokHeap = Heap32First(&HpEntry, PID, HpLst.th32HeapID);
    while(bIsokHeap)
    {
    //Выводим немного информации
    printf("%u n", HpEntry.dwBlockSize);
    //Шагаем дальше
    bIsokHeap = Heap32Next(&HpEntry);
    }*/
    //выводим инфу о куче в общем
    printf("%u n", HpLst.dwSize);
    //шагаем дальше
    bIsok = Heap32ListNext(pSnapHeaps, &HpLst);
}
CloseHandle(pSnapHeaps);
return 1;
}

Ну вот, теперь тока осталось написать о структурах THREADENTRY32, HEAPENTRY32 и HEAPLIST32:
typedef struct tagTHREADENTRY32{
DWORD dwSize;    //размер структуры
DWORD cntUsage; //число ссылок
DWORD th32ThreadID; //идентификатор
DWORD th32OwnerProcessID; //родительский процесс
LONG tpBasePri;    //основной приоритет (при инициализации)
LONG tpDeltaPri; //изменение приоритета
DWORD dwFlags; //зарезервировано
} THREADENTRY32;
typedef THREADENTRY32 * PTHREADENTRY32;
typedef THREADENTRY32 * LPTHREADENTRY32;

typedef struct tagHEAPENTRY32
{
    DWORD  dwSize; //размер структуры
    HANDLE hHandle;     // хэндл этого блока
    DWORD  dwAddress;   // линейный адрес начала блока
    DWORD  dwBlockSize; // размер блока в байтах
    DWORD  dwFlags; //флаги
/*
LF32_FIXED Блок памяти имеет фиксированную позицию
LF32_FREE  Блок памяти не используется
LF32_MOVEABLE  Блок памяти может перемещаться
*/
    DWORD  dwLockCount; число "замков"
    DWORD  dwResvd; // зарезервировано
    DWORD  th32ProcessID;   // родительский процесс
    DWORD  th32HeapID;      // идентификатор кучи
} HEAPENTRY32;
typedef HEAPENTRY32 *  PHEAPENTRY32;
typedef HEAPENTRY32 *  LPHEAPENTRY32;

typedef struct tagHEAPLIST32
{
    DWORD  dwSize; //размер структуры
    DWORD  th32ProcessID;   // родительский процесс
    DWORD  th32HeapID;      //куча в контексте процесса
    DWORD  dwFlags; //флаг. Значение всегда одно:
// HF32_DEFAULT - основная куча процесса
} HEAPLIST32;

вызовы функций EnumerateHeaps, EnumerateThreads и EnumerateModules можно проводить из EnumerateProcs. Все скомпилино в Visual C++ 6.0. В тексте использована информация из MSDN и книги Джеффри Рихтера "Создание эффективных win32 приложений" (имхо эта книга - настольная для системного программиста).

0

4

В чем прикол тупа передирать статьи, даже не читаючи...

0

5

ЛИЧНО Я ВСЁ ЧИТАЛА!!!
ВОТ ГАД КАПС ЛОК,КЛИНИТ ПАРАЗИТ.

0


Вы здесь » Форум системного администратора » С++ » Статьи про С++