Page 1 of 5

Firefox, mozilla based browser URL

Posted: Fri Dec 15, 2006 4:07 pm
by rsts
Try as I might I can not seem to figure out how to get the url from a mozilla based browser. Seems they do it somewhat different than ie and it requires traversing some damn (or was that Dom?) tree structure I haven't been able to navigate - or even understand how to get to.

Freak had some information in the post
http://www.purebasic.fr/english/viewtopic.php?t=16965
but it seems to be for ie and not Dom.

Anyone who's gotten a firefox URL or traversed the Dom or has any other suggestion or pointers?

cheers

Posted: Sat Dec 16, 2006 4:57 pm
by Sparkie
I cannot come up with a clean way of doing this. :?

An ugly hack would be to send the Firefox window the F6 shortcut (selects text in address bar) and copy it to the clipboard. :oops:

Posted: Sat Dec 16, 2006 8:54 pm
by netmaestro
I love nothing better than an ugly hack, especially when I get to blame it on another coder! In this case, it's Sparkie's fault.

One wrinkle is that the F6 key will alternately select and deselect the address bar, so it has to be sent once, tested, and resent if it didn't get a result. So it's even that much uglier.

Enough preamble, on to the junk coding! This is working here:

Code: Select all

Procedure.s GetFireFoxURL()
  w = FindWindow_("MozillaUIWindowClass",0)
  If w
    safetext.s = GetClipboardText()
    ClearClipboard()
    If IsIconic_(w)
      ShowWindow_(w,#SW_SHOWNORMAL)
    EndIf
    SetForegroundWindow_(w)
    keybd_event_(#VK_F6,0,0,0)
    keybd_event_(#VK_F6,0,#KEYEVENTF_KEYUP,0)
    Delay(50)
    keybd_event_(#VK_LCONTROL,0,0,0)
    keybd_event_(#VK_C,0,0,0)
    Delay(50)
    keybd_event_(#VK_C,0,#KEYEVENTF_KEYUP,0)
    keybd_event_(#VK_LCONTROL,0,#KEYEVENTF_KEYUP,0)
    If LCase(Left(GetClipboardText(),7))<>"http://"
      SetForegroundWindow_(w)
      keybd_event_(#VK_F6,0,0,0)  
      keybd_event_(#VK_F6,0,#KEYEVENTF_KEYUP,0)
      Delay(50)
      keybd_event_(#VK_LCONTROL,0,0,0)
      keybd_event_(#VK_C,0,0,0)
      Delay(50)
      keybd_event_(#VK_C,0,#KEYEVENTF_KEYUP,0)
      keybd_event_(#VK_LCONTROL,0,#KEYEVENTF_KEYUP,0)
    EndIf
    result.s = GetClipboardText()
    If safetext <> ""
      SetClipboardText(safetext)
    EndIf
    ProcedureReturn result
  Else
    ProcedureReturn "Failed"
  EndIf
EndProcedure

Debug GetFireFoxURL()
Garbage to the end of all the lines, but - it works.

Posted: Sat Dec 16, 2006 9:10 pm
by Num3
AFAIK, firefox doesn't use WIN32 API, it has it's own custom 'gadget' API...

So there is no way in hell you can get text from one of it's controls, unless you of course you use the 'uggly hack' ... LOL

Posted: Sat Dec 16, 2006 9:29 pm
by Sparkie
You can blame me all you want...in the end we all know it was netmaestro who hacked all the pieces together. :P :twisted:

You are correct Num3, I believe Firefox uses XUL or somesuch creature for it's GUI. :?

Posted: Sat Dec 16, 2006 11:52 pm
by rsts
Ugly hacks are wonderful. :D

In firefox (at least my version) it's alt/d instead of F6, but this did the job.

Where would I be without you guys? I know - still struggling to determine when I had no item selected in a linked list :)

cheers

Posted: Sat Dec 16, 2006 11:55 pm
by PB
> An ugly hack would be to send the Firefox window the F6 shortcut (selects
> text in address bar) and copy it to the clipboard

Hehe, I've been doing that for years, but with CTRL+L to select the Address
Bar, to avoid the F6 bug that netmaestro mentions. I never posted my tip
here because I was ashamed of having to do it that way. :oops: But here it is.

@netmaestro: Again, I swear I did not copy your code. We just think alike!
And also, you should check for both "http://" and "https://", for secure sites.

Code: Select all

Procedure.s GetFirefoxURL()
  ff=FindWindow_("MozillaUIWindowClass",0)
  If ff
    SetForegroundWindow_(ff)
    keybd_event_(#VK_CONTROL,0,0,0) ; Hold down Control key.
    keybd_event_(#VK_L,0,0,0) : keybd_event_(#VK_L,0,#KEYEVENTF_KEYUP,0) ; Go to Address Bar.
    keybd_event_(#VK_C,0,0,0) : keybd_event_(#VK_C,0,#KEYEVENTF_KEYUP,0) ; Copy the address.
    keybd_event_(#VK_CONTROL,0,#KEYEVENTF_KEYUP,0) ; Release Control key.
    Sleep_(125) : u$=GetClipboardText() ; Delay seems to be needed here.
  EndIf
  ProcedureReturn u$
EndProcedure

Debug GetFirefoxURL()
Further, here's some Visual Basic code that I once found that supposedly
does it... maybe someone here can convert it to PureBasic?

Code: Select all

I got to playing around with the Active Accessibility
approach. I don't know whether this is really a usable
solution, but it's interesting. This is VB6 code. I guess
it's about the same for VB5.
    This code would need some adjustments for your
purpose, but this shows it can be done, at least.

  As for AA, it's in Windows at least as far back as
Win98, but I'm not certain that it's always installed
by default.

----------------------------------------------
   Set the following code if a form named "F1":

Private Sub bHook_Click()
Hook
End Sub

Private Sub bUnhook_Click()
UnHook
End Sub

Place 2 buttons, as named above, with captions "hook" and
"unhook".

Place a textbox named "Text1"
-----------------------------------

In a module add this code (Reference to Accessibility needed in
Project -> References. Lib. is oleacc.dll. Set "Show hidden
Objects" in object browser if you want intellisense.)

Public Const EVENT_MIN = 1&
Private Const ROLE_COMBOBOX = &H2E&
Private Const OB_ACCELERATORCHANGE = &H8012&
Private Const SYS_ALERT = 2&
Public Const WINEVENT_SKIPOWNPROCESS = 2&
Public Const OB_REORDER = &H8004&

Private Declare Function SetWinEventHook Lib "user32.dll" (ByVal eventMin As
Long, ByVal eventMax As Long, ByVal hmodWinEventProc As Long, ByVal
pfnWinEventProc As Long, ByVal idProcess As Long, ByVal idThread As Long,
ByVal dwFlags As Long) As Long
Private Declare Function UnhookWinEvent Lib "user32.dll" (ByVal lHandle As
Long) As Long
Private Declare Function AccessibleObjectFromEvent Lib "oleacc" (ByVal HWnd
As Long, ByVal dwId As Long, ByVal dwChildId As Long, ppacc As IAccessible,
pvarChild As Variant) As Long

Private LHook As Long

Public Sub Hook()
  Dim LRet As Long
  LHook = SetWinEventHook(SYS_ALERT, OB_ACCELERATORCHANGE, 0&, AddressOf
WinEventFunc, 0, 0, WINEVENT_SKIPOWNPROCESS)
End Sub

Public Sub UnHook()
Dim LRet As Long
  If LHook = 0 Then Exit Sub
 LRet = UnhookWinEvent(LHook)
End Sub

Public Function WinEventFunc(ByVal HookHandle As Long, ByVal LEvent As Long,
ByVal HWnd As Long, ByVal idObject As Long, ByVal idChild As Long, ByVal
idEventThread As Long, ByVal dwmsEventTime As Long) As Long
  Dim ObA As IAccessible
  Dim LRet As Long
  Dim V As Variant
  Dim s As String, s1 As String, sName As String
    On Error Resume Next

 Select Case LEvent

  Case OB_REORDER
      LRet = AccessibleObjectFromEvent(HWnd, idObject, idChild, ObA, V)

      If LRet = 0 Then
        F1.Text1.Text = "--"
         If CLng(ObA.accRole(V)) = 46 Then '-- combobox.
            If ObA.accName(V) = "Location" Then
               F1.Text1.Text = ObA.accValue(V)
            End If
         End If
      End If

  End Select
   WinEventFunc = 0
End Function

-------------------------------

Open Firefox, run the project, click "Hook".
Edit the Firefox location bar.
You should see the  text in Text1 keep up
with any changes you make in Firefox's
location bar.

Posted: Sun Dec 17, 2006 12:01 am
by rsts
Many thanks - netmaestro's code got me going - i'll have to study the vb stuff to see if i can decipher it.

Nice tip about the https:// - i had forgotten to check for that. :)

cheers

Posted: Wed Dec 20, 2006 4:46 am
by Sparkie
This isn't perfect but figured I'd throw it out there for someone to improve on it. I'm short on time but I'll try to get back to this later this weekend. Thanks to PB for posting the original VB code. :)

Code: Select all

; ************************************************ 
; Code:   Track Firefox url changes (no IE / Opera support as of yet)
; Author: Sparkie 
; Date:   December 21, 2006 
; OS:     Windows only 
;...Code converted from VB to PB
;...Thanks To PB for posting the original VB code
;...Code is not yet perfect so feel free to clean
;...it up and use as you wish.
; ************************************************ 

;############
; Constants
;############
#WINEVENT_OUTOFCONTEXT = 0
#WINEVENT_SKIPOWNPROCESS = $2 
#CHILDID_SELF = 0
#ROLE_COMBOBOX = $2E 
#EVENT_OBJECT_VALUECHANGE = $800E

;############
; Hook proc
;############
Procedure WinEventFunc(HookHandle.l, LEvent.l, hwnd.l, idObject.l, idChild.l, idEventThread.l, dwmsEventTime.l)
  Protected oba.IAccessible
  Select LEvent 
    Case #EVENT_OBJECT_VALUECHANGE
      If CallFunction(0, "AccessibleObjectFromEvent", hwnd, idObject, idChild, @oba, @v.VARIANT) = #S_OK
        v\vt = #VT_I4
        v\lVal = 0
        r = oba\get_accRole(v, @v)
        If v\lVal = #ROLE_COMBOBOX
          v\vt = #VT_I4
          v\lVal = 0
          Asc$ = Space(#MAX_PATH)
          Uni$ = Space(#MAX_PATH*2+2) 
          MultiByteToWideChar_(#CP_ACP, 0, @Asc$, -1, @Uni$, Len(Asc$)*2+2) 
          bstr = SysAllocString_(@Uni$) 
          If oba\get_accValue(v, @bstr) = #S_OK
            ;...accName = "Location" in Firefox
            ;...accName = "Address" in IE
            ;r = *oba\get_accName(v, @*bstr)
            len = WideCharToMultiByte_(#CP_ACP, 0, bstr, -1, 0, 0, 0, 0) 
            url$ = Space(len) 
            WideCharToMultiByte_(#CP_ACP, 0, bstr, -1, @url$, len, 0, 0)    
            AddGadgetItem(1, -1, url$)
          EndIf
          SysFreeString_(bstr)
        EndIf
      EndIf
  EndSelect 
EndProcedure

;############
; Main Window
;############
If OpenWindow(0, 0, 0, 500, 400, "Read FireFox URL", #PB_Window_SystemMenu) And CreateGadgetList(WindowID(0)) 
  hdll = OpenLibrary(0, "Oleacc.dll")
  EditorGadget(1, 10, 15, 480, 380) 
  ;...Set event hook
  eHook = SetWinEventHook_(#EVENT_OBJECT_VALUECHANGE, #EVENT_OBJECT_VALUECHANGE, #Null, @WinEventFunc(), 0, 0, #WINEVENT_OUTOFCONTEXT | #WINEVENT_SKIPOWNPROCESS) 
  Repeat 
    Event = WaitWindowEvent() 
  Until Event = #PB_Event_CloseWindow 
  ;...Cleanup in isle 53
  If eHook
    UnhookWinEvent_(eHook)
  EndIf
  If hdll
    CloseLibrary(0)
  EndIf
EndIf 
End 

Posted: Wed Dec 20, 2006 5:26 am
by rsts
Have to study this one a bit.

Right now I get nothing but not exactly sure what it's supposed to show or how to use it.

Maybe I'll know more by the time you get back :)

enjoy :D

cheers

Posted: Wed Dec 20, 2006 6:33 am
by PB
Yeah, doesn't work here either (nothing in the EditorGadget).

Posted: Wed Dec 20, 2006 6:38 am
by rsts
Never seem to be getting a v\lval of 46 - it's set to 0 and doesn't seem to be changing.

or
r = oba\get_accRole(v, @v)
always returns zero.

Posted: Wed Dec 20, 2006 11:36 am
by netmaestro
OK, main problem is too much filtering. The best idea, as I see it, is to take everything you get without restriction and only pay attention to an accValue with a URL in it. Also, restricting the hook to #EVENT_OBJECT_VALUECHANGE doesn't work as the "golden" event seems to be $8005, which I can't find the constant name for. But by setting MIN to EVENT_MIN and MAX to MAXWORD in the hook, you're saying "Gimme all of it, I'll keep what I want", which is safest as you may not be able to trust it to always be the same. Anyway - this is working well here:

Code: Select all

;************************************************ 
; Code:   Track Firefox url changes (no IE / Opera support as of yet) 
; Author: Sparkie 
; Date:   December 21, 2006 
; OS:     Windows only 
;...Code converted from VB to PB 
;...Thanks To PB for posting the original VB code 
;...Code is not yet perfect so feel free to clean 
;...it up and use as you wish. 
; ************************************************ 
;
; *** IMPORTANT *** This approach requires an editorgadget on your window
;
;############ 
; Constants 
;############ 
#WINEVENT_OUTOFCONTEXT = 0 
#WINEVENT_SKIPOWNPROCESS = $2 
#CHILDID_SELF = 0 

;############ 
; Hook proc 
;############ 
Procedure WinEventFunc(HookHandle.l, LEvent.l, hwnd.l, idObject.l, idChild.l, idEventThread.l, dwmsEventTime.l) 
  Static oldurl$ 
  Protected oba.IAccessible 

  If CallFunction(0, "AccessibleObjectFromEvent", hwnd, idObject, idChild, @oba, @v.VARIANT) = #S_OK 
    v\vt = #VT_I4 
    v\lVal = #CHILDID_SELF 
    ; ...Prepare a spot for the bstr 
    Asc$ = Space(#MAX_PATH) 
    Uni$ = Space(#MAX_PATH*2+2) 
    MultiByteToWideChar_(#CP_ACP, 0, @Asc$, -1, @Uni$, Len(Asc$)*2+2) 
    bstr = SysAllocString_(@Uni$) 
    ; ...Put the returned value in it 
    If oba\get_accValue(v, @bstr) = #S_OK 
      ; ...Convert the bstr into an ascii string 
      len = WideCharToMultiByte_(#CP_ACP, 0, bstr, -1, 0, 0, 0, 0) 
      url$ = Space(len) 
      WideCharToMultiByte_(#CP_ACP, 0, bstr, -1, @url$, len, 0, 0) 
      ; ...See if it contains a URL 
      If Left(url$,4) = "http" 
        If url$<>oldurl$ 
          oldurl$ = url$ 
          AddGadgetItem(1, -1, url$) 
        EndIf 
      EndIf 
    EndIf 
    SysFreeString_(bstr) 
  EndIf 

EndProcedure 

;############ 
; Main Window 
;############ 
If OpenWindow(0, 0, 0, 500, 240, "Read URL From Any Browser",$CF0001) And CreateGadgetList(WindowID(0)) 
  StickyWindow(0,1)
  hdll = OpenLibrary(0, "Oleacc.dll") 
  EditorGadget(1,0, 0, 500, 240) 
  ;...Set event hook 
  eHook = SetWinEventHook_(1, #MAXWORD, #Null, @WinEventFunc(), 0, 0, #WINEVENT_OUTOFCONTEXT | #WINEVENT_SKIPOWNPROCESS) 
  Repeat 
    Event = WaitWindowEvent() 
  Until Event = #PB_Event_CloseWindow 
  ;...Cleanup in isle 53 
  If eHook 
    UnhookWinEvent_(eHook) 
  EndIf 
  If hdll 
    CloseLibrary(0) 
  EndIf 
EndIf 
End 
Also, this version works equally well for IE, and theoretically should work for Opera too. If someone could test opera that would be great.

Posted: Wed Dec 20, 2006 12:04 pm
by PB
Great teamwork, guys! This topic shows how good this community is. :D

The only catch with netmaestro's code is that it doesn't get the URL if Firefox
doesn't have the focus when his code runs, but that's a very trivial thing to fix.

BTW, does anyone know why this doesn't work if the EditorGadget is removed?

Posted: Wed Dec 20, 2006 1:03 pm
by netmaestro
BTW, does anyone know why this doesn't work if the EditorGadget is removed?
I've been researching that for the past day or so and can come up with nothing. In fact, day before yesterday I almost chucked the whole project because I was using a text gadget and getting nothing. My current research is focused on getting away from the event hook altogether and trading it in for AccessibleObjectFromWindow or possibly AccessibleObjectFromPoint and just getting the current url when you want it, instead of a constant update from a hook proc.