Текст книги "Delphi. Трюки и эффекты"
Автор книги: Александр Чиртик
Жанр: Программирование, Компьютеры
сообщить о неприемлемом содержимом
Текущая страница: 18 (всего у книги 24 страниц)
Не менее популярным и функциональным приложением из пакета Microsoft Office является Microsoft Excel. Это программа для работы с электронными таблицами. Как и уже знакомое нам приложение Microsoft Word, Microsoft Excel также обладает возможностью создания и редактирования документов (в данном случае таблиц) посредством СОМ. Преимущества использования Microsoft Excel из других программ очевидны, так как она предоставляет широкий спектр возможностей по построению диаграмм, графиков, произведению различных расчетов и пр. Поэтому в качестве примера создадим приложение, которое будет выполнять запуск Microsoft Excel, добавление новой книги, создание листа и помещение в его ячейки текста и формул.
Как и в случае с Microsoft Word, будет использоваться объект THnaOleVariant. Но методы и свойства СОМ-сервера поменяются. Рассмотрим исходный текст приложения для выполнения несложных операций с сервером Microsoft Excel (листинг 9.8).
Листинг 9.8. Работа с Microsoft Excel
unit COMinExcel;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics,
Controls, Forms,
Dialogs,
//Включаем модуль работы с COM-объектами
ComObj;
type
TFormCOMExcel = class(TForm)
//Процедура, вызываемая при создании формы
procedure FormCreate(Sender: TObject);
//Процедура, вызываемая при завершении работы приложения
procedure FormDestroy(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
FormCOMExcel: TFormCOMExcel;
//Объявление объекта OleVariant с именем Microsoft Excel
Excel: OleVariant;
implementation
{$R *.dfm}
procedure TFormCOMExcel.FormCreate(Sender: TObject);
begin
//Инициализируем объект
Excel := CreateOleObject('Excel.Application');
//Устанавливаем видимым окно приложения Microsoft Excel
Excel.Visible := true;
//Добавляем новую книгу
Excel.Application.Workbooks.Add;
//Вводим текст в ячейку с индексом E5
Excel.Application.Worksheets.Item['Лист1'].
Cells.Item[5,5].FormulaR1C1 := '! ТЕКСТ !';
//Задаем характеристики шрифта
Excel.Application.Worksheets.Item['Лист1'].
Cells.Item[1,1].Font.Bold := true;
//В ячейку с индексом A1 записываем формулу
Excel.Application.Worksheets.Item['Лист1'].
Cells.Item[1,1].FormulaR1C1 := '=18*2';
end;
procedure TFormCOMExcel.FormDestroy(Sender: TObject);
begin
//Закрываем приложение Microsoft Excel
Excel.Quit;
end;
end.
Предложенный листинг демонстрирует основы удаленного управления приложением Microsoft Excel. Запуск Microsoft Excel, заполнение ячеек новой таблицы происходит в функции FormCreate.
Во время создания главной формы приложения-примера на экране появится окно программы Microsoft Excel с числом в ячейке с индексом А1 и текстом в ячейке с индексом Е5. Хотя в ячейку с индексом А1 мы записывали =18*2, на экране в этой ячейке будет отображаться 32, так как Microsoft Excel автоматически преобразует выражения в ячейках.
Глава 10
Окна других приложений
• Ловушки Windows
• Программа «Оконный шпион»
Здесь мы будем использовать сведения, приведенные в предыдущих главах (а точнее, в главах 1, 2 и 8), для построения программы, позволяющей проводить различные операции с окнами приложений. Вы также дополнительно познакомитесь с техникой применения ловушек (hook) в Windows и увидите пример реального использования проецирования файла в память для обмена данными между несколькими приложениями. Причем второе в нашем примере обусловлено особенностью работы ловушек, следящих за работой других приложений. Вы также узнаете, как перечислять все открытые окна и, соответственно, получать к ним доступ. Но обо всем по порядку.
10.1. Ловушки Windows
Из предыдущих глав вам должен быть понятен или, по крайней мере, известен механизм, который используется Windows для управления окнами приложений, – сообщения. Вероятно, большая мощь этого механизма и в то же время его уязвимость состоят в возможности посылки сообщений любым окнам (окнам одного процесса или окнам других процессов).
В Windows также предусмотрен мощный механизм, позволяющий следить за некоторыми важными событиями в системе и, конечно, производить мониторинг сообщений, получаемых различными окнами. Речь идет об установке так называемых ловушек. Ловушка представляет собой функцию, вызываемую при возникновении определенного события, например перед получением каким-либо окном нового сообщения, при нажатии клавиши, записи события в системный журнал и т. д.: все зависит от того, для каких событий разработчики предусмотрели ловушки. Интересен тот факт, что в Windows предусмотрены даже ловушки для отладки других ловушек.
Мы рассмотрим некоторые наиболее простые виды ловушек, перехватывающих сообщения окон. По глобальности действия рассмотренные нами ловушки являются устанавливаемыми на отдельный поток: при ошибке в функции-ловушке это безопаснее для системы.
Начинается создание ловушки с написания собственно функции-ловушки, имеющей следующий прототип:
function HookProc(code: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT stdcall;
Параметр code используется для обозначения тех случаев, когда функция ловушки должна вызвать специальную API-функцию CallNextHookEx и вернуть значение, возвращенное ею. Назначения параметров wParamи lParam этой функции сильно зависят от того, для реакции на какое именно событие ловушка используется.
Для регистрации ловушки используется API-функция SetWindowsHookEx, имеющая следующий прототип:
function SetWindowsHookEx(idHook: Integer; //Тип ловушки
lpfn: TFNHookProc; //Адрес функции-ловушки
hmod: HINST; //Используемый модуль, в котором
//расположена функция ловушки
dwThreadId: DWORD //Идентификатор потока, для
//которого создается ловушка
): HHOOK; stdcall;
В случае успешного создания ловушки функция SetWindowsHookEx возвращает дескриптор новой ловушки (ненулевое значение).
Для удаления ловушки используется функция UnhookWindowsHookEx, принимающая единственный параметр – дескриптор ловушки, возвращенный функцией SetWindowsHookEx. Причем удаление ловушки нужно производить обязательно, поэтому по крайней мере при закрытии приложения не следует забывать вызывать функцию UnhookWindowsHookEx.
Теперь несколько слов о функции CallNextHookEx. Ее объявление имеет следующий вид:
function CallNextHookEx(hhk: HHOOK; nCode: Integer;
wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
В чем важность этой функции? Она предназначена для продолжения передачи сообщения по цепочке ловушек (ведь одновременно несколько приложений могут создать несколько ловушек). Вызов этой функции настоятельно рекомендуется осуществлять в любом случае (независимо от значения параметра code функции-ловушки), только если целью не стоит блокирование других ловушек.
Виды ловушекПриведем список некоторых простых типов ловушек, а именно констант из модуля Windows, их обозначающих и передаваемых в функцию SetWindowsHookEx:
• WH_CALLWNDPROC – функция ловушки вызывается каждый раз до вызова функции обработки сообщений окон, созданных наблюдаемым потоком;
• WH_CALLWNDPROCRET – вызывается каждый раз при возврате из функции обработки сообщений окон наблюдаемого потока;
• WH_KEYBOARD – функция ловушки вызывается перед обработкой сообщений WM_KEYDOWN и WM_KEYUP оконной функцией исследуемого потока;
• WH_MOUSE – вызывается перед обработкой оконной функцией наблюдаемого потока сообщений от манипулятора «мышь».
Рассмотрим, какое значение имеют параметры 1 Par am и wParam функции-ловушки в каждом из перечисленных случаев.
Перехват вызова оконной функции
Итак, для ловушки WH_CALLWNDPROC, которая, кстати, используется в рассматриваемом далее приложении, два последних параметра функции-ловушки трактуются следующим образом:
• wParam – равен нулю, если сообщение послано в окно тем же потоком, в котором исполняется функция ловушки, и не равен нулю, если сообщение послано другим потоком;
• lParam – указатель на структуру TCWPStruct, содержащую информацию о сообщении, которое передано окну (и будет передано в оконную функцию).
Объявление структуры TCWPStruct с описанием ее полей выглядит следующим образом:
type TCWPStruct = packed record
lParam: LPARAM; //Параметр сообщения
wParam: WPARAM; //Параметр сообщения
message: UINT; //Код сообщения
hwnd: HWND; //Окно, которому адресовано сообщение
end;
Ниже приводится пример преобразования параметра lParam функции ловушки к указателю на структуру с последующей проверкой кода сообщения (фрагмент программы):
var hook_data : hook_data: ^TCWPStruct;
begin
hook_data := Pointer(lParam);
if hook_data^.message = WM_SIZE then
begin
//Реагируем на изменение размера окна
end;
end;
Получение доступа к данным, передаваемым в остальные функции ловушки (а именно, несложное преобразование типов у операции с указателем), осуществляется аналогичным образом, поэтому более демонстрироваться не будет.
Перехват возврата из оконной процедуры
Для ловушки WH_CALLWNDPROCRET параметры wParam и lParam функции-ловушки следует трактовать следующим образом:
• wParam – равен нулю, если сообщение послано другим процессом, и не равен нулю в противном случае;
• lParam – указатель на структуру TCWPRetStruct, содержащую информацию о сообщении, которое передано окну (и будет передано в оконную функцию).
Объявление структуры TCWPRetStruct с описанием ее полей выглядит следующим образом:
type TCWPRetStruct = packed record
lResult: LRESULT; //Значение, возвращенное оконной функцией
lParam: LPARAM; //Параметр сообщения
wParam: WPARAM; //Параметр сообщения
message: UINT; //Код сообщения
hwnd: HWND; //Дескриптор окна-получателя
end;
Перехват сообщений клавиатурного ввода
Для ловушки WH_KEYBOARD параметры wParam и lParam функции-ловушки следует трактовать следующим образом:
• wParam – код нажатой клавиши;
• lParam – первые 16 бит этого параметра означают количество повторений нажатия; старшие 16 бит используются для дополнительного описания состояния клавиатуры в момент нажатия клавиши.
Параметры wParam и lParam полностью аналогичны параметрам сообщений WM_KEYDOWN И WM_KEYUP.
Перехват сообщений от мыши
В ловушку WH_KEYBOARD в параметрах wParam и lParam передаются следующие значения:
• wParam – код сообщения мыши;
• lParam– указатель на структуру TMouseHookStruct.
Объявление структуры TMouseHookStruct с описанием полей выглядит следующим образом:
type TMouseHookStruct = packed record
pt: TPoint; //Экранные координаты указателя мыши
hwnd: HWND; //Дескриптор окна-получателя сообщения
wHitTestCode: UINT; //Код, возвращенный оконной функцией
//в ответ на сообщение WM_NCHITTEST
dwExtraInfo: DWORD; //Дополнительные данные
end;
Если вы забыли, какое значение имеет для окна coo6nreHHeWM_NCHITTEST, то можете вновь обратиться к гл. 1.
Расположение функции-ловушки и DLLТеперь поговорим немного о расположении функции-ловушки.
Казалось бы, что здесь может быть такого: написал функцию в модуле, строго соответствующую приведенному ранее прототипу, передал ее адрес в функцию SetWindowsHookEx и используй ловушку. Но не так все просто. Функция ловушки может находиться в исполняемом файле только в том случае, если предполагается использовать ее для перехвата сообщений потока (потоков) того же процесса. Тогда в функцию создания ловушки в качестве параметра hmod следует передавать нулевое значение.
Если же предполагается слежение за другими приложениями (за потоками других процессов), то функция ловушки должна быть экспортируемой функцией DLL. Тогда в функцию SetWindowsHookEx передается дескриптор модуля DLL (похоже, что это адрес в адресном пространстве процесса, куда спроецирован файл DLL). Библиотека (DLL) может загружаться как при запуске приложения (если используется так называемое load-time связывание), так и динамически при помощи API-функции LoadLibrary:
function LoadLibrary(lpLibFileName: PChar): HMODULE; stdcall;
Функция принимает в качестве параметра путь DLL и возвращает дескриптор загруженного модуля (или 0 в случае ошибки). Если библиотека больше не нужна, то можно вызвать функцию FreeLibrary, передав в качестве единственного параметра возращенный ранее функцией LoadLibrary дескриптор модуля DLL
Возвращаясь к теме расположения ловушки зададимся вопросом: почему именно DLL? Чем плохо расположение ловушки в ЕХЕ-модуле приложения? Самое время вспомнить о том, что каждый процесс в Windows выполняется в своем собственном адресном пространстве. Поэтому адрес функции в исполняемом файле одного процесса вполне может быть адресом структуры данных где-то внутри другого процесса (рис. 10.1).
Рис. 10.1. Пример адресного пространства разных процессов
В отличие от ЕХЕ-файлов, файлы библиотек легко проецируются в адресное пространство использующего их процесса. Разместив функцию ловушки в DLL и указав дескриптор модуля этой DLL, мы предоставляем системе полную информацию для того, чтобы она смогла:
• спроецировать библиотеку с ловушкой в адресное пространство исследуемого процесса;
• однозначно определить положение (адрес) функции-ловушки в адресном пространстве исследуемого процесса.
Описанные выше манипуляции с DLL проиллюстрированы на рис. 10.2 (Процесс 2 на рисунке – процесс, в который внедряется ловушка).
Рис. 10.2. Загрузка DLL с ловушкой в адресное пространство исследуемого процесса
Теперь нет никаких препятствий в вызове функции-ловушки при наблюдении за другим процессом.
Примечание
В каждой библиотеке реализуется функция DIIMain, вызываемая (упрощенно) при загрузке/выгрузке библиотеки. Жаль только, что при описанном способе подгрузки DLL эта функция не вызывается. Это приводит к усложнению кодаловушки, в чем вы сможете вскоре убедиться.
10.2. Программа «Оконный шпион»
Перейдем, наконец, к практической части главы: рассмотрим создание программы, позволяющей составлять список (а точнее, дерево) всех окон, просматривать и изменять их свойства, а также осуществлять перехват сообщений выбранного окна (недаром мы столько времени потратили на рассмотрение ловушек Windows).
Несмотря на свое «противозаконное» название, рассматриваемая программа может весьма пригодиться при отладке приложений, а отнюдь непри их взломе и шпионаже (хотя многое зависит от добросовестности лица, использующего программу). В частности, с помощью этой программы была найдена ошибка, на долгое время закравшаяся в один из примеров гл. 2: из-за неправильной установки стилей при ручном создании главного окна программы не удавалось добиться правильной перерисовки элемента управления «рамка».
Составление списка открытых оконСписок (а точнее, дерево) окон, открытых в момент запуска программы, показан на рис. 10.3.
Рис. 10.3. Дерево открытых окон
Форма, показанная на рис. 10.3, имеет имя f rmMain. Элемент управления TreeView имеет имя tree. Часть программы, отвечающая за построение дерева, относительно проста. Она использует вскользь рассмотренный в гл.2 механизм перечисления окон.
Составление дерева окон начинается с процедуры LoadWindowsTree, которая и запускает перечисление окон верхнего уровня, то есть окон, родителем которых формально является окно Рабочего стола (листинг 10.1).
Листинг 10.1. Начало составления дерева окон
procedure TfrmMain.LoadWindowsTree();
var
desktop: TTreeNode;
//enInfo: TEnumInfo;
begin
tree.Items.Clear;
//Добавление узла для Рабочего стола
desktop := tree.Items.Add(tree.Items.GetFirstNode, 'Рабочий
стол');
//Перечисление окон
enInfo.tree := tree;
enInfo.parent := desktop;
EnumWindows(Addr(NewWindow), Integer(Addr(enInfo)));
end;
Сразу следует привести объявление структуры, интенсивно используемой (далее это будет видно) при составлении дерева:
Type
TEnumInfo = Record
tree: TTreeView; //Компонент TreeView
parent: TTreeNode; //Элемент дерева, соответствующий
//текущему окну, дочерние
//окна которого перечисляются
end;
При нахождении каждого нового окна вызывается функция NewWindow (ее адрес передан в API-функцию EnumWindows). Функция NewWindow (листинг 10.2) решает две задачи. Во-первых, она добавляет в дерево элемент, соответствующий найденному окну. Во-вторых, запускает поиск дочерних окон относительно найденного окна, что позволяет перечислить все окна (от главной формы приложения до кнопок, надписей и т. д.).
Листинг 10.2. Добавление в дерево информации об окне и поиск дочерних окон
function NewWindow(wnd: HWND; param: LPARAM):BOOL; stdcall;
var
wndNode, parentNode: TTreeNode;
begin
wndNode := AddWindowToTree(wnd); //Добавление информации об
окне в дерево
//Перечисление дочерних окон
parentNode := enInfo.parent;
enInfo.parent := wndNode;
EnumChildWindows(wnd, Addr(NewWindow), param);
enInfo.parent := parentNode;
//Продолжать перечисление (после перечисления
//всех дочерних окон)
NewWindow := True;
end;
Используемая в листинге 10.3 функция AddWindowToTree добавляет элемент, соответствующий найденному окну, в дерево (определяет текст заголовка окна и имя оконного класса):
Листинг 10.3. Добавление элемента, соответствующего окну, в дерево
function AddWindowToTree(wnd: HWND): TTreeNode;
var
caption, classname: String;
text: String;
node: TTreeNode;
begin
//Получение текста окна
SetLength(caption, SendMessage(wnd, WM_GETTEXTLENGTH, 0, 0) + 1);
SetLength(caption, SendMessage(wnd, WM_GETTEXT, Length(caption),
Integer(PAnsiChar(caption))));
//Имя класса окна
SetLength(classname, 1024);
SetLength(classname, GetClassName(wnd, PAnsiChar(classname),
100));
//Формирование текста для элемента и добавление его в дерево
text := '"' + caption + '" ' + classname;
node := enInfo.tree.Items.AddChild( enInfo.parent, text );
node.Data := Pointer(wnd); //Не забываем запомнить
//дексриптор окна
AddWindowToTree := node;
end;
Вот, собственно, и все, что требуется для построения полного дерева окон, показанного на рис. 10.3.
Получение информации об окнеСледующей функцией «оконного шпиона» является определение более-менее полной информации об окне, выбранном в дереве. Форма с информацией о выделенном в дереве окне (в данном случае это пресловутая кнопка Пуск) показана на рис. 10.4.
Рис. 10.4. Форма свойств окна
Начинается все с того, что по команде меню Правка → Свойства вызывается метод ShowWindowProp созданного при запуске программы объекта f rmWindowProp. Этот метод принимает в качестве параметра дескриптор окна, информацию о котором нужно отобразить (дескриптор сохраняется в поле Data каждого элемента при построении дерева) (листинг 10.4).
Листинг 10.4. Подготовка формы свойств выбранного окна
procedure TfrmWindowProp.ShowWindowProp(window: HWND);
begin
wnd := window;
LoadWindowInfo();
ShowModal(); //Не забываем показать сами себя
end;
Переменная wnd, в которой сохраняется переданный BShowWindowProp дескриптор окна, является членом класса Tf rmWindowProp. Она нужна для того, чтобы другие методы формы Tf rmWindowProp могли получать доступ к дескриптору окна.
Определение заголовка, имени класса, идентификатора окна, а также области экрана, занимаемой окном, осуществляется в процедуре LoadWindowInf о (листинг 10.5).
Листинг 10.5. Определение общей информации об окне
procedure TfrmWindowProp.LoadWindowInfo();
var
rect: TRect;
buffer: String;
begin
//Сбор сведений об окне
//..имя класса
SetLength(buffer, 1024);
SetLength(buffer, GetClassName(wnd, PAnsiChar(buffer), 1024));
txtClassName.Text := buffer;
//..имя (заголовок) окна
SetLength(buffer, SendMessage(wnd, WM_GETTEXTLENGTH, 0, 0) + 1);
SendMessage(wnd, WM_GETTEXT, Length(buffer),
Integer(PAnsiChar(buffer)));
txtWindowName.Text := buffer;
//..идентификатор (или дескриптор меню) окна
txtId.Text := IntToStr(GetWindowLong(wnd, GWL_ID));
//..оконный прямоугольник
GetWindowRect(wnd, rect);
txtWindowRect.Text :=
'(' + IntToStr(rect.Left) + ',' + IntToStr(rect.Top) + ')' +
' – ' +
'(' + IntToStr(rect.Right) + ',' + IntToStr(rect.Bottom) + ') ' +
IntToStr(rect.Right–rect.Left) + 'x' + IntToStr(rect.Bottom –
rect.Top);
//Определение стиля окна
LoadWindowStyle();
LoadWindowExStyle();
end;
Если вы внимательно просмотрели листинг 10.5, то могли заметить вызовы двух процедур в двух последних строках кода. Процедура LoadWindowStyle заполняет списки используемых и доступных оконных стилей (см. рис. 10.4), а процедура LoadWindowExStyle соответственно заполняет списки используемых и доступных дополнительных (или расширенных) стилей окна.
Реализация процедуры LoadWindowStyle приводится в листинге 10.6
Листинг 10.6. Заполнение списков оконных стилей
procedure TfrmWindowProp.LoadWindowStyle();
var
i: Integer;
style: DWORD;
begin
style := GetWindowLong(wnd, GWL_STYLE);
lstStyle.Clear();
lstAvailStyle.Clear();
//Выделение из 32-битного значения составляющих стиля окна
for i := 0 to 17 do
if styles[i].value and style <> 0 then
begin
//Стиль используется
lstStyle.Items.Add(styles[i].name);
styles[i].used := True;
end
else
begin
//Стиль не используется
lstAvailStyle.Items.Add(styles[i].name);
styles[i].used := False;
end;
end;
Вместо громоздкой проверки наличия в значении, возвращенном API-функцией GetWindowLong, битов каждого возможного стиля при помощи, например, case здесь используется глобальный массив styles структур Styleinf о. Объявление типа структуры (записи) Styleinf о выглядит следующим образом:
type
StyleInfo = record
value: DWORD; //Код стиля
name: String; //Текстовое обозначение стиля
used: Boolean; //Служебное поле
end;
Каждый элемент массива styles хранит информацию об определенном оконном стиле. Объявление этого массива, так же, как структуры Stylelnfo и прочих рассмотренных в этом разделе типов данных, находится в модуле WindowData, расположенном на диске в папке с номером главы.
Ниже приведено объявление массива styles (флаги стиля, являющиеся комбинацией других флагов, в массив не попали) (листинг 10.7).
Листинг 10.7. Массив с информацией об оконных стилях
styles: array [0..17] of StyleInfo =
(
(value: WS_BORDER; name: 'WS_BORDER'),
(value: WS_CAPTION; name: 'WS_CAPTION'),
(value: WS_CHILD; name: 'WS_CHILD'),
(value: WS_CLIPCHILDREN; name: 'WS_CLIPCHILDREN'),
(value: WS_DISABLED; name: 'WS_DISABLED'),
(value: WS_DLGFRAME; name: 'WS_DLGFRAME'),
(value: WS_HSCROLL; name: 'WS_HSCROLL'),
(value: WS_MAXIMIZE; name: 'WS_MAXIMIZE'),
(value: WS_MAXIMIZEBOX; name: 'WS_MAXIMIZEBOX'),
(value: WS_MINIMIZE; name: 'WS_MINIMIZE'),
(value: WS_MINIMIZEBOX; name: 'WS_MINIMIZEBOX'),
(value: WS_OVERLAPPED; name: 'WS_OVERLAPPED'),
(value: WS_POPUP; name: 'WS_POPUP'),
(value: WS_SYSMENU; name: 'WS_SYSMENU'),
(value: WS_TABSTOP; name: 'WS_TABSTOP'),
(value: WS_THICKFRAME; name: 'WS_THICKFRAME'),
(value: WS_VISIBLE; name: 'WS_VISIBLE'),
(value: WS_VSCROLL; name: 'WS_VSCROLL')
);
Процедура LoadWindowExStyle реализована практически так же, как и процедура LoadWindowStyle. Только она заполняет cnncKHlstExStyle HlstAvailExStyle и обращается к массиву exstyles, а не styles. Поэтому приведем объявление только массива exstyles (листинг 10.8).
Листинг 10.8. Массив с информацией о дополнительных оконных стилях
exstyles: array [0..18] of StyleInfo =
(
(value: WS_EX_ACCEPTFILES; name: 'WS_EX_ACCEPTFILES'),
(value: WS_EX_APPWINDOW; name: 'WS_EX_APPWINDOW'),
(value: WS_EX_CLIENTEDGE; name: 'WS_EX_CLIENTEDGE'),
(value: WS_EX_CONTEXTHELP; name: 'WS_EX_CONTEXTHELP'),
(value: WS_EX_CONTROLPARENT; name: 'WS_EX_CONTROLPARENT'),
(value: WS_EX_DLGMODALFRAME; name: 'WS_EX_DLGMODALFRAME'),
(value: WS_EX_LAYERED; name: 'WS_EX_LAYERED'),
(value: WS_EX_LEFT; name: 'WS_EX_LEFT'),
(value: WS_EX_LEFTSCROLLBAR; name: 'WS_EX_LEFTSCROLLBAR'),
(value: WS_EX_MDICHILD; name: 'WS_EX_MDICHILD'),
(value: WS_EX_NOACTIVATE; name: 'WS_EX_NOACTIVATE'),
(value: WS_EX_NOINHERITLAYOUT; name: 'WS_EX_NOINHERITLAYOUT'),
(value: WS_EX_NOPARENTNOTIFY; name: 'WS_EX_NOPARENTNOTIFY'),
(value: WS_EX_RIGHTSCROLLBAR; name: 'WS_EX_RIGHTSCROLLBAR'),
(value: WS_EX_STATICEDGE; name: 'WS_EX_STATICEDGE'),
(value: WS_EX_TOOLWINDOW; name: 'WS_EX_TOOLWINDOW'),
(value: WS_EX_TOPMOST; name: 'WS_EX_TOPMOST'),
(value: WS_EX_TRANSPARENT; name: 'WS_EX_TRANSPARENT'),
(value: WS_EX_WINDOWEDGE; name: 'WS_EX_WINDOWEDGE')
);
Правообладателям!
Это произведение, предположительно, находится в статусе 'public domain'. Если это не так и размещение материала нарушает чьи-либо права, то сообщите нам об этом.