Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations TouchToneTommy on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Making a form "always on top" / form persistence 1

Status
Not open for further replies.

stevemelaaron

Programmer
Sep 14, 2000
25
US
I think that I may have a solution to the "always on top" dilemma. You must set up a "sentinel" that checks to see which form is currently on top, and if the desired form is not, then set it to be so. First, set up these three WinAPI functions and global constants (the constants are for the SetWindowPos function):


Declare Function GetTopWindow Lib "user32" (ByVal hwnd As Long) As Long

Declare Function GetDesktopWindow Lib "user32" () As Long

Declare Function SetWindowPos Lib "user32" (ByVal hwnd As Long, ByVal hWndInsertAfter As Long, ByVal x As Long, ByVal y As Long, ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long) As Long

Global Const SWP_NOSIZE = &H1
Global Const SWP_NOMOVE = &H2
Global Const SWP_NOACTIVATE = &H10
Global Const SWP_NOOWNERZORDER = &H200
Global Const HWND_TOPMOST = -1
Global Const HWND_NOTOPMOST = -2

Global Const FLAGS = SWP_NOOWNERZORDER Or SWP_NOACTIVATE Or SWP_NOMOVE Or SWP_NOSIZE


Next, insert this code in the appropriate area of the program (probably in the Form_Activate event, though you could associate it with a command button click or a menu option):


' Set up variable to handle return value from SetWindowPos API call
Dim SetWindowPosReturn as Long

' Call SetWindowPos to set Form1 as topmost window on screen
SetWindowPosReturn =
SetWindowPos Form1.hwnd,HWND_TOPMOST,0,0,0,0,FLAGS)


Now, set up a timer with a reasonably short interval on your form, say 1000 msec or so, and plug this code into it's event procedure:


' Set up variables to handle return values from API calls
Dim GetDesktopWindowReturn as Long
Dim GetTopWindowReturn as Long

' Get handle to desktop
GetDesktopWindowReturn = GetDesktopWindow

' Get handle to topmost window on desktop
GetTopWindowReturn = GetTopWindow(GetDesktopWindowReturn)

' Check to see if the handle from the topmost window
' matches the handle of Form1 - if not, call
' SetWindowPos to put it back on top
If Form1.hwnd<>GetTopWindowReturn Then
SetWindowPosReturn = SetWindowPos
Form1.hwnd,HWND_TOPMOST,0,0,0,0,FLAGS)
End If


I've tested this a few different ways, and it works just fine, albeit at the expense of firing a timer event every second or so. [sig][/sig]
 
That seems a bit complicated. Haven't you had any luck using SetWindowPos in the form Resize event? It wouldn't prevent a new window with the TopMost attribute from covering your app's window but, surely, there must be an easier way to remain on top without the use of a timer.

Scratching my head....
[sig]<p> <br><a href=mailto: > </a><br><a href= plain black box</a><br>Don't sit down. It's time to dig another one.[/sig]
 
the SetWindowPos has always worked for me, being a single line command, never had to use a timer, and it always worked for me. [sig]<p>Karl<br><a href=mailto:kb244@kb244.com>kb244@kb244.com</a><br><a href= </a><br>Experienced in : C++(both VC++ and Borland),VB1(dos) thru VB6, Delphi 3 pro, HTML, Visual InterDev 6(ASP(WebProgramming/Vbscript)<br>
[/sig]
 
The one difficulty that I ran into when attempting to maintain topmost status using SetWindowPos was when I would minimize then restore a window that was originally under the form. When the window was restored, the form lost its' topmost status, even when calling SetWindowPos from the form's resize event. The only way I could come up with to solve this problem was to query the desktop with GetTopWindow and re-call SetWindowPos if the form was no longer topmost. Granted, in most cases placing SetWindowPos in the form's resize event (as well as in the activate event) will &quot;fill the bill&quot; for maintaining a form's persistance, but for my purposes, I needed to make absolutely certain that the form would stay on top. [sig][/sig]
 
Well, this lot always works for me...
Code:
Public Declare Function SetWindowPos Lib &quot;user32&quot; _
                    (ByVal hwnd As Long, ByVal hWndInsertAfter As WndInsertAfterEnum, _
                    ByVal x As Long, ByVal y As Long, ByVal cx As Long, _
                    ByVal cy As Long, ByVal wFlags As SetWindowPosFlagsEnum) As Long

Public Enum WndInsertAfterEnum
    HWND_BOTTOM = 1
    HWND_BROADCAST = &HFFFF&
    HWND_DESKTOP = 0
    HWND_NOTOPMOST = -2
    HWND_TOP = 0
    HWND_TOPMOST = -1
End Enum

Public Enum SetWindowPosFlagsEnum
    SWP_FRAMECHANGED = &H20
    SWP_DRAWFRAME = SWP_FRAMECHANGED
    SWP_HIDEWINDOW = &H80
    SWP_NOACTIVATE = &H10
    SWP_NOCOPYBITS = &H100
    SWP_NOMOVE = &H2
    SWP_NOOWNERZORDER = &H200
    SWP_NOREDRAW = &H8
    SWP_NOREPOSITION = SWP_NOOWNERZORDER
    SWP_NOSIZE = &H1
    SWP_NOZORDER = &H4
    SWP_SHOWWINDOW = &H40
End Enum

Then, to get a form to stay on top...
Code:
SetWindowPos form.hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE Or SWP_NOMOVE

and to stop a form from being always on top...
Code:
SetWindowPos form.hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE Or SWP_NOMOVE

In my experience a single call to SetWindowPos is all that's needed.
[sig]<p> Jonathan<br><a href=mailto:j.w.george@virginnet.co.uk>j.w.george@virginnet.co.uk</a><br><a href= > </a><br>Working against: Visual Basic 6, Access 97, Visual Interdev 6, VBScript, Active Server Pages, SQL Server 6.5, Oracle 7[/sig]
 
Jonathan-

Thanks for the reply! Unfortunately, when I tried your code, I got the same result as I mentioned in my previous post - the form remains topmost until you minimize then restore a window/form under it. At that point, the restored window becomes topmost.
[sig][/sig]
 
Now I remember...... Call it in the form activate event as well. [sig]<p>Mike<br><a href=mailto:michael.j.lacey@ntlworld.com>michael.j.lacey@ntlworld.com</a><br><a href= Cargill's Corporate Web Site</a><br>[/sig]
 
That's quite strange, I've tried but I can't seem to duplicate the behaviour you mention. How exactly do you make it happen?

I've only recently started using the API - I was attracted to it by the whole host of new and exciting ways to crash, hang and otherwise stuff up my computer :)

Cheers
[sig]<p> Jonathan<br><a href=mailto:j.w.george@virginnet.co.uk>j.w.george@virginnet.co.uk</a><br><a href= > </a><br>Working against: Visual Basic 6, Access 97, Visual Interdev 6, VBScript, Active Server Pages, SQL Server 6.5, Oracle 7[/sig]
 
Thanks so much! I was looking for some code to do this. You are my hero! :) Remove &quot;nospam&quot; from my email address to reply.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top