Moving other application's windows

Posted on 2003-11-05
Medium Priority
Last Modified: 2010-05-01
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!)?
Question by:TWCMIL
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
LVL 17

Expert Comment

ID: 9694066
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.

Accepted Solution

lmckenzie earned 1200 total points
ID: 9694157
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

Expert Comment

ID: 9694615
    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.


Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!


Author Comment

ID: 9697911
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.
LVL 17

Assisted Solution

zzzzzooc earned 800 total points
ID: 9699336
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

Author Comment

ID: 9699709
The combo of the 2 worked beautifully.

Thanks for all the help... points given for code writers!

Featured Post

New benefit for Premium Members - Upgrade now!

Ready to get started with anonymous questions today? It's easy! Learn more.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction While answering a recent question (http://www.experts-exchange.com/Q_27402310.html) in the VB classic zone, I wrote some VB code in the (Office) VBA environment, rather than fire up my older PC.  I didn't post completely correct code o…
This article describes how to use a set of graphical playing cards to create a Draw Poker game in Excel or VB6.
Get people started with the process of using Access VBA to control Excel using automation, Microsoft Access can control other applications. An example is the ability to programmatically talk to Excel. Using automation, an Access application can laun…
This lesson covers basic error handling code in Microsoft Excel using VBA. This is the first lesson in a 3-part series that uses code to loop through an Excel spreadsheet in VBA and then fix errors, taking advantage of error handling code. This l…
Suggested Courses

762 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question