0

I want capture the url of active window based in a substring and add to Memo only if sActiveURL is different of sOldURL.

The trouble in my code is that always is added to Memo the same url ignoring the verification if sActiveURL <> sOldURL.

How fix this?

Main:

type
  TForm1 = class(TForm)
    tmr1: TTimer;
    mmo1: TMemo;
    procedure tmr1Timer(Sender: TObject);
  private
    { Private declarations }
    sActiveURL,sOldURL : string;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  Flag: Boolean;

implementation
uses
 UIAutomationClient_TLB, Activex, StrUtils;

{$R *.dfm}

function GetURL(hTargetWnd: HWND): string;
  function Enumerar(pParent: IUIAutomationElement; Scope: TreeScope; pCondition: IUIAutomationCondition): String;
  var
    found    : IUIAutomationElementArray;
    ALen     : Integer;
    i        : Integer;
    iElement : IUIAutomationElement;

    retorno: integer;
    value : WideString;
    iInter: IInterface;
    ValPattern  : IUIAutomationValuePattern;
  begin
    Result := '';
    Flag := false;
    if pParent = nil then
      Exit;
    pParent.FindAll(Scope, pCondition, found);
    found.Get_Length(ALen);
    for i := 1 to ALen - 1 do
    begin
      found.GetElement(i, iElement);
      iElement.Get_CurrentControlType(retorno);
      if (
          (retorno = UIA_EditControlTypeId) or
          (retorno = UIA_GroupControlTypeId)
         ) then
      begin
        iElement.GetCurrentPattern(UIA_ValuePatternId, iInter);
        if Assigned(iInter) then
        begin
          if iInter.QueryInterface(IID_IUIAutomationValuePattern, ValPattern) = S_OK then
          begin
            ValPattern.Get_CurrentValue(value);
            Result := trim(value);
            Flag := true;
            Break;
          end;
        end;
      end;
      if not Flag then
      begin
        Result := Enumerar(iElement, Scope, pCondition);
      end;
    end;

  end;
var
  UIAuto      : IUIAutomation;
  Ret         : Integer;
  RootElement : IUIAutomationElement;
  Scope       : TreeScope;
  varProp     : OleVariant;
  pCondition  : IUIAutomationCondition;
begin
  Result := '';
  try
    UIAuto := CoCUIAutomation.Create;
    if Succeeded(UIAuto.ElementFromHandle(hTargetWnd, RootElement)) then
    begin
      TVariantArg(varProp).vt    := VT_BOOL;
      TVariantArg(varProp).vbool := True;
      UIAuto.CreatePropertyCondition(UIA_IsControlElementPropertyId,
                                     varProp,
                                     pCondition);
      Scope := TreeScope_Element or TreeScope_Children;
      Result := Enumerar(RootElement, Scope, pCondition);
    end;
  except
    Result := '';
  end;
end;

procedure TForm1.tmr1Timer(Sender: TObject);
begin
sActiveURL := GetURL(GetForegroundWindow);
if sActiveURL <> sOldURL then
begin
if AnsiContainsText(sActiveURL, 'stackoverflow.com') then
   begin
     sOldURL := sActiveURL;
     mmo1.Lines.Add('['+sActiveURL+']<'+DateToStr(Date)+'>');
   end;
end;
end;

UIAutomationClient_TLB.pas


EDITION:

On debug i discovered that none value is attrib to sOldURL variable.

procedure TForm1.tmr1Timer(Sender: TObject);
var
 sActiveURL,sOldURL : string;
begin
sActiveURL := GetURL(GetForegroundWindow);
mmo1.Lines.Add('[sOldURL  =       '+sOldURL+'      ]');
mmo1.Lines.Add('[sActiveURL  =       '+sActiveURL+'      ]');
mmo1.Lines.Add('');
if sActiveURL <> sOldURL then
begin
if AnsiContainsText(sActiveURL, 'stackoverflow.com') then
   begin
     sOldURL := sActiveURL;
     mmo1.Lines.Add(sActiveURL);
     mmo1.Lines.Add('');
     mmo1.Lines.Add('');
   end;
end;
end;

enter image description here

Rudy Velthuis
  • 28,387
  • 5
  • 46
  • 94
  • 2
    Have you debugged to see what is in sOldURL at time of comparison? (Hint - disable the timer at start of routine and re-enable at end to do debugging). – Dsm Feb 07 '18 at 14:28
  • @Dsm, this is a great trouble, my code is right but is very strange that `<>` or even `=` fails. –  Feb 07 '18 at 15:12
  • 2
    Indeed. Which is why you need to debug. As it stands your code appears to be OK, so you need to find at why it isn't. The starting point is to make sure that sOldURL and sActiveURL actually contain what you expect. If they do not then you need to investigate why not. – Dsm Feb 07 '18 at 15:18
  • What does `GetURL(GetForegroundWindow);` return if some other window than your browser, f.ex. your own application window, has focus? The content of your memo by any chance? Whos content changes for every timer tick, since you write to it? Just some speculation. – Tom Brunberg Feb 07 '18 at 15:43
  • @TomBrunberg, my trouble is that none operator of comparation like `<>` or `=` is working with code of `Timer` by unknow reason. –  Feb 07 '18 at 15:51
  • I need that add url to `Memo` only if active url contains determinated substring and actual url is different of previous detected. In others words, should add url to `Memo` only 1 time to each detection of url containg the specified substring. –  Feb 07 '18 at 15:55
  • Stop whining about operators not working! That is simply not true. Pay attention to what @Dsm said about checking exact content of `sOldURL` and `sActiveURL`. In `Enumerar()` you are looking for an edit control (`UIA_EditControlTypeId`), probably in an attempt to get the content of the browsers address editor. But you will get any focused windows first edit control content. Either answer Dsm's comments or simply delete this question if you can't take note of the offered help. – Tom Brunberg Feb 07 '18 at 16:03
  • @Dsm, i edited the question with the possible reason of this trouble. –  Feb 07 '18 at 16:29
  • Your edit does not correspond to your original post. In the original post sOldURL and sActiveURL were class variables, an so persistent. In your post they are local variables and to the comparison is invalid as they will be created and destroyed every time. – Dsm Feb 07 '18 at 16:37
  • BTW this way of debugging is not good. Try to learn how to use the debugger. It is a lot faster. – Dsm Feb 07 '18 at 16:39
  • @Dsm, the result is the same (with class variables or locals). Tested! –  Feb 07 '18 at 16:44

1 Answers1

0

The reason is as I shortly described in comments and is visible when the focused window is not your browser, for example your applications wiindow with the mmo1: TMemo:

GetForegroundWindow() returns the window that has focus.

Your GetURL(GetForegroundWindow) searches for an edit control (UIA_EditControlTypeId), of the focused window, and finds your memo control and returns the content of the memo.

Further, if you change focus to your browser, its URL will be correctly recorded in the memo, and if you return focus to your application, the condition if AnsiContainsText(sActiveURL, 'stackoverflow.com') will be true.

You then write to the memo, adding what you think is a real URL, and then this will be repeated for every timer event.

You need to only check the real browser window (skip all other) for its current URL. Try this, if you are using IE, otherwise you must modify FindWindow():

procedure TForm24.tmr1Timer(Sender: TObject);
var                //
  hIEWnd: HWND;    //
begin
  hIEWnd := FindWindow('IEFrame', nil);  //
  sActiveURL := GetURL(hIEWnd);          //
//  sActiveURL := GetURL(GetForegroundWindow);
  if sActiveURL <> sOldURL then
  begin
    if AnsiContainsText(sActiveURL, 'stackoverflow.com') then
    begin
      sOldURL := sActiveURL;
      mmo1.Lines.Add('[' + sActiveURL + ']<' + DateToStr(Date) + '>');
    end;
  end;
end;

Modified lines are marked with //

Tom Brunberg
  • 20,312
  • 8
  • 37
  • 54