PDA

Просмотр полной версии : Помогите пожалуйста с EnumWindows


Doc
10.04.2008, 10:14
Имеется приложение, при старте создается сокет (на winsock), ставится на прослушку и стартует поток-диспетчер, который следит, подключился ли к нам кто-то, если да, то стартует еще один поток, который обрабатывает клента.
Из этого потока вызывается EnumWindows - она перечисляет все окна верхнего уровня и передает их хэндлы callback функции, дак вот, при вызове не из основного потока в callback идут нули, а должны идти хэндлы. Вопрос: как из неосновного потока правильно вызвать EnumWindows? Или тут вообще нужен другой подход.

P.S.: Задача отыскать чужое окно, по команде с удаленного компьютера (за этим и используются сокеты)

Kuvaldum
10.04.2008, 17:18
Не должно быть никаких отличий. Тут дело в чем-то другом. Показывай код.

Doc
11.04.2008, 06:49
//объявления классов потоков
//поток-диспетчер
type TDispThread = class(TThread)
Sock:TSocket;
private
protected
procedure execute; override;
end;

//поток выполнения обслуживания клиента
type TMyServThread = class(TThread)
qwestion:Integer;
ASock:TSocket;
private
protected
procedure Execute; override;
function EnumProc(Wd:hWnd; param:LongInt):Boolean; stdcall;
end;


//в процедуре создания формы открываем сокет и стартуем поток - диспетчер
procedure TForm1.FormCreate(Sender: TObject);
var
D:WSAData;
S,ASock:TSocket;
A:TSockAddr;
ASockAddr:PSockAddr;
begin
//вызываем старт winsock, но ошибок не обрабатываем, т.к. юзеру не надо знать что у него стоит эта вещь
try
WSAStartUp(MakeWord(2,0),D);

//начиняем структуру адреса инфой
A.sin_family:=AF_INET;
A.sin_port:=htons(3333);
A.sin_addr.S_addr:=htonl(INADDR_ANY);

//создаем сокет
S:=Socket(AF_INET,SOCK_STREAM,IPPROTO_IP);

//биндим сокет
Bind(S,A,sizeof(A));

//ставим сокет на прослушку
Listen(S,3);

//создаем поток-диспетчер
Disp:=TDispThread.Create(true);
Disp.Priority:=tpNormal;
Disp.FreeOnTerminate:=true;
//передаем диспетчеру открытый на прослушивание серверный сокет
Disp.Sock:=S;
//стартуем поток-диспетчер
Disp.Resume;

except
WSACleanUp();
end; {try}

end;


//код потока-диспетчера
procedure TDispThread.execute;
var
So:TSocket;
Opt:PChar;
begin
Opt:='1';
//запуск цикла ожидания подключения
while true do
begin
So:=Accept(Sock,nil,nil);
if So <> INVALID_SOCKET then
begin
//установим опции ассептнутого сокета (чтобы он у нас сразу высвобождался, как только будет закрыт)
SetSockOpt(So,SOL_SOCKET,SO_LINGER,Opt,SizeOf(Opt));
//даем информацию потоку обслуживания клиента
MyThread:=TMyServThread.Create(true);
MyThread.Priority:=tpNormal;
MyThread.FreeOnTerminate:=true;
//передаем потоку ассептнутый сокет
MyThread.ASock:=So;
//запускаем поток на выполнение
MyThread.Resume;
end;{if}
//проверяем, не отработал ли клиентский поток
if MyThread.Terminated = true then
//чистим сокет
CloseSocket(So);
end; {while}
end;


//а вот сам поток обслуживания клиента
procedure TMyServThread.Execute;
var buf:array[0..100] of char;
begin
recv(ASock,buf,sizeof(buf),0);
ShowMessage(buf);
if buf = 'close1c0' then
begin
qwestion:=0;
ShutDown(ASock,0);
CloseSocket(ASock);
EnumWindows(@TMyServThread.EnumProc,0);
end;{if close1c0}
if buf = 'close1c1' then
begin
qwestion:=1;
ShutDown(ASock,0);
CloseSocket(ASock);
EnumWindows(@TMyServThread.EnumProc,0);
end;{if}
MyThread.Terminate;
end;

//и процедура EnumProc
//callback функция которая будет обрабатывать результаты enumwindow
function TMyServThread.EnumProc(Wd:hWnd; param:LongInt):Boolean; stdcall;
var
hSnap:THandle;
pe:TProcessEntry32;
pt:TThreadEntry32;
PID,wndPID:DWord;
BHY,BHN:THandle; //хэндл кнопки
begin
PID:=0;
//получаем pid нашего процесса
pe.dwSize:=SizeOf(pe);
hSnap:=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
If Process32First(hSnap,pe) then begin
if pe.szExeFile='1cv7s.exe' then
PID:=pe.th32ProcessID;
While Process32Next(hSnap,pe) do begin
If pe.szExeFile='1cv7s.exe' then
begin
PID:=pe.th32ProcessID;
break;
end;{if}
end; {while}
end; {if}
//конец получения pid

if IsWindow(Wd) = true then
begin
GetWindowThreadProcessID(Wd,wndPID);
if wndPID = PID then
begin
//мы нашли наше окно (1с), теперь пошлем ему сигнал о закрытии
PostMessage(Wd,WM_CLOSE,0,0);
if qwestion = 1 then
begin
//у нас появится дочернее окно о подтверждении закрытия, его то мы и будем искать
if FindWindow(nil,'1С:Предприятие') <> 0 then
begin
//мы нашли окно с кнопкой
BHN:=FindWindowEX(FindWindow(nil,'1С:Предприятие'),0,'Button','&Нет');
if BHN <> 0 then
begin
SetWindowText(BHN,'Жми меня!');
//SendMessage(BHN,BM_CLICK,0,0);
end; {if BHN}
end;{if}
end;{if}
end;{if}
end;{if}
EnumProc:=true;
end;

P.S.:Сильно не ругайте, если код кривоват, только учусь писать многопоточные приложения и работать напрямую с Winsock