.netwinformsspy++freerdpgetclientrect

VB.NET GetClientRect() returns nothing for child process in WinForm


Writing a WinForm project in VB.NET on VS 2017, and I am opening an instance of FreeRDP in SplitContainer2.Panel1. This works just fine, but I would like to scale the form to initially fit the FreeRDP window. In order to do this, I first need to know the size of the FreeRDP instance.

Unfortunately, every attempt I have made returns nothing. I am trying to use GetClientRect() from the Windows API, but all I ever get back is 0's (or nothing, I suppose). This is the first time I have played with API calls, so I am not sure what I am doing wrong. I have verified I have the correct handle with a break in VS

(I apologize if these scale poorly. Hard to judge on scaled 4k)

enter image description here

compared to Spy++

enter image description here

So, I have confirmed I have the correct hWnd handle, but when I call a GetClientRect(), I get nothing back.

Here is the relevant code:

Dim rdpWnd As New IntPtr
Dim proc As New Process

Private Declare Auto Function GetClientRect Lib "user32.dll" ( _
    ByVal hWnd As IntPtr, ByVal lpRect As RECT) As Boolean

<StructLayout(LayoutKind.Sequential)>
Private Structure RECT
    Private Left As Short
    Private Top As Short
    Private Right As Short
    Private Bottom As Short
End Structure

Private Sub Form_Load( _
    sender As Object, e As EventArgs) Handles MyBase.Load

    Dim startInfo As New ProcessStartInfo With {
        .FileName = """" & appPath & "\console\wfreerdp.exe""",
        .Arguments = "/parent-window:" & SplitContainer2.Panel1.Handle.ToString() & " /t:" & vmId
    }
    proc = Process.Start(startInfo)

    rdpWnd = getWindowHandle(Me.Text, vmId)
End Sub

Private Function getWindowHandle(caption As String, Guid As String) As IntPtr

    Dim hWnd As IntPtr = FindWindow(Nothing, caption)
    If hWnd.Equals(IntPtr.Zero) Then
        Return Nothing
    End If

    .......

    Dim hWndRdp As IntPtr = FindWindowEx(hWndChild4, IntPtr.Zero, Nothing, Guid)
    If hWndRdp.Equals(IntPtr.Zero) Then
        Return Nothing
    End If

    Return hWndRdp
End Function

At this point, I am looking at a console window of a Hyper-V VM in my form, but when I click the proverbial Button1...

Private Sub Button1_MouseClick( _
    sender As Object, e As MouseEventArgs) Handles Button1.MouseClick

    Dim myRect As New RECT
    GetClientRect(rdpWnd, myRect)
    Dim rdpWndWidth As Short = myRect.Right - myRect.Left
    Dim rdpWndHeight As Short = myRect.Bottom - myRect.Top
    MsgBox("Width: " & rdpWndWidth & vbCrLf & 
           "Height: " & rdpWndHeight)
End Sub

The MsgBox() returns:

enter image description here

and the variables in VS:

enter image description here

What am I doing wrong? Why can I not get the client size when I can clearly see Spy++ can? I have spent many hours trying to figure this out, and I would appreciate the assistance in getting this milestone checked-off. About to move onto something else and come back later if I can't get it soon.


Solution

  • You are passing the RECT struct by value to GetClientRect. This creates a copy of the struct. As a result, the original RECT value is never modified by the method call, and so all its fields will have default values (i.e. zero).

    Change your method signature to

    Private Declare Auto Function GetClientRect Lib "user32.dll" ( _
        ByVal hWnd As IntPtr, ByRef lpRect As RECT) As Boolean
    

    (note the ByRef keyword).