Solved

ShowWindowAsync is not working

Posted on 2010-09-14
17
1,330 Views
Last Modified: 2012-05-10
I have a VB.net application. This app has one user triggered action which is to open a web site on IE browser. The app will search for all the IE tabs to see if the same web site has been opened.  If such a tab is found then refresh that tab with an updated URL (so that it won't create a new tab or window every time). Also if the IE window is minimized, it should restore or maximize the window.  I was able to use "Microsoft Internet Control" to find the tab, update the tab with new URL and get the window handle of the tab.  For restoring window, I did  some search, many people recommend using ShowWindowAsync. I tried that, it did not seem to work. The window would remain minimize. Following is the code snippet.

 

'openIE is SHDocVw.InternetExplorer
If (Not openIE Is Nothing) Then
Try
openIE.Navigate(url) 'update with new URL
Dim ret As Long
ret = ShowWindowAsync(openIE.HWND, 1) '1 is SW_NORMAL,
ret = ShowWindowAsync(openIE.HWND, 9) '3 is SW_SHOWMAX, 9 is SW_RESTORE


ret = BringWindowToTop(openIE.HWND)
ret = SetForegroundWindow(openIE.HWND)

Catch e As Exception  
      MsgBox("Exception: " & e.Message)
End Try

End If

      When I ran this program, there was no error or exception.  However, IE would stay minimized.  I don't know why this is not working and if there is any way to debug it; or if there is other way to accomplish the same thing; Any help will be appreciated.

 
Thanks

0
Comment
Question by:mingxun
  • 10
  • 7
17 Comments
 
LVL 29

Expert Comment

by:nffvrxqgrcfqvvc
ID: 33676926
I think what you will need to do here is verify that OpenIE.HWND is actually the window handle to the (Main) window IEFrame (classname) or not zero. You can use spy++ utility to match to verify the handles.
Which language are you using Classic VB6 or VB.NET?
Which operating system are you testing under?
0
 
LVL 29

Expert Comment

by:nffvrxqgrcfqvvc
ID: 33676935
Ahh.. your using VB.NET didn't even see the Try Catch Block... But yeah see if the handles match up correctly.
0
 

Author Comment

by:mingxun
ID: 33682906
Thanks for the response. I used message box to display the handle and  spy++ to get the handle of the IEFrame. They did match, except one is hex, another is digit. However, from spy++,  I didn't see any message going to that IEFrame after that ShowWindowAsync was called.  Do you know any other testing I could do? Thanks for your help.
0
 
LVL 29

Accepted Solution

by:
nffvrxqgrcfqvvc earned 50 total points
ID: 33683145
Can you post the declerations of your ShowWindowAsync() method.
Dim ret As Long <---- This should be an IntPtr value.
Here is an example of restoring a minimized window.

<DllImport("user32.dll", ExactSpelling:=True, SetLastError:=True, CharSet:=CharSet.Auto)> _

    Private Shared Function ShowWindowAsync(ByVal hWnd As IntPtr, ByVal nCmdShow As Integer) As <MarshalAs(UnmanagedType.Bool)> Boolean

    End Function

    <DllImport("user32.dll", ExactSpelling:=True, SetLastError:=True, CharSet:=CharSet.Auto)> _

    Private Shared Function IsIconic(ByVal hWnd As IntPtr) As <MarshalAs(UnmanagedType.Bool)> Boolean

    End Function

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        Dim hWindow As IntPtr

        hWindow = &H3502B2 ' The handle to IEFrame goes here.

        If IsIconic(hWindow) Then

            ShowWindowAsync(hWindow, 9) 'SW_RESTORE

        End If

    End Sub

Open in new window

0
 

Author Closing Comment

by:mingxun
ID: 33683826
Using your ShowWindowAsync() declaration seems have solved my problem.  The declaration I used did not have the DllImport in the declaration. So it probably could not find the function in runtime. It would be helpful if it could throw a runtime exception for not being able to find the function.

Thanks
0
 
LVL 29

Expert Comment

by:nffvrxqgrcfqvvc
ID: 33683877
Good to know it works for you =) .. It would generally throw an exception but the decleration you used might have been incorrect, it's possible that you found a VB6 version which uses the Long Data type but in VB.NET what would be Long in VB6 is actually an Integer data type in VB.NET.
0
 

Author Comment

by:mingxun
ID: 33685017
The declaration I used is like this:

Public Shared Function ShowWindowAsync(ByVal hWnd As IntPtr, ByVal cmdShow As Integer) As Boolean
End Function

I believed I copied the function declaration from one website, which I could not remember.   But the program compiled and no exception in runtime.
0
 
LVL 29

Expert Comment

by:nffvrxqgrcfqvvc
ID: 33685080
Yeah what you have really is just a shared procedure which basically doesn't do anything and is exactly the same as just creating your own method.
You never did call into the actual API at anytime during your calls rather just calling into a blank procedure. =)
0
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 

Author Comment

by:mingxun
ID: 33688535
I started working on this VB.net project several months back. So my experience on VB.net is very limited.  Before that, I mostly programmed in Java and C++.  I thought VB's function declaration is like function definition in C++ header file, which will help compiling. In runtime, it still needs to look for actual function implementation. I also think that my program has only the function declaration for ShowWindowAsync. My program doesn't have the implementation. And when I debug my program, this function always returns 0. That is something I don't understand.  I have another problem, if IE window has many tabs, and the tab I am interesting is not active right now. How could I make that tab active or getting focus using vb.net? Any pointer will be appreciated.
0
 
LVL 29

Expert Comment

by:nffvrxqgrcfqvvc
ID: 33691444
The individual tabs are more complicated to activate because they use DirectUIHWND class. Microsoft never added functionality to work with individual tabs the only support I know is with the IAccessible Interface. If you have the Windows SDK you can use the Inspect utility to look at the objects then using IAccessible to iterate through the objects.
Here is an example I quickly wrote that will activate the TAB of a specified (tab title) =)

You must add a reference to IAccessible, Under the IDE menu select Project > Add Reference > .NET Tab > Accessibility
Create new class named: IETab.vb
Add the following code to the class in the code section.
You can use it like this (using this question title as an example)
'// Usage

IETab.ActivateTabByTitle("ShowWindowAsync is not working")
 
 

Imports System.Runtime.InteropServices



Public Class IETab

    'egl1044

    Public Shared Sub ActivateTabByTitle(ByVal title As String)



        Dim objCount As Integer

        Dim tabCount As Integer

        Dim tabTitle As String = String.Empty



        Dim acc As Accessibility.IAccessible = Nothing

        Dim accTabRow As Accessibility.IAccessible = Nothing



        Dim h1 As IntPtr = SafeNativeMethods.FindWindowEx(IntPtr.Zero, IntPtr.Zero, "IEFrame", Nothing)

        Dim h2 As IntPtr = SafeNativeMethods.FindWindowEx(h1, IntPtr.Zero, "CommandBarClass", Nothing)

        Dim h3 As IntPtr = SafeNativeMethods.FindWindowEx(h2, IntPtr.Zero, "ReBarWindow32", Nothing)

        Dim h4 As IntPtr = SafeNativeMethods.FindWindowEx(h3, IntPtr.Zero, "TabBandClass", Nothing)

        Dim h5 As IntPtr = SafeNativeMethods.FindWindowEx(h4, IntPtr.Zero, "DirectUIHWND", Nothing)



        Dim IID_IAccessible As New Guid("{618736E0-3C3D-11CF-810C-00AA00389B71}")



        If SafeNativeMethods.AccessibleObjectFromWindow(&H9503C8, &HFFFFFFFC, IID_IAccessible, acc) = 0 Then

            '// Enumerate the objects and find the "Tab Row"

            '// Quick(Tabs(Ctrl + Q)

            '// TAB List

            '// TAB Row

            objCount = acc.accChildCount

            For i = 1 To objCount

                If acc.accChild(i).accName(0).ToLower.Equals("tab row") Then

                    '// Found the Tab Row.

                    accTabRow = DirectCast(acc.accChild(i), Accessibility.IAccessible)

                    '// The number of tabs in this row + new tab

                    tabCount = accTabRow.accChildCount

                    For tabs As Integer = 1 To tabCount

                        '// The title of each tabs

                        tabTitle = accTabRow.accChild(tabs).accName(0)

                        '// Activate the tab

                        If tabTitle.ToLower.Equals(title.ToLower) Then

                            accTabRow.accChild(tabs).accDoDefaultAction(0)

                        End If

                    Next

                    Exit For

                End If

            Next

            Marshal.FinalReleaseComObject(acc)

        End If

    End Sub

End Class



Public Class SafeNativeMethods

    <DllImport("user32.dll", ExactSpelling:=False, SetLastError:=True, CharSet:=CharSet.Unicode)> _

    Friend Shared Function FindWindowEx(ByVal hwndParent As IntPtr, _

                                        ByVal hwndChildAfter As IntPtr, _

                                        ByVal lpszClass As String, _

                                        ByVal sWindowTitle As String) As IntPtr

    End Function



    <DllImport("oleacc.dll", ExactSpelling:=True, SetLastError:=True, CharSet:=CharSet.Unicode)> _

    Friend Shared Function AccessibleObjectFromWindow(ByVal hWnd As IntPtr, _

                                                      ByVal dwObjectID As Integer, _

                                                      ByRef refID As Guid, _

                                                      ByRef ppvObject As Accessibility.IAccessible) As Integer

    End Function

End Class

Open in new window

0
 
LVL 29

Expert Comment

by:nffvrxqgrcfqvvc
ID: 33691478
My Bad... On Line 22 while I was debugging I left the hard coded window handle. You have to change line 22 to the following (h5) variable.
 

If SafeNativeMethods.AccessibleObjectFromWindow(h5, &HFFFFFFFC, IID_IAccessible, acc) = 0 Then

Open in new window

0
 
LVL 29

Expert Comment

by:nffvrxqgrcfqvvc
ID: 33691508
BTW: You also might want to change it up for example its possible that more than one IEFrame exists so start at the IEFrame HWND that has the Tabs you want to target. The example currently will just find the first IEFrame available.
0
 

Author Comment

by:mingxun
ID: 33692852
Thanks for the quick response. I tried IETab. I got an exception on line 29.

 Exception - Value does not fall within the expected range.      

From the debugger,objCount is 7, and quick watch shows
+            acc.accChild(1)      {"Value does not fall within the expected range."}      Object

I changed the code a little bit so that I can pass the hwnd to the function. Following is the code:


Imports System.Runtime.InteropServices

Public Class IETab
    'egl1044
    Public Shared Sub ActivateTabByTitle(ByVal title As String, ByVal hwnd As IntPtr)

        Dim objCount As Integer
        Dim tabCount As Integer
        Dim tabTitle As String = String.Empty

        Dim acc As Accessibility.IAccessible = Nothing
        Dim accTabRow As Accessibility.IAccessible = Nothing

        Dim h1 As IntPtr = SafeNativeMethods.FindWindowEx(IntPtr.Zero, IntPtr.Zero, "IEFrame", Nothing)
        Dim h2 As IntPtr = SafeNativeMethods.FindWindowEx(h1, IntPtr.Zero, "CommandBarClass", Nothing)
        Dim h3 As IntPtr = SafeNativeMethods.FindWindowEx(h2, IntPtr.Zero, "ReBarWindow32", Nothing)
        Dim h4 As IntPtr = SafeNativeMethods.FindWindowEx(h3, IntPtr.Zero, "TabBandClass", Nothing)
        Dim h5 As IntPtr = SafeNativeMethods.FindWindowEx(h4, IntPtr.Zero, "DirectUIHWND", Nothing)

        Dim IID_IAccessible As New Guid("{618736E0-3C3D-11CF-810C-00AA00389B71}")

        If SafeNativeMethods.AccessibleObjectFromWindow(hwnd, &HFFFFFFFC, IID_IAccessible, acc) = 0 Then
            '// Enumerate the objects and find the "Tab Row"
            '// Quick(Tabs(Ctrl + Q)
            '// TAB List
            '// TAB Row
            objCount = acc.accChildCount
            For i = 1 To objCount
                If acc.accChild(i).accName(0).ToLower.Equals(title) Then
                    '// Found the Tab Row.
                    accTabRow = DirectCast(acc.accChild(i), Accessibility.IAccessible)
                    '// The number of tabs in this row + new tab
                    tabCount = accTabRow.accChildCount
                    For tabs As Integer = 1 To tabCount
                        '// The title of each tabs
                        tabTitle = accTabRow.accChild(tabs).accName(0)
                        '// Activate the tab
                        If tabTitle.ToLower.Equals(title.ToLower) Then
                            accTabRow.accChild(tabs).accDoDefaultAction(0)
                        End If
                    Next
                    Exit For
                End If
            Next
            Marshal.FinalReleaseComObject(acc)
        End If
    End Sub
End Class

Public Class SafeNativeMethods
    'Friend Charset
    '<DllImport("user32.dll", ExactSpelling:=False, SetLastError:=True, CharSet:=CharSet.Unicode)> _
    <DllImport("user32.dll", ExactSpelling:=False, SetLastError:=True)> _
    Friend Shared Function FindWindowEx(ByVal hwndParent As IntPtr, _
                                        ByVal hwndChildAfter As IntPtr, _
                                        ByVal lpszClass As String, _
                                        ByVal sWindowTitle As String) As IntPtr
    End Function

    '<DllImport("oleacc.dll", ExactSpelling:=True, SetLastError:=True, CharSet:=CharSet.Unicode)> _
    <DllImport("oleacc.dll", ExactSpelling:=True, SetLastError:=True)> _
    Friend Shared Function AccessibleObjectFromWindow(ByVal hWnd As IntPtr, _
                                                      ByVal dwObjectID As Integer, _
                                                      ByRef refID As Guid, _
                                                      ByRef ppvObject As Accessibility.IAccessible) As Integer
    End Function
End Class

Open in new window

0
 
LVL 29

Expert Comment

by:nffvrxqgrcfqvvc
ID: 33692960
Remove line 14 or comment it out and then the HWND for the IEFrame just needs to begin on line 15 only change needed.
For example.

Dim h2 As IntPtr = SafeNativeMethods.FindWindowEx(hwnd, IntPtr.Zero, "CommandBarClass", Nothing)

Open in new window

0
 

Author Comment

by:mingxun
ID: 33693481
After the change, I still got the same exception. It seems for some reason acc.accChild is not accessible or is not a list.
0
 
LVL 29

Expert Comment

by:nffvrxqgrcfqvvc
ID: 33693501
I have to ask did you change line 22 back to h5 variable?
If SafeNativeMethods.AccessibleObjectFromWindow(h5, &HFFFFFFFC, IID_IAccessible, acc) = 0 Then

Open in new window

0
 

Author Comment

by:mingxun
ID: 33694308
My fault, I did not change that to h5. Now after that change, it is working now. Thanks. I will probably need to spend some time to read the document to understand what it does.

Thanks again.
0

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

A long time ago (May 2011), I have written an article showing you how to create a DLL using Visual Studio 2005 to be hosted in SQL Server 2005. That was valid at that time and it is still valid if you are still using these versions. You can still re…
It was really hard time for me to get the understanding of Delegates in C#. I went through many websites and articles but I found them very clumsy. After going through those sites, I noted down the points in a easy way so here I am sharing that unde…
Get a first impression of how PRTG looks and learn how it works.   This video is a short introduction to PRTG, as an initial overview or as a quick start for new PRTG users.
Here's a very brief overview of the methods PRTG Network Monitor (https://www.paessler.com/prtg) offers for monitoring bandwidth, to help you decide which methods you´d like to investigate in more detail.  The methods are covered in more detail in o…

705 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

20 Experts available now in Live!

Get 1:1 Help Now