На чем ты написана, радость моя?

Часть первая. Шпионим за оконными классами

Скажите, пожалуйста, у вас никогда не возникало желания в ресторане узнать рецепт понравившегося блюда? Спрашивали? "Ах, нельзя? Какая жалость! Ну тогда хотя бы скажите ингредиенты... Что, серьёзно - только лук, картошка и майонез?! Не может быть..."

Когда видишь хорошо, и даже не просто хорошо, а великолепно сделанную программу, возникает желание узнать, как именно она разработана. И если с open-source программами это не составляет никаких трудностей, то сделать это в случае коммерческих разработок - большая проблема. Впрочем, каждый программист знает, что существуют такие вещи, как отладчики и дизассемблеры. С их помощью любую программу, написанную для платформы Windows, можно представить в виде ассемблерных кодов. Действие это в отношении чужих программ не приветствуется и даже, скажем прямо, является наказуемым в соответствии с международным законодательством. Хотя разве это остановит одержимого любопытством исследователя?.. Да и не любую программу получится так "разложить по базису": если написана она, например, на Java, то обычным Windows-дизассемблером её не возьмёшь. То же самое касается и тех программ, которые созданы для платформы Microsoft .NET Framework.

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

Сегодня мы рассмотрим только один способ распознавания инструмента, с помощью которого создано приложение. Только один - из-за ограничений в объёме, свойственных газетным статьям. Я назвал бы его "Шпионим за оконными классами". Он, конечно, не идеален, поскольку применим только к тем программам, которые имеют стандартный пользовательский интерфейс Windows. Если программа запускается в консольном режиме (т.е. не имеет графического интерфейса как такового), то этот способ не сработает. Если интерфейс программы оформляется с помощью т.н. "скинов", то способ тоже работает не всегда.

Каждый элемент управления, будь то окно, кнопка, панель инструментов или что-либо ещё, при создании регистрируется в системе. При этом он получает уникальный дескриптор (handle), который нужен для того, чтобы программа могла точно установить, с каким именно элементом управления пользователь в данный момент взаимодействует. При регистрации окна (а с точки зрения системы, кнопка - такое же окно, как и то окно, на котором она расположена) всегда указывается название оконного класса этого элемента управления. Это указывается именно для того, чтобы отличать кнопку от панели задач, а панель задач - от строки поиска в Internet Explorer. При этом, как известно, большинство программ используют интерфейс, созданный с помощью специализированных библиотек. Таких библиотек много - VCL, MFC, Windows Forms... Каждая из них имеет свои особенности именования таких классов. Именно этим свойством графического интерфейса Windows-приложений мы и воспользуемся.

Итак, приступим к исследованиям. Во-первых, нам нужен какой-нибудь инструмент для того, чтобы узнавать имена оконных классов тех или иных элементов управления. Такие инструменты есть, и их существует не так уж и мало, однако я укажу лишь два, от самых популярных производителей - Microsoft Spy++, входящий в состав Visual Studio, и Borland WinSight, входящий в поставку Delphi и C++ Builder. Лично я работал именно с WinSight (его можно найти в папке Delphi\Bin\Ws32.exe), и, соответственно, рассказ будет именно о нём. Впрочем, Spy++ работает аналогично, и чтобы разобраться с ним, достаточно лишь некоторое время внимательно почитать справку.

Верхняя половина окна утилиты - дерево оконных элементов управления, зарегистрированных на текущий момент в системе. Там отображаются все окна, а не только те, которые видны пользователю, в том числе все системные. Поэтому, собственно говоря, их там и так много. Нижняя половина - очередь сообщений Windows, которые относятся к выделенному в верхней половине окну, впрочем, сейчас нас нижняя половина не слишком интересует. В связи с обилием окон в дереве возникает проблема: как узнать в списке именно то окно, которое нас в данный момент интересует? Делать вручную это не всегда просто, поэтому лучше воспользоваться встроенными в WinSight возможностями. Для этого в меню "Spy" нужно выбрать (отметить галочкой) пункт "Follow Focus". Теперь, когда он отмечен, достаточно сделать активным на экране нужное окно, а после переключиться на WinSight по комбинации клавиш Alt+Tab. WinSight самостоятельно выделит в дереве нужное окно, так что нам остаётся лишь исследовать его.

Информация об окне в WinSight представлена в следующем виде: Tree Handle {Class} Module Position "Title". Tree - это идентификатор типа окна: Icon и Overlapped - главное окно, Child и Popup - ему подчинённые. Handle - это тот самый уникальный дескриптор, который получает оконный элемент при регистрации в системе. Он представлен в виде числа в шестнадцатеричной форме записи (например, 004201DA). Class, который записан в фигурных скобочках, - это и есть тот самый оконный класс, ради которого и делается вся эта катавасия. Module - имя исполняемого файла, к которому относится данное окно, Position - экранные координаты окна, а Title - заголовок окна. Но нас, как я уже говорил, интересует сейчас, в первую очередь, атрибут Class.

Теперь давайте возьмём несколько программ и поизучаем их с помощью WinSight. Лично я выбрал несколько, заведомо написанных с помощью разных библиотек - Total Commander, NUnit, Microsoft HTML Help Workshop, WinRAR, QuickHTML Suite и Hexapad.

Главное окно Total Commander имеет класс TTOTAL_CMD, а названия классов всех дочерних окон начинаются с префикса "T" (TDrivePanel, TButtonBar, TMyPanel, TComboBox). Как написано в справке к Total Commander, "Total Commander разработан с использованием Borland Delphi 1.0 (16 бит) и 2.0 (32 бит)". То есть программы, разработанные с использование библиотеки Visual Components Library (VCL), применяемой в Delphi, имеют в названиях оконных классов префикс "T". К сожалению, по одному этому признаку идентифицировать наверняка язык разработки не удастся, так как эта библиотека используется и при разработке приложений в Borland C++ Builder. Программисты, использующие VCL, наверняка обратили внимание на то, что название оконного класса совпадает с названием класса компонента в IDE.

Теперь давайте посмотрим на Hexapad (bonanzas.rinet.ru), разработанный также с использованием Delphi. Только вместо VCL разработчиком применялась KOL - альтернативная объектная библиотека. Как видно, названия всех оконных классов начинаются с "obj_". Поскольку версия KOL для C++ Builder не существует, можно с уверенностью утверждать при виде приложения, оконные классы элементов которого начинаются с "obj_", что оно написано на Delphi.

А сейчас, уважаемые, посмотрим в сторону WinRAR. Оконные классы элементов управления этой программы имеют следующие имена: WinRarWindow, ComboBoxEx32, ComboBox, Edit, ToolbarWindow32, msctls_statusbar32, SysListView32, SysHeader32 и др. Те, кто когда-либо работал с диалогами в виде ресурсов, знает, что большинство имён этих классов в точности соответствуют определённым в системе классам. Поскольку программисту на Delphi или C++ Builder обычно нет необходимости использовать напрямую Windows API, то можно с определённой долей уверенности считать, что эта программа написана на языке C++ без использования каких-либо сторонних библиотек (или, что менее вероятно, на Delphi, но без VCL). Впрочем, как показывает исследование HTML Help Workshop, интерфейс которого создан при помощи Microsoft Foundation Classes (MFC), такие же имена у классов будут при использовании этой библиотеки. Впрочем, для приложений, использующих MFC и написанных, соответственно, с помощью Microsoft Visual C++, характерно наличие оконных классов, названия которых начинается с "Afx". Хотя их может и не быть - например, в том же HTML Help Workshop таких классов намного меньше тех, что имеют стандартные имена. И ещё стоит отметить, что MFC могут использовать и разработчики, работающие с другими компиляторами C++ и в других средах разработки.

Так что, в общем случае, при встрече с подобными именами классов (вроде msctls_statusbar32, SysListView32, BUTTON, EDIT и т.д.) нам становится ясно, что... ничего, собственно, и не ясно.

Немного лучше обстоят дела с приложениями для .NET Framework. Я специально выбрал для рассмотрения NUnit, который точно написан на C# и поставляется с исходными текстами. Кстати, именно его оконные классы, в основном, и попали на скриншот. Как видите, они имеют вид "WindowsForms10.XXXXXXX". Часть после точки может быть любой, но это начало - "WindowsForms10" - отличительный признак .NET-приложений. Впрочем, вопрос о языке, с помощью которого разработано это приложение, всё равно остаётся открытым.

QuickHTML Suite (amelso.narod.ru) написана на Visual Basic 6-й версии. Соответственно, WinSight показывает множество оконных классов данной программы, в имени которых содержится набор символов "RT6". Этот набор символов и можно считать опознавательным для программ, созданных с помощью Visual Basic 6.

Вот так обстоят дела. Думаю, немного "поковырявшись" с другими средами разработки, можно выяснить, какой отпечаток накладывают они на оконные классы создаваемых с их помощью приложений. Однако, как видите, этот метод исследования программ имеет много минусов, среди которых - низкая точность в отношении программ, написанных на "голом" WinAPI или с использованием Microsoft Foundation Classes. Поэтому в следующий раз я расскажу про другие способы исследования программ с целью выяснить, на чём они были написаны.

Вадим СТАНКЕВИЧ

Версия для печатиВерсия для печати

Номер: 

25 за 2006 год

Рубрика: 

Software
Заметили ошибку? Выделите ее мышкой и нажмите Ctrl+Enter!