procedure TForm1.Button1Click(Sender: TObject); var Wnd: HWND; function EnumWindowsProc(const AWnd: HWND; const AParam: LPARAM): BOOL; stdcall; begin if AWnd = Wnd then Caption := 'OK'; Result := True; end; begin Wnd := Handle; EnumWindows(@EnumWindowsProc, 0); end;Не обращайте внимание на его бессмысленность, вопрос не в этом, а в корректности кода.
Это предварительная задачка, подготовка к реальной задачке, вторая часть будет опубликована через неделю (и, да, на этот раз - действительно через неделю, т.к. я написал и вторую часть и ответ и поставил их на авто-публикацию; к сожалению, это означает, что ответ не будет включать комментарии к ответам на задачку, если только я не обновлю его до авто-публикации).
Бонус: возможно, вы уже догадались, что будет во второй части?
Читать далее: часть 2.
Ну, EnumWindows - это API функция винды, и когда она вызывает callback функцию EnumWindowsProc, она не передаёт указатель Self, поэтому "Caption := 'OK'" должен будет вызвать исключение.
ОтветитьУдалитьНу и, переменная WND в теле этой процедуры то-же будет не видна - ведь она вызывается через callback функцию.
Точнее так: из callback функции EnumWindowsProc недоступны данные процедуры, вызвавшей EnumWindows - ни указатель Self, ни переменная Wnd.
Задачка очень интересная.
ОтветитьУдалить> не передаёт указатель Self, переменная WND в теле этой процедуры будет не видна...
В этом случае код бы не компилировался. А он компилируется, и даже работает. Но неправильно.
Да, помню меня это сильно удивило, когда я столкнулся с таким первый раз - компилятор "видит" переменные, а на самом деле эти переменные выходят из области видимости.
ОтветитьУдалитьНаверняка следующая часть будет связана со стеком
1. Self не передается в callback
ОтветитьУдалить2. эта строка не верная "if AWnd = Wnd then" т.к. вместо значения Wnd берется что-то от балды со стека - можно вообще на AV налететь при хорошем везении
3. ну и это, из-за пункта 1 тоже не верно "Caption := 'OK';"
На самом деле Wnd и Self сохраняются в стеке TForm1.Button1Click, и затем оттуда получаются EnumWindowsProc.
УдалитьПросто в данном случае это не работает. Такое вот ограничение вложенной функции, ее можно вызвать только непосредственно из основной функции.
Конечно сохраняется, я даже и спорить не будут. Но что нам это дает, если калбэк не умеет получать эту информацию? :)
Удалитьvar
ОтветитьУдалитьForm1: TForm1;
Wnd: HWND;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
(*
область видимости переменной ограничена локальным стеком,
поэтому Wnd будет не доступна для EnumWindowsProc
переносим переменную Wnd в объявление глобальных переменных
var
Wnd: HWND;
*)
function EnumWindowsProc(const AWnd: HWND; const AParam: LPARAM): BOOL; stdcall;
begin
if AWnd = Wnd then
begin
(* Caption := 'OK'; *) // Свойство Caption окна не доступно при вызове EnumWindowsProc
SetWindowText(Wnd, 'ОК'); // Изменяем Caption окна например так
Result := False; // При нахождении окна программы, прерываем выполнение EnumWindows
end else
Result := True;
end;
begin
Wnd := Handle;
EnumWindows(@EnumWindowsProc, 0);
end;
После чего значение глобальной переменной перезатрет любой сторонний поток, который тоже имеет к ней доступ.
УдалитьВы серьезно? :)
Компилятор рассчитает кадр стека относительно Button1Click. Но в действительности вызов EnumWindowsProc произойдет из другой подпрограммы.
ОтветитьУдалитьНо раз есть пользовательский параметр, чего же ним не воспользоваться?
-------
procedure TForm1.Button1Click(Sender: TObject);
function EnumWindowsProc(Wnd: HWND; Param: LPARAM): LongBool; stdcall;
begin
if Param = 0 then
begin
SetLastError(ERROR_INVALID_PARAMETER);
Result := false;
end
else if TForm(Param).Handle = Wnd then
begin
TForm(Param).Caption := 'OK';
SetLastError(ERROR_SUCCESS);
Result := false;
end
else
Result := true;
end;
begin
if not EnumWindows(@EnumWindowsProc, LPARAM(Self)) and (GetLastError <> ERROR_SUCCESS) then
RaiseLastOSError;
end;
Блин, почему блог только в "Simple" отображается? Где нормальные десктопные шаблоны?
ОтветитьУдалитьУвы, не получалось у меня нормально настроить отображения на всех устройствах. Поэтому поменял тему на попроще - теперь блог можно нормально читать на компе, планшетах и мобилках.
УдалитьПри желании можно вручную использовать несколько динамических шаблонов, но их работу я не проверял.
Этот комментарий был удален автором.
УдалитьМеня вполне устраивал статичный старый, CodeMonkey. Вполне удобный был.
Удалить