за 1-3 параметры уверен, а вот 4й - в msdn написано, что там должна быть структура с координатами курсора, а везде в сети там тупо 0 или 1, но я подозреваю, что это очередной ГК.. хотя раньше всегда так же делал, ну вот сейчас опять работает как-то непонятно и через раз.
Проще, ну это для краткости) А xPos-yPos это искать координаты кнопки ведь?
Автор: IUnknown 19.06.2011 15:31
xPos и yPos - это координаты мыши (относительно клиентской части окна W), которые будут переданы в обработчик WM_LBUTTONDOWN.
Автор: Unconnected 19.06.2011 15:32
Проще, ну это для краткости) А xPos-yPos это искать координаты кнопки ведь?
added: и ещё.. в msdn про последний параметр что-то было про "выше-левее угла клиентской области", что ли, не совсем понял. Это, случаем, значило не то, что клик не будет работать, если кнопка вне экрана (окно так расположено, например) ?
Автор: IUnknown 19.06.2011 15:34
Цитата
в msdn про последний параметр что-то было про "выше-левее угла клиентской области", что ли, не совсем понял.
Это?
Цитата(MSDN)
The coordinate is relative to the upper-left corner of the client area.
"Координата относительно верхнего левого угла клиентской области".
Автор: Unconnected 19.06.2011 16:00
Procedure clickng(w:THandle); var r,r2:TRect; p:TPoint; begin getwindowrect(w,r); p:=r.TopLeft; SendMessage(w, WM_LBUTTONDOWN, MK_LBUTTON, MakeLong(p.x, p.y)); SendMessage(w, WM_LBUTTONUP, MK_LBUTTON, MakeLong(p.x,p.y)); end;
Сделал так.. что-то он вообще кликать перестал, только тень на кнопке появляется.
Автор: IUnknown 19.06.2011 16:17
Следи за руками:
p:=r.TopLeft; ScreenToClient(w, p); // Я ж 2 раза написал - что относительно клиентской области КНОПКИ SendMessage(w, WM_LBUTTONDOWN, MK_LBUTTON, MakeLong(p.x, p.y));
Теперь нажимается?
Автор: Unconnected 19.06.2011 16:33
O_o нажалось... я сначала примерно так же пробовал, только ScreenToClient-ом возвращал значение в другую переменную, а там видать входной параметр сам и изменяется.. спасибо)
Автор: Unconnected 20.06.2011 0:10
deleted
Автор: TarasBer 20.06.2011 9:31
А тебе для чего посылать щелчок? Я когда таким образон радиогруппу переключал (потому что это наименее накладный способ, не запоминать ИД первого и последнего элементов), Вольво меня разругал.
Автор: Unconnected 20.06.2011 11:53
Ну, надо кнопку нажать.. или ещё как-то можно её нажать, не щелчком? Он как-то нестабильно работает. У меня на машине всегда, а на других иногда вообще не кликает, хотя тоже XP.. посмотрите, может не так делаю чего..
const kname='PrivatCom'; var kh,but1h:THandle; Procedure clickng(w:THandle); var r:TRect; p:TPoint; begin getwindowrect(w,r); p:=r.TopLeft; ScreenToClient(w, p); sendMessage(w, WM_LBUTTONDOWN, MK_LBUTTON, MakeLong(p.x, p.y)); sendMessage(w, WM_LBUTTONUP, MK_LBUTTON, MakeLong(p.x, p.y)); end;
function GetText(wnd:THandle):string;stdcall; var p:array [0..pred(MAX_PATH)] of char; begin GetWindowText(wnd,p,max_path); result:=strpas(p); end;
var res:THandle; fn:string;
function ChildTree(Han:THandle; Info: lparam):BOOL;stdcall; var sp:string; begin sp:=ansiuppercase(gettext(han)); if pos(fn,sp)>0 then begin res:=han; result:=false; end else result:=true; end;
function findbut(h:THandle;fnk:string):THandle; //ищет дочерние окна h, в именах которых есть fnk begin res:=0;fn:=fnk; enumChildWindows(h,@ChildTree, 0); result:=res; end;
function findnewk(k:THandle):THandle; //может быть несколько окон с одним caption-ом, ищет новое, var d:integer; //если его нет, ждет пока оно появится 50 с. begin d:=0;result:=0; repeat result:=findbut(0,kname); sleep(1);inc(d); until ((result<>k) and (result<>0)) or (d=50000); end;
Procedure kdown; var k:THandle; begin kh:=findnewk(0); sleep(3000); //надо ли? if kh<>0 then but1h:=findbut(kh,'ПОДКЛЮЧЕНИЕ') else exit; clickng(but1h); end;
Автор: TarasBer 20.06.2011 12:07
Чтобы нажать кнопку, надо просто вызвать ту же процедуру, которая сидит в ветке WM_COMMAND->ID_BTN_1 в оконной процедуре.
Автор: Unconnected 20.06.2011 12:15
Что-то новое.. и как её вызвать, тоже sendmessage какой-то?
Автор: IUnknown 20.06.2011 12:29
Цитата
посмотрите, может не так делаю чего..
Угу... Все не так... Не надо делать этот ужасный цикл длительностью до 50 секунд. Проверил один раз - нет на экране подходящего окна - все, устанавливай хук. Глобальный. На HCBT_CREATEWND. Там проверяй заголовок создаваемого окна, и если он - тот, что нужен, то работай дальше (дождись появления окна на экране и пошли ему Enter, если кнопка, которую ты пытаешься нажать - дефолтная, а в большинстве случаев это так - то она и нажмется. Если не дефолтная - то надо будет искать).
На данный момент у меня твой код не работает. По одной простой причине:
if pos(fn,sp)>0 then begin // Ищем заголовок
, если учесть, что в fn находится заголовок, НЕ приведенный к верхнему регистру, то программа даже теоретически не может отработать. Никогда (поскольку 'PrivatCom' и 'PRIVATCOM' - это очень уж разные вещи для компьютера). Либо ты показываешь не тот код, который работает, либо выдаешь желаемое за действительное...
Автор: Unconnected 20.06.2011 12:36
Ооо нет, опять эти dll, мэппинг, затыки на пустом месте.. а почему бы не проверять хотя бы в таймере наличие нужного окна? Кнопки все дефолтные (TButton и TBitButton).
added:
Цитата
Либо ты показываешь не тот код
Да да, в оригинале большими буквами, эту константу уже тут допечатывал.. так то хэндлы всегда находятся, но нажимается далеко не всегда.
Автор: IUnknown 20.06.2011 12:43
Цитата
а почему бы не проверять хотя бы в таймере наличие нужного окна?
Да мне-то все равно, хоть вручную проверяй (показывай каждую секунду сообщение пользователю, "если на экране появилось окошко с заголовком bla_bla_bla, то подведите мышу к кнопке ПОДКЛЮЧЕНИЕ и нажмите левую кнопку мыши. Если нет - нажмите Cancel"). Только вот пользоваться такой программой никому на фиг не надо. Равно как и той, что работает по таймеру.
Выбирай, присоединяться к 90% "писателей кода", либо учиться, наконец, делать нормально... Как выберешь - скажешь...
Автор: Unconnected 20.06.2011 12:58
Хочу нормально, а с дллками связываться не хочу... Ладно, допустим есть у меня хэндл кнопки\окна, чтобы отправить ей WM_COMMAND, надо ID кнопки где-то взять же?
Автор: TarasBer 20.06.2011 13:22
> Что-то новое.. и как её вызвать, тоже sendmessage какой-то?
Нет, тупо берёшь и вызываешь.
Ты ведь нажимаешь кнопку своего приложения, так? У тебя на эту кнопку уже повешена какая-то процедура, так? Ну вот её тупо и вызывай.
Автор: Unconnected 20.06.2011 13:27
Если бы своего, то понятное дело не кликал бы так) В общем, посмотрел, что окну при нажатии шлётся: извещение BN_CLICKED, в wParam лежит ID кнопки, а в lParam - её хэндл, или окна.. вот как бы ID получить.
function GetText(wnd:THandle):string;stdcall; var p:array [0..pred(MAX_PATH)] of char; begin GetWindowText(wnd,p,max_path); result:=strpas(p); end;
function CheckWinControls(h : HWND; lp : LPARAM) : BOOL; stdcall; begin if Pos(UpperCase(sButton), UpperCase(GetText(h))) > 0 then begin PostMessage(HiWord(lp), WM_COMMAND, MakeWParam(GetDlgCtrlID(h), BN_CLICKED), h); FoundAndPressed := True; result := False; end else result := True;
end; function CheckWinCaption(h : HWND; lp : LPARAM) : BOOL; stdcall; begin result := true; if Pos(UpperCase(sCaptionToFind), UpperCase(GetText(h))) > 0 then begin EnumChildWindows(h, @CheckWinControls, MakeLParam(0, h)); if FoundAndPressed then result := False; end; end;
Procedure kdown; var Counter : Integer; begin Counter := 0; FoundAndPressed := False; repeat EnumWindows(@CheckWinCaption, 0); Application.ProcessMessages; // На всякий случай, можно без этого Inc(Counter); Sleep(1000); until FoundAndPressed or (Counter > 50); end;
А теперь - внимание, вопрос: не запуская этот код - подумай, он будет работать или нет? Чем чревато, в общем, все плюсы и минусы - в студию... У меня Delphi 2009 под WinXP, если что. Итак?
Автор: Unconnected 20.06.2011 16:45
Procedure clickng(w:THandle); begin postmessage(winh,WM_COMMAND,MAKEWPARAM(GetDlgCtrlID(w),BN_CLICKED),winh); end;
так надо? Вроде не напутал с hi\low в wparam.
added: ну вообще должен работать, только при отправке WM_COMMAND в lParam должно быть Handle to the control window - я так понял, хэндл самого окна, а не кнопки.. Тут сделано две Callback-процедуры - а у меня одна, смысл её искать окно с определённым кэпшном на другом окне (то есть и окно на раб. столе найдет, и кнопку на окне). Вообще как-то по-интересному - где-то в lParam втыкается просто хэндл, где-то с Makelparam.. А, ещё для русских строк у меня работает только ANSIUppercase.
Автор: IUnknown 20.06.2011 17:44
Цитата
только при отправке WM_COMMAND в lParam должно быть Handle to the control window - я так понял, хэндл самого окна, а не кнопки..
Да ладно... Control window - это оно и есть, окно контрола, т.е, кнопки...
Цитата
Тут сделано две Callback-процедуры - а у меня одна, смысл её искать окно с определённым кэпшном на другом окне
Смысл - в том, что не надо путать EnumWindows и EnumChildWindows. Каждый занимается своим делом: EnumWindows ищет нужную форму на десктопе, а EnumChildWindows - на найденной форме ищет дочерний контрол. Опять же, ты можешь делать как хочешь, но если ты используешь функции не по назначению - потом не удивляйся некорректному поведению программы.
Вообще как-то по-интересному - где-то в lParam втыкается просто хэндл, где-то с Makelparam
Ну, передай в PostMessage тоже с MakeLParam... Работоспособности это не меняет...
Цитата
А, ещё для русских строк у меня работает только ANSIUppercase.
У тебя это тоже присутствует, кстати. Твой AnsiUpperCase не работает для русских строк на моей машине, ибо у меня ANSI-страница - другая.
Автор: Unconnected 21.06.2011 1:50
Ок, разделяю и властвую) То есть, Uppercase далеко не универсальный? Что с этим можно сделать?.. Из-за этого опять могут вылезти непонятки, в других моментах..
Автор: IUnknown 21.06.2011 8:39
Цитата
То есть, Uppercase далеко не универсальный? Что с этим можно сделать?
Это зависит от версии компилятора. По крайней мере D2009 и выше позволяют написать:
if Pos(WideUpperCase(WideString(sCaptionToFind)), WideUpperCase(WideString(GetText(h)))) > 0 then // ...
, и это работает, если исходник сохранен в UTF8 (я вообще взял себе за привычку все исходники сохранять в UTF8, а не в ANSI, не только дельфийские)
В принципе, можно было бы и убрать эту промежуточную конвертацию в WideString, это уже чтоб наверняка...
Автор: Unconnected 22.06.2011 1:13
Ого, а у меня D7.. короче решил не заморачиваться, сделал перекрывающую функцию, надеюсь будет на всех машинах с русским языком работать:
Function upppercase(s:string):string; var i:integer; begin for i:=1 to length(s) do begin if (s[i] in ['a'..'z']) or (s[i] in ['à'..'ÿ']) then s[i]:=chr(ord(s[i])-32); end; result:=s; end;