Меню Новости Программы Статьи Форум Контакты

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Статьи
 

СтатьиПрограммированиеDelphi

 

SysListView32. Получение списка элементов

Автор: Blacksus

Сегодня мы поговорим о WinApi и системном компоненте SysListView32, в Delphi этот компонент называется TListView. Вы можете увидеть его в проводнике Windows, именно этот компонент используется для отображения файлов.

Многие новички в программировании боятся слова WinApi, т.к. работать с этим не так просто как с визуальной средой Delphi и несколькими щелчками мыши не обойтись для обращения к какому-либо компоненту. Но в данной статье я постараюсь показать, что ничего страшного в этом слове нет и если немного разобраться с одним примером на WinApi, то все станет простым и понятным, т.к. все взаимодействие с системой через WinApi продумано и сделано предельно логично. Но есть некоторые тонкости, которые трудно понять и особенно трудно найти литературу, в которой эти тонкости были бы описаны. Именно это делает представление о WinApi таким для новичков.

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

Рисунок 1

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

Теперь перейдем непосредственно к теме данной статьи.

Сразу оговорюсь, что пример рассматриваемый в данной статье подходит только для WindowsXP, у Windows Vista и Windows 2000 немного другая структура иерархии.

На рисунке 1 представлена иерархия окон формы проводника. Каждый элемент на рисунке имеет хэндл (показан в квадратных скобках "[ ]"), класс (показан в фигурных скобках "{ }"), и иногда название окна (между фигурными и квадратными скобками).

Как видно из рисунка 1, компонент SysListView32 находится на самом дне в иерархии формы проводника. Он имеет 5 предков. Чтобы получить список элементов, нам нужно знать хэндл этого компонента. В WinApi есть специальные функции, которые позволяют найти окно по имени и/или его классу. Одну из таких функция мы будем использовать - это FindWindowEx.

Описание функции FindWindowEx.

FindWindowEx(

hwndParent: HWND , // хэндл родительского окна
hwndChildAfter: HWND , // хэндл дочернего окна
lpszClass: LPCTSTR, // ссылка на имя класса
lpszWindow: LPCTSTR // ссылка на имя окна
): HWND;

Данная функция вернет хэндл найденного окна, если выполнится удачно, иначе вернется 0.

Для того, чтобы добраться до SysListView32, нам придется последовательно получать все хэндлы его предков. Код такой функции представлен ниже:

Как видно из кода, на каждом шаге дополнительно происходит проверка на корректность возвращаемого результат. Если он равен 0, то программа выдаст сообщение о том, какое именно окно в цепочке не найдено и прекратит дальнейший поиск.

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

Далее рассмотрим функцию получения имен элементов. Вот ее код:

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

Теперь рассмотрим поближе код процедуры. Сначала получим число элементов, чтобы перебирать их в цикле. Далее получим pid процесса, это уникальный идентификатор, его можно получить зная хэндл любого окна, принадлежащего процессу. Затем откроем процесс для записи и чтения, т.к. структуру мы будем в него записывать, а результат работы сообщения в виде строки считывать. Следующий шаг это выделение памяти под структуру и строку в чужом адресном пространстве. Далее в цикле заполняем структуру в своем адресном пространстве и переписываем ее в адресное пространство проводника, затем отправляем сообщение компоненту SysListView32 о том, что хотим получить имя очередного элемента и указываем в качестве параметров ссылку на структуру и строку, куда будет записано имя элемента. После этого осталось прочитать строку из адресного пространства проводника в наше адресное пространство и прибавить ее к результату. После работы цикла следует очистить выделенную в чужом адресном пространстве память, чтобы не засорять ее. Для наглядности работу этой процедуры можно увидеть на рисунке 2.

Рисунок 2

Теперь рассмотрим на примере как пользоваться этими процедурами. Для этого нам потребуется три компонента на форме: TEdit, TMemo и TButton. В TEdit должен быть записан заголовок окна, которое содержит SysListView32. Откройте любую папку и перепишите ее заголовок с учетом регистра. Например, на рисунке 3 папка имеет заголовок Blacksus.przone.ru.

Рисунок 3

В TMemo будет выведен результат работы функции. А при нажатии на кнопку следует выполнить следующий код:

Отмечу, что данная статья применима не только для проводника, но и для любого приложения имеющего SysListView32. Т.е. имена элементов можно извлечь абсолютно из любого приложения, использующего этот компонент. Но следует помнить, что путь к окну компонента, скорее всего, будет другой, при этом изменится функция GetListViewHandle. Чтобы увидеть какие именно окна являются предками SysListView32 в другом приложении и легко модифицировать функцию, рекомендую воспользоваться программой "InqSoft Window Scanner", она является абсолютно бесплатной и скачать ее можно отсюда.

Исходный код примера можно скачать тут, а программу тут.

   

Сайт создан в системе uCoz