Stratos: Punto de Encuentro de Desarrolladores

¡Bienvenido a Stratos!

Acceder

Foros





Por qué y cómo evitar que ChangeDisplaySettings() cambie de lugar los iconos?

Iniciado por _Grey, 05 de Febrero de 2009, 05:39:40 PM

« anterior - próximo »

_Grey

Utilizo el ChangeDisplaySettings() para pasar a fullscreen y salir de él, pero una vez de cada muchas me encuentro que al regresar al escritorio los iconos han cambiado de lugar. He buscado por san Google, y parece que es algo más o menos común, pero curiosamente no encuentro por ningún lugar la forma correcta de llamar a ChangeDisplaySettings() para que no haga tal fechoría.

Puede alguien decirme por qué ocurre y como evitarlo?!?!?

Para entrar en fullscreen hago esto:
// Pone la ventana a pantalla completa segun GDI
bool Window::SetFullScreenGDI(int x,int y,ColorMode cm,int hz){ // GDI

bool creada;
DEVMODE ModoPantalla;

// Si no esta creada, la crea
if(!GetProperty(CREATE)){
Create(true);
creada=true;
} else creada=false;

// Pone pantalla completa
ModoPantalla.dmSize = sizeof(DEVMODE); // Tamaño de la estructura
ModoPantalla.dmBitsPerPel = (cm==COLOR8INDEX)?8:(cm==COLOR16RGB)?16:(cm==COLOR16XRGB)?16:(cm==COLOR24RGB)?24:(cm==COLOR32XRGB)?32:(cm==COLOR32ARGB)?32:0;// Profundidad de color
ModoPantalla.dmPelsWidth = x; // Ancho
ModoPantalla.dmPelsHeight = y; // Alto
ModoPantalla.dmDisplayFrequency = hz; // Refresco
ModoPantalla.dmFields = DM_PELSWIDTH | // VALORES A USAR DE LA ESTRUCTURA
DM_PELSHEIGHT |
DM_BITSPERPEL |
DM_DISPLAYFREQUENCY;

// Pone pantalla completa
if(ChangeDisplaySettings(&ModoPantalla,CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL){
// No pudo poner pantalla completa
if(creada) // Se creo en la funcion, la destruye
Destroy();
logMsg("( ~ %d ) ( %s ) Window::SetFullScreen(int x,int y,ColorMode cm,int hz) : fallo el ChangeDisplaySettings() con %dx%dx%s %dHz.",
__LINE__,__FILE__,x,y, (cm==COLOR8INDEX)?"8":(cm==COLOR16RGB)?"16RGB":(cm==COLOR16XRGB)?"16XRGB":(cm==COLOR24RGB)?"24":(cm==COLOR32XRGB)?"32XRGB":(cm==COLOR32XRGB)?"32ARGB":"?(solo son validos COLOR8INDEX,COLOR16RGB,COLOR24RGB,COLOR32XRGB)", hz);
return false;
}

// Guarda valor de Stickykeys
m_skOriginal.cbSize= sizeof (STICKYKEYS);
m_skOriginal.dwFlags = 0;
SystemParametersInfo(SPI_GETSTICKYKEYS,sizeof (STICKYKEYS),&m_skOriginal,0);
// Desactiva Stickykeys
STICKYKEYS stickyOff = m_skOriginal;
stickyOff.dwFlags &=SKF_STICKYKEYSON;
SystemParametersInfo(SPI_SETSTICKYKEYS,sizeof (STICKYKEYS),&stickyOff,0);

// Fuerza estilo WS_POPUP, necesario para ventana a pantalla completa
m_bFullScreen=true;
SetWindowLong(m_hWnd,GWL_STYLE,WS_POPUP);
m_nXFullScreen=x;
m_nYFullScreen=y;
m_cmFullScreen=cm;
m_nHZ=hz;
SetWindowPos(m_hWnd,HWND_TOPMOST/*HWND_TOP*/,0,0,x,y,SWP_SHOWWINDOW); // Se asegura que sea la visible

return true;
}


He puesto también el codigo del Stikykeys y demás por si tiene algo que ver... todo y que lo dudo.

Y para salir de fullscreen hago esto otro:
// Sale de pantalla completa segun GDI
void Window::FullScreenExitGDI(){

if(!m_bFullScreen) return;

// sale de fullscreen
ChangeDisplaySettings(NULL,0);

// Desactiva flag m_bFullScreen(para que funcionen SetSize() y SetPosition())
m_bFullScreen=false;

// Restaura la ventana normalmente
if(GetProperty(CREATE)){
// Restaura estilo,posicion y tamaño de ventana
SetWindowLong(m_hWnd,GWL_STYLE,GetStyleWindow(m_wtWindowType));
SetWindowPos(m_hWnd,HWND_NOTOPMOST,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE|SWP_SHOWWINDOW); // Se asegura que sea la visible
SetPosition(m_uX,m_uY);
SetSize(m_uWidth,m_uHeight);
}

// Restaura valor de stickykeys
SystemParametersInfo(SPI_SETSTICKYKEYS,sizeof (STICKYKEYS),&m_skOriginal,0);

}


Gracias.

[EX3]

Si no se me olvida esta noche o mañana te miro un codigo que tengo en VB6 donde hago el cambio a pantalla completa con GDI repetando la configuracion del escritorio. Asi de memoria creo que habia que agregar un par de flags a la funcion para evitar el problema o quizas usar otra funcion del GDI. Aun asi, podrias usar DirectDraw para aplicar unicamnete el modo de video a pantalla completa y evitar este fallo. Aun estando en sintaxis VB, echa un ojo al codigo de este ejemplo a ver si te sirviera. De todas formas cuando pueda te subo el codigo via GDI (tambien en sintaxis VB6, sorry  ^_^')

Salu2...
José Miguel Sánchez Fernández
.NET Developer | Game Programmer | Unity Developer

Blog | Game Portfolio | LinkedIn | Twitter | Itch.io | Gamejolt

Pogacha

La verdad es que no estoy seguro, pero fijate estas son las propiedades de la ventana que yo uso:

if( Get_FullScreen() )
{
dwExStyle = WS_EX_APPWINDOW;
dwStyle = WS_POPUP | WS_VISIBLE| WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
}
else
{
dwExStyle = WS_EX_CLIENTEDGE;
dwStyle = WS_MINIMIZEBOX | WS_SYSMENU | WS_BORDER | WS_CAPTION | WS_VISIBLE| [b]WS_CLIPSIBLINGS | WS_CLIPCHILDREN[/b];
}


Ademas yo pongo las propiedades de la ventana antes de cambiar a modo fullscreen cosa que tape todo, no se si eso influira.
Seguramente nada de esto solucionara tu problema :(

Suerte :P

_Grey

Por lo poco que se es cosa de ChangeDisplaySettings(), no de los flags de la ventana, pero no encuentro la forma correcta de llamarla. Es más, en mucho codigo que se puede encontrar por internet se llama exactamente como yo hago, lo que me recuerda que más de uno y de dos programillas freeware o incluso share te hace la "broma" de trastocarte el escritorio.
Respecto a hacerlo con las DirectX... bueno, también trabaja a nivel de Dx sin tal problema, pero lo tengo hecho de tal manera que pueda funcionar sin Dx usando rutinas por soft y GDI, y claro, ahí no puedo usar SetDisplayMode() sino las funciones de la API de Windows.

Supongo que el código de [EX3] podra ayudar, que esté en VB6 no debería ser problema mientra se vea la llamada y demás.

Gracias a los dos por vuestro tiempo.

[EX3]

Wenas. Aqui traigo el codigo que mencionaba, este tambien usa ChangeDisplaySettings():
Código (vbnet) [Seleccionar]
Option Explicit

Const WM_DISPLAYCHANGE = &H7E
Const HWND_BROADCAST = &HFFFF&
Const CCDEVICENAME = 32
Const CCFORMNAME = 32
Const DM_BITSPERPEL = &H40000
Const DM_PELSWIDTH = &H80000
Const DM_PELSHEIGHT = &H100000
Const CDS_TEST = &H4
Const CDS_FULLSCREEN As Long = &H4
Const DISP_CHANGE_SUCCESSFUL = 0
Const DISP_CHANGE_RESTART = 1
Const BITSPIXEL = 12

Private Type DEVMODE
    dmDeviceName As String * CCDEVICENAME
    dmSpecVersion As Integer
    dmDriverVersion As Integer
    dmSize As Integer
    dmDriverExtra As Integer
    dmFields As Long
    dmOrientation As Integer
    dmPaperSize As Integer
    dmPaperLength As Integer
    dmPaperWidth As Integer
    dmScale As Integer
    dmCopies As Integer
    dmDefaultSource As Integer
    dmPrintQuality As Integer
    dmColor As Integer
    dmDuplex As Integer
    dmYResolution As Integer
    dmTTOption As Integer
    dmCollate As Integer
    dmFormName As String * CCFORMNAME
    dmUnusedPadding As Integer
    dmBitsPerPel As Integer
    dmPelsWidth As Long
    dmPelsHeight As Long
    dmDisplayFlags As Long
    dmDisplayFrequency As Long
End Type

Private Declare Function EnumDisplaySettings Lib "user32" Alias "EnumDisplaySettingsA" (ByVal lpszDeviceName As Long, ByVal iModeNum As Long, lpDevMode As Any) As Boolean
Private Declare Function ChangeDisplaySettings Lib "user32" Alias "ChangeDisplaySettingsA" (lpDevMode As Any, ByVal dwFlags As Long) As Long
Private Declare Function GetDeviceCaps Lib "gdi32" (ByVal hdc As Long, ByVal nIndex As Long) As Long
Private Declare Function CreateDC Lib "gdi32" Alias "CreateDCA" (ByVal lpDriverName As String, ByVal lpDeviceName As String, ByVal lpOutput As String, ByVal lpInitData As Any) As Long
Private Declare Function DeleteDC Lib "gdi32" (ByVal hdc As Long) As Long
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long

Dim OldX As Long, OldY As Long, nDC As Long
Dim Bpp As Long
Dim IsRestore As Boolean

Public Width As Long, Height As Long

Public Function ChangeRes(X As Long, Y As Long) As Boolean
    Dim DevM As DEVMODE, ScInfo As Long, erg As Long, an As VbMsgBoxResult
   
    'Get the info into DevM
    erg = EnumDisplaySettings(0&, 0&, DevM)
   
    'This is what we're going to change
    DevM.dmFields = DM_PELSWIDTH Or DM_PELSHEIGHT Or DM_BITSPERPEL
    DevM.dmPelsWidth = X 'ScreenWidth
    DevM.dmPelsHeight = Y 'ScreenHeight
    DevM.dmBitsPerPel = Bpp 'Bits '(can be 8, 16, 24, 32 or even 4)
   
    'Now change the display and check if possible
    erg = ChangeDisplaySettings(DevM, CDS_TEST)
   
    'Check if succesfull
    Select Case erg&
        Case DISP_CHANGE_SUCCESSFUL
            erg = ChangeDisplaySettings(DevM, CDS_FULLSCREEN)
            ScInfo = Y * 2 ^ 16 + X
            'Notify all the windows of the screen resolution change
            SendMessage HWND_BROADCAST, WM_DISPLAYCHANGE, ByVal Bpp, ByVal ScInfo
            ' Everything's ok:
            ChangeRes = True
        Case Else
            ' Mode not supported:
            ChangeRes = False
    End Select
End Function

Private Sub Class_Initialize()
    'KPD-Team 1999
    'URL: http://www.allapi.net/
    'E-Mail: KPDTeam@Allapi.net
    Dim nDC As Long
   
    'retrieve the screen's resolution
    OldX = Screen.Width / Screen.TwipsPerPixelX
    OldY = Screen.Height / Screen.TwipsPerPixelY
   
    'Create a device context, compatible with the screen
    nDC = CreateDC("DISPLAY", vbNullString, vbNullString, ByVal 0&)
    Bpp = GetDeviceCaps(nDC, BITSPIXEL)
End Sub

Private Sub class_Terminate()
    If Not IsRestore Then Restore
End Sub

Public Sub Restore()
    'restore the screen resolution
    ChangeRes OldX, OldY ', GetDeviceCaps(nDC, BITSPIXEL)
    'delete our device context
    DeleteDC nDC
   
    IsRestore = True
End Sub


No soy experto en la materia pero me imagino que el truco estara en la parte en que llama a SendMessage para notificar a Windows del cambio de resolucion de pantalla. Una cosa. Acabo de probar el codigo para ver que exactamente respeta la configuracion de iconos del escritorio, cosa que cumple, pero el programa se me queda colgado. No se si es cosa de Visual Basic o quizas de alguna llamada mal hecha en el codigo.

Cita de: _Grey en 06 de Febrero de 2009, 10:04:15 PM
Respecto a hacerlo con las DirectX... bueno, también trabaja a nivel de Dx sin tal problema, pero lo tengo hecho de tal manera que pueda funcionar sin Dx usando rutinas por soft y GDI, y claro, ahí no puedo usar SetDisplayMode() sino las funciones de la API de Windows.
Hombre, el codigo que te decia por DDraw solo aplica el modo de video, pero no te impide renderizar con Direct3D, OpenGL o GDI por lo que podria ser igualmente valido para la parte por soft que quieres implementar.

Ya me cuentas si te funciono :)

Salu2...
José Miguel Sánchez Fernández
.NET Developer | Game Programmer | Unity Developer

Blog | Game Portfolio | LinkedIn | Twitter | Itch.io | Gamejolt

_Grey

Me cuesta creer, pero por más que fuerzo el programa con cambios de fullscreen a ventana y viciversa ¡me respeta los iconos!.

El problema me estaba minando en cantidad, sólo encontraba gente desahogándose contra la documentación de Microsoft, o comformándose con que era problema de la API de Win. En la documentación advierten del problema, invitándote a llamar a la función desde otro Thread sin HWND asociado a él, pero después de hacerlo seguía ocurriendo. Hasta ahora!
Tus sospechas parecen ser ciertas, ha bastado con el SendMessage para despistar a Windows y que no hiciera de las suyas.

Gracias mil !!.

[EX3]

José Miguel Sánchez Fernández
.NET Developer | Game Programmer | Unity Developer

Blog | Game Portfolio | LinkedIn | Twitter | Itch.io | Gamejolt






Stratos es un servicio gratuito, cuyos costes se cubren en parte con la publicidad.
Por favor, desactiva el bloqueador de anuncios en esta web para ayudar a que siga adelante.
Muchísimas gracias.