|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Visual Basic FAQ SetWindowLong: Create a Floating Window |
||
Posted: | Thursday December 26, 1996 | |
Updated: | Monday December 26, 2011 | |
Applies to: | VB4-32, VB5, VB6, and VB3, VB4-16 with appropriate declarations | |
Related: | SetWindowPos: Create a Topmost Window SetWindowLong: Create a Floating Window Pure VB: Simulating Owned Windows for MDI Children |
Prerequisites |
None. |
|
Another
popular question! This code, like
the SetWindowPos method it the Topmost routine, creates a child form that is topmost to the application. However, unlike
the Topmost method, the form set with this method will not float overtop of other applications. In addition, the floating window
constructed here will minimize and restore automatically with the parent window, making real floating toolbar windows a snap.
But note .. this code changes the parent relationship of forms. Improper use of this API can cause GPF in VB and possibly in Windows. Please see the Comments following the example. During the design stage, you must ensure that on the floating form you have a command button to either end the application correctly, or to unload the floating window. And when using this method, never stop the app using the VB 'Stop' button. * Note: VB6 introduced a change (second parameter) to the Show command that will achieve this same result: frmChild.Show vbModeless, frmMain |
BAS Module Code |
Add the following code to a BAS module: |
|
Option Explicit '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' Copyright ©1996-2011 VBnet/Randy Birch, All Rights Reserved. ' Some pages may also contain other copyrights by the author. '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' Distribution: You can freely use this code in your own ' applications, but you may not reproduce ' or publish this code on any web site, ' online service, or distribute as source ' on any media without express permission. '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' Public Const GWL_HWNDPARENT = (-8) Public Declare Function SetWindowLong Lib "user32" _ Alias "SetWindowLongA"_ (ByVal hwnd As Long, ByVal nIndex As Long, _ ByVal wNewLong As Long) As Long |
Form Code |
In the general declarations area of the floating form (not the parent form!) place all of the following code: |
|
Option Explicit Private OriginalParenthWnd As Long Private Sub Form_Load() OriginalParenthWnd = SetWindowLong(Me.hwnd, _ GWL_HWNDPARENT, _ parent.hwnd) End Sub Private Sub Form_Unload() 'Restore the original parent before unloading Call SetWindowLong(Me.hwnd, GWL_HWNDPARENT, OriginalParenthWnd) End Sub Private Sub Command1_Click() 'force the Unload sub to execute to end, 'preventing a crash Unload Me 'In addition, make sure that the parent form 'implicitly unloads the floating form before it 'unloads itself. End Sub |
Comments |
The code above creates a window which appears (while the application has focus) as a topmost window, but which will 'follow'
the parent window if it is minimized or restored, or fall behind any other app that is brought to the top (gains focus). This
is similar to the behaviour of the property and tool windows in the SDI-style VB design environments, and many other popular
programs like PageMaker and PhotoShop.
Unlike a simple topmost window (see SetWindowPos: SetWindowPos: Create a Topmost Window) the SetWindowLong API actually changes the window parent/child relationship via the API call. Because of this, should the application be terminated by closing or ending the application with the VB toolbar Stop button, or the parent form's window close command (or pressing the X), the floating windows Unload sub will not execute. Since the window relationship was changed during execution (via the API call), and was not reset on ending, a VB GPF will occur, causing VB to crash. It is therefore imperative that you:
A window which has been made 'floating' with the above code does not require to be set to topmost as well .. the above takes care of that as well. Once the application has been developed, you may want to remove the 'unload' or 'end' command button from the floating form, and use either the normal File/Exit method of ending your application, or do so through some other command or code sequence. To ensure that I don't cause a GPF, my personal practice has been to declare a global (public) variable in a bas module as a 'loaded' flag, and set this to true on the load of the floating form. Then, when the application ends, in the main form's unload sub I check to see if this variable is still true. If it is, I call the floating form's unload routine by issuing an Unload command, assuring that the unload sub has fired. In the floating form's unload sub, after the API, I set the flag variable to false. The app can then be ended safely. Note that under 16-bit Windows, the name of the API is SetWindowWord, not SetWindowLong. The name was changed for the 32-bit operating systems (Win95/98/NT4) to properly reflect the data being altered (a 4 byte Long in a 32-bit OS vs. a 16 bit Word in a 16-bit OS). |
|
|
|
|||||
|
|||||
|
|||||
Copyright ©1996-2011 VBnet and Randy Birch. All Rights Reserved. |