winapi - GetWindowRect devuelve un tamaño que incluye bordes "invisibles"
vb6 windows-10 (4)
¿Cómo puedo convencer a Windows de que me permita trabajar con las coordenadas de la ventana real?
Ya estás trabajando con las coordenadas reales. Windows10 simplemente ha elegido ocultar los bordes de tus ojos. Pero, sin embargo, todavía están allí. Al pasar el ratón por los bordes de la ventana, el cursor cambiará al cursor de cambio de tamaño, lo que significa que todavía está sobre la ventana.
Si desea que sus ojos coincidan con lo que Windows le está diciendo, puede intentar exponer esos bordes para que sean visibles nuevamente, utilizando el tema Aero Lite:
http://winaero.com/blog/enable-the-hidden-aero-lite-theme-in-windows-10/
Estoy trabajando en una aplicación que coloca las ventanas en la pantalla en un estilo de cuadrícula.
Al ejecutar esto en Windows 10, hay una gran brecha entre las ventanas.
La investigación adicional muestra que
GetWindowRect
está devolviendo valores inesperados, incluido un borde invisible, pero no puedo hacer que devuelva los valores reales con el borde visible.
1)
Este hilo
sugiere que esto es así por diseño y puede "arreglarlo" al vincularlo con winver = 6.
Mi entorno no lo permite, pero he intentado cambiar la PE
MajorOperatingSystemVersion
y
MajorOperatingSystemVersion
a 6 sin afectar
2) Ese mismo hilo también sugiere usar
DwmGetWindowAttribute
con
DWMWA_EXTENDED_FRAME_BOUNDS
para obtener las coordenadas reales de DWM, que funciona, pero significa cambiar en todas partes que obtienen las coordenadas de la ventana.
Tampoco permite establecer el valor, lo que nos permite invertir el proceso para poder establecer el tamaño de la ventana.
3)
Esta pregunta
sugiere que es falta de conciencia de DPI en el proceso.
Ni establecer el indicador de
SetProcessDpiAwareness
DPI en el manifiesto ni llamar a
SetProcessDpiAwareness
tuvo ningún resultado.
4) Por capricho, también he intentado agregar los indicadores de compatibilidad de Windows Vista, 7, 8, 8.1 y 10, y los temas de Windows se manifiestan sin cambios.
Esta ventana se mueve a 0x0, 1280x1024, supuestamente para llenar toda la pantalla, y al consultar las coordenadas, obtenemos los mismos valores. Sin embargo, la ventana es en realidad 14 píxeles más estrecha, para tener en cuenta el borde en versiones anteriores de Windows.
¿Cómo puedo convencer a Windows de que me permita trabajar con las coordenadas de la ventana real?
Puede responder al mensaje
WM_NCCALCSIZE
, modificar el comportamiento predeterminado de
WndProc
para eliminar el borde invisible.
Como explican
este documento
y
este documento
, cuando
wParam
> 0, a petición,
wParam.Rgrc[0]
contiene las nuevas coordenadas de la ventana y cuando el procedimiento regresa, la respuesta
wParam.Rgrc[0]
contiene las coordenadas del nuevo rectángulo cliente.
El ejemplo de código de golang:
case win.WM_NCCALCSIZE: log.Println("----------------- WM_NCCALCSIZE:", wParam, lParam) if wParam > 0 { params := (*win.NCCALCSIZE_PARAMS)(unsafe.Pointer(lParam)) params.Rgrc[0].Top = params.Rgrc[2].Top params.Rgrc[0].Left = params.Rgrc[0].Left + 1 params.Rgrc[0].Bottom = params.Rgrc[0].Bottom - 1 params.Rgrc[0].Right = params.Rgrc[0].Right - 1 return 0x0300 }
Windows 10 tiene bordes delgados invisibles a la izquierda, derecha e inferior, se usa para agarrar el mouse para cambiar el tamaño.
Los bordes podrían verse así:
7,0,7,7
(izquierda, arriba, derecha, abajo)
Cuando llama a
SetWindowPos
para colocar la ventana en estas coordenadas:
0, 0, 1280, 1024
La ventana seleccionará esas coordenadas exactas, y
GetWindowRect
devolverá las mismas coordenadas.
Pero visualmente, la ventana parece estar aquí:
7, 0, 1273, 1017
Puedes engañar a la ventana y decirle que vaya aquí:
-7, 0, 1287, 1031
Para hacer eso, obtenemos el grosor del borde de Windows 10:
RECT rect, frame;
GetWindowRect(hwnd, &rect);
DwmGetWindowAttribute(hwnd, DWMWA_EXTENDED_FRAME_BOUNDS, &frame, sizeof(RECT));
//rect should be `0, 0, 1280, 1024`
//frame should be `7, 0, 1273, 1017`
RECT border;
border.left = frame.left - rect.left;
border.top = frame.top - rect.top;
border.right = rect.right - frame.right;
border.bottom = rect.bottom - frame.bottom;
//border should be `7, 0, 7, 7`
Luego compensa el rectángulo así:
rect.left -= border.left;
rect.top -= border.top;
rect.right += border.left + border.right;
rect.bottom += border.top + border.bottom;
//new rect should be `-7, 0, 1287, 1031`
¡A menos que haya una solución más simple!
AdjustWindowRectEx
(o en Windows 10 y posterior,
AdjustWindowRectExForDpi
) puede ser útil.
Estas funciones convertirán un rectángulo de cliente en un tamaño de ventana.
Sin embargo, supongo que no desea superponer los bordes, por lo que probablemente esta no sea una solución completa, pero puede ser parte de la solución y puede ser útil para otras personas que se encuentran con esta pregunta.
Aquí hay un fragmento rápido de mi base de código donde los he utilizado con éxito para establecer el tamaño de la ventana para obtener el tamaño de cliente deseado, perdone las macros de manejo de errores:
case win.WM_NCCALCSIZE:
log.Println("----------------- WM_NCCALCSIZE:", wParam, lParam)
if wParam > 0 {
params := (*win.NCCALCSIZE_PARAMS)(unsafe.Pointer(lParam))
params.Rgrc[0].Top = params.Rgrc[2].Top
params.Rgrc[0].Left = params.Rgrc[0].Left + 1
params.Rgrc[0].Bottom = params.Rgrc[0].Bottom - 1
params.Rgrc[0].Right = params.Rgrc[0].Right - 1
return 0x0300
}
Todavía hay dos ambigüedades en el caso de uso anterior:
- Mi ventana tiene un menú, pero tengo que pasar falso para el parámetro del menú o obtengo el tamaño incorrecto. ¡Actualizaré esta respuesta con una explicación si descubro por qué es así!
- Todavía no he leído sobre cómo Windows maneja la conciencia de DPI, así que no estoy seguro de cuándo desea usar esa función frente a la que no tiene DPI.