Codejock Forums Homepage
Forum Home Forum Home > Codejock Products > ActiveX COM > Suite Pro
  New Posts New Posts RSS Feed - TrayIcon GetForegroundWindow Problem
  FAQ FAQ  Forum Search   Events   Register Register  Login Login

TrayIcon GetForegroundWindow Problem

 Post Reply Post Reply
Author
Message
jpbro View Drop Down
Senior Member
Senior Member
Avatar

Joined: 12 January 2007
Status: Offline
Points: 1355
Post Options Post Options   Thanks (0) Thanks(0)   Quote jpbro Quote  Post ReplyReply Direct Link To This Post Topic: TrayIcon GetForegroundWindow Problem
    Posted: 19 January 2008 at 6:12pm
Hi,

I'll describe the behaviour I'm trying to achieve:

1) User clicks TrayIcon and my form is the foreground window -> MinimizeToTray(Me.hWnd)
2) User clicks TrayIcon and my form is *not* the foreground window -> SetForegroundWindow(Me.hWnd)
3) User clicks TrayIcon and my form is minimized to tray -> MaximizeFromTray(Me.hWnd)

However, when using GetForegroundWindow in the TrayIcon Click event, the hWnd for my form is never returned (I believe the taskbar hwnd always gets returned). Any body have any idea on a good way to go about this?

Thanks in advance.

Back to Top
JKDev View Drop Down
Groupie
Groupie


Joined: 27 September 2007
Location: Ireland
Status: Offline
Points: 59
Post Options Post Options   Thanks (0) Thanks(0)   Quote JKDev Quote  Post ReplyReply Direct Link To This Post Posted: 21 January 2008 at 10:01am
Back to Top
jpbro View Drop Down
Senior Member
Senior Member
Avatar

Joined: 12 January 2007
Status: Offline
Points: 1355
Post Options Post Options   Thanks (0) Thanks(0)   Quote jpbro Quote  Post ReplyReply Direct Link To This Post Posted: 21 January 2008 at 10:45am
Hi JKDev, thanks for the reply.

The code you provided does bring the window to the front, the problem I am having though is that I can't figure out a way to determine if my window (or its thread) is the foreground window in the TrayIcon Click event because the Shell_TrayWnd class becomes the foreground window *before* the Click event fires.

It seems that no matter what window appears to be the foreground window (i.e. an instance of Notepad, or my project), then GetForegroundWindow always returns the hwnd for the Shell_TrayWnd class. This makes it impossible (as far as I have found so far) to perform the actions I require in the Click event (Minimize if foreground, Maximize if minimized to tray, Bring to front if not foreground and not minimized to tray). Any ideas?

Thanks again.
Back to Top
JKDev View Drop Down
Groupie
Groupie


Joined: 27 September 2007
Location: Ireland
Status: Offline
Points: 59
Post Options Post Options   Thanks (0) Thanks(0)   Quote JKDev Quote  Post ReplyReply Direct Link To This Post Posted: 21 January 2008 at 10:51am
have you tried getting the window in the mouse down or up event instead of the click event?...
Back to Top
jpbro View Drop Down
Senior Member
Senior Member
Avatar

Joined: 12 January 2007
Status: Offline
Points: 1355
Post Options Post Options   Thanks (0) Thanks(0)   Quote jpbro Quote  Post ReplyReply Direct Link To This Post Posted: 21 January 2008 at 11:06am
I have, unfortunately the events are out of order so the Shell_TrayWnd class grabs the focus before any events fire. Most controls fire events in the MouseDown, MouseUp, Click order, but the TrayIcon control fires Click, MouseDown, MouseUp.

I have just about found a solution though - the second part of the code you sent has a task list example. What I am doing now is checking the task list on click to see if my app is the first in the list, and if so, assuming it is the foreground window. Seems to be working so far...I'll test it some more, clean up the code and then post it here if it is working.

Thanks.
Back to Top
jpbro View Drop Down
Senior Member
Senior Member
Avatar

Joined: 12 January 2007
Status: Offline
Points: 1355
Post Options Post Options   Thanks (0) Thanks(0)   Quote jpbro Quote  Post ReplyReply Direct Link To This Post Posted: 21 January 2008 at 11:47am
The following method should work in *most* cases. The IsForegroundTaskWindow call may incorrectly return false in the case where a legitimate task window with no caption is actually in front of the passed window, but hopefully this is a rare occurence?

In a module:

Option Explicit

' Required Win32 API Declarations
Private Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hWnd As Long, lpdwProcessId As Long) As Long
Private Declare Function EnumWindows Lib "user32" (ByVal lpEnumFunc As Long, ByVal lParam As Long) As Long
Private Declare Function IsWindowVisible Lib "user32" (ByVal hWnd As Long) As Long
Private Declare Function GetParent Lib "user32" (ByVal hWnd As Long) As Long
Private Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hWnd As Long, ByVal nIndex 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 GetForegroundWindow Lib "user32" () As Long
Private Declare Function SetForegroundWindow Lib "user32" (ByVal hWnd As Long) As Long
Private Declare Function IsIconic Lib "user32" (ByVal hWnd As Long) As Long
Private Declare Function ShowWindow Lib "user32" (ByVal hWnd As Long, ByVal nCmdShow As Long) As Long
Private Declare Function AttachThreadInput Lib "user32" (ByVal idAttach As Long, ByVal idAttachTo As Long, ByVal fAttach As Long) As Long
' API Constants
Private Const GWL_HWNDPARENT As Long = (-8) ' Constant used to determine window owner
Private Const SW_SHOW = 5   ' Bring to front
Private Const SW_RESTORE = 9    ' Restore from minimized

Private mlngForegroundTaskHwnd As Long

Public Function IsForegroundTaskWindow(hWnd As Long) As Long
    '---------------------------------------------------------------------------------------
    ' Procedure : IsForegroundTaskWindow
    ' Created   : January 21, 2008
    ' Author    : Jason Peter Brown (jbrown@statslog.com)
    ' Purpose   : To determine whether our window is the foreground window during a
    '             TrayIcon Click event
    ' Notes     : This is necessary because Shell_TrayWnd class steals the focus before
    '             we can test if our window is the foreground window
    ' Returns   : True if passed hWnd is (most likely) the foreground window
    '             False if not
    ' Issues    : May be incorrect if the actual foreground task window has no caption
    '---------------------------------------------------------------------------------------

    Call EnumWindows(AddressOf EnumWindowsProc, hWnd)   ' Determine the hwnd of the foreground task
    IsForegroundTaskWindow = (mlngForegroundTaskHwnd = hWnd)    ' If the results from EnumWindowsProc matches the passed hwnd, we can assume we are the foreground task
    mlngForegroundTaskHwnd = 0  ' Reset the Foreground Task Hwnd for the next call
End Function

Private Function EnumWindowsProc(ByVal hWnd As Long, ByVal lParam As Long) As Long
    '---------------------------------------------------------------------------------------
    ' Procedure : EnumWindowsProc
    ' Created   : January 21, 2008
    ' Author    : Jason Peter Brown (jbrown@statslog.com), adapted from code by
    '             Karl E. Peterson (http://vb.mvps.org/articles/ap199902.pdf)
    ' Purpose   : To discover the hWnd of the foreground task window (window with a caption)
    ' Returns   : 1 to continue searching windows in the task list
    '             0 to stop searching windows
    ' Issues    : Will be incorrect if the actual foreground task window has no caption
    '---------------------------------------------------------------------------------------
   
    Dim strWindowText As String ' Window Caption
    Dim r As Long   ' API return value
    Dim lngContinue As Long: lngContinue = 1    ' 1 = search for next window, 0 = stop searching
    Dim lngThread1 As Long  ' For comparing the hWnd thread to the lParam thread
    Dim lngThread2 As Long  ' If they are the same, the we can assume our window
                            ' is the foreground task window
    '
    ' Make sure we meet visibility requirements.
    '
    If IsWindowVisible(hWnd) Then
        '
        ' It shouldn't have any parent window, either.
        '
        If GetParent(hWnd) = 0 Then
            '
            ' And, finally, it shouldn't have an owner.
            '
            If GetWindowLong(hWnd, GWL_HWNDPARENT) = 0 Then
                '
                ' Retrieve windowtext (caption)
                ' We do this, because we are looking for the first
                ' window with a caption. This *should* be the topmost task window

                strWindowText = Space$(256)
                r = GetWindowText(hWnd, strWindowText, Len(strWindowText))
                If r Then
                    ' There was a window caption, so this is (hopefully) a task window
                    ' This will cause problems if the actual foreground task window
                    ' does not have a caption...Ideas?

                    ' Get the ThreadIDs of the hWnd and lParam, to see if they are the same
                    lngThread1 = GetWindowThreadProcessId(hWnd, ByVal 0&)
                    lngThread2 = GetWindowThreadProcessId(lParam, ByVal 0&)

                    If lngThread1 = lngThread2 Then
                        ' The threads are the same, so our window is the foreground window
                        mlngForegroundTaskHwnd = lParam
                    Else
                        ' The threads are different, so the foreground window is NOT our window
                        mlngForegroundTaskHwnd = hWnd
                    End If
                    lngContinue = 0    ' If we have gone this far, we should stop searching
                    ' because we are either the foreground task window or not
                    ' at this point
                End If

            End If
        End If
    End If
    EnumWindowsProc = lngContinue  ' Return 1 to keep looking for a window, otherwise 0 if we are done
End Function

Public Function ForceForegroundWindow(ByVal hWnd As Long) As Boolean
    '---------------------------------------------------------------------------------------
    ' Procedure : ForceForegroundWindow
    ' Created   : January 21, 2008
    ' Author    : Karl E. Peterson (http://vb.mvps.org/articles/ap199902.pdf) with minor
    '             style modifications by Jason Peter Brown (jbrown@statslog.com)
    ' Purpose   : To push a window to the foreground under all known circumstances
    ' Returns   : True on success, False on failure
    '---------------------------------------------------------------------------------------
    Dim lngThread1 As Long
    Dim lngThread2 As Long
    Dim r As Long
    Dim strClass As String
    '
    ' Nothing to do if already in foreground.
    '
    If hWnd = GetForegroundWindow() Then
        ForceForegroundWindow = True
    Else
        ' VB4/32, VB5, VB6 Push Your Way to the Front
        ' First need to get the thread responsible for
        ' the foreground window, then the thread running
        ' the passed window.
        '
        lngThread1 = GetWindowThreadProcessId(GetForegroundWindow, ByVal 0&)
        lngThread2 = GetWindowThreadProcessId(hWnd, ByVal 0&)
        '
        ' By sharing input state, threads share their
        ' concept of the active window.
        '
        If lngThread1 <> lngThread2 Then
            Call AttachThreadInput(lngThread1, lngThread2, True)
            r = SetForegroundWindow(hWnd)
            Call AttachThreadInput(lngThread1, lngThread2, False)
        Else
            r = SetForegroundWindow(hWnd)
        End If
        '
        ' Restore and repaint
        '
        If IsIconic(hWnd) Then
            Call ShowWindow(hWnd, SW_RESTORE)
        Else
            Call ShowWindow(hWnd, SW_SHOW)
        End If
        '
        ' SetForegroundWindow return accurately reflects
        ' success.
        ForceForegroundWindow = CBool(r)
    End If
End Function

Then, in your form:

Private Sub TrayIcon1_Click()
    On Error Resume Next

    If mblnMinimized Then
        ' We are minimized to the tray
        Me.TrayIcon1.MaximizeFromTray Me.hWnd   ' Restore
        Me.WindowState = vbMaximized    ' Maximize
        mblnMinimized = False   ' Clear the minimized flag
    Else
        ' We are *not* minimized to the tray
        If IsForegroundTaskWindow(Me.hWnd) Then
            ' Our window is most likely the foreground task window,
            Me.TrayIcon1.MinimizeToTray Me.hWnd ' so minimize it to the tray
            mblnMinimized = True    ' Flag that we are indeed minimized to the tray
        Else
            ' Our window is most likely not the foreground task window
            ForceForegroundWindow Me.hWnd   ' So bring our window to the front
        End If
    End If
End Sub


Private Sub Form_Resize()
    On Error Resume Next

    If Me.WindowState = vbMinimized Then
        Call TrayIcon1_Click
    End If
End Sub

For the record, I also set the ShowInTaskbar property to False for my window. This allows it to only appear in the system tray. Hope this helps someone (and thanks for your help JKDev)!
Back to Top
 Post Reply Post Reply
  Share Topic   

Forum Jump Forum Permissions View Drop Down

Forum Software by Web Wiz Forums® version 12.04
Copyright ©2001-2021 Web Wiz Ltd.

This page was generated in 0.188 seconds.