WebGadget - retreiving URL of link under pointer

Just starting out? Need help? Post your questions and find answers here.
soerenkj
User
User
Posts: 95
Joined: Mon Jun 14, 2004 10:19 pm

WebGadget - retreiving URL of link under pointer

Post by soerenkj »

hello, here is another challenge for the WebGadget experts..

how do I retreive the URL of a link that the mouse is pointing to? (when, for example, the right mouse button is pressed)

ps. I also wondered, does the WebGadget control send some event when a page is finished loading? (so that we don't have to use the busy waiting stuff)
Sparkie
PureBatMan Forever
PureBatMan Forever
Posts: 2307
Joined: Tue Feb 10, 2004 3:07 am
Location: Ohio, USA

Post by Sparkie »

how do I retreive the URL of a link that the mouse is pointing to? (when, for example, the right mouse button is pressed)
I've got some working code here but it needs a little more clean up before I post it. I hope to have it here within the next 24 hours.
ps. I also wondered, does the WebGadget control send some event when a page is finished loading? (so that we don't have to use the busy waiting stuff)
Yes, I believe there is a better method. All this WebGadget interface stuff has my head spinning 8O right now so I'll take a closer look this weekend (time permitting). ;)
What goes around comes around.

PB 5.21 LTS (x86) - Windows 8.1
Sparkie
PureBatMan Forever
PureBatMan Forever
Posts: 2307
Joined: Tue Feb 10, 2004 3:07 am
Location: Ohio, USA

Post by Sparkie »

Slowly but surely, I'm beginning to get a grasp on this Interface stuff. I'm still a little fuzzy on some parts, especially on the Release() of Interface pointers. What exactly happens if I don't release an Interface pointer along the way? Having said that, I have tested and things appear to be ok here on WinXP with PB 3.91F.

The following code is just a beginnnig. As soon as I can get a better grasp of things like
Pointer to a variable of type VARIANT of type VT_DISPATCH that receives the IDispatch interface of an object with a default method that is invoked when the event occurs 8O
I'll be able to (I hope) use more conventional methods. For now I'm using a hooked mouse on the WegGadget window to detect #WM_RBUTTONDOWN and #WM_RBUTTONUP. There is a much better way to do this but it's still zooming over my head at this time. (see above quote) :?

This may also work on PB < 3.91. Because I use WindowMouseX() , WindowMouseY() you'll have to uncomment the 3 lines for PB ver < 3.91

Code: Select all

;GetCursorPos_(@cpos.POINT);
;ScreenToClient_(hBrowser, @cpos)
;If pDocument2\elementFromPoint(cpos\x, cpos\y, @pElement) = #S_OK
and then comment the line after those 3

Code: Select all

If pDocument2\elementFromPoint(WindowMouseX() , WindowMouseY() , @pElement) = #S_OK
When the web page loads, you can right-click on *most* links and see the href in the statusbar. At this time, it only seems to work for text links. Image links seem to require something else so I'll continue looking to find a way. ;)

Also, I have disabled the context menu but you can enable it by changing result = 1 to result = 0 in the MouseProc() procedure.


Ok, here's what I have so far.

Code: Select all

pElement.IHTMLElement
pAnchor.IHTMLAnchorElement
pDispatch.IDispatch
pDocument2.IHTMLDocument2
WebObject.IWebBrowser2
Global pDispatch, pElement, pAnchor, pDocument2, hBrowser, WebObject, webInit

Procedure doweb()
  
  If pDispatch : pDispatch\Release() : EndIf
   
  If WebObject\get_document(@pDispatch) = #S_OK
    
    If pDispatch\QueryInterface(?IID_IHTMLDocument2, @pDocument2) = #S_OK 
      hChild1 = FindWindowEx_(GadgetID(0), 0, "Shell Embedding", 0)
      hChild2 = FindWindowEx_(hChild1, 0, "Shell DocObject View", 0)
      hBrowser = FindWindowEx_(hChild2, 0, "Internet Explorer_Server", 0)
      If hBrowser = 0 ; is our browser window available yet
        
        If pDispatch : pDispatch\Release() : EndIf
        
        webInit = #False ; browser window not available yet
      Else
        webInit = #True ; browser window available
      EndIf
      
    EndIf
    
  EndIf
  
EndProcedure

Procedure MouseProc(nCode, wParam, lParam)
  *ms.MOUSEHOOKSTRUCT = lParam
  
  Select wParam
    
    Case #WM_RBUTTONUP
      
      StatusBarText(1, 0, "")
      currentsb$ = ""
      
    Case #WM_RBUTTONDOWN
      
      If pDocument2
        ;- I use WindowMouseX() and WindowMouseY() so for
        ;- PureBasic ver < 3.91, uncomment the next 3 lines
        ;GetCursorPos_(@cpos.POINT);
        ;ScreenToClient_(hBrowser, @cpos)
        ;If pDocument2\elementFromPoint(cpos\x, cpos\y, @pElement) = #S_OK
        
        ;- for PureBasic ver < 3.91, comment the next line
        If pDocument2\elementFromPoint(WindowMouseX() , WindowMouseY() , @pElement) = #S_OK
          
          If pElement\QueryInterface(?IID_IHTMLAnchorElement, @pAnchor)= #S_OK
            pElement\Release()
            pAnchor\get_href(@BSTR_Anchor)
            aLen = WideCharToMultiByte_(#CP_ACP, 0, BSTR_Anchor, -1, 0, 0, 0, 0)
            anchor$ = Space(aLen) 
            WideCharToMultiByte_(#CP_ACP, 0, BSTR_Anchor, -1, @anchor$, aLen, 0, 0)
            SysFreeString_(BSTR_Anchor) 
            
            If currentsb$ <> anchor$
              StatusBarText(1, 0, anchor$)
              currentsb$ = anchor$
            EndIf
            
            pAnchor\Release()
            
          Else
            StatusBarText(1, 0, "")
            currentsb$ = ""
              
          EndIf
          
        EndIf
          
      EndIf
      result = 1 ;result = 0 enables context menu
      
  EndSelect 
  
ProcedureReturn result
EndProcedure

If OpenWindow(0, 0, 0, 700, 500,  #PB_Window_SystemMenu , "Hypertext Info") 
  If CreateStatusBar(1, WindowID())
    
  EndIf
  
  If CreateGadgetList(WindowID()) 
    hWeb = WebGadget(0, 0, 0, WindowWidth(), WindowHeight()-25, "http://www.purearea.net/pb/CodeArchiv/English.html") 
    WebObject = GetWindowLong_(GadgetID(0), #GWL_USERDATA)
  EndIf 
  
  hInstance = GetModuleHandle_(0)
  lpdwProcessId = GetWindowThreadProcessId_(WindowID(), 0)
  hhook = SetWindowsHookEx_(#WH_MOUSE, @MouseProc(), 0, lpdwProcessId)
   
EndIf 

Repeat 
   
  Event = WaitWindowEvent() 
  
  If Event = 32770 And webInit = #False
    doweb()
  EndIf
  
Until Event = #PB_Event_CloseWindow 
If hhook : UnhookWindowsHookEx_(hhook) : EndIf
If pDispatch : pDispatch\Release() : EndIf

End  

DataSection
IID_IHTMLDocument2:
;332C4425-26CB-11D0-B483-00C04FD90119
Data.l $332C4425
Data.w $26CB, $11D0
Data.b $B4, $83, $00, $C0, $4F, $D9, $01, $19 

IID_IHTMLAnchorElement:
;3050F1DA-98B5-11CF-BB82-00AA00BDCE0B
Data.l $3050F1DA
Data.w $98B5, $11CF
Data.b $BB, $82, $00, $AA, $00, $BD, $CE, $0B 

EndDataSection
Any and all input is greatly appreciated. I'd really like to get a better understanding of how and why Interfaces work (or not), and more importantly how to use them properly. :D
What goes around comes around.

PB 5.21 LTS (x86) - Windows 8.1
soerenkj
User
User
Posts: 95
Joined: Mon Jun 14, 2004 10:19 pm

Post by soerenkj »

:-D :-D. I would have never figured that out.. Thanks!

which references do you use? how do you know that you can query the element-interface for an 'anchor'-interface, and from where do you get the numbers in the data section..?!

there are some things in your code that I don't understand:

1. what is the event 32770 and why does the mainwindow repeatedly receive a timer event?
2. what is the difference between hBrowser and hWeb? I think you are only getting the hBrowser to support 3.90 (?)

besides that I don't understand why you are saying that there is a better way than using a hook - is there something wrong with that?

I'm still very interested if you know a way to avoid the busy waiting for the browser to become ready, and if you find a way to make it work with picture links - I will also look into that myself now..
Sparkie
PureBatMan Forever
PureBatMan Forever
Posts: 2307
Joined: Tue Feb 10, 2004 3:07 am
Location: Ohio, USA

Post by Sparkie »

I would have never figured that out...
That's what I thought too. Just takes a little patience and some good research. If I can do it, anyone can. :)

For window and gadget info, I use WinDowse

For more detailed window / gadget / message info WinSpector

For finding VB / C / C++ code to convert to PB GoogleGroups

For constants ApiViewer

For API functions / interfaces / messages / structures MS full PSDK

And of course my favorite source is Home Sweet Home!
how do you know that you can query the element-interface for an 'anchor'-interface...
It's all in the PSDK I downloaded. For online reference, you can use the MSDN Library
...from where do you get the numbers in the data section..?!
The PSDK download has a Tool (OLE-COM Object viewer) that supplies that info.
1. what is the event 32770 and why does the mainwindow repeatedly receive a timer event?
I don't know, but read this and this. I use 32770 only because it seems to appear as soon as the WebGadget is ready to go. Problem is, the 32770 continues to appear throuout the session.
what is the difference between hBrowser and hWeb
hBrowser returns the handle to the actual web window (Internet Explorer_Server class).
hWeb returns the handle to the WebGadget (AtlAxWin class)
I need hBrowser in PB ver < 3.91 to get the correct ScreenToClient mouseX, mouseY positions. In PB 3.91, this is handled by the WindowMouseX() and WindowMouseY(). I also need hBrowser to return #False unitl the Internet Explorer_Server class window is created. When #True, I know I have the window. I can then start querying the interface.
...I'm still very interested if you know a way to avoid the busy waiting for the browser to become ready
I think I will now start to use WebObject\get_ReadyState(@rs), as this seems to work for my use. Other than get_ReadyState giving you more detail, there doesn't seem to be much difference from get_Busy.

get_ReadyState
Retrieves the ready state of the object.
#READYSTATE_LOADING = 1,
# READYSTATE_LOADED = 2,
# READYSTATE_INTERACTIVE = 3,
# READYSTATE_COMPLETE = 4

READYSTATE_UNINITIALIZED
Default initialization state.

READYSTATE_LOADING
Object is currently loading its properties.

READYSTATE_LOADED
Object has been initialized.

READYSTATE_INTERACTIVE
Object is interactive, but not all of its data is available.

READYSTATE_COMPLETE
Object has received all of its data.
get_Busy...
Retrieves a BOOL value indicating whether the object is engaged in a navigation or downloading operation.
#TRUE The control is busy.
#FALSE The control is not busy.
besides that I don't understand why you are saying that there is a better way than using a hook - is there something wrong with that?
Nothing wrong with the hook. I would rather use the onmouseover property of the interface. Just seems cleaner to me. ;)
...and if you find a way to make it work with picture links
I'm sure it's possible, so we'll see who finds the answer first. ;)
What goes around comes around.

PB 5.21 LTS (x86) - Windows 8.1
soerenkj
User
User
Posts: 95
Joined: Mon Jun 14, 2004 10:19 pm

Post by soerenkj »

thanks for the references. WinDowse looks interesting, I guess I could find a use for that.. however, it doesn't seem to work with the application I made (nothing happens when I move the mouse over its main window, as does when I do that with another applications main window)

from the psdk I installed the 'Core' and the 'Internet development' references. Now I've been browsing arround for hours, but I still can't figure out how to know which interfaces I can query the objects for.. how did you know that you can get an IHTMLAnchorElement from the IHTMLElement?!

about the problem of finding the url of a picture link: with a lot of patience and fruitless research I've made it so far as to guess that I can get an 'IHTMLImgElement' from the IHTMLElement. Now I'm wondering if there is some way to get the IHTMLAnchortElement (a href tag) that must be kind of 'surrounding' it.....
I'm afraid to open the psdk again.

ps. how/where did you learn about the AtlAxWin and Internet Explorer_Server classes?
Sparkie
PureBatMan Forever
PureBatMan Forever
Posts: 2307
Joined: Tue Feb 10, 2004 3:07 am
Location: Ohio, USA

Post by Sparkie »

...(nothing happens when I move the mouse over its main window
Most likely due to a conflict between my mousehook and the mousehook of WinDowse. I'll take a look at my code again and see if i can fix that. Until then, you can comment out my mousehook

Code: Select all

;hhook = SetWindowsHookEx_(#WH_MOUSE, @MouseProc(), 0, lpdwProcessId)
and see if that fixes the problem for now.
...how did you know that you can get an IHTMLAnchorElement from the IHTMLElement?!
To be honest, I'm not sure how I figured that out. I either got lucky or I found a post here or in Google Groups that helped show me the way. I'm pretty sure it was the latter. ;)

I've been working on the getting the image anchor to cooperate, but so far all I get on right-click is the url to the image itself. I must be missing a step along the way. :?
ps. how/where did you learn about the AtlAxWin and Internet Explorer_Server classes?
If you mean where did I learn of their existence, WinDowse revealed that info to me. If you mean how did I learn to code for them, I haven't yet. :razz:
What goes around comes around.

PB 5.21 LTS (x86) - Windows 8.1
Nico
Enthusiast
Enthusiast
Posts: 274
Joined: Sun Jan 11, 2004 11:34 am
Location: France

Post by Nico »

Another Way, what you think of it?

Code: Select all

; Original code by Sparkie

WebObject.IWebBrowser2
Global WebObject

Procedure link()
    If WebObject\get_document(@pDispatch.IDispatch) = #S_OK 
        If pDispatch\QueryInterface(?IID_IHTMLDocument2, @pDocument2.IHTMLDocument2) = #S_OK        
            If pDocument2\elementFromPoint(WindowMouseX() , WindowMouseY() , @pElement.IHTMLElement) = #S_OK           
                If pElement\QueryInterface(?IID_IHTMLAnchorElement, @pAnchor.IHTMLAnchorElement)= #S_OK                   
                  pAnchor\get_href(@BSTR_Anchor) 
                  aLen = WideCharToMultiByte_(#CP_ACP, 0, BSTR_Anchor, -1, 0, 0, 0, 0) 
                  anchor$ = Space(aLen) 
                  WideCharToMultiByte_(#CP_ACP, 0, BSTR_Anchor, -1, @anchor$, aLen, 0, 0) 
                  SysFreeString_(BSTR_Anchor)             
                  If currentsb$ <> anchor$ 
                    StatusBarText(0, 0, anchor$) 
                    currentsb$ = anchor$ 
                  EndIf             
                pAnchor\Release() 
                EndIf                            
            pElement\Release()
            EndIf       
      pDocument2\Release()
      EndIf         
    pDispatch\Release()  
    EndIf 
EndProcedure 


If OpenWindow(0, 10, 10, 700, 500, #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget, "WebGadget ReadyState") 

  If CreateStatusBar(0, WindowID()) 
    StatusBarText(0, 0, "") 
  EndIf 
      
  If CreateGadgetList(WindowID()) 
    WebGadget(0, 10, 10, 680, 460, "http://www.purearea.net/pb/CodeArchiv/English.html") 
    WebObject = GetWindowLong_(GadgetID(0), #GWL_USERDATA) 
  EndIf 
   
EndIf 

Repeat 
   EventID.l=WaitWindowEvent()
        
    If   hBrowser = 0
       hChild1 = FindWindowEx_(GadgetID(0), 0, "Shell Embedding", 0) 
        hChild2 = FindWindowEx_(hChild1, 0, "Shell DocObject View", 0) 
        hBrowser = FindWindowEx_(hChild2, 0, "Internet Explorer_Server", 0) 
        SetParent_(hBrowser,WindowID(0))
    EndIf
  
  If isBusy 
    WebObject\get_ReadyState(@isReady) 
      
      Select isReady 
        Case 1 
        page=0
          StatusBarText(0, 0, "Page Loading") 
          
        Case 2
          StatusBarText(0, 0, "Page Loaded") 
          
        Case 3
          page=1 
          StatusBarText(0, 0, "Page is interactive with some data missing") 
          
        Case 4 
          page=1
          StatusBarText(0, 0, "Page finished loading") 
          
      EndSelect 
  EndIf 
          
  WebObject\get_busy(@isBusy) 
  

      Select EventID
        Case #WM_MOUSEMOVE
        Hcursor=GetCursor_() 
        If page
            If Hcursor<>65555 And  Hcursor<>65553
            link()
            Else 
            StatusBarText(0, 0, "") 
            EndIf 
        EndIf 
        
        Case #WM_CLOSE
            quit=1
    EndSelect 
 
Until quit=1 

End

DataSection 
IID_IHTMLDocument2: 
;332C4425-26CB-11D0-B483-00C04FD90119 
Data.l $332C4425 
Data.w $26CB, $11D0 
Data.b $B4, $83, $00, $C0, $4F, $D9, $01, $19 

IID_IHTMLAnchorElement: 
;3050F1DA-98B5-11CF-BB82-00AA00BDCE0B 
Data.l $3050F1DA 
Data.w $98B5, $11CF 
Data.b $BB, $82, $00, $AA, $00, $BD, $CE, $0B 

EndDataSection
soerenkj
User
User
Posts: 95
Joined: Mon Jun 14, 2004 10:19 pm

Post by soerenkj »

Nico, as far as I can see, the method is the same - except that you use the cursor to find out if there is a link to be shown. And it also doesn't work with picture links...
but anyway, I think the code is pretty.
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5342
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Post by Kwai chang caine »

hello at all.

Excuse my bad english :oops:

For me two, nothing happens when I move the mouse over its main window.

I have comment out the mousehook

Code: Select all

;hhook = SetWindowsHookEx_(#WH_MOUSE, @MouseProc(), 0, lpdwProcessId)
and it's not good :cry:

I have Windows 2000

That is the reason ????

Thanks
ImageThe happiness is a road...
Not a destination
User avatar
Shardik
Addict
Addict
Posts: 1989
Joined: Thu Apr 21, 2005 2:38 pm
Location: Germany

Post by Shardik »

Take a look into this post from freak (first post):
http://www.purebasic.fr/english/viewtopic.php?t=16837

Download his incude file "WebGadgetExtras.PB"
http://freak.purearea.net/code/WebGadgetExtras.pb

And paste the example code from his first posting into your IDE.
If using PB 4.x, change

Code: Select all

If OpenWindow(0, 0, 0, 800, 600, #PB_Window_SystemMenu|#PB_Window_ScreenCentered, "WebGadget example")
to

Code: Select all

If OpenWindow(0, 0, 0, 800, 600, "WebGadget example", #PB_Window_SystemMenu|#PB_Window_ScreenCentered)
and change

Code: Select all

If CreateGadgetList(WindowID())
to

Code: Select all

If CreateGadgetList(WindowID(0)) 
and voila, it's working...
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5342
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Post by Kwai chang caine »

That's ok :D

Thanks to your help Shardik

I whish you a good day
ImageThe happiness is a road...
Not a destination
User avatar
a_carignan
User
User
Posts: 81
Joined: Sat Feb 21, 2009 2:01 am
Location: Canada

Re: WebGadget - retreiving URL of link under pointer

Post by a_carignan »

Hello,
Oddly it gives incomprehensible Chinese characters.
I would like to have a code that really gives the links.
tank you.
infratec
Always Here
Always Here
Posts: 6817
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: WebGadget - retreiving URL of link under pointer

Post by infratec »

Then simply adapt the code to the new version of PB. :wink:

Hint: ASCII -> Unicode

And about which code you are talking?
Here are listed and referenced many of them.
User avatar
a_carignan
User
User
Posts: 81
Joined: Sat Feb 21, 2009 2:01 am
Location: Canada

Re: WebGadget - retreiving URL of link under pointer

Post by a_carignan »

I'm talking about the two sample code on this page.
I tried to convert the text with its command lines:

Code: Select all

*ascii=Ascii(anchor$)
anchor$=PeekS(*ascii,-1)
But it doesn't work, it's still Chinese. :?
Post Reply