CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 13 of 13

Hybrid View

  1. #1
    Join Date
    Jun 2004
    Location
    NH
    Posts
    678

    How to make a form ALWAYS ON TOP!

    Code:
        Const HWND_NOTOPMOST As Int32 = -2
        Const HWND_TOPMOST As Int32 = -1
        Const HWND_TOP As Int32 = 0
        Const HWND_BOTTOM As Int32 = 1
        Const SWP_NOSIZE As Int32 = 1
        Private Structure RECT
            Public rLeft, rTop, rRight, rBottom As Int32
        End Structure
        Private Declare Function apiGetTopWindow Lib "user32" Alias "GetTopWindow" (ByVal hWnd As Int32) As Int32
        Private Declare Function apiGetWindowRect Lib "user32" Alias "GetWindowRect" (ByVal hWnd As Int32, ByRef lpRect As RECT) As Boolean
        Private Declare Function apiSetWindowPos Lib "user32" Alias "SetWindowPos" (ByVal hWnd As Int32, ByVal hWndInsertAfter As Int32, ByVal X As Int32, ByVal Y As Int32, ByVal cx As Int32, ByVal cy As Int32, ByVal wFlags As Int32) As Boolean
        Private Declare Function apiLockWindowUpdate Lib "user32" Alias "LockWindowUpdate" (ByVal hWndLock As Int32) As Int32
        Private t As New Threading.Thread(AddressOf KeepOnTop)
        Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            t.Start() '''''''''''''''''''''''''''''Start thread to keep top most status
        End Sub
        Private Sub Form1_Closing(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles MyBase.Closing
            t.Abort() ''''''''''''''''''''''''''''''''Abort keeping the window topmost
        End Sub
        Private Sub KeepOnTop()
            Dim hwnd As Int32, r As New RECT
            Do
                hwnd = Me.Handle.ToInt32
                apiLockWindowUpdate(0)'''''''''''''''''''''''''''Unlock any previous calls
                apiLockWindowUpdate(hwnd) ''''''''''''''''''''Lock the desktop from updating for a moment, so that tooltips dont get stranded
                If apiGetTopWindow(HWND_TOP) <> hwnd Then ''''If the topmost window is not the specified window
                    apiGetWindowRect(hwnd, r) ''''''''''''''''Get rectangular dimensions of the specified window
                    apiSetWindowPos(hwnd, HWND_TOPMOST, r.rLeft, r.rTop, 0, 0, SWP_NOSIZE) 'Set the specified window as the topmost
                    apiLockWindowUpdate(0) '''''''''''''''''''''''Unlock desktop so that it can update itself visually
                End If
                System.Threading.Thread.Sleep(1) '''''''''''''Sleep for the shortest period possible
            Loop
        End Sub
    Last edited by TT(n); January 19th, 2008 at 02:47 AM. Reason: extra description

  2. #2
    Join Date
    Nov 2006
    Posts
    20

    Re: How to make a form ALWAYS ON TOP!

    No workie in 2005, generates a cross-thread error.

  3. #3
    Join Date
    Nov 2006
    Posts
    20

    Re: How to make a form ALWAYS ON TOP!

    This takes care of the cross threading issue, using Delegates. Is this the best way to do this in this example? Aside from using the SetWindowPos API to set the form on top

    Code:
    Public Class Form1
    
        Public Declare Function apiFindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Integer
        Public Declare Function apiGetTopWindow Lib "user32" Alias "GetTopWindow" (ByVal hwnd As Integer) As Integer
        Public Declare Function apiGetDesktopWindow Lib "user32" Alias "GetDesktopWindow" () As Integer
        Dim rTopMost As New System.Threading.Thread(AddressOf ReturnTopMost) 'Declare thread for returning topmost
    
        Delegate Function HandleDelegate() As Int32
        Public hndl As HandleDelegate
    
        Delegate Sub setTopMostDelegate()
        Public setTopMost As setTopMostDelegate
    
        Delegate Sub setRefreshDelegate()
        Public setRefresh As setRefreshDelegate
    
        Delegate Function getTextDelegate() As String
        Public getText As getTextDelegate
    
        Public Sub setTopMostSub()
            Me.TopMost = True
        End Sub
    
        Public Sub setRefreshSub()
            Me.Refresh()
        End Sub
    
        Public Function getHandleFunc() As Int32
            Return Me.Handle.ToInt32
        End Function
    
        Public Function getTextSub() As String
            Return Me.Text.ToString
        End Function
    
        Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            hndl = New HandleDelegate(AddressOf getHandleFunc)
            setTopMost = New setTopMostDelegate(AddressOf setTopMostSub)
            setRefresh = New setRefreshDelegate(AddressOf setRefreshSub)
            getText = New getTextDelegate(AddressOf getTextSub)
    
            rTopMost.Start() 'Start Return Top Most thread.
        End Sub
    
        Private Sub Form1_Closing(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles MyBase.Closing
            rTopMost.Abort() 'Abort TopMost thread if the main form is closed 
        End Sub
    
        Public Sub ReturnTopMost()
    
            Dim iHndl As Int32
    
            iHndl = Me.Invoke(hndl)
    
            Try
                Do
                    System.Threading.Thread.Sleep(1) 'Sleep for a short period
                    If apiGetTopWindow(apiGetDesktopWindow) <> iHndl Then
                        Me.Invoke(setTopMost)
                        Me.Invoke(setRefresh)
                    End If
                    apiFindWindow(vbNullString, Me.Invoke(getText))  'This throws an error if the main window has been terminated.
                Loop
            Catch ex As Exception
                MessageBox.Show(ex.Message)
            End Try
    
        End Sub
    
    End Class
    Last edited by Cutha; November 14th, 2006 at 07:28 PM.

  4. #4
    Join Date
    Jun 2004
    Location
    NH
    Posts
    678

    Re: How to make a form ALWAYS ON TOP!

    Thanks, it looks pretty good!
    I think SetWindowPos, would be better for use with external forms.
    A bit more more work perhaps.

  5. #5
    Join Date
    Jun 2004
    Location
    NH
    Posts
    678

    Re: How to make a form ALWAYS ON TOP!

    OOoops, Cutha you must of looked at the example after I edited it.

    The refresh should be in the loop every time. Sorry.
    Check to make sure it does not consume cycles in an idle state.
    For example Sleep(0), uses a bunch.


    Change the ReturnTopMost sub:
    Code:
       Public Sub ReturnTopMost()
    
            Dim iHndl As Int32
    
            iHndl = Me.Invoke(hndl)
    
            Try
                Do
                    System.Threading.Thread.Sleep(1) 'Sleep for a short period
                    If apiGetTopWindow(apiGetDesktopWindow) <> iHndl Then
                        Me.Invoke(setTopMost)
                    End If
                        Me.Invoke(setRefresh)
                    apiFindWindow(vbNullString, Me.Invoke(getText))  'This throws an error if the main window has been terminated.
                Loop
            Catch ex As Exception
                MessageBox.Show(ex.Message)
            End Try
    
        End Sub

  6. #6
    Join Date
    Feb 2005
    Location
    Israel
    Posts
    1,475

    Re: How to make a form ALWAYS ON TOP!

    You did it right by using Invoke.

    I just have a non-relevant comment that I couldn't stop myself from writing: Don't use On Error GoTo. This is VB6 syntax. Never use GoTo and Labels. Use exceptions instead (Try...Catch)

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured