使用DwmGetWindowAttribute无法获取RECT窗口尺寸问题求助
问题分析与解决
你的代码里DwmGetWindowAttribute返回尺寸始终为0,主要有几个核心原因:
1. 调用时机过早
在SetParent之后立刻调用DwmGetWindowAttribute,此时cmd窗口还未完成DWM相关的初始化流程,导致无法正确读取属性值。
2. 控制台窗口不适合用DWMWA_EXTENDED_FRAME_BOUNDS
cmd属于控制台窗口,这类窗口对DWM属性的支持有限,更可靠的方式是使用GetWindowRect获取窗口整体尺寸,或GetClientRect获取客户区尺寸。
3. 未检查DwmGetWindowAttribute的返回值
该函数返回HRESULT类型值,非0则表示调用失败,你没有对返回结果做判断,无法定位具体失败原因。
修改后的代码示例
以下是调整后的代码,改用GetWindowRect获取尺寸,并增加句柄有效性检查:
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 <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("user32.dll", EntryPoint:="GetWindowRect")> Private Shared Function GetWindowRect(ByVal hWnd As IntPtr, ByRef lpRect As RECT) As <MarshalAs(UnmanagedType.Bool)> Boolean 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 proc.MainWindowHandle = IntPtr.Zero Then Return ' 确保窗口句柄有效 If SetParent(proc.MainWindowHandle, Panel1.Handle) <> IntPtr.Zero Then Tmr.Stop() Dim WindowRect As New RECT ' 使用GetWindowRect获取窗口尺寸 If GetWindowRect(proc.MainWindowHandle, WindowRect) Then Dim Width = WindowRect.right - WindowRect.left Dim Height = WindowRect.bottom - WindowRect.top MessageBox.Show("Height: " & Height & " Width: " & Width) 'Me.Size = New Size(Width, Height) SetWindowPos(proc.MainWindowHandle, New IntPtr(HWND_BOTTOM), 0, 0, Panel1.ClientSize.Width, Panel1.ClientSize.Height, 0) Else MessageBox.Show("获取窗口尺寸失败") End If 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
额外说明
如果一定要使用DwmGetWindowAttribute,需要做以下调整:
- 确保系统启用了DWM特效(Windows Vista及以上默认启用,可通过任务管理器确认)
- 增大Timer的Interval到500ms,给窗口足够时间完成初始化
- 检查函数返回值,示例代码如下:
Dim result = DwmGetWindowAttribute(proc.MainWindowHandle, DWMWA_EXTENDED_FRAME_BOUNDS, WindowRect, Marshal.SizeOf(WindowRect)) If result = 0 Then ' S_OK表示调用成功 Dim Width = WindowRect.right - WindowRect.left Dim Height = WindowRect.bottom - WindowRect.top MessageBox.Show("Height: " & Height & " Width: " & Width) Else MessageBox.Show("DwmGetWindowAttribute调用失败,错误码:" & result.ToString("X")) End If
内容的提问来源于stack exchange,提问作者Eric van Loon
相关产品推荐
相关产品推荐

