-
November 14th, 2006, 06:10 PM
#1
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
-
November 14th, 2006, 06:46 PM
#2
Re: How to make a form ALWAYS ON TOP!
No workie in 2005, generates a cross-thread error.
-
November 14th, 2006, 07:25 PM
#3
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.
-
November 14th, 2006, 08:18 PM
#4
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.
-
November 14th, 2006, 08:35 PM
#5
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
-
November 15th, 2006, 05:43 AM
#6
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
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|