• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 723
  • Last Modified:

WebBrowser detection

PROBLEM: I can't find a function to enumerate non-standalone Internet Explorer web browsers on a system. The "Microsoft Internet Controls" (shdocvw.dll) function only "sees" separate Internet Explorer applications, not web browser controls by other apps.


  Open a VB project.  Go to Projects/References and check "Microsoft Internet Controls" (shdocvw.dll).

  Create a form with the following code:

Private Sub Command1_Click()

 Dim SWs As New SHDocVw.ShellWindows
 Dim IE As SHDocVw.InternetExplorer
 For Each IE In SWs
   MsgBox "found a browser: " & IE.FullName & vbCrLf & IE.hWnd
 End Sub

  If you run it without any other application running, it should return nothing.  If you open up Internet Explorer, it will detect that IE application.

  So far, no problem.

  Now, for the VB project, go to Project/Components and add "Microsoft Internet Controls" (shdocvw.dll).  Drag a webbrowser container onto the form.

  Add the following to your Form_Load:

Private Sub Form_Load()
   WebBrowser1.Navigate "www.mamma.com"
End Sub

 When you run the project now, you should see the web page to www.mamma.com displayed.

 PROBLEM:  But when you click the Command1 button, you still only detect the standalone IE application.  

 (Let's pretend like the other web browser isn't really part of your own project - it is really running on another application.  I used a WebBrowser control on the same detection project for brevity.)

  (Also, I need a solution that doesn't use the "ObjectFromLResult" function in the oleacc.dll which sucks big time for Win95 and Win98 boxes.)
  • 9
  • 8
  • 2
  • +2
1 Solution
Richie_SimonettiIT OperationsCommented:
I think you could detect webbrowser control if you set registerasbrowser property.
=====Bas module code===
Private Declare Function EnumChildWindows& Lib "user32" (ByVal hParent As Long, ByVal lpEnumFunc As Long, ByVal lParam As Long)
Private Declare Function GetClassName Lib "user32" Alias "GetClassNameA" (ByVal hWnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long
Private Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hWnd As Long, ByVal lpString As String, ByVal cch As Long) As Long
Private Declare Function EnumWindows& Lib "user32" (ByVal lpEnumFunc As Long, ByVal lParam As Long)
Private Declare Function GetParent Lib "user32" (ByVal hWnd As Long) As Long

Dim sURLs() As String
Dim nCount As Integer

Public Function EnumAllBrowsers() As Variant
   EnumWindows AddressOf EnumWinProc, 0
   EnumAllBrowsers = sURLs
End Function

Function EnumWinProc(ByVal hWnd As Long, ByVal lParam As Long) As Long
  If GetWndClass(hWnd) = "Shell DocObject View" Then
     nCount = nCount + 1
     ReDim Preserve sURLs(nCount - 1)
     sURLs(nCount - 1) = GetWndText(GetParent(hWnd))
  End If
  EnumChildWindows hWnd, AddressOf EnumChildWinProc, 0
  EnumWinProc = 1
End Function

Function EnumChildWinProc(ByVal hWnd As Long, ByVal lParam As Long) As Long
  If GetWndClass(hWnd) = "Shell DocObject View" Then '
     nCount = nCount + 1
     ReDim Preserve sURLs(nCount - 1)
     sURLs(nCount - 1) = GetWndText(GetParent(hWnd))
  End If
  EnumChildWinProc = 1
End Function

Private Function GetWndClass(hWnd As Long) As String
  Dim k As Long, sName As String
  sName = Space$(128)
  k = GetClassName(hWnd, sName, 128)
  If k > 0 Then sName = Left$(sName, k) Else sName = "No class"
  GetWndClass = sName
End Function

Private Function GetWndText(hWnd As Long) As String
  Dim k As Long, sName As String
  sName = Space$(128)
  k = GetWindowText(hWnd, sName, 128)
  If k > 0 Then sName = Left$(sName, k) Else sName = "No name"
  GetWndText = sName
End Function

'=========Form code=======
Private Sub Command1_Click()
   Dim Result As Variant
   Result = EnumAllBrowsers
   For i = 0 To UBound(Result)
       Debug.Print Result(i)
   Next i
End Sub

Private Sub Form_Load()
  WebBrowser1.Navigate "http://www.astalavista.com"
End Sub

EasyAimAuthor Commented:

  I appreciate your code.  I'm embarrassed that I did not clarify my question better....

  Similar to your code, I can get the 'hWnd' of a webbrowser object; however, I can not extract any useful information from the object using only the 'hWnd'.

  What I need is to instantiate an 'SHDocVw.ShellWindows' for a specific webbrowser so I can extract the HTML code out of it similar to my original example code.

   In other words, my goal is:

  Given a webbrowser object (i.e. "Shell DocObject View" or "Internet Explorer_Server") I need to extract the HTML code out of it.

   I'll double the points for this solution.

Free Tool: ZipGrep

ZipGrep is a utility that can list and search zip (.war, .ear, .jar, etc) archives for text patterns, without the need to extract the archive's contents.

One of a set of tools we're offering as a way to say thank you for being a part of the community.

Did you see this sample http://www.domaindlx.com/e_morcillo/scripts/tips/en/ie/iedom.asp ?
 Though it use oleacc.dll, it works for me at w98.

EasyAimAuthor Commented:

  Yes, I am currently using the oleacc.dll to perform a similar method of extracting the DOM from webserver objects.
  The problem is that the oleacc.dll apparently is not backward compatible and installation packages for Win95, Win98, Win2000, etc.. are notoriously difficult to "get right" due to this sorry dll design.
   I can't believe the only method of extracting HTML from a webbrowser object on a computer is through the use of this magical dll.
Richie_SimonettiIT OperationsCommented:
It is not the only way but it depends upon from what window you need to do it.
EasyAimAuthor Commented:
Any more information there, Richie?  What do you mean?  I'm primarily interested in extracting info from the "Internet Explorer_Server" component (without using the oleacc.dll).
Richie_SimonettiIT OperationsCommented:
Well, i misread previous comments, sorry.
What i did try is a different approach:
What about to catch IE_server "creation" instead of enumerate
running instances?
Bad idea!
As i told previously, we cannot enumerate webbrowser with shellwindows if the app with webbrowser control has not setted its property
registerasbrowser to true.
Just do a try with your first code setting that property and you will see what i mean.
I am in a dead way.
EasyAimAuthor Commented:
Thanks for your research Richie.  And good try with that English language.   If I understand you correctly, you are also at a "dead end" trying to solve this problem also.

I hate threads that start out promising and then just peter out due to no solution.

I'll keep ratching up the points for a solution for a few more days.

Again, the question is:  Using Visual Basic, how do you extract the DOM or HTML code from an "Internet Explorer_Server" component without using the 'oleacc.dll'?
Richie_SimonettiIT OperationsCommented:
To this very time, i think you have to stick to oleacc dll. Sorry.
Note: I did a try enumerating child windows (strange, it doesn't returns "Internet Explorer_Server" but:
"Shell Embedding" and
"Shell DocObject View")

PS: My english is more ugly than my code ;)
Richie_SimonettiIT OperationsCommented:
I don't know why but i had to do a little modification to
Edammo's code in link posted by Ark.
It simply doesn't works for me!!!

Well, this code assumes that you have a command button, a listbox,
a richtextbox, a webbrowser control and a reference to Microsoft HTML Object library (to do things easily, just as your example ;)
You need a module also.
Take in mind that this code could be modified to do things more "correct", i just did a "working" one in a hurry.

Option Explicit

'in a module
Public DocHwnd As Long
Public arrHwnd() As Long    'to store handles
Dim iedoc As IHTMLDocument2

   Data1 As Long
   Data2 As Integer
   Data3 As Integer
   Data4(0 To 7) As Byte
End Type
Declare Function RegisterWindowMessage Lib "user32" _
   Alias "RegisterWindowMessageA" ( _
      ByVal lpString As String) As Long

Declare Function SendMessageTimeout Lib "user32" _
   Alias "SendMessageTimeoutA" ( _
      ByVal hwnd As Long, _
      ByVal msg As Long, _
      ByVal wParam As Long, _
      lParam As Any, _
      ByVal fuFlags As Long, _
      ByVal uTimeout As Long, _
      lpdwResult As Long) As Long
Declare Function ObjectFromLresult Lib "oleacc" ( _
      ByVal lResult As Long, _
      riid As UUID, _
      ByVal wParam As Long, _
      ppvObject As Any) As Long
Declare Function lstrcmp Lib "kernel32" Alias "lstrcmpA" (ByVal lpString1 As String, ByVal lpString2 As String) As Long
Declare Function GetClassName Lib "user32" Alias "GetClassNameA" (ByVal hwnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long
Declare Function EnumChildWindows Lib "user32" (ByVal hWndParent As Long, ByVal lpEnumFunc As Long, ByVal lParam As Long) As Long
Declare Function EnumWindows Lib "user32" (ByVal lpEnumFunc As Long, ByVal lParam As Long) As Boolean

Function IEDOMFromhWnd(hwnd As Long) As IHTMLDocument
Dim spDoc As IUnknown
Dim lRes As Long
Dim lMsg As Long
Dim hr As Long

' Register the message
lMsg = RegisterWindowMessage("WM_HTML_GETOBJECT")
' Get the object
Call SendMessageTimeout(hwnd, lMsg, 0, 0, SMTO_ABORTIFHUNG, 1000, lRes)

If lRes Then
   ' Initialize the interface ID
   With IID_IHTMLDocument
      .Data1 = &H626FC520
      .Data2 = &HA41E
      .Data3 = &H11CF
      .Data4(0) = &HA7
      .Data4(1) = &H31
      .Data4(2) = &H0
      .Data4(3) = &HA0
      .Data4(4) = &HC9
      .Data4(5) = &H8
      .Data4(6) = &H26
      .Data4(7) = &H37
   End With
   ' Get the object from lRes
   hr = ObjectFromLresult(lRes, IID_IHTMLDocument, 0, IEDOMFromhWnd)
End If
End Function

Public Function EnumWindowsProc(ByVal hwnd As Long, ByVal lParam As Long) As Boolean
    Static idx As Integer ' to use for array
    ReDim Preserve arrHwnd(idx)
    arrHwnd(idx) = hwnd
    idx = idx + 1
    'continue enumeration
    EnumWindowsProc = True
End Function

Public Function EnumChildProc(ByVal hwnd As Long, ByVal lParam As Long) As Long
    Dim sSave As String, lret As Long
    sSave = Space$(255)
    lret = GetClassName(hwnd, sSave, 255)
    sSave = Left$(sSave, lret)
    If sSave = "Internet Explorer_Server" Then
        Set iedoc = IEDOMFromhWnd(hwnd)
        If Not iedoc Is Nothing Then
            With frmWB.rtb
                .Text = .Text & vbCrLf & vbCrLf & iedoc.documentElement.innerHTML & vbCrLf & vbCrLf & "|------- Begin of new HTML Document ---------|"
            End With
        End If
    'DocHwnd = hwnd
    End If
    'continue enumeration
    EnumChildProc = 1
End Function

' form:
Object = "{EAB22AC0-30C1-11CF-A7EB-0000C05BAE0B}#1.1#0"; "SHDOCVW.DLL"
Object = "{3B7C8863-D78F-101B-B9B5-04021C009402}#1.2#0"; "RICHTX32.OCX"
Begin VB.Form frmWB
   Caption         =   "Form1"
   ClientHeight    =   6510
   ClientLeft      =   60
   ClientTop       =   345
   ClientWidth     =   6765
   LinkTopic       =   "Form1"
   ScaleHeight     =   6510
   ScaleWidth      =   6765
   StartUpPosition =   3  'Windows Default
   Begin RichTextLib.RichTextBox rtb
      Height          =   2145
      Left            =   15
      TabIndex        =   3
      Top             =   4320
      Width           =   6705
      _ExtentX        =   11827
      _ExtentY        =   3784
      _Version        =   393217
      Enabled         =   -1  'True
      ScrollBars      =   2
      TextRTF         =   $"frmWB.frx":0000
   Begin VB.ListBox List1
      Height          =   3765
      Left            =   15
      TabIndex        =   2
      Top             =   525
      Width           =   2130
   Begin VB.CommandButton Command1
      Caption         =   "Command1"
      Height          =   405
      Left            =   45
      TabIndex        =   1
      Top             =   60
      Width           =   2085
   Begin SHDocVwCtl.WebBrowser wb1
      Height          =   4230
      Left            =   2205
      TabIndex        =   0
      Top             =   45
      Width           =   4560
      ExtentX         =   8043
      ExtentY         =   7461
      ViewMode        =   0
      Offline         =   0
      Silent          =   0
      RegisterAsBrowser=   0
      RegisterAsDropTarget=   1
      AutoArrange     =   0   'False
      NoClientEdge    =   0   'False
      AlignLeft       =   0   'False
      ViewID          =   "{0057D0E0-3573-11CF-AE69-08002B2E1262}"
      Location        =   ""
Attribute VB_Name = "frmWB"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = True
Attribute VB_Exposed = False
Option Explicit

Private Sub Command1_Click()
Dim i As Integer
Dim lret As Long, buff As String
buff = Space$(255)
EnumWindows AddressOf EnumWindowsProc, ByVal 0&
For i = 0 To UBound(arrHwnd)
    lret = GetClassName(arrHwnd(i), buff, 255)
    With List1
        .AddItem arrHwnd(i) & vbTab & Left$(buff, lret)
    End With
    EnumChildWindows arrHwnd(i), AddressOf EnumChildProc, 0& 'hWnd
Next i

End Sub

Private Sub Form_Load()
    'KPD-Team 2000
    'URL: http://www.allapi.net/
    'E-Mail: KPDTeam@Allapi.net
    wb1.Navigate "C:\Mis documentos\Editctls.htm"
End Sub
Richie_SimonettiIT OperationsCommented:
Hi EasyAim, what's up!
EasyAimAuthor Commented:
 Yes, I'm currently using code similar to what you submitted and it works for many of the newer operating systems.  I am after some code that does not use the "oleacc.dll" which 'ObjectFromLresult()' requires.  This DLL is not backward compatible and causes problems on older operating systems (i.e. Win95).
Richie_SimonettiIT OperationsCommented:
couldn't you distribute that dll?
EasyAimAuthor Commented:
 The "oleacc.dll" is problematic when dealing with multiple operating systems especially older Win95/98.  The purpose of this thread is to determine if there is a method of extracting DOM info from foreign webbrowser components without the use of "oleacc.dll".
EasyAimAuthor Commented:
I appreciate all the responses but apparently there isn't a readily available solution other than the use of the "oleacc.dll".
Richie_SimonettiIT OperationsCommented:
Well, instead of delete this, ask community support to PAQ it. It will no cost you and some other people could get it regardless oleacc.dll's inferno.
EasyAimAuthor Commented:
"ask community support to PAQ"....     What exactly does this mean?
Richie_SimonettiIT OperationsCommented:
Ask a question in http://www.experts-exchange.com/commspt/ telling what you want to do with this question.

No comment has been added lately, so it's time to clean up this TA.
I will leave a recommendation in Community Support that this question is:
- refund/PAQ
Please leave any comments here within the
next seven days.
per recommendation

Community Support Moderator @Experts Exchange
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Cloud Class® Course: SQL Server Core 2016

This course will introduce you to SQL Server Core 2016, as well as teach you about SSMS, data tools, installation, server configuration, using Management Studio, and writing and executing queries.

  • 9
  • 8
  • 2
  • +2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now