одинадцатый, функцию EnumChildWindows необходимо вызывать из самой callback функции EnumThrWndProc! Я теперь уже забросила первый вариант, который вы привели. Использую тот, который в посте #6. Поэтому буду показывать на примере именно его.
Да простят меня модераторы, но приведу код полностью (в который раз!), чтобы не оставалось никаких неясностей, в конце концов...
Код:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
THandles = array of HWND;
TThreadIdHandles = record
ThreadId: Cardinal;
Handles: THandles;
end;
TForm1 = class(TForm)
StartProgramBtn: TButton;
GetTextBtn: TButton;
Memo1: TMemo;
procedure StartProgramBtnClick(Sender: TObject);
procedure GetTextBtnClick(Sender: TObject);
private
{ Private declarations }
procedure GetAllWndHandlesFromThreads;
public
{ Public declarations }
end;
var
Form1: TForm1;
ThreadIdHandles: array[0..3] of TThreadIdHandles;
function EnumThrWndProc(hndl: HWND; lprm: LPARAM): BOOL; stdcall;
function EnumChildWndProc(hndl: HWND; lprm: LPARAM): BOOL; stdcall;
implementation
{$R *.dfm}
function EnumChildWndProc(hndl: HWND; lprm: LPARAM): BOOL; stdcall;
var
WndTxt: PChar;
begin
Result := True;
GetMem(WndTxt, 255);
try
GetWindowText(hndl, WndTxt, 255);
Form1.Memo1.Lines.Add(StrPas(WndTxt));
finally
FreeMem(WndTxt, 255);
end;
end;
function EnumThrWndProc(hndl: HWND; lprm: LPARAM): BOOL; stdcall;
var
ToolWndStyle: Integer;
PrevHandlesLen: Integer;
begin
Result := True;
ToolWndStyle := GetWindowLong(hndl, GWL_EXSTYLE) and WS_EX_TOOLWINDOW;
{ take into account only non-tool windows from the thread }
if ToolWndStyle = 0 then
with ThreadIdHandles[lprm] do
begin
PrevHandlesLen := Length(Handles);
SetLength(Handles, PrevHandlesLen + 1);
Handles[PrevHandlesLen] := hndl;
end;
EnumChildWindows(hndl, @EnumChildWndProc, 0);
end;
procedure TForm1.GetAllWndHandlesFromThreads;
var
i: Byte;
begin
for i := 0 to 3 do
EnumThreadWindows(ThreadIdHandles[i].ThreadId, @EnumThrWndProc, i);
end;
procedure TForm1.StartProgramBtnClick(Sender: TObject);
const
WinDirPath = 'g:\programs\forex\mt4';
ProgPath = 'g:\programs\forex\mt4\terminal.exe';
var
i: Byte;
_si: STARTUPINFO;
_pi: PROCESS_INFORMATION;
Evnt: THandle;
begin
for i := 0 to 3 do
begin
ThreadIdHandles[i].Handles := nil;
FillChar(_si, SizeOf(_si), 0);
_si.cb := SizeOf(_si);
_si.dwFlags := STARTF_USESHOWWINDOW;
_si.wShowWindow := SW_SHOWNORMAL;
CreateProcess(@ProgPath[1], nil, nil, nil, False, NORMAL_PRIORITY_CLASS, nil,
@WinDirPath[1], _si, _pi);
ThreadIdHandles[i].ThreadId := _pi.dwThreadId;
end;
// do a delay only once before calling GetAllWndHandlesFromThreads proc.
Evnt := CreateEvent(nil, False, False, nil);
WaitForSingleObject(Evnt, 1500);
CloseHandle(Evnt);
Form1.GetAllWndHandlesFromThreads();
end;
procedure TForm1.GetTextBtnClick(Sender: TObject);
var
i: Byte;
j: Integer;
wndtxt: PChar;
begin
GetMem(wndtxt, 200);
try
Memo1.Lines.Clear;
for i := 0 to 3 do
for j := 0 to High(ThreadIdHandles[i].Handles) do
begin
GetWindowText(ThreadIdHandles[i].Handles[j], wndtxt, 200);
Memo1.Lines.Add(StrPas(wndtxt));
end;
finally
FreeMem(wndtxt, 200);
end;
end;
end.
При переборе дочерних теперь выводятся в Memo заголовки кнопок и прочего.
P.S.
одинадцатый, уже давайте что-ли пользоваться BB-кодами, а то схватите предупреждение от Admin'а или модератора...
Код оформляется так: [code]Сюда вставляется код[/code]
P.P.S. По поводу различий при запуске с ярлыка и с CreateProcess. Раскопайте в справке описание функции CreateProcess. Возможно, что дело в том, что вы не используете атрибуты безопасности при запуске приложения. Вместо некоторых
nil, которые вы передаете в параметрах функции CreateProcess, в общем случае должны стоять указатели на структуру SECURITY_ATTRIBUTES. Хотя я не утверждаю, что дело именно в этом. И атрибутами безопасности я никогда не пользовалась...