Delphi сделать окно активным

Обновлено: 07.05.2024

Delphi сделать окно активным

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

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

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

Синтаксис:
function SetForeGroundWindow(Wd: Hwnd):Boolean;

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

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

Синтаксис:
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);

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 Прокручивается окно вертикально.

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

Синтаксис:
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) Как свернуть все окна системы . (как свернуть все окна системы кроме окна программы)
// Любимая наша процедура.

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; // Интервал, с которым будем проверять наличие окон

// Любимая наша процедура
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 она не откликается. А убрать программку ужас как хочется.

Синтаксис:
function GetSystemMenu(Wnd: HWnd; Revert: Bool): HMenu;

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

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

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

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

Синтаксис:
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 указывает, что такого пункта в системном меню нет. ИМХО первый вариант более пригоден для получения списка строк системного меню, в то время как второй - д ля определения присутствует ли данная команда в системном меню.

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

Синтаксис:
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;

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

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

Синтаксис:
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;

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

Синтаксис:
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) Добавлять «необходимые» пункты меню.

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

Синтаксис:
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;

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

Синтаксис:
procedure DeleteMenu(Menu: HMenu Position, Flags: Word): Bool;

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

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

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

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

Синтаксис:
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.

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

Синтаксис:
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.

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

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

Синтаксис:
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 Непорядок !

Синтаксис:
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;

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

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

Синтаксис:
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 нет, что обидно, но мы это исправим.

Синтаксис:
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;

Delphi сделать окно активным

if ActivatePreviousInstance("TMainForm") then Halt(1);

> Если окно приложения свернуто, то твой код не отображает

Только, окно приложения - это окно класса (windows) TApplication.
Если есть хендл любого другого окна приложения (дельфи, билдер),
то окно приложения можно найти как
happ := GetWindowLong(wnd, GWL_HWNDPARENT)

Не так.
Не foreground приложение не может сделать себя
(другого) foreground.

> Или мы говорим о разных вещах?

Мои утверждения вполне, IMHO, применимы
к любым не-foreground windows приложениям.

function GetMEError(): Integer;

uses Windows, Forms;

Не желательно, а : Обязательно изменить!

Вообще-то, подобные вещи должны браться из реестра.
Т.е., сделать в HKCU раздел формата
\Software\CompanyName\ProductName\..
где второе, третье и др. брать из Version Info,
ключ ActivatePrevInstance (REG_DWORD) 0x1.
Т.е., имя проекции файла формировать из уникальной цепочки.

Кроме того, для активации предыдущей копии полезно
передавать дополнительно параметры комстроки.
Этого можно добиться, например, перечитыванием mmf
при Application.OnActivate. Хотя, это потребует некоторых
усилий по синхронизации. Например, четыре байта файла
использовать для переменной, которая будет
InterLockedCompareExchange.

Ну, и для приложений с формами можно предложить
вполне сравнимый способ без использования
объектов ядра.

> Ну, и для приложений с формами можно предложитьвполне сравнимый
> способ

>

Так предложите. Или хотя бы намекните :-)

>> Ну, и для приложений с формами можно предложить

> Так предложите. Или хотя бы намекните :-)

В CreateWnd (override) главной формы делаем (до inherited)
EnumWindows для поиска окон формы по ее классу, и,
в случае обнаружения такого окна, посылаем ему через
SendMessageTimeOut(wnd, WM_COPYDATA,
параметры комстроки, а также, в cds.dwData - искомый uid.

А в обработчике WM_COPYDATA главной формы полученный uid
сравнивается с собственным, и, в случае равенства,
возвращается (после приема комстроки) Result <> 0.

Т.е., если SendMessageTO успешно - активируем предыдущую копию,
иначе - вызываем inherited для создания окна формы.

Вот, собс-но, вся схема.

> Т.е., если SendMessageTO успешно - активируем предыдущую
> копию,

Delphi сделать окно активным

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


> Во-первых, не ясно и с первым

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


> непонятно, почему известно, что он работает

Тыщу раз использовал! Не верите - проверьте.

> ПРИЛОЖЕНИЕ ДОЛЖНО ВЫЗЫВАТЬ ALLOWFOREGROUNDWINDOW.

Во-первых, не надо на меня кричать, я и не собирался
преступным путем вытаскивать левые окна foreground.

> Тыщу раз использовал! Не верите - проверьте.

Даже пробывать не буду, бо бред.

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

Да я не на Вас кричу, Вы мне ничего плохого не сделали. Если у Вас сложилось такое впечатление, то искренне прошу прощения. Это крик души ;)


> Во-вторых, AFGW здесь причем только поскольку
> в msdn в статье ей посвященной есть перечень ограничений,
> которые некоторым следовало бы выучить наизусть.

Хм, о чем это Вы? Даже специально залез в MSDN, ничего особенного в remarks не нашел.


> Рихтер-то тут причем? Он подобным всплытием, слава Богу,
>
> не страдает

Там достаточно подробно описано работы всплывающих окон.


> Возможно, что SFGW просто спутана, скажем, с SetFocus.

> Хм, о чем это Вы? Даже специально залез в MSDN, ничего особенного
> в remarks не нашел.

Remarks

Starting with Microsoft Windows 98 and Windows 2000, the system restricts which processes can set the foreground window. A process can set the foreground window only if one of the following conditions is true:

The process is the foreground process.
The process was started by the foreground process.
The process received the last input event.
There is no foreground process.
The foreground process is being debugged.
The foreground is not locked (see LockSetForegroundWindow).
The foreground lock time-out has expired (see SPI_GETFOREGROUNDLOCKTIMEOUT in SystemParametersInfo).

> не рабочий? Если да, то вы объективно неправы. Жаль что
> не хотите проверять, ну да ладно, это Ваше дело, я не буду
> настаивать ;) А если вы утверждаете, что код рабочий, но
> вот делать так категорически не надо, то тут частично соглашусь.

Код нерабочий, а методы бесполезные (вредные).
Ранее здесь уже частично объяснял.

> текст в MS Word. Потом берет - и из меню запускает вторую
> копию MyCoolProg. Теперь нам нужно из второй копии найти
> первую и поместить поверх всего, а вторую - закрыть. Окно
> первой копии будет заблокировано, так как по первым двум
> пунктам - оно не принадлежит foreground-process (вторая
> копия) и процесс первой копии не создан foreground-process-
> ом.

А не надо пытаться активировать вторую копию из non-foreground первой.
Вторая же - является таковой по закону, бо запущена by the foreground
process (Explorer), который, в свою очередь, был таковым благодаря
received the last input event (меню).

>умный не тот, кто много знает, а тот, кто умеет найти информацию и воспользоваться ей.


> Ты привел код, ну и доказывай его работоспособность.

> Хотя вот оно что! Если переводить буквально "процесс получил
> последним событие ввода", то это еще и объясняет трюк с

Пусть так, но уж никак не "Процесс подключен (?) к очереди ввода"

Только ничего это не объясняет, бо SI пошлет ввод foreground
процессу, а не вызывающему SFGW.

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

Я Вам Рихтера процитирую, ладно.

. Чтобы прекратить всю эту неразбериху, Microsoft сделала SetForegroundWindow чуть поумнее. В частности, эта функция срабатывает, только если вызывающий поток уже подключен к RIT или если поток, связанный с RIT R данный момент, не получал ввода на протяжении определенного периода (который задается функцией System ParametersInfo и значением SPI_SETFOREGROUNDLOCKTIMEOUT)

> Вот 100% рабочий код.

Любой сегодня работающий код на эту тему
уже завтра станет неработающим.

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

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

Вторая же - является таковой по закону, бо запущена by the foreground
process (Explorer) - раз

который, в свою очередь, был таковым благодаря
received the last input event (меню). - два

и три: запущенная проводником копия, являясь foreground,
может делать SFGW по первому пункту.

> Я Вам Рихтера процитирую, ладно.

Да я с ним и не спорил :)

> А от себя добавлю, что с помощью AttachThreadinput можно
> заставить два потока совместно использовать одну очередь
> ввода.

Ну, хорошо, приаттачься своим потоком, скажем, к Блокноту
и заставь его OnKeyDown ;) на нажатие к-л клавиши в ем.

Можешь и в msdn заглянуть, ради любопытства.

Те мои пользователи, которые использую ICQ - отключили этот поплавок, поскольку работать не возможно, только начинаешь бить текст как он всплывает и уже дальше бьешь в нем.

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

> копию из non-foreground первой." Я ничего про активирование
> второй из первой не писал!

Да, был невнимателен, sorry.
Т.е., описанный тобой (нами) путь вполне легален и не
требует никаких трюков. MS - гарантирует ;)

Delphi сделать окно активным

Идеи то есть, но ты представь что у тебя будет еще одна такая программа постоянно вылезающая поверх всех окон))

а вот что тебе нужно, вроде на делфи так делается

Не помогло, теперь примерно каждую миллисекунду то наша форма то taskmgr.exe стаёт активным
Сделать это возможно, так как если самому в панели задач клинкнуть по окну, или же на рабочем столе за то место что выходит за taskmgr.exe то работает. Подтвердите свой е-майл

это, извините, говнокод

надо перекрывать CreateParams и выставлять необходимые параметры окну
но так ли оно надо ?

Форумчанин

это, извините, говнокод

надо перекрывать CreateParams и выставлять необходимые параметры окну
но так ли оно надо ?

Сделать окно активным

Как сделать, чтобы каждые 2 минуты мое окно становилось активным?

__________________
Если программа даёт неверный результат - в ней ошибка. Если же результат правильный - ошибок, как минимум, две.

02.06.2012, 05:55

Так проходящий

Версия Delphi: 7Lite

Репутация: 6063

setforegroundwindow

02.06.2012, 06:06

Версия Delphi: 7, XE3, 10.2

Репутация: 49089

setforegroundwindow


Под Win7/Vista работать не будет. Там сложнее. И не уверен, что это можно сделать.

02.06.2012, 08:04

Версия Delphi: 7

Репутация: 10

Под Win7/Vista работать не будет. Там сложнее. И не уверен, что это можно сделать.

Ну может что-то можно придумать?

__________________
Если программа даёт неверный результат - в ней ошибка. Если же результат правильный - ошибок, как минимум, две.

02.06.2012, 08:12

Так проходящий

Версия Delphi: 7Lite

Репутация: 6063

07.08.2012, 12:23

Версия Delphi: 7

Репутация: 10

Никто не знает?

__________________
Если программа даёт неверный результат - в ней ошибка. Если же результат правильный - ошибок, как минимум, две.

07.08.2012, 13:03

Sir Richard Abramson

Версия Delphi: XE10

Репутация: выкл

Под Win7/Vista работать не будет. Там сложнее. И не уверен, что это можно сделать.

Странно, у меня вроде работало, окно поднималось. Win7 x86.

__________________
— Как тебя понимать?
— Понимать меня не обязательно. Обязательно меня любить и кормить вовремя.

07.08.2012, 13:10

Let Me Show You

Адрес: Северодвинск

Версия Delphi: 7, XE5

Репутация: 59586

Никто не знает?

просто специально тянул 2 месяца)))

__________________
Пишу программы за еду.
__________________

07.08.2012, 16:30

Версия Delphi: 7

Репутация: 10

Как этим пользоваться?

__________________
Если программа даёт неверный результат - в ней ошибка. Если же результат правильный - ошибок, как минимум, две.

Delphi сделать окно активным

Читал я как то давненько в книге по Делфи 4 о такой штуке, но как тогда до меня ничего не дошло так и теперь для меня это загадка.

В принципе если постараться то исходник я могу достать но.
Попробовал на пустых окошках сделать то, что советует
hDrummer
1."Можно переключить главную форму на Form2 в меню Project->Options" - нельзя т.к. - она главная на ней все элементы управления.
2. "Вызвать метод Form2.BringToFront" - Это интересно, но где. в каком месте .

Даже вот просто допустим, что у нас две формы одна главная и должна ей остаться, а вторая для ввода данных .
и куда мы засандаливаем метод "Form2.BringToFront"

Функция FindWindow Группа ссылок: Окна

Описание:
function FindWindow(ClassName, WindowName: PChar): HWnd;

Находит pодительское окно веpхнего уpовня с совпадающими ClassName и WindowName. Не осуществляет поиск дочеpних окон.

Паpаметpы:
ClassName: Имя класса окна (заканчивающееся пустым символом, nil - если все классы).
WindowName: Текстовый заголовок окна или 0, если все окна.

Возвpащаемое значение:
Описатель окна; 0 - если такого окна нет.

ВОТ ЕЩЕ ПРИМЕР ПРИМЕНЕНИЯ

Как определить работает ли уже данное приложение или это первая его копия?

Для Delphi 1. Каждый экземпляр программы имеет ссылку на свою предыдущую копию - hPrevInst: hWnd. Ее можно проверить перед созданием приложения и при необходимости отреагировать соответствующим образом. Если запущена только одна копия, то эта ссылка равна нулю.
Пример:

Тогда можно так извратиться: кинуть на форму таймер, написать в событии onTimer такой код:

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

Delphi сделать окно активным

"A good example is a debugger when it hits a breakpoint."


Добавлено
не работает, причем честно об этом говорит (

Сначала нужно вызвать

SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, (LPVOID)0, SPIF_SENDWININICHANGE | SPIF_UPDATEINIFILE);

Зтем можно вызывать SetForegroundWindow.

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

сначала сворачиваем нашу прогу
Application.Minimize;

если "сворачивали в трей", то
if not IsWindowVisible(Application.Handle) then
ShowWindow(Application.Handle, SW_SHOW);

ну и восстанавливаем.
Application.Restore;
а уже при ресторе окно вылазит вперёд

кстати, если кто-то предложит лучший метод (без Minimize), буду очень благодарен

Что значит что с ним что без него?
Функция SystemParametersInfo вообще отработала корректно или ты не проверял на предмет ошибки?

Так вот если не проверял то проверь. Это делается с помощью GetLastError если функция SystemParametersInfo вернёт тебе ноль.

Если же функция отработала успешно, то вызови её же но с параметром SPI_GETFOREGROUNDLOCKTIMEOUT и убедись что она возвратит ноль.

После корректного вызова этой функции и установки свойства SETFOREGROUNDLOCKTIMEOUT в ноль система будет сразу делать окно активным с помощью SetForegroundWindow. Система не будет вызывать функцию FlashWindowEx.

я не знаю, какие у вас винды, а уменя WinXp.
под Win2000 всё точно так же.

Да, такая ситуация тоже возможна и она является штатной. Если текущий foreground-процесс вызвал функцию LockSetForegroundWindow.

Согласен что нужно. Но это просто один из вариантов как всё-таки сделать своё окно поверх всех, даже тогда когда никто этого нехочет и всеми средствами препятствует этому. Появится активное системное модальное окно, а после его закрытия уже делай основым то из своих окно которое необходимо.

На некорректные параметры такую ошибку система не выдаст. С параметрами у него судя по всему всё в порядке. А вот поотключать все лишние запущенные приложения попробовать стоит. Фалит из-за одного из них.

Активация второго окна. помогите

Помощь в написании контрольных, курсовых и дипломных работ здесь.

94731 / 64177 / 26122 Ответы с готовыми решениями:

Активация кнопки, верхняя панель окна
Учусь работать с делфи. Понемногу разбираюсь. Собрал небольшую программку.. Теперь вопрос: как.

Активация окна
Прошу помощи ребята. Много перерыл не могу найти ответа. Set SH = CreateObject(&quot;WScript.Shell&quot;).

Запуск второго окна перед стартом главного окна
необходимо запустить второе окно до старта основного окна и вызвать основное окно после завершения.

Активация модального окна
Всем привет ! я использую фреймворк boostrap 3 нужен такой способ но как сделать правильно не.

104 / 105 / 18 Создай другое окно потом создай на первом окне кнопку и вбей туда код
имя второго окно.visible;=true; 63952 / 47410 / 32681 легко)
делай что бы сначало открывалась форма2 и пропиши при правильном пароле что бы открывалась форма 1.
250 / 71 / 18 Записей в блоге: 3

Лови программист =)) Тут все правильно только вот как ты будешь организовывать задачу пароля это уже твоя проблема =)

Нужно создать две формы с именами Form1 и Form2

Создать два Edit с Именами Edit1 и Edit2 и кнопочку с именем Button1
Код указанный выше расположен на Form1


САМОЕ ГЛАВНОЕ НЕ ЗАБУДЬ ПРИВЯЗАТЬ ФОРМЫ ДРУГ К ДРУЖКЕ. делается это путем такой операции указанной ниже.

File/Use Unit.. И там тыркаем два раза на каждую форму! И так по всем формам сначало активируем первую форму, проделываем так со второй!

87844 / 49110 / 22898

Помощь в написании контрольных, курсовых и дипломных работ здесь.


Активация окна из ViewModel
Есть ли лучший способ сделать активацию окна из под ViewModel? (желательно не нарушая принципы.

winapi Активация окна
Добрый вечер!Прошу помочь в следующем: Обеспечить обработку при которой после активации команды.

Активация окна мышью
Как сделать активным окно при наведении мышью, но без переключения окна на передний план.

Читайте также: