Go Premium for a chance to win a PS4. Enter to Win

x
?
Solved

ShowWindowAsync is not working

Posted on 2010-09-14
17
Medium Priority
?
1,492 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
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 29

Accepted Solution

by:
nffvrxqgrcfqvvc earned 200 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
 

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

Learn Veeam advantages over legacy backup

Every day, more and more legacy backup customers switch to Veeam. Technologies designed for the client-server era cannot restore any IT service running in the hybrid cloud within seconds. Learn top Veeam advantages over legacy backup and get Veeam for the price of your renewal

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Today I had a very interesting conundrum that had to get solved quickly. Needless to say, it wasn't resolved quickly because when we needed it we were very rushed, but as soon as the conference call was over and I took a step back I saw the correct …
If you need to start windows update installation remotely or as a scheduled task you will find this very helpful.
this video summaries big data hadoop online training demo (http://onlineitguru.com/big-data-hadoop-online-training-placement.html) , and covers basics in big data hadoop .
We’ve all felt that sense of false security before—locking down external access to a database or component and feeling like we’ve done all we need to do to secure company data. But that feeling is fleeting. Attacks these days can happen in many w…
Suggested Courses

927 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