Acerca de:

Este blog contiene los códigos, ejemplos y bases de datos que he usado cuando aprendía acerca de algún tema específico. En lugar de borrarlos (una vez dominado ya el tema), he decidido publicarlos :)

miércoles, 23 de octubre de 2013

Cómo evadir la limitación de tamaño de una ventana en Windows

Por diseño, Microsoft Windows limita el tamaño de las ventanas a (en píxeles):
(12 + ancho de la resolución de pantalla) x (12 + alto de la resolución de pantalla)

Más información en StackOverflow.

Por allí hallé quienes afirman que se puede superar esta restricción. Y entonces me topé con este código, de la misma Microsoft, en Visual Basic 6.

Lo copio aquí para que no se vaya a perder:

En un módulo bas:

 Option Explicit

      Private Const GWL_WNDPROC = -4
      Private Const WM_GETMINMAXINFO = &H24

      Private Type POINTAPI
          x As Long
          y As Long
      End Type

      Private Type MINMAXINFO
          ptReserved As POINTAPI
          ptMaxSize As POINTAPI
          ptMaxPosition As POINTAPI
          ptMinTrackSize As POINTAPI
          ptMaxTrackSize As POINTAPI
      End Type

      Global lpPrevWndProc As Long
      Global gHW As Long

      Private Declare Function DefWindowProc Lib "user32" Alias _
         "DefWindowProcA" (ByVal hwnd As Long, ByVal wMsg As Long, _
          ByVal wParam As Long, ByVal lParam As Long) As Long
      Private Declare Function CallWindowProc Lib "user32" Alias _
         "CallWindowProcA" (ByVal lpPrevWndFunc As Long, _
          ByVal hwnd As Long, ByVal Msg As Long, _
          ByVal wParam As Long, ByVal lParam As Long) As Long
      Private Declare Function SetWindowLong Lib "user32" Alias _
         "SetWindowLongA" (ByVal hwnd As Long, _
          ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
      Private Declare Sub CopyMemoryToMinMaxInfo Lib "KERNEL32" Alias _
         "RtlMoveMemory" (hpvDest As MINMAXINFO, ByVal hpvSource As Long, _
          ByVal cbCopy As Long)
      Private Declare Sub CopyMemoryFromMinMaxInfo Lib "KERNEL32" Alias _
         "RtlMoveMemory" (ByVal hpvDest As Long, hpvSource As MINMAXINFO, _
          ByVal cbCopy As Long)

      Public Sub Hook()
          'Start subclassing.
          lpPrevWndProc = SetWindowLong(gHW, GWL_WNDPROC, _
             AddressOf WindowProc)
      End Sub

      Public Sub Unhook()
          Dim temp As Long

          'Cease subclassing.
          temp = SetWindowLong(gHW, GWL_WNDPROC, lpPrevWndProc)
      End Sub

      Function WindowProc(ByVal hw As Long, ByVal uMsg As Long, _
         ByVal wParam As Long, ByVal lParam As Long) As Long
          Dim MinMax As MINMAXINFO

          'Check for request for min/max window sizes.
          If uMsg = WM_GETMINMAXINFO Then
              'Retrieve default MinMax settings
              CopyMemoryToMinMaxInfo MinMax, lParam, Len(MinMax)

              'Specify new minimum size for window.
              MinMax.ptMinTrackSize.x = 200
              MinMax.ptMinTrackSize.y = 200

              'Specify new maximum size for window.
              MinMax.ptMaxTrackSize.x = 500
              MinMax.ptMaxTrackSize.y = 500

              'Copy local structure back.
              CopyMemoryFromMinMaxInfo lParam, MinMax, Len(MinMax)

              WindowProc = DefWindowProc(hw, uMsg, wParam, lParam)
          Else
              WindowProc = CallWindowProc(lpPrevWndProc, hw, uMsg, _
                 wParam, lParam)
          End If
      End Function


El truco es fácil: donde están los números en rojo, escribimos nuestros números enormes favoritos. Yo le puse por código a una ventana (Form) dimensiones de 2050*1600 píxeles, en una resolución de pantalla de 1024*768 (la restricción por defecto sería 1036*780).

Para hacer esto en el form ponemos:

      Option Explicit

      Private Sub Form_Load()
          'Save handle to the form.
          gHW = Me.hwnd

          'Begin subclassing.
          Hook 
          ' le ponemos un tamaño ENORME 
          Me.Height = 1600
          Me.Width = 2050
      End Sub

      Private Sub Form_Unload(Cancel As Integer)
          'Stop subclassing.
          Unhook
      End Sub 


Y funcionó.

Ya no intenté con dimensiones mayores porque una ventana con aproximadamente el doble de alto y ancho que la resolución de pantalla parece ser suficientemente grande. Deduzco que el máximo que puede aguantar el sistema operativo depende de la memoria máxima que le puede asignar a semejante ventanón y antes que la RAM empiece a echar humo.

Como son puras llamadas a Apis de WIndows, se puede traducir este código a Visual C++ o a .Net usando DLLImport.

No hay comentarios: