1

I got the following code from here and have changed it a little and I have changed the original question a little also.

The timer interval is set to 5000.
After the following 3 events occur the 'Events OnTimer' procedure will start to work.

  • 1.WebBrowser1.Navigate('Any webpage');
  • 2.wait for it to load
  • 3.programmatically press a download file button

The problem now is I can't find the 'Edit'(Class Name) handle that belongs to(or is the child of) the 'Save as' dialog box. The handle for the 'Edit' comes to '0' in the code below, but if I use my mouse pointer and the following code:

HND:= WindowFromPoint(PNT);
Label1.Caption:= IntToStr(HND);

the handle gives a result. Once I have the handle, I can use:

SetWindowText(EditHandle, 'test text'); 

to change the text in 'Edit'(Class Name).

procedure TForm1.Timer1Timer(Sender: TObject);
Var
WHandle : HWND ;
ParentHandle : DWORD ;
P : Array[0..256] Of Char ;
ProcessIdActif : DWORD ;

begin
ProcessIdActif := 0 ;
GetWindowThreadProcessId (handle,@ProcessIdActif);
WHandle := FindWindow( Nil, Nil);
While (WHandle <> 0) Do
  begin 
    P[0] := #0;
    GetWindowText(WHandle, P, 255);
    if P[0] <> #0 then
      begin
        GetWindowThreadProcessId (WHandle,@ParentHandle);
        if ProcessIdActif = ParentHandle then
          begin
          if CompareText(p,'File Download') = 0 then
            begin
              ButtonHandle := FindWindowEx(WHandle, 0, 'Button', '&Save');
              if (ButtonHandle > 0) then
               PostMessage(ButtonHandle, BM_CLICK, 0, 0);       
            end
          else if CompareText(p,'Save As') = 0 then
            begin
              EditHandle := FindWindowEx(WHandle, 0, 'Edit',NIL);
              if (EditHandle > 0) then
                SetWindowText(EditHandle, 'test text');
            end;                
          end;
      end;
      WHandle := GetWindow(WHandle, GW_HWNDNEXT);
  end;
end;

I've been trying to understand everything here but I'm missing something.

I'm able to press any windows dialog button by moving the mouse and pressing the mouse programatically, but I'd like to figure out how to press these buttons in a cleaner way.

Ken White
  • 123,280
  • 14
  • 225
  • 444
Peter James
  • 237
  • 1
  • 6
  • 18
  • Why use a visual component to download a file. Do it with something like Indy. – David Heffernan Nov 20 '12 at 07:19
  • @David The question is about pressing buttons and controlling dialog boxes, not down loading files. But, to answer your question, here are 2 links:[link](http://stackoverflow.com/questions/13377779/how-do-i-keep-an-embedded-browser-from-prompting-where-to-save-a-downloaded-file) ,[link](http://stackoverflow.com/questions/13306237/downloading-csv-files-in-delphi/13312489#13312489) – Peter James Nov 20 '12 at 07:32
  • I was just trying to point you towards what may have been a simpler solution. – David Heffernan Nov 20 '12 at 07:39
  • I guess you also realise that CompareText(p,'File Download') means the code only works on English versions of Windows. This demonstrates the problems with these sort of approaches. If you absolutely have to control another program's UI then use the automation interface. That's what it's there for. – David Heffernan Nov 20 '12 at 07:42
  • automation interface? Do you have an example of it? – Peter James Nov 20 '12 at 08:07
  • Oh I'm sorry. I read your comment above as tellling me that I should answer questions instead of asking them. But I see that I completely misunderstood you!! Sorry. – David Heffernan Nov 20 '12 at 08:28
  • 2
    There's not much to it. You send a BM_CLICK to the button you want to click. If it's not working it maybe because the dialog is not active (see remarks of BM_CLICK's docs), or perhaps some other thing (like a wrong handle f.i.). – Sertac Akyuz Nov 20 '12 at 09:35
  • @Sertac oh, I see, thanks. I didn't realize that the BM_CLICK had to be sent to the actual button. I was trying to send it to the dialog box instead. Thanks again. – Peter James Nov 20 '12 at 23:16
  • @Sertac hey, I changed the question a little, was wondering if you have any ideas. – Peter James Nov 21 '12 at 11:53
  • @james - Test the code I posted, it may help to understand things if it works on your side. :) – Sertac Akyuz Nov 21 '12 at 15:20
  • @Sertac Wow, I see. Thanks for that. I think I might start editing msdn, by putting example Delphi code in there. Not that anyone uses Delphi anymore. – Peter James Nov 22 '12 at 08:47
  • @Sertac I've written about 100 lines of code, trying to find what the 'Edit' handle is, but I can't find it. It has no siblings, no parent and no children. I've found the handles for every other button, static etc. but no Edit handle. I don't even need it, but I can't stop until I can find it programatically without my mouse pointing to it. Any other ideas? – Peter James Nov 22 '12 at 15:04
  • @james - The edit is sure a child window, at the very least it's the immediate child of the file name combo box. You can use a tool like spy++ to figure out the window hierarchy of the open/save dialog. – Sertac Akyuz Nov 22 '12 at 18:27

1 Answers1

1

Disclaimer: the below code is not meant to be used in any way, it won't work correctly if the environment is different anyway (W7 here).

Anyway, put the below in your timer handler and try to workout the differences (if it works hopefully..) with the code in the question:

var
  WHandle, ButtonHandle, EditHandle: HWND;
begin
  WHandle := FindWindow('#32770', 'File Download');
  if WHandle <> 0 then begin
    SetForegroundWindow(WHandle);
    ButtonHandle := GetDlgItem(WHandle, $114B);
    if ButtonHandle <> 0 then begin  // click the button
      // the dialog/button is kind of deaf.. 
      while IsWindowEnabled(WHandle) do begin
        SendMessage(ButtonHandle, BM_CLICK, 0, 0);
        Sleep(100);
      end;
      WHandle := 0;
      while WHandle = 0 do begin     // wait for the save as dialog
        WHandle := FindWindow('#32770', 'Save As');
        Sleep(100);
      end;
      while not IsWindowVisible(WHandle) do
        Sleep(100);
      // get through the edit handle
      WHandle := FindWindowEx(WHandle, 0, 'DUIViewWndClassName', nil);
      EditHandle := GetWindow(GetWindow(GetWindow(GetWindow
                    (WHandle, GW_CHILD), GW_CHILD), GW_CHILD), GW_CHILD);
      SetWindowText(EditHandle, 'test text');
    end;
  end;
Sertac Akyuz
  • 54,131
  • 4
  • 102
  • 169
  • Thanks Sertac. I found the 'Edit' with spy++. In windows XP it was:EditHandle := GetWindow(GetWindow(GetWindow(GetWindow(GetWindow(GetWindow(GetWindow(GetWindow(GetWindow(GetWindow(GetWindow(WHandle,GW_CHILD),GW_HWNDNEXT),GW_HWNDNEXT),GW_HWNDNEXT),GW_HWNDNEXT),GW_HWNDNEXT),GW_HWNDNEXT),GW_HWNDNEXT),GW_HWNDNEXT),GW_CHILD),GW_CHILD); – Peter James Nov 23 '12 at 00:06
  • @james - In XP, I believe you can probably get the edit with GetDlgItem(WHandle, edt1) (edt1=$0480) ([link](http://msdn.microsoft.com/en-us/library/windows/desktop/ms646960(v=vs.85).aspx) for others), WHandle being either the save dialog's handle or its immediate child, cannot remember which one right now. – Sertac Akyuz Nov 23 '12 at 00:22
  • 1
    Thanks again. I was able to get the combo box using cmb13($047c) but couldn't get the edt1($0480) to work. So handle is now EditHandle:=GetWindow(GetWindow(GetDlgItem(WHandle,$047c),GW_CHILD),GW_CHILD); which is a lot cleaner. Thanks again. It was good fun. – Peter James Nov 23 '12 at 06:03