Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Delphi программирование > Общие вопросы Delphi
Регистрация

Восстановить пароль

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 28.10.2010, 22:42   #1
Roof
Форумчанин
 
Аватар для Roof
 
Регистрация: 01.02.2007
Сообщений: 785
По умолчанию метод как параметр процедуры

1) Есть рабочий код поиска всех верхних окон в системе:
Код:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    ListBox1: TListBox;
    procedure Button1Click(Sender: TObject);
  private
    TopHandle: Hwnd;
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

function EnumProc(Wd: HWnd; Param: LongInt): Boolean; stdcall;
var
  Nm: array[0..1255] of Char; // буфер для имени
  Cs: array[0..1255] of Char; // буфер для класса
begin
  GetWindowText(Wd, Nm, 1255);
  GetClassName(Wd, Cs, 1255);

  if ISWindowVisible(Wd) then
  begin

    if string(Cs) = 'TSomeClass' then
    begin
      Form1.TopHandle := Wd;
      Form1.ListBox1.Items.Add(string(Nm) + '/' + string(Cs) + '/' +
        IntToStr(Wd))
    end
    else
      Form1.ListBox1.Items.Add(string(Nm) + '/' + string(Cs));

  end;
  Result := TRUE; // продолжать искать окна…
end;

procedure GetAllWindow;
begin
  Form1.ListBox1.Clear;
  EnumWindows(@EnumProc, 0);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  GetAllWindow;
end;

end.
2) Решил оформить в виде класса:
Код:
unit AutoWorkApi;

interface

uses ShellApi, Windows, Classes, SysUtils;

type
  TVaEnumProc = function (Wd: HWnd; Param: LongInt): Boolean of object; stdcall;
type
  TAutoWorkApi = class
  private
    FTopHandle: Hwnd;  // для верхнего окна
    FCountTopWindow: Integer; //количество верхних окон
    FNameClassList: TStringList; //список верхних окон
    FVaEnumProc: TVaEnumProc; //

  public
    property TopHandle: Hwnd read FTopHandle write FTopHandle;
    property NameClassList: TStringList read FNameClassList
      write FNameClassList;
    property CountTopWindow: Integer read FCountTopWindow
      write FCountTopWindow;
    constructor Create;
    destructor Destroy;
    procedure GetAllWindow; //найти все верхние окна
    function EnumProc(Wd: HWnd; Param: LongInt): Boolean; stdcall;
  end;

implementation

{ TAutoWorkApi }

procedure TAutoWorkApi.GetAllWindow;
begin
  FNameClassList.Clear;
  EnumWindows(@FVaEnumProc, 0); //тут хочу передавать функцию как параметр
  FCountTopWindow := FNameClassList.Count;
end;

constructor TAutoWorkApi.Create;
begin
  inherited;
  FVaEnumProc := EnumProc;
  FNameClassList := TStringList.Create;
end;

destructor TAutoWorkApi.Destroy;
begin
  FNameClassList.Free;
  inherited;
end;

function TAutoWorkApi.EnumProc(Wd: HWnd; Param: LongInt): Boolean; stdcall;
var
  Nm: array[0..1255] of Char; // буфер для имени
  Cs: array[0..1255] of Char; // буфер для класса
begin
  GetWindowText(Wd, Nm, 1255);
  GetClassName(Wd, Cs, 1255);

  if ISWindowVisible(Wd) then
  begin

    if string(Cs) = 'TSomeClass' then
    begin
      FTopHandle := Wd;
      FNameClassList.Add(string(Nm) + '/' + string(Cs) + '/' +
         IntToStr(Wd))
    end
    else
         FNameClassList.Add(string(Nm) + '/' + string(Cs));

  end;
  Result:= TRUE; // продолжать искать окна…
end;

end.
3) Вот код программы, где использую свой класс:
Код:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls, ShellApi, CommCtrl, AutoWorkApi;

type
  TForm1 = class(TForm)
    ButFindAllTopWindows: TButton;
    Panel1: TPanel;
    procedure FormCreate(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure ButFindAllTopWindowsClick(Sender: TObject);

  private
    AutoWorkApi: TAutoWorkApi;

    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
implementation
{$R *.dfm}




procedure TForm1.ButFindAllTopWindowsClick(Sender: TObject);
begin
  AutoWorkApi.GetAllWindow;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  AutoWorkApi.Free;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  AutoWorkApi := TAutoWorkApi.Create;
end;


end.
Однако при событии procedure TForm1.ButFindAllTopWindowsClick(Se nder: TObject);
Возникает ошибка:
First chance exception at $7C812AFB. Exception class EAccessViolation with message 'Access violation at address 00000000. Read of address 00000000'. Process Project1.exe (4084)

Что я не так сделал в методе procedure TAutoWorkApi.GetAllWindow; ?
Изо всей благодати
В руках крепко сжатых
Я донесу только капли
Roof вне форума Ответить с цитированием
Старый 29.10.2010, 00:51   #2
Пепел Феникса
Старожил
 
Аватар для Пепел Феникса
 
Регистрация: 28.01.2009
Сообщений: 21,000
По умолчанию

сча скину наработку.

Код:
type
  TVaEnumProc = function (Wd: HWnd):Boolean of object; stdcall;
type
  TAutoWorkApi = class
  private
    FTopHandle: Hwnd;  // для верхнего окна
    FCountTopWindow: Integer; //количество верхних окон
    FNameClassList: TStringList; //список верхних окон
    FVaEnumProc: TVaEnumProc; //

  public
    property TopHandle: Hwnd read FTopHandle write FTopHandle;
    property NameClassList: TStringList read FNameClassList
      write FNameClassList;
    property CountTopWindow: Integer read FCountTopWindow
      write FCountTopWindow;
    constructor Create;
    destructor Destroy;
    procedure GetAllWindow; //найти все верхние окна
    function EnumProc(Wd: HWnd): Boolean; stdcall;
  end;

implementation

{ TAutoWorkApi }

function TAWA(Wd: HWnd;AWA:TAutoWorkApi):Boolean;stdcall;
begin
 Result:=AWA.FVaEnumProc(Wd);
end;

procedure TAutoWorkApi.GetAllWindow;
begin
  FNameClassList.Clear;
  EnumWindows(@TAWA,Integer(Self)); //тут хочу передавать функцию как параметр
  FCountTopWindow := FNameClassList.Count;
end;

constructor TAutoWorkApi.Create;
begin
  inherited;
  FVaEnumProc := EnumProc;
  FNameClassList := TStringList.Create;
end;

destructor TAutoWorkApi.Destroy;
begin
  FNameClassList.Free;
  inherited;
end;

function TAutoWorkApi.EnumProc(Wd: HWnd):Boolean; stdcall;
var
  Nm: array[0..1255] of Char; // буфер для имени
  Cs: array[0..1255] of Char; // буфер для класса
begin
  GetWindowText(Wd, Nm, 1255);
  GetClassName(Wd, Cs, 1255);

  if ISWindowVisible(Wd) then
  begin

    if string(Cs) = 'TSomeClass' then
    begin
      FTopHandle := Wd;
      FNameClassList.Add(string(Nm) + '/' + string(Cs) + '/' +
         IntToStr(Wd))
    end
    else
         FNameClassList.Add(string(Nm) + '/' + string(Cs));

  end;
  Result:= TRUE; // продолжать искать окна…
end;

end.
примерно так, для развития советую посмотреть стандартный класс TThread вам нужен примерно такой же принцип.
завтра если надо(правда поздно вечером) могу написать полнее пример(красивее, с событием нахождения окна или событием окончания поиска, на выбор
Хорошо поставленный вопрос это уже половина ответа. | Каков вопрос, таков ответ.
Программа делает то что написал программист, а не то что он хотел.
Функции/утилиты ждут в параметрах то что им надо, а не то что вы хотите.
Пепел Феникса вне форума Ответить с цитированием
Старый 29.10.2010, 01:40   #3
Roof
Форумчанин
 
Аватар для Roof
 
Регистрация: 01.02.2007
Сообщений: 785
По умолчанию

Отлично, теперь все заработало. Спасибо Большое. TTheard погляжу обязательно. Пример с событиями пока не нужен, спасибо.
Теперь возник вопрос:
Попробовал сделать так:
Код:
function TAWA(Wd: HWnd;AWA:TAutoWorkApi):Boolean;stdcall;
begin
 Result := AWA.EnumProc(Wd, 0);
end;
И все работает.
Т.е. мои фантазии насчет переменной процедурного типа данных оказались вовсе лишними? Имею ввиду это:
Код:
type
  TVaEnumProc = function (Wd: HWnd):Boolean of object; stdcall;
...
FVaEnumProc: TVaEnumProc; //
...
FVaEnumProc := EnumProc;
...
Изо всей благодати
В руках крепко сжатых
Я донесу только капли
Roof вне форума Ответить с цитированием
Старый 29.10.2010, 19:44   #4
Пепел Феникса
Старожил
 
Аватар для Пепел Феникса
 
Регистрация: 28.01.2009
Сообщений: 21,000
По умолчанию

в принципе она в вашем случае не нужна.
Хорошо поставленный вопрос это уже половина ответа. | Каков вопрос, таков ответ.
Программа делает то что написал программист, а не то что он хотел.
Функции/утилиты ждут в параметрах то что им надо, а не то что вы хотите.
Пепел Феникса вне форума Ответить с цитированием
Старый 29.10.2010, 20:09   #5
Roof
Форумчанин
 
Аватар для Roof
 
Регистрация: 01.02.2007
Сообщений: 785
По умолчанию

Еще раз большое спасибо за помощь. Вопрос решен.
Изо всей благодати
В руках крепко сжатых
Я донесу только капли
Roof вне форума Ответить с цитированием
Старый 29.10.2010, 21:55   #6
TwiX
Участник клуба
 
Аватар для TwiX
 
Регистрация: 28.07.2009
Сообщений: 1,510
По умолчанию

А почему с функцией класса это не работает и зачем нужно писать Integer(Self)
TwiX вне форума Ответить с цитированием
Старый 29.10.2010, 22:04   #7
Пепел Феникса
Старожил
 
Аватар для Пепел Феникса
 
Регистрация: 28.01.2009
Сообщений: 21,000
По умолчанию

впервые за долгое время умудрился задаблпостить.
Хорошо поставленный вопрос это уже половина ответа. | Каков вопрос, таков ответ.
Программа делает то что написал программист, а не то что он хотел.
Функции/утилиты ждут в параметрах то что им надо, а не то что вы хотите.
Пепел Феникса вне форума Ответить с цитированием
Старый 29.10.2010, 22:05   #8
Пепел Феникса
Старожил
 
Аватар для Пепел Феникса
 
Регистрация: 28.01.2009
Сообщений: 21,000
По умолчанию

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

а второе, это просто приведение типов, ибо функция принимает Integer, как пользовательские данные.
Хорошо поставленный вопрос это уже половина ответа. | Каков вопрос, таков ответ.
Программа делает то что написал программист, а не то что он хотел.
Функции/утилиты ждут в параметрах то что им надо, а не то что вы хотите.
Пепел Феникса вне форума Ответить с цитированием
Старый 29.10.2010, 22:55   #9
TwiX
Участник клуба
 
Аватар для TwiX
 
Регистрация: 28.07.2009
Сообщений: 1,510
По умолчанию

За первое спасибо, а второе не понял) Зачем в EnumWindows передавать указатель на Self
З.ы. Сегодня тоже один раз задаблпостил - форум лагнул по ходу)
TwiX вне форума Ответить с цитированием
Старый 29.10.2010, 23:08   #10
Пепел Феникса
Старожил
 
Аватар для Пепел Феникса
 
Регистрация: 28.01.2009
Сообщений: 21,000
По умолчанию

Код:
function TAWA(Wd: HWnd;AWA:TAutoWorkApi{тот самый Self}):Boolean;stdcall;
begin
 Result:=AWA.FVaEnumProc(Wd);
end;
говорил же по смотреть как TThread устроено
там тот же метод, точнее я его там и увидел.
Хорошо поставленный вопрос это уже половина ответа. | Каков вопрос, таков ответ.
Программа делает то что написал программист, а не то что он хотел.
Функции/утилиты ждут в параметрах то что им надо, а не то что вы хотите.
Пепел Феникса вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Процедуры и функции(Pascal)Метод Гаусса Zimba Помощь студентам 2 21.06.2010 23:36
Возможно ли подставить параметр процедуры в имя объекта. Kottik Общие вопросы Delphi 6 20.04.2010 10:25
как сделать параметр ГОСЕАН БД в Delphi 6 20.04.2009 07:24
Как передать параметр? Иллидан Общие вопросы Delphi 8 12.07.2008 12:57
Динамически массив как параметр ф-ии SNUPY Помощь студентам 2 11.05.2008 01:16