Help with GetWindowRect()

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • HaLo2FrEeEk
    Contributor
    • Feb 2007
    • 404

    Help with GetWindowRect()

    I'm working on a program that needs to check the bounding rectangle of external application windows. I've found multiple API methods that do just that, GetWindowRect() , GetWindowPlacem ent(), and GetWindowInfo() to name a few. For the most part they works very well. I pass a MainWindowHandl e to the method and they returns some information about the window. I'm gonna explain what each of the methods return, so if you want to skip it, scroll til you see MY QUESTION in bold.

    GetWindowRect() returns a RECT object, not to be confused with a Rectangle. RECT contains the top, left, right, and bottom coordinates instead of top, left, width, and height. (I know that Rectangle does contain right and bottom, but it returns width and height instead)

    GetWindowPlacem ent() returns a WINDOWPLACEMENT object, which contains a bit more information including flags to determine if the window is maximized, minimized, or normal and what state to restore it to. It also contains a RECT that tells what the window's normal position is, that is, the size and location of the window when it is returned to it's normal (not maximized or minimized) state.

    Finally, GetWindowInfo() returns a WINDOWINFO object. This contains the most information yet. It still has a RECT object containing the size and location of the window, but it also has another RECT with the size and location of the client area of the window. There's also two values that hold the size of the window's borders.

    MY QUESTION

    Ok, sorry for that, I wanted to make sure you were familiar with what I'm working with.

    Here's my issue, when a window is maximized it's borders are not visible, but all of the methods that return a window rectangle still appear to take those into account. I have two monitors each with a resolution of 1920x1200, for a total of 3840x1200, set up in dual screen. When I maximize a window in the left monitor and get it's RECT I get this (assuming no task bar):

    {Left=-8,Top=-8,Right=1928,Bo ttom=1208}

    I should get:

    {Left=0,Top=0,R ight=1920,Botto m=1200}

    Now it's simple enough to detect if the values of Left and Top are negative and invert and subtract them from the right and bottom. But what if I have a window maximized in the right monitor? In that case I get this RECT (again assuming no task bar):

    {Left=1912,Top=-8,Right=3848,Bo ttom=1208}

    I should get:

    {Left=1920,Top= 0,Right=3840,Bo ttom=1200}

    In this case the "-8" pixels are actually part of the left monitor, so they don't read as negative, though they are outside of that screen's bounds.

    I'm at a complete loss as to how I could detect and fix this problem, so I'm hoping that some of the smart helpful people here could...well, help me out.

    Thank you in advance, and I apologize for the length of the post, I just thought thorough explanation would help me get the answer I need.
  • GaryTexmo
    Recognized Expert Top Contributor
    • Jul 2009
    • 1501

    #2
    As I understand it, this only happens when a window is maximized... is there a way to tell if this is the case?

    The problem with what you're doing now is a negative top-left corner of a window is actually valid, even if the window isn't maximized. It's easy enough to do, just grab the lower right part of the title bar for any window and drag it up and to the right.

    Now, C# itself has flags to tell whether or not a window is maximized or minimized, but I don't know if this exists in the Windows API or not. A quick google search turned up this...



    If that doesn't work, take a look around (or maybe someone else here will know).

    If there's no way to tell if the window is maximized, I guess you can do a few tricks. What you're already doing could be expanded a bit, something like...

    Code:
    Rectangle window = GetWindowDimensions();
    Rectangle screenRect = GetScreenDimensions();
    int numScreensWide = GetNumberOfScreensWide();
    int numScreensHight = GetNumberOfScreensHigh();
    
    if (window.Width > screenRect.Width / numScreensWide &&
        window.Height > screenRect.Height / numScreensHigh &&
       ( /* any windows top-left corner is around the top-left corner of any of the screens */))
    {
      // window is "likely" maximized
    }
    I'd look into detecting if the window was maximized first, 'cause with the math stuff I'm pretty sure you could fake it out. Probably a rare case, but still.

    Comment

    • HaLo2FrEeEk
      Contributor
      • Feb 2007
      • 404

      #3
      I got it. WINDOWPLACEMENT 's showCmd holds information about the window's show state. A show state of 3 is maximized, so what I ended up doing is passing the border width and height and the showCmd to my ToRectangle() method (inside the RECT struct.) If the showCmd is 3 then I add the borders to the top and left and subtract it from the right and bottom. That gives me the correct window size every time. I have to call GetWindowPlacem ent anyway because I need to restore the window to a visible show state if it isn't currently in one, then bring it to the front of the z-order. Basically I just check if the showCmd is 2 (minimized) and then I check the flags. A 2 flag means that the window was maximized before it was minimized, a 0 flag means that it was normal before it was minimized.

      In doing all this, I also learned how I can move and resize other windows using SetWindowPlacem ent, which is another thing I needed to know.

      Thanks for the reply though, I was about to resort to checking screen dimensions :/

      One other problem I'm having, if I might (it's related.) the process explorer.exe technically always has a visible window: the task bar. If I open up an explorer window though (the C drive, for example,) GetWindowRect doesn't return the proper rectangle for that window, it returns the taskbar. I can't figure out how to get explorer windows to give off their own coordinates. Maybe I'll just have to live without that, but I'd really like to be able to "see" explorer windows like I can with other windows.

      Comment

      • GaryTexmo
        Recognized Expert Top Contributor
        • Jul 2009
        • 1501

        #4
        How does your app differentiate between two windows in the same program? Like, if I made a C# app that launched two windows under the same executable name, "blah.exe" does it find both, or only one of them?

        Is that the same problem you're having with explorer, or somewhat different?

        Comment

        • HaLo2FrEeEk
          Contributor
          • Feb 2007
          • 404

          #5
          Hmmm...good point. Child windows are not detected, only parent windows. For example, I opened a program that I wrote that has a main control form and a secondary, child form. Only the main control form was detected. That's probably the issue I'm having with Explorer.exe, the main window is the taskbar, all other windows (like the C drive or a folder) are children of the taskbar.

          Damn, I guess I'll have to detect whether or not a window has any children windows. Crap. I don't know how to do that.

          Comment

          • GaryTexmo
            Recognized Expert Top Contributor
            • Jul 2009
            • 1501

            #6
            ... yet!


            Kind of a special case problem: I start a process with System.Diagnostics.Process.Start(..) The process opens a splash screen -- this splash screen becomes the main window. The splash screen closes...


            :D

            Comment

            • HaLo2FrEeEk
              Contributor
              • Feb 2007
              • 404

              #7
              You win...forever.

              Thanks. My program is gonna be AWESOME! You might have been the one that helped me with it:

              Own this domain today. We make your shopping experience easy. Friendly and quick customer service.


              Move and resize the rectangle and click the button in the main form to screenshot that portion of the screen. Now you'll be able to drag it over a window and lock it to that window's size and location. I've got some work to do tonight : )

              Now if only I could figure out how to detect when a window is minimized or closed and release the lock...

              Comment

              • GaryTexmo
                Recognized Expert Top Contributor
                • Jul 2009
                • 1501

                #8
                I remember seeing an earlier version of it from another thread. Is the same version as that? So you'll throw the bounds window over any running window and it'll expand/position to encompass it? That's nifty :)

                That window command thing won't help you with that? Maybe when you lock to a window, record the important information. Then stick a timer in there, maybe every second or so, see if that window's state has changed and unlock if so? Just throwing ideas out.

                Comment

                • HaLo2FrEeEk
                  Contributor
                  • Feb 2007
                  • 404

                  #9
                  It's a different version, added a bunch of cool features. Double click the middle to expand full screen, double click any of the handles to expand to that edge or corner of the screen, check a box to hide the screenshot bounds but keep it active (good for taking screenshots of movies.) It'll also detect whether the control form is overlapping the screenshot area and try to move it out of the way, and hide it when you take a screenshot if it still overlaps.

                  And I can detect if a form's show state is changed (minimized), but I don't know how to detect if it's been closed.

                  Comment

                  • GaryTexmo
                    Recognized Expert Top Contributor
                    • Jul 2009
                    • 1501

                    #10
                    I found a few of those (just couldn't remember if it did it before) but not others, cool :D For the double click one, check out the... Screens (?) object in C#, I think you can get the monitor configuration from there. I noticed that if you double click a handle when it's spanning monitors, it still sizes to the first screen. Unless that's' intentional :)

                    If you've got the handle to the window, and it closes, what happens when you try to do something with it? Will it throw an exception, or does it appear to work but just do nothing?

                    Comment

                    • HaLo2FrEeEk
                      Contributor
                      • Feb 2007
                      • 404

                      #11
                      It's intentional, but I'll probably have a user-selectable setting in a future version that will allow you to specify expanding to the current screen or to all screens.

                      And I'm not sure what happens when I try to query the handle of a closed window. The handle shows up as invalid, I'm sure, so I could probably just catch an exception and deal with it.

                      I crashed when I got home last night, so I didn't work on it at all, but I'll try to tonight if I have time. Stay tuned.

                      Comment

                      Working...