Client rectangle coordinates on screen

12,469

Solution 1

Yes, you can do this with the ClientToScreen function:

RECT rc;
GetClientRect(hWnd, &rc); // get client coords
ClientToScreen(hWnd, reinterpret_cast<POINT*>(&rc.left)); // convert top-left
ClientToScreen(hWnd, reinterpret_cast<POINT*>(&rc.right)); // convert bottom-right

What is the "client" rectangle in a browser depends on the browser implementation. You can use Spy++ to discover this for yourself.

Solution 2

To translate a window's client rectangle to screen coordinates, call the MapWindowPoints function. It implements special handling to always return a valid RECT, even when used in scenarios that involve windows with right-to-left layout:

If hWndFrom or hWndTo (or both) are mirrored windows (that is, have WS_EX_LAYOUTRTL extended style) and precisely two points are passed in lpPoints, MapWindowPoints will interpret those two points as a RECT and possibly automatically swap the left and right fields of that rectangle to ensure that left is not greater than right.

Calling ClientToScreen on both points in contrast fails to account for RTL layouts, and can produce an invalid RECT. It fails to adhere to one of the rectangle coordinate invariants:

The coordinate value of a rectangle's right side must be greater than that of its left side. Likewise, the coordinate value of the bottom must be greater than that of the top.

A reliable function to return a window's client rectangle in screen coordinates would look like this:

RECT client_rect_in_screen_space(HWND const hWnd) {
    RECT rc{ 0 };
    if (!::GetClientRect(hWnd, &rc)) {
        auto const err_val{ ::GetLastError() };
        throw std::system_error(err_val, std::system_category());
    }

    ::SetLastError(ERROR_SUCCESS);
    if(::MapWindowPoints(hWnd, nullptr, reinterpret_cast<POINT*>(&rc), 2) == 0) {
        auto const err_val{ ::GetLastError() };
        if (err_val != ERROR_SUCCESS) {
            throw std::system_error(err_val, std::system_category());
        }
    }

    return rc;
}

The question update asks for a different, unrelated issue. There is no API built into the system, that allows you to query a web browser's display area for its HTML content. The most promising solution would be to employ UI Automation. The question, however, is too broad to provide a more detailed answer here.

Solution 3

As commented by Raymond Chen, the preferred way of doing this should be something like the following:

inline POINT get_client_window_position(const HWND window_handle)
{
    RECT rectangle;

    GetClientRect(window_handle, static_cast<LPRECT>(&rectangle));
    MapWindowPoints(window_handle, nullptr, reinterpret_cast<LPPOINT>(& rectangle), 2);

    const POINT coordinates = {rectangle.left, rectangle.top};

    return coordinates;
}
Share:
12,469

Related videos on Youtube

Max Yari
Author by

Max Yari

Hello there! At the moment I'm a freelance fullstack web developer. I usually work with node.js and angular and enjoy getting my hands dirty with new technology. I also like to fiddle around with python and game engines like unity and unreal engine.

Updated on June 04, 2022

Comments

  • Max Yari
    Max Yari almost 2 years

    How can I get coordinates of a window's client area relative to screen?

    I thought about using GetClientRect and ClientToScreen. Also, in a browser window what is ClientRect? Only rectangle with HTML document shown in it, or it includes browser bars and pop-up menus, that can possibly shrink dimension for HTML doc?

    I've tried this:

    HWND hWnd;
    RECT rc;
    if (GetClientRect(hWnd, &rc)) // get client coords 
    {
        MapWindowPoints(hWnd, NULL, reinterpret_cast<POINT*>(&rc), 2); // converts rect rc points
        return rc.top;
    }
    

    But the sad thing is that browser's client rectangle includes all those pop-up browser menus and bars, therefore can't be used to detect accurate coordinates of browsers HTML document space. If anyone got suggestions how it can be done, will try it gladly.

  • Raymond Chen
    Raymond Chen about 11 years
    Note that returns an invalid rectangle on RTL systems. Better is to use MapWindowPoints with a length of 2.
  • Max Yari
    Max Yari about 11 years
    Stack around the variable rc was corrupted, seems you are right, will try MapWindowPoints now
  • AbePralle
    AbePralle over 10 years
    I don't know what an RTL system is, but would declaring and using a separate POINT struct instead of a cast fix that issue? That seems to work fine for me and my purposes.
  • user2120666
    user2120666 about 8 years
    As pointed by Mr. Raymond Chen, this snippet causing problem on RTL systems, so please dont use this.
  • Camille Goudeseune
    Camille Goudeseune about 8 years
    If RTL means right to left, ScreenToClient can have problems (msdn.microsoft.com/en-us/library/windows/desktop/…) but the docs for ClientToScreen don't mention this.
  • IInspectable
    IInspectable about 6 years
    @AbePralle: RTL is short for right-to-left. It refers to text layouts, that are written from right to left, such as Arabic script. Using a separate POINT structure doesn't produce a valid rectangle.
  • Admin
    Admin about 3 years
    why do you call the ClientToScreen two times, one for left and one for right?
  • Jonathan Potter
    Jonathan Potter about 3 years
    @Ivanzinho ClientToScreen works on a POINT (x,y) and a rectangle consists of two POINTs (top-left, bottom-right). But better to use the MapWindowPoints function as suggested by Raymond Chen.
  • Admin
    Admin about 3 years
    @JonathanPotter is this not an ugly design? ClientToScreen would have returned a POINT instead of replacing the input argument with the output result. It's hard to wrap the idea of how it works this way, are they saving some CPU cycles or RAM to chose that unnatural design?
  • Jonathan Potter
    Jonathan Potter about 3 years
    @Ivanzinho This API would probably date back to the mid-1980s. C didn't support returning structs then and I'm guessing the API was designed around that limitation.