Results 1 to 7 of 7

Thread: Window always on bottom

  1. #1

    Thread Starter
    Fanatic Member
    Join Date
    Jun 1999
    Location
    California, USA
    Posts
    662
    I am writing a windows shell and i am looking for a way to keep a window behind all open windows (even when it is active)

    Currently, i am subclassing the wm_activateapp message and using setwindowpos to move the window to the bottom, but this is not as smooth as i want it to be.

    I'm just wondering how windows explorer does it so i can finish my shell.

    I've looked through the MSDN Win32 SDK looking for a window style that does this. I've looked for flags for setwindowpos. I've also looked for a windows message. No luck what-so-ever.

    The subclass method is the only thing i can think of, but it still remains in front of explorer, so i know that the subclassing method is not the same method that explorer uses.

  2. #2
    Fanatic Member crispin's Avatar
    Join Date
    Aug 2000
    Location
    2 clicks west of a Quirkafleeg...Cornwall, England
    Posts
    754
    try this:
    Code:
    Const HWND_BOTTOM = 1
    Const SWP_NOSIZE = &H1
    Const SWP_NOMOVE = &H2
    
    
    i = SetWindowPos(hwnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOSIZE Or SWP_NOMOVE)
    Crispin
    VB6 ENT SP5
    VB.NET
    W2K ADV SVR SP3
    WWW.BLOCKSOFT.CO.UK

    [Microsoft Basic: 1976-2001, RIP]

  3. #3

    Thread Starter
    Fanatic Member
    Join Date
    Jun 1999
    Location
    California, USA
    Posts
    662
    that will work until the window is activated. I need the window to stay at the bottom even when it's activated

  4. #4
    Fanatic Member PsychoMark's Avatar
    Join Date
    Feb 2001
    Location
    Netherlands
    Posts
    540

    Got it!

    I found a solution, but it has two small problems:

    - You can only use it on a borderless form
    - The desktop refreshes if it's activated

    But if you're making a shell, those shouldn't be a problem, since there's no such thing as a desktop


    The solution was simple, I subclassed the WM_ACTIVATE as you already did, and noticed that when you use a border, it can still come to the top if you hold the button on the titlebar, so I set BorderStyle to None and it worked. The only problem was that it showed the form being on top of the others for a few milliseconds and then went back.

    The subclassing was done using the vbAccelerator subclassing component, so I don't know exactly how it's done otherwise. But basically, I consumed the WM_ACTIVATE message (ISubclass_MsgResponse = emrConsume, if you use the vbAccelerator component) and used the following code in the WindowProc event:

    Code:
    Call LockWindowUpdate(Me.hwnd)
    Call SetWindowPos(hwnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOSIZE Or SWP_NOMOVE)
    Call LockWindowUpdate(0)
    This worked great, even the controls on the form can still be used normally. The only real problem was that the desktop refreshed because of the LockWindowUpdate...

    Good luck!
    Teaudirenopossum.Musasapientumfixaestinaure.
    (I can't hear you. There's a banana in my ear)

  5. #5

    Thread Starter
    Fanatic Member
    Join Date
    Jun 1999
    Location
    California, USA
    Posts
    662

    Re: Window always on bottom

    Wow, it only took me 10 year to solve this one proper...

    Subclass the WM_WINDOWPOSCHANGING message. The lParam is a WINDOWPOS. In vb6, you need to use RtlMoveMemory api function to copy the lParam to an empty WINDOWPOS variable.

    Set the hWndInsertAfter field to HWND_BOTTOM and copy the structure back to the lParam.

    In .Net (where I solved this problem), override the wndproc method. Look for the WINDOWPOSCHANGING message.

    vb Code:
    1. Dim memloc As IntPtr = m.LParam
    2. Dim pos As WINDOWPOS = m.GetLParam(GetType(WINDOWPOS))
    3.  
    4. pos.hWndInsertAfter = HWND_BOTTOM
    5.  
    6. Marshal.StructureToPtr(pos, memloc, True)

  6. #6
    Frenzied Member
    Join Date
    Dec 2008
    Location
    Melbourne Australia
    Posts
    1,487

    Re: Window always on bottom

    Quote Originally Posted by agent View Post
    Wow, it only took me 10 year to solve this one proper...

    Subclass the WM_WINDOWPOSCHANGING message. The lParam is a WINDOWPOS. In vb6, you need to use RtlMoveMemory api function to copy the lParam to an empty WINDOWPOS variable.

    Set the hWndInsertAfter field to HWND_BOTTOM and copy the structure back to the lParam.

    In .Net (where I solved this problem), override the wndproc method. Look for the WINDOWPOSCHANGING message.

    vb Code:
    1. Dim memloc As IntPtr = m.LParam
    2. Dim pos As WINDOWPOS = m.GetLParam(GetType(WINDOWPOS))
    3.  
    4. pos.hWndInsertAfter = HWND_BOTTOM
    5.  
    6. Marshal.StructureToPtr(pos, memloc, True)
    Could you (or any Good Samaritan) attach a small (but working) VB6 example project ?

    Thanks,
    Rob

    PS I wouldn't know a windows shell if I found it on the beach. All I am looking for is a normal VB6 program running in a normal Windows (XP) that will allow my project's Form (or whatever display) always be on the bottom. It would show in front of the normal Windows desktop, but would never be in front of other running applications.
    Last edited by Bobbles; Dec 23rd, 2012 at 06:16 AM. Reason: clarification

  7. #7
    Default Member Bonnie West's Avatar
    Join Date
    Jun 2012
    Location
    InIDE
    Posts
    4,060

    Re: Window always on bottom

    Code:
    'In a BAS module
    Option Explicit
    
    Private Const GWL_WNDPROC          As Long = (-4&)   'Sets a new address for the window procedure.
    Private Const HWND_BOTTOM          As Long = 1       'Places the window at the bottom of the Z order.
    Private Const WM_DESTROY           As Long = &H2     'Sent when a window is being destroyed.
    Private Const WM_WINDOWPOSCHANGING As Long = &H46    'Sent to a window whose size, position, or place in the Z order is about to change as a result of a call to the SetWindowPos function or another window-management function.
    
    Private Declare Function CallWindowProc Lib "user32.dll" Alias "CallWindowProcW" (ByVal lpPrevWndFunc As Long, ByVal hWnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
    Private Declare Function SetWindowLong Lib "user32.dll" Alias "SetWindowLongW" (ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
    Private Declare Sub PutMem4 Lib "msvbvm60.dll" (ByVal Ptr As Long, ByVal Value As Long)
    
    Private m_PrevWndFunc As Long
    
    'In Form_Load(), call it like: Subclass hWnd
    Public Function Subclass(ByVal hWnd As Long) As Boolean
        m_PrevWndFunc = SetWindowLong(hWnd, GWL_WNDPROC, AddressOf WindowProc)
        Subclass = m_PrevWndFunc <> 0&
    End Function
    
    Private Function WindowProc(ByVal hWnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
        Select Case uMsg
            Case WM_WINDOWPOSCHANGING
                PutMem4 lParam + 4&, HWND_BOTTOM                           'hWndInsertAfter
                Exit Function                                              'Return zero
    
            Case WM_DESTROY
                uMsg = SetWindowLong(hWnd, GWL_WNDPROC, m_PrevWndFunc):     Debug.Assert uMsg
                uMsg = WM_DESTROY
        End Select
    
        WindowProc = CallWindowProc(m_PrevWndFunc, hWnd, uMsg, wParam, lParam)
    End Function
    The Windows Shell:

    The Windows UI provides users with access to a wide variety of objects necessary for running applications and managing the operating system. The most numerous and familiar of these objects are the folders and files that reside on computer disk drives. There are also a number of virtual objects that allow the user to perform tasks such as sending files to remote printers or accessing the Recycle Bin. The Shell organizes these objects into a hierarchical namespace and provides users and applications with a consistent and efficient way to access and manage objects.
    On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop: Else Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
    Declare Sub CrashVB Lib "msvbvm60" (Optional DontPassMe As Any)

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