Moving other application's windows

I have an application that's a Shell App bar that runs at the top of the screen.

We have a poorly written app that we use for our customer database... problem is, this application slowly moves upwards in increments at screen resolutions of 1024x768 or higher for some reason. Eventually, it works its way underneath my app bar.

So, I want my app bar to "bump" windows down X pixels if they take over (or under technically) its space. I'll probably fire it when a user moves their mouse over my App Bar or even clicks it; I think I'd need to scan for all open windows, and if their window hwnd is within the top X pixels, bump them down Y pixels...

Here's the abstract code of what I'm trying to do:

Sub MoveWindowsAtTheTop()
    For Each Window that's not maximized
        If The Top Position of the Window is within X pixels of the top of the screen Then
            Move this window down Y pixels
        End If
End Sub

I'm no API expert and I can't get past Enumerating Unmaximized, open windows. I would think I would need to use EnumWindows ; IsWindowVisible() ; GetWindowText ; GetWindowRect ; ClientToScreen ; ScreenToClient ; MoveWindow ; SetWindowPos.

Can anyone convert this to real, working VB6 code (NOT using .NET!)?
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

When you create an AppBar, the desktop "space" is reserved so nothing can get in the way. You need to set the window position (SetWindowPos) of your AppBar window to z-order top so nothing is able to go above the window.

>> this application slowly moves upwards in increments at screen resolutions of 1024x768 or higher for some reason

I suggest you resolve that issue instead of looking for a solution such as what you asked for. If you'd still like an example of enumerating through all maximized windows, I can come up with something.
I'm no API expert by any means either but I tried this and it seems to work on my system.  Assuming you have a list of window handles, pass each one to the MoveUnderlappedWindow function.  If the top of the window is less than the limit you set, it will be moved by the amount you specify in lngOffset.  If it's only the DB app's window that causes problems, use the FindWindow api call to get it's handle rather than enumerating all of them.  You could also use the GetWindowRect on your own appiication's window to get it's bottom position and use that instead of the top of screen offset

Option Explicit

Private Type RECT
    Left As Long
    Top As Long
    Right As Long
    Bottom As Long
End Type

Private Declare Function GetWindowRect Lib "user32" (ByVal hwnd As Long, lpRect As RECT) As Long
Private Declare Function MoveWindow Lib "user32" (ByVal hwnd As Long, ByVal X As Long, ByVal Y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal bRepaint As Long) As Long
Private Declare Function IsZoomed Lib "user32" (ByVal hwnd As Long) As Long

Private Function MoveUnderlappedWindow(lngHandle as long)

Dim lngHandle As Long
Dim AppRect As RECT
Dim lngTop As Long
Dim lngHeight As Long
Dim lngLeft As Long
Dim lngWidth As Long
Dim lngResult As Long
Dim lngOffset As Long
Dim lngUpperLimit as long

lngUpperLimit = 'Whatever position you want to keep windows below
lngOffset = 10 'Choose how far below you want to move them

    If CBool(IsZoomed(lngHandle)) = vbFalse Then 'Window not maximized
        lngResult = GetWindowRect(lngHandle, AppRect) 'Get the window's position
        lngHeight = AppRect.Bottom - AppRect.Top
        lngWidth = AppRect.Right - AppRect.Left
        lngLeft = AppRect.Left
        lngTop = AppRect.Top
            If AppRect.Top < lngUpperLimit Then 'Is it underlapped?
                lngTop = lngUpperLimit + lngOffset
                lngResult = MoveWindow(lngHandle, lngLeft, lngTop, lngWidth, lngHeight, True)
            End If
    End If
End Function

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
    If the database app is so "poorly written", you would probably be better off rewriting it in VB.  If the app is encountering such severe problems, how trustworthy is the data being manipulated by it? VB is very string at communicating with databases.

    Just a thought.


Big Business Goals? Which KPIs Will Help You

The most successful MSPs rely on metrics – known as key performance indicators (KPIs) – for making informed decisions that help their businesses thrive, rather than just survive. This eBook provides an overview of the most important KPIs used by top MSPs.

TWCMILAuthor Commented:
Well I've tried this:

I like the philosophy that zzzzzooc has... fix my app instead of messing with others, but from my expiriments, it's not possible to prevent every window from moving above a point on the screen. I did add the SetWindowPos() code but the problem is the application would be under the App Bar, not over it. For some reason the DB application thinks it can go under the App Bar. Quite frankly I can manually drag anything under it... it's just that this DB app strangely moves up all by itself.

I'd love to get rid of this DB application, but it's not feasible... we paid $120K+ for it, and it's a GUI front-end of our AS400, and re-training 700+ employees is just not going to happen.

I think I'll stick with the original request... lmckenzie is on track, but since my Windows API knowledge is pretty much non-existent, I just need the code to get a list of window handles so I can pass it to the function lmckenzie posted above to close & award points.
Something such as the below should work. Just put it together quickly so it might need tweaking.


Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function GetWindow Lib "user32" (ByVal hwnd As Long, ByVal wCmd As Long) As Long

Private Const GW_HWNDNEXT = 2
Private Sub Form_Load()
    Dim ColWindows As New Collection, iLoop As Integer
    Call ListWindows(ColWindows)
    For iLoop = 1 To ColWindows.Count
        Debug.Print ColWindows.Item(iLoop) 'This is the window handle
    Next iLoop
    Set ColWindows = Nothing
End Sub
Private Function ListWindows(ByRef ColWindows As Collection)
    Dim lHandle As Long
    lHandle = FindWindow(vbNullString, vbNullString)
    Do Until lHandle = 0
        ColWindows.Add lHandle
        lHandle = GetWindow(lHandle, GW_HWNDNEXT)
End Function
TWCMILAuthor Commented:
The combo of the 2 worked beautifully.

Thanks for all the help... points given for code writers!
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Visual Basic Classic

From novice to tech pro — start learning today.