Solved

GetWindowRect API from within a control

Posted on 1998-11-19
7
556 Views
Last Modified: 2013-12-25
Here's something which is seemingly correct (I think), but it doesn't work.

I've placed the following inside the control. The purpose is to provide a property get to obtain the screen coordinates of the control itself. Ie, coordinates relative to the screen, and not just the container.

*****
Private Declare Function GetWindowRect Lib "user32" (ByVal hwnd As Long, lpRect As RECT) As Long

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

Dim ControlRect As RECT

Public Property Get X_Left() As Long
    GetWindowRect UserControl.hwnd, ControlRect
    X_Left = ControlRect.Left
End Property

(there are actually 3 other property get for the other 3 values, but it doesn't matter since they are basically the same)

********

The GetWindowRect API is supposed to give the rect in screen coordinates, but it doesn't seem to work if this is inside the code of a control.

At runtime, reading the property actually returns a 0. Effectively, the 4 values of the rect returns, but the top left hand corner is 0,0. I.e. the rect returned is actually (0,0,something,something). The size of the control is returned correctly, but the position is wrong.

I've tried the same code on a form, but changed 'UserControl' to 'Picture1', and placed a dummy picture control, just to try obtaining the coordinates of the pic control. It works correctly in this case.

I know that by calculating the position of the control relative to the form would pretty much do what I want, but it is a requirement that the algorithm be within the control. I must be able to obtain the screen coord by just reading a control property.

That's my problem and it's giving me hard time. Any help will be greatly appreciated.
Thanks a lot in advance.

>>Shak<<
0
Comment
Question by:Shak
7 Comments
 
LVL 1

Expert Comment

by:csalves
Comment Utility
Hi,
I think you can't get values from public Properties
I will give you another simple way of solving your problem.
Put your property Private
create global variables or constantes for x and y.

In your private property
assign to x = form.left + control + left, this gives you the position of control relative to screen.

you can do the same for top.

if you need to know the control area you can do the same using the control width and hight.

bye,



0
 
LVL 2

Expert Comment

by:kswinney
Comment Utility
If you want actual screen coordinates there's more to do than the code that you have.

You'll need to call ClientToScreen to convert the top/left and bottom/right points to screen coordinates.

If you'd like I can provide some sample code.

HTH.
0
 

Author Comment

by:Shak
Comment Utility
This control is to be used by others, and the user of the control should be able to get the values just be reading a property. Making something global would not be advisable

0
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 

Author Comment

by:Shak
Comment Utility
On the comment from kswinney,
I've actually tried out the ClientToScreen API but it doesn't seem to work. This is the new code:

****

Private Declare Function GetWindowRect Lib "user32" (ByVal hwnd As Long, lpRect As RECT) As Long
Private Declare Function ClientToScreen Lib "user32" (ByVal hwnd As Long, lpPoint As POINTAPI) As Long

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

Private Type POINTAPI
        x As Long
        y As Long
End Type

Dim ControlRect As RECT
Dim ControlPnt As POINTAPI

Public Property Get X_Left() As Long
    GetWindowRect UserControl.hwnd, ControlRect
    ControlPnt.x = ControlRect.Left
    ControlPnt.y = ControlRect.Top
    ClientToScreen UserControl.hwnd, ControlPnt
    X_Left = ControlPnt.x
End Property
Public Property Get X_Right() As Long
    GetWindowRect UserControl.hwnd, ControlRect
    ControlPnt.x = ControlRect.Right
    ControlPnt.y = ControlRect.Bottom
    ClientToScreen UserControl.hwnd, ControlPnt
    X_Right = ControlPnt.x
End Property

****

In this case, I'm just reading the x value of the top-left and bottom-right corner. The y value would be similar.

When the container of this control is ran, the value that is returned from the property get is not in screen coordinates. The 1st x value is always 2 (dunno why), while the 2nd x value reflects the size of the control correctly. If I move the form around the screen, the 2 x values remain the same. They should be different since the control is now on a different part of the screen (though still in the same place on the form). Also, if I place the control on a different part on the form, the x values still remain the same. In effect, the result that I'm getting from ClientToScreen is the same as that from GetWindowRect.

Hope to get any kind of assistance.
Thanks a million in advance.

>>Shak<<

0
 
LVL 13

Expert Comment

by:Mirkwood
Comment Utility
take a look at the values of  parent.left/top and extender.left/top and convert these values use clienttoscreen.


0
 

Author Comment

by:Shak
Comment Utility
Thanks to Mirkwood for suggesting,

But in this case, your suggestion won't work because I need my control to be invisible at runtime. Thus, the left/top properties can not be retrieved when the container is running.

More description of what my control should be able to do:
It is basically an invisible control that sits on the container, but the container (may be IE script or VB form) should be able to obtain coordinates of the location of the invisible control at runtime. Therefore, the script or form will be able to determine exactly where the control is on the screen, even if the form or IE has been moved around.

Thanks a lot anyway.
0
 
LVL 14

Accepted Solution

by:
Matti earned 200 total points
Comment Utility
I made this so that it can't have focus but this focus thing has no meaning to the code.

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 Controlrect As RECT
'Default Property Values:
Const m_def_cx = 0
Const m_def_cy = 0
Const m_def_cx1 = 0
Const m_def_cy1 = 0
'Property Variables:
Dim m_cx As Long
Dim m_cy As Long
Dim m_cx1 As Long
Dim m_cy1 As Long

Private Sub Timer1_Timer()
'Timer interval was 20 on first test, but it is better make it adjustable and on/off property is also needed, no need to load the processor if new values are not needed, this timer alow update values when user moves the form. If you don't want timer
solution then make a update property to call this in sub

GetWindowRect UserControl.hwnd, Controlrect
cx = Controlrect.Left
cy = Controlrect.Right
cx1 = Controlrect.Bottom
cy1 = Controlrect.Top
Label1.Caption = Str$(cx) ' It has 4 labels to see the test values all the time these may be removed
Label4.Caption = Str$(cx1)
Label3.Caption = Str$(cy)
Label2.Caption = Str$(cy1)
DoEvents
End Sub
Public Property Get cx() As Long
    cx = m_cx
End Property

Public Property Let cx(ByVal New_cx As Long)
    m_cx = New_cx
    PropertyChanged "cx"
End Property

Public Property Get cy() As Long
    cy = m_cy
End Property

Public Property Let cy(ByVal New_cy As Long)
    m_cy = New_cy
    PropertyChanged "cy"
End Property

Public Property Get cx1() As Long
    cx1 = m_cx1
End Property

Public Property Let cx1(ByVal New_cx1 As Long)
    m_cx1 = New_cx1
    PropertyChanged "cx1"
End Property

Public Property Get cy1() As Long
    cy1 = m_cy1
End Property

Public Property Let cy1(ByVal New_cy1 As Long)
    m_cy1 = New_cy1
    PropertyChanged "cy1"
End Property

'Initialize Properties for User Control
Private Sub UserControl_InitProperties()
    m_cx = m_def_cx
    m_cy = m_def_cy
    m_cx1 = m_def_cx1
    m_cy1 = m_def_cy1
End Sub

'Load property values from storage
Private Sub UserControl_ReadProperties(PropBag As PropertyBag)

    m_cx = PropBag.ReadProperty("cx", m_def_cx)
    m_cy = PropBag.ReadProperty("cy", m_def_cy)
    m_cx1 = PropBag.ReadProperty("cx1", m_def_cx1)
    m_cy1 = PropBag.ReadProperty("cy1", m_def_cy1)
End Sub

'Write property values to storage
Private Sub UserControl_WriteProperties(PropBag As PropertyBag)

    Call PropBag.WriteProperty("cx", m_cx, m_def_cx)
    Call PropBag.WriteProperty("cy", m_cy, m_def_cy)
    Call PropBag.WriteProperty("cx1", m_cx1, m_def_cx1)
    Call PropBag.WriteProperty("cy1", m_cy1, m_def_cy1)
End Sub

'The debuger project code:
This project has a form and four labels and one timer on it when this form is moved by the uses the control place can be seen on labels.

Option Explicit

Private Sub Timer1_Timer()
Label1.Caption = Str(UserControl11.cx)
Label2.Caption = Str(UserControl11.cy)
Label3.Caption = Str(UserControl11.cx1)
Label4.Caption = Str(UserControl11.cy1)
End Sub

'**Extra comments ******************************

I used the VB interface wizard for ActiveX controls to get property codes automaticly.
All return values are now pixels on screen.

I tested this whit VB5 desingtime and exe and Win98  IE 4.72.3110.4  (SP1)

Then I try to chance it similar like your code, it stop working when I remove the timer, it give the first
cordinates only when the window appears your case it is the upper left corner.

Then I released that you never write those properities to properitybag correctly.









0

Featured Post

Find Ransomware Secrets With All-Source Analysis

Ransomware has become a major concern for organizations; its prevalence has grown due to past successes achieved by threat actors. While each ransomware variant is different, we’ve seen some common tactics and trends used among the authors of the malware.

Join & Write a Comment

I’ve seen a number of people looking for examples of how to access web services from VB6.  I’ve been using a test harness I built in VB6 (using many resources I found online) that I use for small projects to work out how to communicate with web serv…
I was working on a PowerPoint add-in the other day and a client asked me "can you implement a feature which processes a chart when it's pasted into a slide from another deck?". It got me wondering how to hook into built-in ribbon events in Office.
Show developers how to use a criteria form to limit the data that appears on an Access report. It is a common requirement that users can specify the criteria for a report at runtime. The easiest way to accomplish this is using a criteria form that a…
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…

772 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

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now