13 de abril de 2014

Controlar múltiples monitores

Artículo original: Handling Multiple Monitors
http://doughennig.blogspot.com/2007/04/handling-multiple-monitors.html
Autor: Doug Hennig
Traducido por: Ana María Bisbé York

Una de las cosas que hice con mi nuevo portátil fue configurarle múltiples monitores. Algunos desarrolladores que conozco y respeto lo han hecho desde hace años, así que supongo que ya sea hora de que yo también lo intente. No hay nada que decir, me gusta. Tengo generalmente el Examinador y explorador de Windows abiertos en el segundo monitor y mantengo el monitor primario para aquellas cosas que hago a lo largo del día (principalmente VFP y Outlook). Soy más productivo ahora que no tengo que moverme entre la pila de ventanas ni moverme o redimensionar constantemente una ventana.

Sin embargo, una de las cosas que he descubierto hoy, es que algunas de mis aplicaciones no respetan el segundo monitor. Por ejemplo, tengo una clase llamada SFPersistentForm que arrastro a la mayoría de mis formularios. Esta clase guarda el tamaño y posición del formulario cuando se cierra y lo restaura cuando se abre nuevamente, dando al usuario la experiencia que el espera al trabajar con este formulario. Sin embargo, he descubierto que si abro el formulario y lo muevo al segundo monitor, luego llo cierro, y cuando lo reabro el formulario se muestra sin embargo, en el primer monitor (es un formulario con Desktop = .T., por tanto puede existir fuera de la aplicación).

Rápidamente encontré la razón: el código intentaba evitar la situación en la que el formulario pudiera abrirse fuera de los límites de la pantalla, haciéndolo invisible. El siguiente código controla esto:
Thisform.Width = min(max(Thisform.Width, 0, Thisform.MinWidth), ;
  _screen.Width)
Thisform.Height = min(max(Thisform.Height, 0, Thisform.MinHeight), ;
  _screen.Height)
Thisform.Left = min(max(Thisform.Left, 0), _screen.Width - 50)
Thisform.Top = min(max(Thisform.Top, 0), _screen.Height - 50)
("-50"  se utiliza para garantizar que el formulario no comience exactamente  la derecha del borde del monitor, haciéndolo esencialmente invisible.)

Existen dos problemas con este código. Primero, la confiabilidad en _SCREEN asume que el formulario existe con _SCREEN, que es un formulario de nivel superior o uno con Desktop = .T., que no es necesariamente el caso. Segundo, si se maximiza _SCREEN, solo cabe en el monitor actual. Si el formulario está en el otro monitor, las dimensiones de _SCREEN son irrelevantes.

Inicialmente cambié el código:
if Thisform.Desktop or Thisform.ShowWindow = 2
  lnWidth = sysmetric(1)
  lnHeight = sysmetric(2)
else
  lnWidth = _screen.Width
  lnHeight = _screen.Height
endif Thisform.Desktop ...
Thisform.Width = min(max(Thisform.Width, 0, Thisform.MinWidth), ;
  lnWidth)
Thisform.Height = min(max(Thisform.Height, 0, Thisform.MinHeight), ;
  lnHeight)
Thisform.Left = min(max(Thisform.Left, 0), lnWidth - 50)
Thisform.Top = min(max(Thisform.Top, 0), lnHeight - 50)
Sin embargo, SYSMETRIC() sólo devuelve valores para el monitor primario. Entonces, cambié las sentencias a:
declare integer GetSystemMetrics in Win32API integer
#define SM_CXVIRTUALSCREEN 78 && Ancho Virtual 
#define SM_CYVIRTUALSCREEN 79 && Altura Virtual 
lnWidth = GetSystemMetrics(SM_CXVIRTUALSCREEN)
lnHeight = GetSystemMetrics(SM_CYVIRTUALSCREEN)
Ahora el formulario se reabre en la misma posición exacta, incluyendo el monitor donde estaba antes.

Enlace a la clase Multiple Monitor Classhttps://doughennig.blogspot.com/2010/02/multiple-monitor-class.html (Gracias Hernan Cano por el enlace)

8 de abril de 2014

Ubicacion de la carpeta System32, Font, y Programs File

Este codigo permite saber la ubicacion fisica de las carpetas System32, Font, y Programs File.

**** LLevado De VISUAL Basic a lenguaje FOXPRO por In_21
#DEFINE CSIDL_FONTS 20 && Carpeta de Fuentes
#DEFINE CSIDL_PROGRAM_FILES 0x0026 && Carpeta de Programas
#DEFINE CSIDL_SYSTEM 37&& Carpeta de Sistema, System32
* La Api
DECLARE INTEGER SHGetSpecialFolderPath IN shell32.DLL ;
   LONG HWND , STRING @sPath ,LONG Folder
#DEFINE MAX_PATH 255 && Maximo de caracteres del Buffer

LOCAL strLocation,La_Ruta
* Inicializacion
strLocation = ""
La_Ruta = ""
* Aqui determinas cual de las carpetas quieres buscar, 
*   en este caso buscamos la carpeta para programas
lngCSIDL = CSIDL_PROGRAM_FILES 
* Rellenamos la variable con el maximo de espacios (255)
strLocation = SPACE(MAX_PATH) 
* Llamada a la API de Windows, pasando la varibale strLocation por valor
La_Ruta = ObtenerCarpetaEspecial(@strLocation, lngCSIDL) 

* A pantalla para saber la ruta
MESSAGEBOX(La_Ruta) 

FUNCTION ObtenerCarpetaEspecial()
  PARAMETERS strParamLocation, lngParamCSIDL
  LOCAL La_Carpeta
  =SHGetSpecialFolderPath(0, @strParamLocation, lngParamCSIDL)
  *  Quitarle el caracter de Nulo al final
  La_Carpeta = SUBSTR(RTRIM(strParamLocation),1,LEN(RTRIM(strParamLocation))-1)
  RETURN La_Carpeta
ENDFUNC