Delphi World - это проект, являющийся сборником статей и малодокументированных возможностей  по программированию в среде Delphi. Здесь вы найдёте работы по следующим категориям: delphi, delfi, borland, bds, дельфи, делфи, дэльфи, дэлфи, programming, example, программирование, исходные коды, code, исходники, source, sources, сорцы, сорсы, soft, programs, программы, and, how, delphiworld, базы данных, графика, игры, интернет, сети, компоненты, классы, мультимедиа, ос, железо, программа, интерфейс, рабочий стол, синтаксис, технологии, файловая система...
Мечты вуайериста - чужие окна 2

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

Несколько предварительных сурьезных слов.

Вынужден сказать, что многое изложенное ниже может привести к неприятным последствиям. Например, к тому, что программа или система будет зависать. Поэтому будем считать, что читатель находиться в трезвом уме и здравой памяти и не будет совершать необдуман ные действия. Прежде чем убить или закрыть чужое окно, подумайте, а зачем это окно вообще висит. Помните, что если окна висят в системе значит это кому то нужно ?! (почти Маяковский). Ну а теперь немного попугав для проформы перейдем к делу.

Содержание:

Несколько предварительных сурьезных слов.
Режимы отображение окон верхнего уровня.
Системное меню и кнопки заголовка.
Некоторые дополнительные возможности.
Итоги

Итак…

Режимы отображение окон верхнего уровня.

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

Функция SetForegroundWindow

Синтаксис:


function SetForeGroundWindow(Wd: Hwnd):Boolean; 

Описание: Показывает верхние окно системы.

Параметры:

Wnd: Идентификатор окна.
Возвращаемое значение: True- если функция отработала, False- при ошибке.

Процедура BringWindowToTop

Синтаксис:


procedure BringWindowToTop(Wnd: HWnd);

Описание: Активизирует и перемещает Wnd в вершину стека перекрывающихся окон.

параметры:

Wnd: Всплывающее или дочернее окно.
Возвращаемое значение: Нет

Теперь попробуем проделать с неким окном, имеющим идентификатор окна HD:HWnd некие стандартные действия:

1) Свернуть данное окно;
2) Развернуть данное окно;
3) Закрыть данное окно.

Все данные действия могут быть проделаны с окном при помощи стандартной функции SendMessage или PostMessage, с различными параметрами:

1) SendMessage(HD,WM_SYSCOMMAND,SC_MINIMIZE,0);
2) SendMessage(HD,WM_SYSCOMMAND,SC_MAXIMIZE,0);
3) SendMessage(HD,WM_SYSCOMMAND,SC_CLOSE,0);

Существуют и другие константы, для сообщений вида WM_SYSCOMMAND:

SC_CLOSE Закрывает окно.
SC_CONTEXTHELP Изменяет курсор на вопросительный знак.
SC_DEFAULT Выбирает элемент по умолчанию; эмулирует двойное нажатие на Системное меню.
SC_HOTKEY Инициирует окно, связанное с текущим - указанной комбинацией горячих клавиш.
SC_HSCROLL Прокручивается горизонтально окно.
SC_KEYMENU Открывает Системное меню как результат нажатия клавиши.
SC_MAXIMIZE (или SC_ZOOM) Разворачивает окно.
SC_MINIMIZE (или SC_ICON) Сворачивает окно.
SC_MONITORPOWER Устанавливает состояние дисплея.
SC_MOUSEMENU Открывает Системное меню как результат щелчка мыши.
SC_MOVE Перемещает окно.
SC_NEXTWINDOW Переходит к следующему окну.
SC_PREVWINDOW переходит к предыдущему окну.
SC_RESTORE Восстанавливает окно к его нормальной позиции и размеру.
SC_SCREENSAVE Запускает стандартный скринсейвер.
SC_SIZE Задает размеры окно.
SC_TASKLIST Выполняет или инициирует Windows Task Manager.
SC_VSCROLL Прокручивается окно вертикально.

Первый параметр - описатель искомого окна, второй сообщение (в нашем случае WM_SYSCOMMAND) третий одна из констант приведенных выше, четвертый параметр - координаты (x- младшее слово y - старшее).

Можно, так же, показать или скрыть окно, используя функцию API:

Процедура ShowWindow

Синтаксис:


function ShowWindow(Wnd: HWnd; CmdShow: Integer); 

Описание: отображает или прячет окно образом, указанным параметром CmdShow.

параметры:

Wnd: Всплывающее или дочернее окно.
CmdShow - одна из констант:

SW_HIDE
SW_MAXIMIZE
SW_MINIMIZE
SW_RESTORE
SW_SHOW
SW_SHOWDEFAULT
SW_SHOWMAXIMIZED
SW_SHOWMINIMIZED
SW_SHOWMINNOACTIVE
SW_SHOWNA
SW_SHOWNOACTIVATE
SW_SHOWNORMAL

Возвращаемое значение: Не нуль, если окно было ранее видимым; нуль - если оно было ранее спрятанным.

Константы позволяют скрыть/показать окно с различными типами (распахнутым, свернутым, неактивным и пр.)

Давайте теперь попробуем решить ряд наиболее часто встречающихся проблем:

1) Как свернуть все окна системы ??? (как свернуть все окна системы кроме окна программы)


// Любимая наша процедура.
{Для того чтобы использовать данный пример необходимо наличие кнопки Button1.}

function EnumMiniProc (Wd: HWnd; Param: LongInt): Boolean; stdcall; // Обязательно stdcall !!! 
Begin
 If  Wd<>Form1.Handle then // если это не наша программа 
        If  IsWindowVisible(WD) then       // если окно видимо
            If  not IsIconic(WD) then      // если окно не свернуто
              If  isWindow(WD) then        // и вообще это - окно.
                 ShowWindow(WD, SW_MINIMIZE); // свернем его.
EnumProc := TRUE; // продолжаем перебирать все окна системы.
end;

procedure TForm1.Button1Click(Sender: : TObject); // допустим, закрываем по нажатию на клавишу
begin
 EnumWindows (@EnumMiniProc, 0); // отрабатываем сворачивание окон.
end;

Для того чтобы окно программы тоже сворачивалось достаточно убрать строку If Wd<>Form1.Handle then в EnumMiniProc

Конечно, можно поставить еще массу условий, по которым будут минимизироваться окна, но это уже дело конкретной задачи.

Еще один пример, который бывает зачастую нужен:

2) Как закрыть (или постоянно закрывать) окна, например содержащие в заголовке подстроку «Реклама»

Закрыть все окна, содержащие определенную подстроку в заголовке.


Const
    ReclamaName : String = 'Реклама' ; // строка, по которой мы узнаем, что это - реклама.
    TimeInterval     : Integer = 500;  // Интервал, с которым будем проверять наличие окон
{Для того чтобы использовать данный пример необходимо наличие таймера  Timer1.}
// Любимая наша процедура
function EnumCloseProc (Wd: HWnd; Param: LongInt): Boolean; stdcall; // Обязательно stdcall !!! 
Var
       Nm:Array[0..255] of Char;  // буфер для имени
   zName:String;

Begin
 GetWindowText(Wd,Nm,255);         // считываем  текст заголовка окна
 ZName:=AnsiUpperCase(String(Nm)); // преобразуем к верхнему регистру т.е РЕКЛАМА
If Pos(ReclamaName,zName)<>0 then SendMessage(WD,WM_SYSCOMMAND,SC_CLOSE,0);
EnumProc := TRUE;                  // продолжаем перебирать все окна системы.
end;

procedure Tform1.Timer1Timer(Sender: TObject); // будем проверять по таймеру…
begin
 Timer1.Interval:= TimeInterval;  // установим время до следующего вызова
 EnumWindows (@EnumCloseProc, 0); // отрабатываем закрытие окон.
end;


Понятно, что настоящая реклама не дает себе таких заголовков, но общий принцип останется тем же, а так попробуйте поискать общее в заголовках окна, названии классов окна и т.п. Кроме того, использование таймера чревато тем, что окон в системе очень много и за установленный интервал времени все окна не будут отработаны, это приведет к замедлению работы системы. Но решение данной подзадачки автор оставляет за читателем, благо особых сложностей с этим нет (увеличения интервала времени, установка логического условия о том, что проверка уже идет, вставка оператора Application.ProcessMessages и проч.)

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

Системное меню и кнопки заголовка.

Системное меню, отображает обычно ряд доступных стандартных функций применимых к окнам.

Обычно к таким функциям относятся следующие команды (применительно к локализованным Windows, в англоязычных названия будут другие, есть подозрения, что английские J):

Восстановить - восстанавливает размер окна.
Переместить - перемещает окно.
Размер - позволяет изменить размер окна.
Свернуть - сворачивает окно до иконки (минимизирует).
Развернуть - разворачивает окна до максимально возможного размера
Закрыть - закрывает окно.

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

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

Зачем манипулировать доступными командами системного окна ??? Ну, например, есть окошко, у которого кнопка закрыть - недоступна, а в системном меню пункта закрыть нет, да и на Alt+F4 она не откликается. А убрать программку ужас как хочется.

Процедура GetSystemMenu

Синтаксис:


function GetSystemMenu(Wnd: HWnd; Revert: Bool): HMenu;

Описание: Считывает системное меню окна для копирования и модификации.

параметры:

Wnd: Всплывающее или дочернее окно.
Revent: Нуль, чтобы возвращался описатель для копирования системного меню, и не нуль, чтобы возвращался описатель исходного системного меню.
Возвращаемое значение: идентификатор системного меню;
0 - если Revert отлична от нуля и системное меню не модифицировано.

Для начала надо получить идентификатор системного меню. При помощи приведенной выше функции.

Далее попробуем определить, что именно содержится в системном меню (надо сказать, что приведенные ниже функции API справедливы для любых меню, а не только системных, но об этом несколько позже):

Процедура GetMenuString

Синтаксис:


function GetMenuString(Menu: HMenu; IDItem: Word; Str: PChar;
  MaxCount: Integer; Flag: Word): Integer;

Описание: копирует метку элемента меню в Str. параметры:

Menu: идентификатор меню.
IDItem: идентификатор элемента меню.
Str: принимающий буфер.
MaxCount: размер буфера.
Flag: Одна из констант меню

mf_ByPosition - определять пункт меню по порядковому номеру
mf_ByCommand - определять пункт меню по выполняемой команде.

Возвращаемое значение: Количество реально скопированных байт.

Как видно из описания функции возможно два варианта определения списка по номеру или по выполняемой команде.

Если Flag = mf_ByCommand тогда в качестве IDItem передаются стандартные команды (см. константы в WM_SYSCOMMAND. Предыдущий раздел).

Например


I:=GetMenuString (hMenu, SC_CLOSE, Mn,255,mfByCommand);

Возвращает название пункта системного меню, отвечающего за закрытие окна. I=0 указывает, что такого пункта в системном меню нет.

Если Flag = mf_ByPosition тогда в качестве IDItem передается порядковый номер искомого пункта меню, начиная с 0

Например


I:=GetMenuString (hMenu, 0, Mn,255,mfByPosition);

Возвращает название самого первого по порядку пункта системного меню (обычно это восстановить). I=0 указывает, что такого пункта в системном меню нет. ИМХО первый вариант более пригоден для получения списка строк системного меню, в то время как второй - д ля определения присутствует ли данная команда в системном меню.

Количество элементов меню можно получить при помощи функции

Процедура GetMenuItemCount

Синтаксис:


function GetMenuItemCount(Menu: HMenu): Word;

Описание: определяет число меню и элементов меню верхнего уровня в указанном меню.

параметры:

Menu: идентификатор меню.
Возвращаемое значение: В случае успешного завершения возвращается число элементов меню; 0 - в противном случае.

Вот как приблизительно может выглядеть функция, которая определяет системное меню окна:

Получение списка системного меню окна.


...
ListBox1 : TlistBox; // Полученный список запихиваем сюда
... ...

Procedure GetSysMenuItem (Wd:HWND); // Передаем идентификатор окна.
Var 
      I,K,Q:Word;
      hMenuHandle : HMENU;
      Nm:Array[0..255] of Char;
Begin
 ListBox1.Clear; // Очистим список перед использованием.
 hMenuHandle:=GetSystemMenu(Wd, FALSE); // Получим идентификатор
if (hMenuHandle = 0) then Exit;  // Если такого меню нет, то выходим
Q:=GetMenuItemCount(hMenuHandle);       // Определяем количество пунктов меню.
For k:=0 to Q-1 do
 Begin
  i:=GetMenuString(hMenuHandle,k,Nm,255,MF_BYPOSITION); // Считываем название
  ListBox1.Items.Add(String(Nm)); // Добавляем в список.
End;
End;


Итак, мы получили список пунктов системного меню. Пустые строки, скорее всего, означают разделители. Так же используются акселераторы (&)

Следующим шагом будет определение состояния того или иного пункта меню.

Процедура GetMenuState

Синтаксис:


function GetMenuState(Menu: HMenu; ID, Flags: Word):

Описание: Считывает инфоpмацию состояния для указанного элемента меню.

параметры:

Menu: идентификатор меню.
IDItem: идентификатор элемента меню.
Flag: Одна из констант меню

mf_ByPosition - определять пункт меню по порядковому номеру
mf_ByCommand - определять пункт меню по выполняемой команде.

Возвращаемое значение: Маски флагов из следующих значений:

mf_Checked - отмеченное галочкой
mf_Disabled - недоступное
mf_Enabled - доступное
mf_MenuBarBreak - в новой строке или столбце с рисовкой разделителя
mf_MenuBreak - в новой строке или столбце без линий
mf_Separator - строка -разделитель
mf_UnChecked - неотмеченное.

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


...
ListBox1 : TlistBox; // Полученный список запихиваем сюда
... ...

Procedure GetSysMenuStatus (Wd:HWND); // Передаем идентификатор окна.
Var
      K,Q,l:Word;
      hMenuHandle : HMENU;
      Nm:Array[0..255] of Char;
      S:String;
Begin
 Form1.ListBox1.Clear; // Очистим список перед использованием.
 hMenuHandle:=GetSystemMenu(Wd, FALSE); // Получим идентификатор
if (hMenuHandle = 0) then Exit;  // Если такого меню нет, то выходим
Q:=GetMenuItemCount(hMenuHandle);       // Определяем количество пунктов меню.
For k:=0 to Q-1 do
 Begin
  GetMenuString(hMenuHandle,k,Nm,255,MF_BYPOSITION); // Считываем название
 S:=String(Nm);
  l:=GetMenuState(hMenuHandle,k,MF_BYPOSITION);         // Считываем состояние пункта меню
  If (L and mf_Separator=mf_Separator) then S:='----------------';  // Если это разделитель
  If (l and mf_Grayed<>mf_Grayed) then S:='(a)'+S;  // Если пункт меню подсвечен 
  Form1.ListBox1.Items.Add(S); // Добавляем в список.
End;
End;

Точно так же можно определять и многие другие параметры пунктов меню. Для получения большего количества информации о пункте меню можно использовать

Пpоцедуpа GetMenuItemInfo

Синтаксис:


function GetMenuItemInfo(Menu: HMenu; ID, Flags: Word; Info:TMenuItemInfo): Word;

Описание: Выдает информацию о пункте меню.

параметры:

Menu: идентификатор меню.
ID: Идентификатор элемента меню.
Flag: Одна из констант меню
mf_ByPosition - определять пункт меню по порядковому номеру (или TRUE)
mf_ByCommand - определять пункт меню по выполняемой команде (или False).
Info : Указатель на структуру MENUITEMINFO


MENUITEMINFO = Record
CbSize : Word;  // размер структуры в байтах
FMask : Word;   // Определяет какие поля записи должны быть установлены или выбраны
FType : Word;   // Тип пункта меню (основные)
    //mft_BitMap - отображаемое с растровым изображением
    // mft_Separator - строка -разделитель 
    // mft_String - строка
    // mft_RadioCheck - строка с возможностью выбора
    // mft_OwnerDraw - рисуемое пользователем
FState : Word; //Состояние пункта меню (основные).
    // mfs_Checked - отмеченное галочкой 
    // mfs_UnChecked - неотмеченное. 
    // mfs_Default - по умолчанию
    // mfs_Grayed - серое.
wID    : Word;           // Идентификатор пункта меню
hSubMenu : HMENU;        // Идентификатор подменю. Если подменю нет то Null
hBmpChecked : HBITMAP;   // Дескриптор растра для выбранного пункта
hBmpUnChecked : HbitMap; // Дескриптор растра для не выбранного пункта
dwItemData : DWORD;      // Определяемое приложением значение
dwTypeData ; PAnsiChar;  // Содержимое пункта меню
cch : Word;              // Длина текста
hBmpItem: HBITMAP;       // Дескриптор отображаемого изображения пункта меню.
End;

Возвращаемое значение: В случае успешного завершения возвращается 1; 0 - в противном случае. Эта функция является упрощенным вариантом монстроподобной GetMenuInfo, которая, к сожалению, поддерживается не везде (Делфа 3 не поддерживает), поэтому описывать и привязываться к этой функции не буду. Итак, мы получили список пунктов системного меню окна . Теперь можно

1) Изменять статус пунктов меню (и соответствующих им кнопок заголовка)
2) Удалять «лишние» пункты меню
3) Добавлять «необходимые» пункты меню.

Будем решать эти вопросы по порядку.

процедура EnableMenuItem

Синтаксис:


function EnableMenuItem(Menu: HMenu; IDEnableItem, Enable: Word): LongBool;

Описание: разрешает, блокирует или затеняет элемент меню в соответствии со значением параметра Enable.

Menu: Идентификатор меню.
IDEnableItem: идентификатор или позиция элемента меню или помечаемый всплывающий элемент.
Enable: Комбинация констант

mf_ByCommand - пункты меню по команде
или
mf_ByPosition - пункты меню по порядку

совмещенные с константами

mf_Disabled, - недоступный
mf_Enabled - доступный
mf_Grayed. - затененый

Возвращаемое значение: Пpедыдущее состояние элемента меню; -1, если элемент не существует..

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

Включение/выключение пункта меню


procedure EnableSysItem(WD:HWND;Number:Integer);
// передаем описатель окна и номер пункта
Var
    hMenuHandle : HMENU;
    i : LongInt;
    l,r : word;
begin
  If (Number<0)  then Exit; // Если такого пункта точно быть не может
  hMenuHandle:=GetSystemMenu(Wd,False); // Получим идентификатор
  if hMenuHandle=0 then Exit; // Если меню нет
  R:=mf_ByPositon; 
  //Прочтем текущее состояние
  l:=GetMenuState(hMenuHandle,Number,MF_BYPOSITION); 
  // Переключим состояние 
  if l and mfs_Disabled <> mfs_Disabled then R:=R or mfs_Disabled
  else R:=R or mfs_Enabled;
   i:=LongInt(EnableMenuItem(hMenuHandle,Number,R));
end;

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

Пpоцедуpа DeleteMenu

Синтаксис:


procedure DeleteMenu(Menu: HMenu Position, Flags: Word): Bool;

Описание: Удаляет элемент из Menu. Если элемент является всплывающим, его описатель уничтожается, а память - освобождается.

Menu: Идентификатор меню.
Position: Положение или идентификатоp команды.
Flags: Одна из констант меню: mf_ByPosition, mf_ByCommand.
Возвращаемое значение: В случае успешного завеpшения - не нуль; в пpотивном случае - 0.

Описание стандартное, поэтому никаких сложностей при использовании данной функции возникнуть не должно. ИМХО использование как раз этой функции - тот случай, когда в качестве параметра flags лучше передавать значение mf_ByCommand явно указывая какую коман ду Вы собираетесь удалить из меню. Так же следует заметить, что удаление пункта меню, которому соответствует кнопка заголовка приведет не к исчезновению кнопки из заголовка, а только к ее затенению.

Добавить пункт меню можно двумя способами: просто добавить пункт в конец меню:

Пpоцедуpа AppendMenu

Синтаксис:


function AppendMenu(Menu: HMenu; Flags, IDNewItem: Word; Name: PChar): Bool;

Описание: Пpисоединяет в конец меню новый элемент, состояние котоpого опpеделяется Flags.

Menu: Идентификатор меню.
IDNewItem: Положение или идентификатоp команды.
Flags: Одна из констант меню: mf_ByPosition, mf_ByCommand.
Name: Название пункта меню.
Возвращаемое значение: В случае успешного завеpшения - не нуль; в пpотивном случае - 0.

Или вставить пункт меню настроив все необходимые параметры

Пpоцедуpа InsertMenuItem

Синтаксис:


function InsertMenuItem (Menu: HMenu; Flags, IDNewItem: Word; Item: :TMenuItemInfo): Bool;

Описание: Вставляет пункт меню.

Menu: Идентификатор меню.
IDNewItem: Положение или идентификатоp команды.
Flags: Одна из констант меню: mf_ByPosition, mf_ByCommand.
Item: Структура определяющая пункт меню (см. описание GetMenuItemInfo)
Возвращаемое значение: В случае успешного завеpшения - не нуль; в пpотивном случае - 0.

Ну и как результат всех наших стараний напишем процедуру, которая разрешает или запрещает кнопку, строку системного меню «закрыть» (а так же комбинацию клавиш Alt+F4):

Удаление или восстановление кнопки закрыть окно.


// Отключает или разрешает так же пункт меню, и комбинацию Alt+F4
Procedure CloseXbtn (Wd:HWND; Enable:Boolean); 
Var
    hMenuHandle : HMENU;
Begin
  hMenuHandle:=GetSystemMenu(Wd,False); // Получим идентификатор
  if hMenuHandle=0 then Exit; // Если меню нет
  If Enable then  // Если надо добавить пункт меню
      AppendMenu (hMenuHandle, mf_ByCommand, SC_Close,'&Закрыть Alt+F4');
        Else DeleteMenu(hMenuHandle, SC_Close, mf_ByCommand);
End;

Конечно, куда правильнее было бы использовать функцию InserMenuItem вместо AppendMenu, тогда можно было бы поставить слева значек «закрыть». Но это уже для любителей самим повозиться с API, очень уж не хочется лишать их этого удовольствия J.

Ну, и, наконец, для развлечения тех, кто продрался сквозь все эти кошмары работы с системным меню, предлагаю маленькое развлечение.

Иногда появляется необходимость нарисовать, что-нибудь (например, кнопку) в заголовке чужого окна (а возможно и своего). Это можно сделать очень и очень просто.

Пpоцедуpа DrawFrameControl

Синтаксис:


function DrawFrameControl (DC:HDC;Rc :Trect; uType,uStyle:Word ): Bool;

Описание: Рисует один из элементов в заголовке окна.
DC : контекст устройства в котором происходит рисование.
Rc : Область в которой будет происходить рисование
UType: Тип элемента одна из констант:

DFC_BUTTON Кнопка
DFC_CAPTION Заголовок
DCF_MENU Меню
DFC_SCROLL Полоса прокрутки
Ustyle : Стиль элемента одна из констант:

Для кнопок

DFCS_BUTTON3STATE Кнопка с тремя состояниями
DFCS_BUTTONCHECK Флажок
DFCS_BUTTONPUSH Кнопка
DFCS_BUTTONRADIO Переключатель
DFCS_BUTTONRADIOIMAGE Картинка для переключателя
DFCS_BUTTONRADIOMASK Маска для переключателя

Для заголовков

DFCS_CAPTIONCLOSE Кнопка закрыть
DFCS_CAPTIONHELP Кнопка помощь (только Window 9x)
DFCS_CAPTIONMAX Кнопка развернуть
DFCS_CAPTIONMIN Кнопка свернуть
DFCS_CAPTIONRESTORE Кнопка восстановить

Для меню

DFCS_MENUARROW Стрелка подменю
DFCS_MENUBULLET Маркер
DFCS_MENUCHECK Маркер - флажек

Для полос прокрутки

DFCS_SCROLLCOMBOBOX Линейка прокрутки выпадаюшего списка DFCS_SCROLLDOWN Кнопка вниз DFCS_SCROLLLEFT Кнопка влево DFCS_SCROLLRIGHT Кнопка вправо DFCS_SCROLLSIZEGRIP Размерная ручка DFCS_SCROLLUP Кнопка вверх

Возвращаемое значение: В случае успешного завеpшения - не нуль; в пpотивном случае - 0.

Заметьте, что это функция только рисует элемент заголовка.

14 Отрисовка «фальшивой» кнопки закрыть в заголовке окна.


Procedure DrawFalseClose (Wd:HWND; xPos:Integer);
Var DC:HDC;
begin
 DC:=GetWindowDC(Wd); // Получим контекст устройства окна
If DC>0 then
 Begin
   DrawFrameControl (DC,Rect(xPos,4,xPos+16,020),DFC_Caption,DFCS_CaptionClose);
   ReleaseDC(Wd,DC); // Освободим контекст устройства.
End;
end;

Некоторые дополнительные возможности

С приложениями (и окнами верхнего уровня в частности) можно делать огромное количество вещей. Если быть честным, то останавливаться подробно на этих возможностях я не собирался. Но оказалось, что решение этих задач интересует достаточно многих. В этом раз деле попробуем привести некоторые, на мой взгляд, наиболее полезные из них.

Самым простым, и наиболее часто используемой является возможность изменять заголовок чужих окон. И действительно, почему в заголовке Дельфы пишется например Delphi ? J Непорядок !

Пpоцедуpа SetWindowText

Синтаксис:


procedure SetWindowText(Wnd: HWnd; Str: PChar);

Описание: Устанавливает название заголовка для окна или текст оpгана упpавления с помощью стpоки, указанной в Str.
Wnd: Идентификатоp окна или оpгана упpавления.
Str: Стpока (заканчивающаяся пустым символом).
Возвращаемое значение:Нет.

И текст, который иллюстрирует работу данной функции, например, находит окно Дельфы и меняет ее заголовок с «Delphi» на любой другой

Замена текста в заголовке окна.


// Передаем новое название например Дельфи
Procedure ChangeDelphi (NewName:String);
Var Wd:HWND;
       Nm:Array[0..255] of Char
       St : String;
       I:Integer;
Begin
  Wd:= FindWindow('TAppBuilder',Nil); // Находим заголовок по классу окна Delphi
 If Wd<=0 then Exit; // Такого окна нет.
GetWindowText(Wd,Nm,255); // Считываем заголовок окна
St:=String(Nm);      // Переводим в строку
I:=Pos('Delphi',St); // Находим положения заголовка
If I>0 then // Если слово Дельфи есть в заголовке
 Begin
  Delete(St,i,Lenght('Delphi'); // Удаляем
  Insert(NewName,St,i); // Вставляем
 SetWindowText(Wd,Pchar(St)); // Отправляем новый заголовок окну.
 End; // Все
end;

Зачастую необходимо выяснить, не зависло ли окно (или вернее насколько живо оно откликается на попытки системы достучаться до него) Для этих целей можно использовать следующий текст

16 Определение не является ли данное окно зависшим.


// Результат True- рабочее окно, False - возможно окно висит 
function WinTimeOut (Wd:HWND;Time:Integer):Boolean; //Описатель окна и время в секундах
Var dwRes:DWORD
begin
 Time:=Time*1000; // Переводим время в миллисекунды 
 Result:=Not SendMessageTimeOut(WD,WM_USER,0,0,SMTO_NORMAL, Time, @dwRes);
end;

Теперь поговорим о, так называемом, подсвечивание окон. Например, при установке точки останова в программе главное окно начинает мерцать. И делает это до тех пор, пока пользователь не переключится в это окно. Как это делается ???

Существует пара функций:

Пpоцедуpа FlashWindow

Синтаксис:


function FlashWindow(Wnd: HWnd; Invert: Bool): Bool;

Описание: Делает окно или пиктогpамму мигающими. Активное состояние откpытого окна инвеpтиpуется.
Wnd: Идентификатоp окна или оpгана упpавления.
Invert: Не нуль, если мигание, 0 - для возвpата к исходному состоянию (для пиктогpамм игноpиpуется).
Возвращаемое значение: Не нуль, если окно до вызова было активным; 0 - в пpотивном случае.

И вторая функция, которая описана для Delphi 5 а для 3 нет, что обидно, но мы это исправим.

Пpоцедуpа FlashWindowEx

Синтаксис:


function FlashWindowEx(var pfwi: FLASHWINFO): BOOL;

Описание: Делает окно или пиктогpамму мигающими. Активное состояние откpытого окна инвеpтиpуется.


FLASHWINFO = record
cbSize: UINT;     // Размер структуры в байтах
hwnd: HWND;       // Идентификатоp окна или оpгана упpавления.
dwFlags: DWORD;   // один из следующих флагов:
    FLASHW_STOP = $0;      // Не мигать
    FLASHW_CAPTION = $1;   // Мигающий заголовок
    FLASHW_TRAY = $2;      // Мигающая кнопка
    FLASHW_ALL = FLASHW_CAPTION or FLASHW_TRAY; // Мигать
    FLASHW_TIMER = $4;     // Мигать пока не будет запущен СТОП
    FLASHW_TIMERNOFG = $C; // Мигать пока не станет верхним
uCount: UINT;     // Сколько раз мигать
dwTimeout: DWORD; // Интервал мигания
end;

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


interface
Const
  FLASHW_STOP = $0;
  FLASHW_CAPTION = $1;
  FLASHW_TRAY = $2;
  FLASHW_ALL = FLASHW_CAPTION or FLASHW_TRAY;
  FLASHW_TIMER = $4;
  FLASHW_TIMERNOFG = $C;
type
  FLASHWINFO = record
    cbSize: UINT;
    hwnd: HWND;
    dwFlags: DWORD;
    uCount: UINT;
    dwTimeout: DWORD;
  end;
  PFLASHWINFO = ^FLASHWINFO;
  TFlashWInfo = FLASHWINFO;

function FlashWindowEx(var pfwi: FLASHWINFO): BOOL; stdcall;
implementation
function FlashWindowEx; external user32 name 'FlashWindowEx'; 
end;

А теперь сама программа, не забудьте подключить модуль кому нужно:

17 Мигающий заголовок окна


// Результат True- рабочее окно, False - возможно окно висит 
procedure SetOnFlash (Wd:HWND;):Boolean; //Описатель окна 
Var f: TFlashWInfo; 
Begin
 f.Hwnd:=Wd;
 f.dwFlags:= FLASHW_ALL;
 f.dwTimeout:=10;
 f.uCount:=100;
 f.cbSize:=SizeOf(F);
 FlashWindowEx(F)
end;


Итоги

Итак, мы научились управлять чужими окнами верхнего уровня:

1. Изменять их положение, размеры
2. Закрывать, сворачивать и восстанавливать

Проект Delphi World © Выпуск 2002 - 2024
Автор проекта: USU Software
Вы можете выкупить этот проект.