none
Win32 API: unable to retrieve controls sizing and position info RRS feed

  • Question

  • I want to get those controls (textbox, label, dropdownlist etc) in a window.

    using GetWindowPlacement(), the size is zero.

    using GetWindowRect(), the values are negative, or if i perform calc like to get the width: right - left, or height, they all ends up zero (same values).

    however at 1 time, during debug, i managed to get positive/seems-valid values from it. but i dunno why the result is not consistent, and now i keep getting "weird" values

    I have no problem getting these info from the window/tab

    within the tab, i can get 3 windows, and inner drill yield me all the zero size windows, which suppose to be lots of controls.

     

    • Moved by Leo Liu - MSFT Monday, December 5, 2011 9:44 AM Moved for better support. (From:Visual C# General)
    Friday, December 2, 2011 7:49 AM

All replies

  • ok, i noticed 2 more oddities:

    the window contains many tab, the 1st tab, it seems like able to get more controls info

    the rest of the tab, seems like only can access very few controls info, seems like stop at 1st (child) level

    2ndly, if i open another tab, purposely click/activate those controls within, when i run my program (that fetch all these windows/controls info), it seems that i can get those touched controls info.

    Friday, December 2, 2011 8:00 AM
  • GetWindowPlacement is normally used with top level windows, not with child controls like a textbox.

    GetWindowRect should work, are you sure you're calling it correctly?

    "the rest of the tab, seems like only can access very few controls info, seems like stop at 1st (child) level"

    It's possible for a tab control to create the children of a tab item only when you switch to that tab item.

    Friday, December 2, 2011 8:15 AM
    Moderator
  •         void SetWinSzPos(MyWinInfo mwi)
            {
                WinApi.WINDOWPLACEMENT wp = WinApi.WINDOWPLACEMENT.Default;
    
                bool chk = WinApi.GetWindowPlacement(mwi.Hwnd, ref wp);
                if (chk)
                {
                    mwi.ShowWinCmd = wp.ShowCmd;
                    mwi.WinSize = new System.Windows.Size(wp.NormalPosition.Width, wp.NormalPosition.Height);
                    mwi.Pos = new System.Windows.Point(wp.NormalPosition.X, wp.NormalPosition.Y);
                }
    
                // if the size is zero, try another approach
                if (mwi.WinSize.IsEmpty || ((mwi.WinSize.Width == 0) && (mwi.WinSize.Height == 0)))
                {
                    WinApi.RECT r;
                    chk = WinApi.GetWindowRect(mwi.Hwnd, out r);
                    if (chk)
                    {
                        mwi.WinSize = new System.Windows.Size(r.Right - r.Left, r.Bottom - r.Top);
                        //mwi.WinSize = new System.Windows.Size(r.Right, r.Bottom);
                        if ((mwi.WinSize.Width == 0) && (mwi.WinSize.Height == 0))
                        {
                        }
                        mwi.Pos = new System.Windows.Point(r.Left, r.Top);
                    }
                }
            }
    

    I believe the API are quite straight forward, just pass in the window handle.

    I can get those inner controls through EnumChildWindows(), but when getting their size/pos, they are zero or negative values.

    Friday, December 2, 2011 8:59 AM
  • What's the definition of WinApi.RECT?

    Friday, December 2, 2011 9:27 AM
    Moderator
  •         [StructLayout(LayoutKind.Sequential)]
            internal struct RECT
            {
                private int _Left;
                private int _Top;
                private int _Right;
                private int _Bottom;
    
                public RECT(RECT Rectangle)
                    : this(Rectangle.Left, Rectangle.Top, Rectangle.Right, Rectangle.Bottom)
                {
                }
                public RECT(int Left, int Top, int Right, int Bottom)
                {
                    _Left = Left;
                    _Top = Top;
                    _Right = Right;
                    _Bottom = Bottom;
                }
    
                public int X
                {
                    get { return _Left; }
                    set { _Left = value; }
                }
                public int Y
                {
                    get { return _Top; }
                    set { _Top = value; }
                }
                public int Left
                {
                    get { return _Left; }
                    set { _Left = value; }
                }
                public int Top
                {
                    get { return _Top; }
                    set { _Top = value; }
                }
                public int Right
                {
                    get { return _Right; }
                    set { _Right = value; }
                }
                public int Bottom
                {
                    get { return _Bottom; }
                    set { _Bottom = value; }
                }
                public int Height
                {
                    get { return _Bottom - _Top; }
                    set { _Bottom = value + _Top; }
                }
                public int Width
                {
                    get { return _Right - _Left; }
                    set { _Right = value + _Left; }
                }
                public POINT Location
                {
                    get { return new POINT(Left, Top); }
                    set
                    {
                        _Left = value.X;
                        _Top = value.Y;
                    }
                }
                public SIZE Size
                {
                    get { return new SIZE(Width, Height); }
                    set
                    {
                        _Right = value.cx + _Left;
                        _Bottom = value.cy + _Top;
                    }
                }
    
                public static implicit operator System.Drawing.Rectangle(RECT Rectangle)
                {
                    return new System.Drawing.Rectangle(Rectangle.Left, Rectangle.Top, Rectangle.Width, Rectangle.Height);
                }
                public static implicit operator RECT(System.Drawing.Rectangle Rectangle)
                {
                    return new RECT(Rectangle.Left, Rectangle.Top, Rectangle.Right, Rectangle.Bottom);
                }
                public static bool operator ==(RECT Rectangle1, RECT Rectangle2)
                {
                    return Rectangle1.Equals(Rectangle2);
                }
                public static bool operator !=(RECT Rectangle1, RECT Rectangle2)
                {
                    return !Rectangle1.Equals(Rectangle2);
                }
    
                public override string ToString()
                {
                    return "{Left: " + _Left + "; " + "Top: " + _Top + "; Right: " + _Right + "; Bottom: " + _Bottom + "}";
                }
    
                public override int GetHashCode()
                {
                    return ToString().GetHashCode();
                }
    
                public bool Equals(RECT Rectangle)
                {
                    return Rectangle.Left == _Left && Rectangle.Top == _Top && Rectangle.Right == _Right && Rectangle.Bottom == _Bottom;
                }
    
                public override bool Equals(object Object)
                {
                    if (Object is RECT)
                    {
                        return Equals((RECT)Object);
                    }
                    else if (Object is System.Drawing.Rectangle)
                    {
                        return Equals(new RECT((System.Drawing.Rectangle)Object));
                    }
    
                    return false;
                }
            }
    
    

     

    i took the "long ver" from http://pinvoke.net/default.aspx/Structures.RECT 

    Friday, December 2, 2011 10:06 AM
  • I rerun the code

    now those controls give me size of x:65, y:176, w = h = 0

    almost all (90%) same

    it can't be, as this mean overlapping on same pos

     

    Friday, December 2, 2011 10:11 AM
  • OK, the code looks right. What kind of windows are those anyway? Is the window that contains those child controls visible on screen (that is not minimized, hidden etc.)? Do you have more than one monitor?
    Friday, December 2, 2011 10:17 AM
    Moderator
  • one monitor.

    yes, it's visible.

    i purposely make that intended tab as active item, only then run the program

    the program is compiled from powerbuilder, ver 8 or 9 damn long time ago.

    it's using MDI, i have no problem accessing the child window, just start having to access controls within tab.


    is there other troubleshooting approach? maybe another api to test something?
    • Edited by Kelmen Friday, December 2, 2011 10:43 AM
    Friday, December 2, 2011 10:42 AM
  • Hmm, I did a quick test with EnumChildWindows and GetWindowRect. Everything works fine here, I get negative coordinates only for some minimized/hidden windows and for windows that are on the other monitor.

    There's a possibility that PowerBuilder does something weird with child controls, like creating a 0 sized textbox for keyboard input purposes and drawing the textbox itself.

    You could use Spy++ (see Visual Studio's tools menu) too get a better view of what child windows exist and their size/position.

    As an alternative API you can try UI Automation: http://msdn.microsoft.com/en-us/library/ms752331.aspx

    Friday, December 2, 2011 11:16 AM
    Moderator
  • In my opinion, we can use reflection to get controls of a Form object, and then use Invokemembers to get properties of a control. You can see the code project:

    http://www.codeproject.com/KB/vista/GetControlProperties.aspx

    It doesn't use any Win APIs, use Reflections.

    Have a nice day.


    Paul Zhou [MSFT]
    MSDN Community Support | Feedback to us
    Tuesday, December 6, 2011 8:35 AM
  • it's not a .net app.
    Wednesday, December 7, 2011 2:25 AM
  • Is it possible caused by tabs?

    For different tabs, create child controls of the same size at the same location. So you get the same size and position.


    Paul Zhou [MSFT]
    MSDN Community Support | Feedback to us
    Wednesday, December 7, 2011 7:47 AM
  • i tried the windows ui automation.

    i can only get the child up to something with button(s) and thumb level, definitely not the childs controls.

    then i installed win 7 sdk, tried the inspect object, tried both msaa and ui automation, cannot get to show me all the controls level, or maybe the tool is limited to window object only.

     

    i also combined my codes using win api and ui automation.

    as using win api, i can detect those controls, but with invalid sizing info, then i tried using ui automation, but give me no different results.

    seems like at least win api can worked up to the controls level.

    maybe the app/powerbuilder using their own mechanism to render/build control.

     

    i'm giving this project a halt, it just getting me no where.

    thx for all the feedbacks.


    • Edited by Kelmen Tuesday, December 13, 2011 9:32 AM
    Tuesday, December 13, 2011 9:29 AM