Is it possible to retain multi monitor settings when one monitor is "unplugged"?

3

Background Info

I recently completed a new 'Home Theater' setup in our new house. In the living room I have a TV and sound bar, and in my office on the other side of the wall I have my PC (running Plex), PS3, Xbox 360, and the router. I installed some new faceplates and ran an HDMI cable, USB cable, and cat6 cable between the rooms. In my office I have the PC, PS3 and x360 connected to a 3-to-1 HDMI splitter, which then runs to the living room TV.

My issue is that I can get everything setup nice to use multiple monitors on my PC, get Plex setup to automatically run on the TV when it starts up, and all that sort of stuff. However, if I switch the HDMI Switch to the PS3, it effectively 'unplugs' the TV as a monitor from my PC, and when I switch back it's like a new monitor has been connected and doesn't retain any of the previous settings. This is especially frustrating for Plex/XBMC and Steam Big Picture which don't remember to startup on that monitor.

My Question

Is there a way to retain all of the mutli-monitor settings for the TV even when it is effectively unplugged? My only other option is to buy and run another HDMI cable through the wall to dedicate to the PC, and use the other one to switch between the PS3/X360. That would work fine, but I would rather not spend the money if I don't have to.

Thanks!

Anthony

Posted 2014-06-17T16:52:47.287

Reputation: 133

Answers

1

Nope, at least not without 3rd party utilities; you are seeing the expected behaviour of Windows.

Check out this SU question: Save window locations of applications, and/or Google for a utility that can save and restore window/icon potions on command. There's quite a few out there that do it, including (possibly) your display driver's utilities.

Ƭᴇcʜιᴇ007

Posted 2014-06-17T16:52:47.287

Reputation: 103 763

Thanks, I expected that would be the case.

I checked that first link and the accepted answer was to check out Display Fusion, which I have the paid version of. For some reason I didn't even think to try using that, I've really only used it for desktop backgrounds and split task bars. – Anthony – 2014-06-17T17:15:42.093

@Anthony - I suggest a script that can be run. The only other suggestion change up the configuration. Leave the PC always plugged in and switch the HDMI on the TV. Connected the switch to HDMI 2 and switch between PS3/X360. This way the PC is always connected, if it wasn't a switch, this wouldn't happen. – Ramhound – 2014-06-17T17:24:14.263

@Ramhound Changing up the configuration and just running 2 HDMI cables through the wall will probably end up being the best solution. I've already got another cable and two more keystone jacks sitting in my cart online, but I'm going to see if I can manage to get close without that first. – Anthony – 2014-06-17T17:39:11.753

@Anthony - The reason this happens is how the HDMI switch actually works. Let me guess its a Monoprice switch? :-) – Ramhound – 2014-06-17T17:50:48.610

@Ramhound It's from Amazon actually, and it's super basic. I know that when I switch the HDMI away from the PC it's pretty much the same thing as unplugging the cable from the monitor, at which point windows does away with it. Display Fusion has monitor configuration profiles that I'll play with when I get home, that might get me most of the way there. If not, second HDMI cable it is! – Anthony – 2014-06-17T17:56:34.200

1

I have opensourced a small program (two, in fact) to solve this.
The first one to save the positions of all the windows:

SaveWinPositions [NumMonitors]
NumMonitors: (1 default) integer (positive) specifying the number of physical screens on the computer. The program will exit is at least this number of screens is not available. Zero (0) to ignore and save anyway.

And the second one to restore them:

RestoreWinPositions [NumMonitors]
NumMonitors: (1 default) integer (positive) specifying the number of physical screens on the computer. The program will wait for this number of screens available to start restoring. Zero (0) to ignore and restore anyway.

You can program them to execute at intervals via Task Scheduler, execute them manually, via hotkey, run them at screensaver start/close (this is what I prefer)... etc.

Here are the two executables (and the source, of course).

Update: I don`t know why, but some people reports that SourceForge consider it as malware, so here is the source code (AHK scripts) for SaveWinPositions :

; SaveWinPositions
; Version v0.22

; Obtiene el nombre, ID, posición y tamaño (x,y,w,h) de todas las ventanas.
; Incluídas las minimizadas.
; Crea un fichero "WinPos.txt" en %TEMP% conteniendo sus posiciones.

; Comprobamos que el programa no se ha activado por un disparo en falso (apagado/encendido casi simultáneo) del salvapantallas:
FileGetTime, FechaOriginal, %TEMP%\WinPos.txt
TiempoTranscurrido := A_Now-FechaOriginal
If TiempoTranscurrido<=5
{   ; Se grabaron datos de posiciones de ventanas hace 5 segundos o menos.
    FileAppend, % "* " . A_YYYY . "-" . A_MM . "-" . A_DD . " " . A_Hour . ":" . A_Min . ":" . A_Sec . " --> " . "SaveWinPositions:-> Se grabaron datos de posiciones de ventanas hace " . TiempoTranscurrido . " segundos. Disparo en falso del salvapantallas. No se almacenarán posiciones de ventanas. Saliendo de SaveWinPositions. `n", %TEMP%\WinPositions-Log.txt
    TrayTip, SaveWinPositions, Se grabaron datos de posiciones de ventanas hace %TiempoTranscurrido% segundos. Disparo en falso del salvapantallas. Abortando., ,1
    sleep 10000
    Exit        ; Disparo en falso del salvapantallas. Cancelando la ejecución del programa.
}

NumParametros = %0%
Parametro1 = %1%
NumeroDePantallasEsperado:=1    ; El sistema dispone de este número de pantallas en total. No se deben mover ventanas ni grabar sus posiciones si no están encendidas todas.
    ;Nótese que este será el valor por defecto de no ser especificado mediante parámetro en la línea de comandos ni existir %A_WorkingDir%\screens.cfg.
If ( NumParametros<1 )  ; Comprobamos el número de parámetros.
{       ; Si no hay parámetros, capturamos el número de pantallas del fichero de configuración (por defecto en el directorio de ejecución del programa), si existe:
    IfExist, screens.cfg    ; Si existe el fichero de configuración...
    {   ; ... leemos de él el número de pantallas esperado.
        FileReadLine,NumeroDePantallasEsperado,%A_WorkingDir%\screens.cfg,1
        FileAppend, % "* " . A_YYYY . "-" . A_MM . "-" . A_DD . " " . A_Hour . ":" . A_Min . ":" . A_Sec . " --> " . "SaveWinPositions:-> No se introdujeron parámetros, se utilizará el extraído del fichero de configuración.`n", %TEMP%\WinPositions-Log.txt
    } else
    {   ; No existe el fichero de configuración: informamos en el log.
        FileAppend, % "* " . A_YYYY . "-" . A_MM . "-" . A_DD . " " . A_Hour . ":" . A_Min . ":" . A_Sec . " --> " . "SaveWinPositions:-> No existe el fichero de configuración.`n", %TEMP%\WinPositions-Log.txt
    }

} else
{   ; Si hay parámetros...
    If ( Parametro1 = 0 )   ; si el parámetro es un 0...
    {   ; Ignorar número de monitores
    IgnoreNumPantallas = 1
    FileAppend, % "* " . A_YYYY . "-" . A_MM . "-" . A_DD . " " . A_Hour . ":" . A_Min . ":" . A_Sec . " --> " . "SaveWinPositions:-> Ignorando número de monitores: se ejecutará el programa sin esperarlos.`n", %TEMP%\WinPositions-Log.txt
    } else
    {   ; si el parámetro es distinto de 0...
        ; ... el parámetro contiene el número de pantallas esperado:
        NumeroDePantallasEsperado = %1%
    }
}
If ( Parametro1 != 0 )  ; a menos que se ignore el número de monitores...
{   ; ... añadimos una entrada al log con el número de pantallas necesarias.
    FileAppend, % "* " . A_YYYY . "-" . A_MM . "-" . A_DD . " " . A_Hour . ":" . A_Min . ":" . A_Sec . " --> " . "SaveWinPositions:-> Numero de monitores esperado: " . NumeroDePantallasEsperado ".`n", %TEMP%\WinPositions-Log.txt
}
; Comprobamos que estén todos los monitores conectados:
SysGet, m, MonitorCount
If ( not IgnoreNumPantallas and m < NumeroDePantallasEsperado )
{
    FileAppend, % "* " . A_YYYY . "-" . A_MM . "-" . A_DD . " " . A_Hour . ":" . A_Min . ":" . A_Sec . " --> " . "SaveWinPositions:-> Número de pantallas actual: " . m . "; se esperaba al menos " . NumeroDePantallasEsperado . ". Saliendo de SaveWinPositions. `n", %TEMP%\WinPositions-Log.txt
    TrayTip, SaveWinPositions, Número de pantallas actual: %m% (se esperaba al menos %NumeroDePantallasEsperado%). Abortando., ,2
    sleep 10000
    Exit        ; No están todas las pantallas. Cancelamos la ejecución del programa.
}

; Comprobamos si el salvapantallas está activo:
SalvaPantallas := WinExist("Protector de pantalla")

FileAppend, % "* " . A_YYYY . "-" . A_MM . "-" . A_DD . " " . A_Hour . ":" . A_Min . ":" . A_Sec . " --> " . "SaveWinPositions:-> Grabando posiciones de las ventanas del Escritorio `n", %TEMP%\WinPositions-Log.txt
FileDelete, %TEMP%\WindowsPositions.txt
WinGet windows, List
Loop %windows%
{
    ContainsSpecialCharacter:=0
    id := windows%A_Index%
    WinGetTitle wt, ahk_id %id%
    WinGet, WinStatus, MinMax, ahk_id %id%
    if (WinStatus=-1)
    {   ; Esta ventana está minimizada.
        WinGetNormalPos(id, x, y, w, h)
        If (x+y+w+h=0)
        {   ; Todas sus coordenadas parecen valer 0. Necesitamos restaurarla para capturarlas corréctamente.
            FileAppend, % "* " . A_YYYY . "-" . A_MM . "-" . A_DD . " " . A_Hour . ":" . A_Min . ":" . A_Sec . " --> " . "SaveWinPositions:-> Posible problema en ventana : " . wt . ". Es necesario restaurarla para detectar sus coordenadas."
            WinRestore, ahk_id %ID%
            WinGetPos, x,y,w,h,ahk_id %ID%
            WinMinimize, ahk_id %ID%
            WindowRestored:=1
        } 
    } else
    {   ; Esta ventana no está minimizada. Recurrimos a captura normal de coordenadas.
        WinGetPos,x,y,w,h,ahk_id %id%
    }
    If (wt and wt!="Inicio")        ; Ignore Windos Title null and "Inicio".
    {   ; Añadir al fichero de datos: Coordenadas, dimensiones y título de la ventana.
        r .= ID . "," . x . "," . y . "," . w . "," . h . "," . wt . "`n"
    }
    FileAppend , %r%, %TEMP%\WindowsPositions.txt
}

; Ordenamos por ID de ventana el fichero resultante:
FileRead, OutputVar, %TEMP%\WindowsPositions.txt
Sort, OutputVar, u  ; Se producen duplicados de líneas, no sabemos aún porqué. :-P

; Duplicamos el fichero anteriormente existente de las posiciones de las ventanas, por si las moscas.
FileDelete, %TEMP%\WinPos-.txt
FileCopy, %TEMP%\WinPos--.txt, %TEMP%\WinPos---.txt
FileCopy, %TEMP%\WinPos-.txt, %TEMP%\WinPos--.txt
FileCopy, %TEMP%\WinPos.txt, %TEMP%\WinPos-.txt
FileDelete, %TEMP%\WinPos.txt
FileAppend, %OutputVar%,%TEMP%\WinPos.txt

If (SalvaPantallas and WindowRestored)
{   ; El programa necesitó desactivar el salvapantallas. Procedemos a reactivarlo:
    FileAppend, % "* " . A_YYYY . "-" . A_MM . "-" . A_DD . " " . A_Hour . ":" . A_Min . ":" . A_Sec . " --> " . "SaveWinPositions:-> Estaba en funcionamiento el salvapantallas y hubo de ser desactivado. Reactivándolo..."
    ; Método alternativo para activación del salvapantallas (requiere NirSoft NirCmd en el path del sistema).
    Run, nircmdc screensaver
}
TrayTip, SaveWinPositions, Posiciones de ventanas grabadas para %NumeroDePantallasEsperado% pantalla(s)., ,1
; Beeps report: correctly finished.
    SoundBeep 1500,100
    SoundBeep 1000,100
    SoundBeep 3500,100
sleep 10000

; Funciones del programa
WinGetNormalPos(hwnd, ByRef x, ByRef y, ByRef w="", ByRef h="")
; Devuelve la posición que tendría la ventana si no estuviera minimizada (posición restaurada).
{
    VarSetCapacity(wp, 44), NumPut(44, wp)
    DllCall("GetWindowPlacement", "uint", hwnd, "uint", &wp)
    x := NumGet(wp, 28, "int")
    y := NumGet(wp, 32, "int")
    w := NumGet(wp, 36, "int") - x
    h := NumGet(wp, 40, "int") - y
}

And this is the code for RestoreWinPositions:

FileDelete, %TEMP%\WinPosWorking.txt
FileCopy, %TEMP%\WinPos.txt, %TEMP%\WinPosWorking.txt

FileGetTime, FechaOriginal, %TEMP%\WinPos.txt
TiempoTranscurrido := A_Now-FechaOriginal

ArrayCount = 0
if TiempoTranscurrido>5     ; Disparo correcto del salvapantallas: activado/apagado no a la misma vez.
{
    Loop, Read, %TEMP%\WinPosWorking.txt   ; This loop retrieves each line from the file, one at a time.
    {
        ArrayCount += 1  ; Keep track of how many items are in the array.
        Array%ArrayCount% := A_LoopReadLine  ; Store this line in the next array element.
    }
    FileAppend, % "# " . A_YYYY . "-" . A_MM . "-" . A_DD . " " . A_Hour . ":" . A_Min . ":" . A_Sec . " --> " . "RestoreWinPositions:--> Fichero de posiciones creado hace " . TiempoTranscurrido . " segundos (Correcto). Restaurando ventanas...." . " `n", %TEMP%\WinPositions-Log.txt
    TrayTip, RestoreWinPositions, Restaurando ventanas..., ,1
}

if TiempoTranscurrido<=5        ; Disparo en falso del salvapantallas: activado/apagado (casi) a la misma vez.
{
    FileAppend, % "# " . A_YYYY . "-" . A_MM . "-" . A_DD . " " . A_Hour . ":" . A_Min . ":" . A_Sec . " --> " . "RestoreWinPositions:--> Fichero de posiciones creado hace " . TiempoTranscurrido . " segundos (demasiado reciente): Salvapantallas activado en falso. Abortando..." . " `n", %TEMP%\WinPositions-Log.txt
    TrayTip, RestoreWinPositions, Fichero de posiciones crado hace %TiempoTranscurrido% segundos (demasiado reciente): Salvapantallas activado en falso. Abortando., ,2
    sleep 10000
    Exit 1
}

NumParametros = %0%
If ( NumParametros>0 )
{
    Parametro1 = %1%
}
NumeroDePantallasEsperado:=1    ; El sistema dispone de este número de pantallas en total. No se deben mover ventanas ni grabar sus posiciones si no están encendidas todas.
    ;Nótese que este será el valor por defecto de no ser especificado mediante parámetro en la línea de comandos ni existir %A_WorkingDir%\screens.cfg.
If ( NumParametros<1 )  ; Comprobamos el número de parámetros.
{       ; Si no hay parámetros, capturamos el número de pantallas del fichero de configuración (por defecto en el directorio de ejecución del programa), si existe:
    IfExist, screens.cfg    ; Si existe el fichero de configuración...
    {   ; ... leemos de él el número de pantallas esperado.
        FileReadLine,NumeroDePantallasEsperado,%A_WorkingDir%\screens.cfg,1
        FileAppend, % "# " . A_YYYY . "-" . A_MM . "-" . A_DD . " " . A_Hour . ":" . A_Min . ":" . A_Sec . " --> " . "RestoreWinPositions:--> No se introdujeron parámetros, se utilizará el extraído del fichero de configuración.`n", %TEMP%\WinPositions-Log.txt
    } else
    {
        FileAppend, % "# " . A_YYYY . "-" . A_MM . "-" . A_DD . " " . A_Hour . ":" . A_Min . ":" . A_Sec . " --> " . "RestoreWinPositions:--> No existe el fichero de configuración.`n", %TEMP%\WinPositions-Log.txt
    }
} else
{   ; Si hay parámetros...
    If ( Parametro1 = 0 )   ; si el parámetro es un 0...
    {   ; Ignorar número de monitores
    IgnoreNumPantallas = 1
    FileAppend, % "# " . A_YYYY . "-" . A_MM . "-" . A_DD . " " . A_Hour . ":" . A_Min . ":" . A_Sec . " --> " . "RestoreWinPositions:-> Ignorando número de monitores: se ejecutará el programa sin esperarlos.`n", %TEMP%\WinPositions-Log.txt
    } else
    {   ; si el parámetro es distinto de 0...
        ; ... el parámetro contiene el número de pantallas esperado:
        NumeroDePantallasEsperado = %1%
    }
}
If ( not IgnoreNumPantallas )   ; a menos que se ignore el número de monitores...
{   ; ... añadimos una entrada al log con el número de pantallas necesarias.
    FileAppend, % "# " . A_YYYY . "-" . A_MM . "-" . A_DD . " " . A_Hour . ":" . A_Min . ":" . A_Sec . " --> " . "RestoreWinPositions:--> El sistema debe tener al menos " . NumeroDePantallasEsperado " pantalla(s).`n", %TEMP%\WinPositions-Log.txt
}
; Comprobamos que estén todos los monitores conectados:
SysGet, m, MonitorCount
If ( m < NumeroDePantallasEsperado )    ; Si no están todas las pantallas todavía activas...
{   ; ... esperamos a que se enciendan.
    FileAppend, % "# " . A_YYYY . "-" . A_MM . "-" . A_DD . " " . A_Hour . ":" . A_Min . ":" . A_Sec . " --> " . "RestoreWinPositions:-> Esperando a que el sistema tenga al menos " . NumeroDePantallasEsperado " pantalla(s).`n", %TEMP%\WinPositions-Log.txt
    InicioEspera := A_Now
    TrayTip, RestoreWinPositions, Esperando que estén encendidas %NumeroDePantallasEsperado% pantallas., ,1
}
While ( not IgnoreNumPantallas and m < NumeroDePantallasEsperado )
{
    SysGet, m, MonitorCount
    Ahora := A_Now
    TiempoLimite := 180 ; Tiempo límite en segundos para esperar a que se enciendan todas las pantallas.
    If ( Ahora>InicioEspera+TiempoLimite )
    {   ; Superado tiempo de espera por pantallas.
        FileAppend, % "# " . A_YYYY . "-" . A_MM . "-" . A_DD . " " . A_Hour . ":" . A_Min . ":" . A_Sec . " --> " . "RestoreWinPositions:-> No están listas las " . NumeroDePantallasEsperado . " pantallas transcurrido el tiempo límite. Cancelando la ejecución del programa.`n", %TEMP%\WinPositions-Log.txt
        TrayTip, RestoreWinPositions, Transcurrido tiempo límite (%TiempoLimite% segundos) esperando que estén encendidas %NumeroDePantallasEsperado% pantallas. Abortando., ,2
        sleep 10000
        Exit ,3     ; No están todas las pantallas transcurridos 3 minutos. Cancelamos la ejecución del programa.
    }
}

; Variable para comprobación de que todas las ventanas han sido corréctamente movidas:
Checking := 0
IncorrectPositionWindows := 65536   ; Just to enter the While loop.

; Repetir hasta que ninguna ventana haya tenido que ser movida.
While IncorrectPositionWindows>0
{
    If Checking>0
    {
        FileAppend, % "# " . A_YYYY . "-" . A_MM . "-" . A_DD . " " . A_Hour . ":" . A_Min . ":" . A_Sec . " --> " . "RestoreWinPositions:--> Alguna(s) ventana(s) no estaban en su posición correcta. Revisando; pasada número " . Checking+1 . " ...." . " `n", %TEMP%\WinPositions-Log.txt
    }
    ; Inicializaciones de variables
    CorrectPositionWindows := 0
    IncorrectPositionWindows := 0

    ; Read from the array:
    Loop %ArrayCount%
    {       ; Extraemos línea a línea los datos de cada ventana individual
        Ventana := Array%A_Index%  ; Todos los datos de la ventana serán almacenados en esta variable.
        coma = ,

        ; Extraemos el ID de la ventana.
        Position := InStr(Ventana, coma)
        StringMid, ID, Ventana, 0, Position-1
        StringTrimLeft, Ventana, Ventana, Position
        ; Extraemos la coordenada X de la ventana.
        Position := InStr(Ventana, coma)
        StringMid, x, Ventana, 0, Position-1
        StringTrimLeft, Ventana, Ventana, Position
        ; Extraemos la coordenada Y de la ventana.
        Position := InStr(Ventana, coma)
        StringMid, y, Ventana, 0, Position-1
        StringTrimLeft, Ventana, Ventana, Position
        ; Extraemos el ancho W de la ventana.
        Position := InStr(Ventana, coma)
        StringMid, w, Ventana, 0, Position-1
        StringTrimLeft, Ventana, Ventana, Position
        ; Extraemos el alto H de la ventana.
        Position := InStr(Ventana, coma)
        StringMid, h, Ventana, 0, Position-1
        StringTrimLeft, Ventana, Ventana, Position
        ; Extraemos el título (lo que quede en el string) de la ventana.
        Titulo := Ventana

        WinGetPos,actualx,actualy,actualw,actualh,ahk_id %ID%
        WinGet, WinStatus, MinMax, ahk_id %ID%
        if WinStatus = -1   ; Si la ventana está minimizada...
        {   ; Tratamos de obtener sus coordenadas restauradas sin tener que restaurarla.
            WinGetNormalPos(ID, actualx, actualy, actualw, actualh)
        }

        If (x=actualx and y=actualy and w=actualw and h=actualh)    ; Si la ventana ya tiene sus coordenadas finales...
        {   ; Incrementamos el contador de ventanas que ya estaban en su posición correcta (no ha sido necesario moverla).
            CorrectPositionWindows := ++CorrectPositionWindows
        } else
        {   IfWinExist, ahk_id %ID% ; Actuaremos sobre la ventana tan solo si la ventana existe.
            {   ; Incrementamos el contador de ventanas que no están en su posición correcta (es necesario moverla).
                IncorrectPositionWindows := ++IncorrectPositionWindows
                FileAppend, % "# " . A_YYYY . "-" . A_MM . "-" . A_DD . " " . A_Hour . ":" . A_Min . ":" . A_Sec . " --> " . "RestoreWinPositions:-->  Moviendo ventana " . Titulo . " de coordenadas (X,Y,W,H): " . actualx . "," . actualy . "," . actualw . "," . actualh . " a coordenadas (X,Y,W,H): " . x . "," . y . "," . w . "," . h . "." . " `n", %TEMP%\WinPositions-Log.txt
                If WinStatus = -1   ; Si la ventana está minimizada...
                {   ; No hay más remedio que restaurarla, moverla, y minimizarla de nuevo (No disponemos de métodos para cambiar las coordenadas de restauración para una ventana minimizada).
                    WinRestore, ahk_id %ID%
                    WinMove, ahk_id %ID%, , x, y, w, h
                    WinMinimize, ahk_id %ID%
                } else
                {   ; Si la ventana no está minimizada, nos basta con moverla.
                WinMove, ahk_id %ID%, , x, y, w, h
                }
            } else  ; Si la ventana no existe...
            {   ; prescindimos de actuar sobre esta ventana.
                FileAppend, % "# " . A_YYYY . "-" . A_MM . "-" . A_DD . " " . A_Hour . ":" . A_Min . ":" . A_Sec . " --> " . "RestoreWinPositions:-->  Omitiendo ventana inexistente: " . Titulo . ". `n", %TEMP%\WinPositions-Log.txt
            }
        }
    }
    If Checking>=10 ; ¿Llevamos más de 10 pasadas intentando poner las ventanas en su sitio?
    {   ; Cancelamos
        FileAppend, % "# " . A_YYYY . "-" . A_MM . "-" . A_DD . " " . A_Hour . ":" . A_Min . ":" . A_Sec . " --> " . "RestoreWinPositions:--> Demasiados intentos de ubicar ventanas. Abortando. :-( `n", %TEMP%\WinPositions-Log.txt
        TrayTip, RestoreWinPositions, Demasiados intentos de ubicar ventanas. Abortando. :-( , ,1
        sleep 10000
        Exit 2
    }
    FileAppend, % "# " . A_YYYY . "-" . A_MM . "-" . A_DD . " " . A_Hour . ":" . A_Min . ":" . A_Sec . " --> " . "RestoreWinPositions:-->  Ventanas que ya estaban en su posición correcta: " . CorrectPositionWindows . ". `n", %TEMP%\WinPositions-Log.txt
    FileAppend, % "# " . A_YYYY . "-" . A_MM . "-" . A_DD . " " . A_Hour . ":" . A_Min . ":" . A_Sec . " --> " . "RestoreWinPositions:-->  Ventanas reubicadas: " . IncorrectPositionWindows . ". `n", %TEMP%\WinPositions-Log.txt
    Checking := ++Checking
}
FileAppend, % "# " . A_YYYY . "-" . A_MM . "-" . A_DD . " " . A_Hour . ":" . A_Min . ":" . A_Sec . " --> " . "RestoreWinPositions:--> Ventanas reubicadas corréctamente. Saliendo del programa. :-) `n", %TEMP%\WinPositions-Log.txt
TrayTip, RestoreWinPositions, Ventanas reubicadas corréctamente. Saliendo del programa. :-), ,1
; Beeps report: correctly finished.
    SoundBeep 1500,100
    SoundBeep 1000,100
    SoundBeep 3500,100
sleep 10000


; Funciones utilizadas por el programa.

WinGetNormalPos(hwnd, ByRef x, ByRef y, ByRef w="", ByRef h="")
; Devuelve la posición que tendría la ventana si no estuviera minimizada (posición restaurada).
{
    VarSetCapacity(wp, 44), NumPut(44, wp)
    DllCall("GetWindowPlacement", "uint", hwnd, "uint", &wp)
    x := NumGet(wp, 28, "int")
    y := NumGet(wp, 32, "int")
    w := NumGet(wp, 36, "int") - x
    h := NumGet(wp, 40, "int") - y
}

Sopalajo de Arrierez

Posted 2014-06-17T16:52:47.287

Reputation: 5 328

SourceForge gives a warning: This file may contain malware and the automatic download has been disabled. – Dunc – 2017-01-05T12:15:02.140

Thanks you, @Dunc . I don't know how to solve that SourceForge problem, but I have posted here the source (AHK files). You just need to compile it using AutoHotkey. – Sopalajo de Arrierez – 2017-01-06T23:27:53.323

0

Download winLayout.exe

To save current window positions on multiple monitors run:

winLayout save

To restore window positions:

winLayout restore

It's no frills, just a single .exe file. To make it easy to run, create a task bar short cut for it.

Disclaimer: I am the author.

Phillip Ngan

Posted 2014-06-17T16:52:47.287

Reputation: 1 210

Please do not post the same answer to multiple questions. If the same information really answers both questions, then one question (usually the newer one) should be closed as a duplicate of the other. You can indicate this by voting to close it as a duplicate or, if you don't have enough reputation for that, raise a flag to indicate that it's a duplicate. Otherwise tailor your answer to this question and don't just paste the same answer in multiple places.

– DavidPostill – 2019-08-27T17:18:46.210