简体   繁体   English

无法使用 DwmGetWindowAttribute 找到 RECT 大小

[英]Unable to find RECT size with DwmGetWindowAttribute

I'm trying to find to find the size of the cmd.exe window which is started as a child.我试图找到小时候开始的 cmd.exe window 的大小。 I like to use this size to resize my form accordingly.我喜欢使用这个尺寸来相应地调整我的表单大小。 For some reason the size returned by DwmGetWindowAttribute is always zero, so I must be doing something wrong here, but I can't find it.由于某种原因, DwmGetWindowAttribute 返回的大小始终为零,所以我一定是在这里做错了,但我找不到它。 Any help will be greatly appreciated.任何帮助将不胜感激。 Kind regards, Eric亲切的问候,埃里克

Imports System.Runtime.InteropServices
Public Class Form1
    Private WithEvents Tmr As New Timer With {.Interval = 100}
    Private Const HWND_BOTTOM As Integer = &H1
    Private WithEvents proc As New Process
    Public Const DWMWA_EXTENDED_FRAME_BOUNDS As Integer = 9
    <DllImport("user32.dll", EntryPoint:="SetParent")>
    Private Shared Function SetParent(ByVal hWndChild As IntPtr, ByVal hWndNewParent As IntPtr) As IntPtr
    End Function
    <DllImport("user32.dll", EntryPoint:="SetWindowPos")>
    Private Shared Function SetWindowPos(ByVal hWnd As IntPtr, ByVal hWndInsertAfter As IntPtr, ByVal X As Integer, ByVal Y As Integer, ByVal cx As Integer, ByVal cy As Integer, ByVal uFlags As UInteger) As <MarshalAs(UnmanagedType.Bool)> Boolean
    End Function
    <DllImport("dwmapi.dll")>
    Shared Function DwmGetWindowAttribute(ByVal hwnd As IntPtr, ByVal dwAttribute As Integer, ByRef pvAttribute As RECT, ByVal cbAttribute As Integer) As Integer
    End Function
    Public Structure RECT
        Public left, top, right, bottom As Integer
    End Structure
    Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Me.Text = "My title"
        proc.EnableRaisingEvents = True
        proc.StartInfo.FileName = "cmd"
        proc.Start()
        Tmr.Start()
    End Sub
    Private Sub Tmr_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles Tmr.Tick
        If SetParent(proc.MainWindowHandle, Panel1.Handle) <> IntPtr.Zero Then
            Tmr.Stop()
            Dim Width As Integer
            Dim Hight As Integer
            Dim WindowRect As New RECT
            DwmGetWindowAttribute(proc.MainWindowHandle, DWMWA_EXTENDED_FRAME_BOUNDS, WindowRect, Marshal.SizeOf(WindowRect))
            Width = WindowRect.right - WindowRect.left
            Hight = WindowRect.bottom - WindowRect.top
            MessageBox.Show("Hight: " & Hight & " Width: " & Width)
            'Me.Size = New Size(Width, Hight)
            SetWindowPos(proc.MainWindowHandle, New IntPtr(HWND_BOTTOM), 0, 0, Panel1.ClientSize.Width, Panel1.ClientSize.Height, 0)
        End If
    End Sub
    Private Sub Proc_Exited(ByVal sender As Object, ByVal e As System.EventArgs) Handles proc.Exited
        Invoke(Sub() Close())
    End Sub
End Class

After implementing all valuable additions of @Jimi, this is the code that works:在实现了@Jimi 的所有有价值的添加之后,这是有效的代码:

Imports System.Runtime.InteropServices
Public Class Form1
    Private WithEvents proc As New Process
    Public Const WM_NCLBUTTONDOWN As Long = &HA1
    Public Const SW_SHOWMAXIMIZED As UInt32 = 3
    Public Const WM_CLOSE = &H10
    Public Const DWMWA_EXTENDED_FRAME_BOUNDS As Integer = 9
    'Function to set the parent window
    Private Declare Function SetParent Lib "user32" (ByVal hWndChild As IntPtr, ByVal hWndNewParent As IntPtr) As IntPtr
    'Function to set the child window position
    Private Declare Function SetWindowPos Lib "user32" (ByVal hWnd As IntPtr, ByVal hWndInsertAfter As IntPtr, ByVal X As Integer, ByVal Y As Integer, ByVal cx As Integer, ByVal cy As Integer, ByVal uFlags As UInteger) As <MarshalAs(UnmanagedType.Bool)> Boolean
    'Function to allow the child to be maximized
    Private Declare Function ShowWindow Lib "user32" (ByVal hwnd As IntPtr, ByVal nCmdShow As Int32) As Boolean
    'Function to retrieve the initail child size
    Private Declare Function DwmGetWindowAttribute Lib "dwmapi" (ByVal hwnd As IntPtr, ByVal dwAttribute As Integer, ByRef pvAttribute As RECT, ByVal cbAttribute As Integer) As Integer
    'Function to set focus to the child window
    Private Declare Function SetForegroundWindow Lib "user32" (ByVal hwnd As IntPtr) As Long
    'Function used to set terminate child window
    Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As IntPtr, ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer
    'Rectangle size, used later to resize the form
    Public Structure RECT
        Public left, top, right, bottom As Integer
    End Structure
    Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Me.Text = "My title"
        proc.EnableRaisingEvents = True
        proc.StartInfo.FileName = "cmd"
        proc.Start()
    End Sub
    Private Sub Tmr_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Shown
        'Wait for 200 ms for the form to load
        proc.WaitForExit(200)
        Dim WindowRect As New RECT
        Dim Width, Hight As Integer
        'Retrieve the initial size of the child window
        DwmGetWindowAttribute(proc.MainWindowHandle, DWMWA_EXTENDED_FRAME_BOUNDS, WindowRect, Marshal.SizeOf(WindowRect))
        Width = WindowRect.right - WindowRect.left
        Hight = WindowRect.bottom - WindowRect.top + 23
        'Set the form size to the initial size of the child window
        Me.Size = New Size(Width, Hight)
        'When the child is started, move the child into the panel and maximize it
        If SetParent(proc.MainWindowHandle, Panel1.Handle) <> IntPtr.Zero Then
            SetWindowPos(proc.MainWindowHandle, IntPtr.Zero, 0, 0, Width, Height, 0)
            ShowWindow(proc.MainWindowHandle, SW_SHOWMAXIMIZED)
        End If
    End Sub
    'Exit form when child terminates
    Private Sub Proc_Exited(ByVal sender As Object, ByVal e As System.EventArgs) Handles proc.Exited
        Invoke(Sub() Close())
    End Sub
    'Set focus on child when the form is activated
    Private Sub Form1_UnFocus(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Activated
        SetForegroundWindow(proc.MainWindowHandle)
    End Sub
    'Set focus on child when the parent titlebar is clicked
    Protected Overrides Sub DefWndProc(ByRef m As System.Windows.Forms.Message)
        If CLng(m.Msg) = WM_NCLBUTTONDOWN Then
            SetForegroundWindow(proc.MainWindowHandle)
        End If
        MyBase.DefWndProc(m)
    End Sub
    'Properly terminate child when the form is closed by the user
    Private Sub Form1_Closed(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Closed
        SendMessage(proc.MainWindowHandle, WM_CLOSE, 0, 0)
    End Sub
End Class

Kind regards, Eric亲切的问候,埃里克

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM