ChangeDisplaySettings(NULL,0) returns DISP_CHANGE_RESTART (on ATI?)

Hi,
I have this strange problem on my laptop* where calling

ChangeDisplaySettings(NULL,0)

returns DISP_CHANGE_RESTART (and does NOT change the display settings back to normal, but when the application closes it DOES). :confused:

At first I thougth I was doing something wrong with the Win32 API, so I wrote this “small” test program. But it seems to work on all other computers I have access to (Combinations of XPPro, XPHome, Win2K / NVidia gf fx, gf4, Intel Extreme / Desktops, Laptops).

What do you think? I would be very thankful for any hints.

*DELL Inspiron 8500, WinXP Home, ATI Mobility Radeon 9000 (Newest Drivers)

Here’s my code:
(Based on NeHe’s tutorials.
The commented out stuff are things I found while searching the archives of this and other forums, but nothing really helped)
</font><blockquote><font size=“1” face=“Verdana, Arial”>code:</font><hr /><pre style=“font-size:x-small; font-family: monospace;”>#include <windows.h>
#include <gl\gl.h>
#include <stdexcept>
#include <iostream>

class Window
{
HDC DC;
HGLRC RC;
HWND Wnd;
HINSTANCE Instance;
DEVMODE DMsaved;

bool		Keys[256];
bool		SysKeys[256];
bool		isActive;
bool		isFullscreen;
bool		isOpen;
int			Width;
int			Height;
int 		Bits;

static LRESULT CALLBACK WndProc(HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
	Window *Win;
	if(Msg==WM_NCCREATE)
	{
		Win=reinterpret_cast&lt;Window*&gt;(reinterpret_cast&lt;CREATESTRUCT*&gt;(lParam)-&gt;lpCreateParams);
		//::SetWindowLong(Wnd,GWL_USERDATA,reinterpret_cast&lt;LONG_PTR&gt;(Win));
		::SetWindowLongPtr(Wnd,GWLP_USERDATA,reinterpret_cast&lt;LONG_PTR&gt;(Win));
	}
	else
	{
		Win=reinterpret_cast&lt;Window*&gt;(GetWindowLongPtr(Wnd,GWLP_USERDATA));
	}

	switch(Msg)
	{
		case WM_ACTIVATE:
		{
			Win-&gt;isActive=(!HIWORD(wParam));
			return 0;
		}
		case WM_SYSCOMMAND:
		{
			switch (wParam)
			{
				case SC_SCREENSAVE:
				case SC_MONITORPOWER:
				return 0;
			}
			break;
		}
		case WM_CLOSE:
		{
			::PostQuitMessage(0);
			return 0;
		}
		case WM_KEYDOWN:
		{
			Win-&gt;Keys[wParam]=true;
			return 0;
		}
		case WM_KEYUP:
		{
			Win-&gt;Keys[wParam]=false;
			return 0;
		}
		case WM_SYSKEYDOWN:
		{
			Win-&gt;SysKeys[wParam]=true;
			return 0;
		}
		case WM_SYSKEYUP:
		{
			Win-&gt;SysKeys[wParam]=false;
			return 0;
		}
	}
	return ::DefWindowProc(Wnd,Msg,wParam,lParam);
}

void EnterFullscreenHelper()
{
	DEVMODE DisplayMode;
	memset(&DisplayMode,0,sizeof(DisplayMode));
	DisplayMode.dmSize=sizeof(DisplayMode);
	DisplayMode.dmPelsWidth		= Width;
	DisplayMode.dmPelsHeight	= Height;
	DisplayMode.dmBitsPerPel	= Bits;
	DisplayMode.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;

	switch(::ChangeDisplaySettings((DEVMODE*)&DisplayMode,CDS_FULLSCREEN))
	{
	case DISP_CHANGE_SUCCESSFUL: break;
	case DISP_CHANGE_BADFLAGS: throw std::runtime_error("EnterFullscreen failed: An invalid set of flags was passed in.");
	case DISP_CHANGE_BADMODE: throw std::runtime_error("EnterFullscreen failed: The graphics mode is not supported. ");
	case DISP_CHANGE_BADPARAM: throw std::runtime_error("EnterFullscreen failed: An invalid parameter was passed in. This can include an invalid flag or combination of flags. ");
	case DISP_CHANGE_FAILED: throw std::runtime_error("EnterFullscreen failed: The display driver failed the specified graphics mode. ");
	case DISP_CHANGE_NOTUPDATED: throw std::runtime_error("EnterFullscreen failed: Windows NT/2000/XP: Unable to write settings to the registry. ");
	case DISP_CHANGE_RESTART: throw std::runtime_error("EnterFullscreen failed: The computer must be restarted in order for the graphics mode to work. ");
	default: throw std::runtime_error("EnterFullscreen failed: Reason Unknown.");
	};

	::ShowCursor(0);
	isFullscreen=true;
}

void LeaveFullscreenHelper()
{
	isFullscreen=false;
	switch(::ChangeDisplaySettings(NULL,0))

// switch(::ChangeDisplaySettings(&DMsaved,0))
{
case DISP_CHANGE_SUCCESSFUL: break;
case DISP_CHANGE_BADFLAGS: throw std::runtime_error(“LeaveFullscreen failed: An invalid set of flags was passed in.”);
case DISP_CHANGE_BADMODE: throw std::runtime_error("LeaveFullscreen failed: The graphics mode is not supported. ");
case DISP_CHANGE_BADPARAM: throw std::runtime_error("LeaveFullscreen failed: An invalid parameter was passed in. This can include an invalid flag or combination of flags. ");
case DISP_CHANGE_FAILED: throw std::runtime_error("LeaveFullscreen failed: The display driver failed the specified graphics mode. ");
case DISP_CHANGE_NOTUPDATED: throw std::runtime_error("LeaveFullscreen failed: Windows NT/2000/XP: Unable to write settings to the registry. ");
case DISP_CHANGE_RESTART: throw std::runtime_error("LeaveFullscreen failed: The computer must be restarted in order for the graphics mode to work. ");
default: throw std::runtime_error(“LeaveFullscreen failed: Reason Unknown.”);
};
/* if(!::ChangeDisplaySettings(NULL,CDS_TEST))
{
::ChangeDisplaySettings(NULL,CDS_RESET);
::ChangeDisplaySettings(&DMsaved,CDS_RESET);
}
else
{
::ChangeDisplaySettings(NULL,CDS_RESET);
}*/
::ShowCursor(1);
}

public:
Window()
:RC(0),DC(0),Wnd(0),Instance(0),isOpen(false),isActive(true),isFullscreen(true)
{
for(int i=0;i<256;i++)SysKeys[i]=Keys[i]=false;
}
~Window()
{
Close();
}

void Open(char* Title, int Width, int Height, int Bits, bool tryFullscreen)
{
	this-&gt;Width=Width;
	this-&gt;Height=Height;
	this-&gt;Bits=Bits;

	RECT		WindowRect;
	WindowRect.left=(long)0;
	WindowRect.right=(long)Width;
	WindowRect.top=(long)0;
	WindowRect.bottom=(long)Height;

	Instance			= GetModuleHandle(NULL);

	WNDCLASS	wc;
	wc.style			= CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
	wc.lpfnWndProc		= (WNDPROC) WndProc;
	wc.cbClsExtra		= 0;
	wc.cbWndExtra		= 0;
	wc.hInstance		= Instance;
	wc.hIcon			= LoadIcon(NULL, IDI_WINLOGO);
	wc.hCursor			= LoadCursor(NULL, IDC_ARROW);
	wc.hbrBackground	= NULL;
	wc.lpszMenuName		= NULL;
	wc.lpszClassName	= "OpenGL";
	if(!::RegisterClass(&wc)) throw std::runtime_error("Failed To Register The Window Class.");

	if(!::EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &DMsaved)) throw std::runtime_error("Failed To Enumerate The Display Settings.");
	
	isFullscreen=false;
	if(tryFullscreen) EnterFullscreenHelper();

	DWORD ExStyle;
	DWORD Style;
	if(isFullscreen)
	{
		ExStyle=WS_EX_APPWINDOW;
		Style=WS_POPUP;
	}
	else
	{
		ExStyle=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
		Style=WS_OVERLAPPEDWINDOW;
	}
	::AdjustWindowRectEx(&WindowRect, Style, FALSE, ExStyle);

	if (!(Wnd=::CreateWindowEx(	ExStyle,
								"OpenGL",
								Title,
								Style /*| WS_CLIPSIBLINGS | WS_CLIPCHILDREN*/,
								0, 0,
								WindowRect.right-WindowRect.left,
								WindowRect.bottom-WindowRect.top,
								NULL,
								NULL,
								Instance,
								this)))
	{
		throw std::runtime_error("Window Creation Error.");
	}

	PIXELFORMATDESCRIPTOR pfd=
	{
		sizeof(PIXELFORMATDESCRIPTOR),
		1,
		PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
		PFD_TYPE_RGBA,
		Bits,
		0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0,PFD_MAIN_PLANE,0,0,0,0
	};

	if(!(DC=::GetDC(Wnd)))
	{
		throw std::runtime_error("Can't Create A GL Device Context.");
	}

	GLuint PixelFormat;
	if(!(PixelFormat=::ChoosePixelFormat(DC,&pfd)))
	{
		throw std::runtime_error("Can't Find A Suitable PixelFormat.");
	}

	if(!::SetPixelFormat(DC,PixelFormat,&pfd))
	{
		throw std::runtime_error("Can't Set The PixelFormat.");
	}

	if(!(RC=::wglCreateContext(DC)))
	{
		throw std::runtime_error("Can't Set The PixelFormat.");
	}

	if(!::wglMakeCurrent(DC,RC))
	{
		throw std::runtime_error("Can't Set The PixelFormat.");
	}
	::ShowWindow(Wnd,SW_SHOW);
	::SetForegroundWindow(Wnd);
	::SetFocus(Wnd);
	isOpen=true;
}

void Close()
{
	if(!isOpen)return;
	isOpen=false;
	if(isFullscreen)
	{
		LeaveFullscreenHelper();
	}

	if(RC)
	{
		if(!::wglMakeCurrent(NULL,NULL))
		{
			throw std::runtime_error("Release Of DC And RC Failed.");
		}

		if(!::wglDeleteContext(RC))
		{
			throw std::runtime_error("Release Rendering Context Failed.");
		}
		RC=0;
	}

	if(DC&&!::ReleaseDC(Wnd,DC))
	{
		throw std::runtime_error("Release Device Context Failed.");
		DC=0;
	}

	if(Wnd&&!::DestroyWindow(Wnd))
	{
		throw std::runtime_error("Could Not Release hWnd.");
		Wnd=0;
	}

	if(!::UnregisterClass("OpenGL",Instance))
	{
		throw std::runtime_error("Could Not Unregister Class.");
		Instance=0;
	}
}

bool Tick()
{
	bool done=false;
	MSG msg;
	while(PeekMessage(&msg,NULL,0,0,PM_REMOVE))
	{
		if (msg.message==WM_QUIT)
		{
			done=true;
		}
		else
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
	}
	return done;
}

void ToggleFullscreen()
{
	int Style,ExStyle;
	if(isFullscreen)
	{
		LeaveFullscreenHelper();
		
		ExStyle=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
		Style=WS_OVERLAPPEDWINDOW/*|WS_VISIBLE*/;
	}
	else
	{
		EnterFullscreenHelper();

		ExStyle=WS_EX_APPWINDOW/*|WS_EX_TOPMOST*/;
		Style=WS_POPUP/*|WS_VISIBLE*/;
	}

	::ShowWindow(Wnd,SW_HIDE);	// &lt;-- This keeps Desktop from getting "dirty" on W2k.

	::SetWindowLongPtr(Wnd,GWL_STYLE,Style);
	::SetWindowLongPtr(Wnd,GWL_EXSTYLE,ExStyle);

	if(!::SetWindowPos(Wnd,
		isFullscreen?HWND_TOPMOST:HWND_NOTOPMOST,
		0,0,Width,Height,
		/*SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|*/SWP_NOCOPYBITS|SWP_SHOWWINDOW|SWP_FRAMECHANGED))
	{
		throw std::runtime_error("SetWindowPos failed.");
	}
}

bool isInFullscreen() { return isFullscreen; }
bool isKeyPressed(int i) { return Keys[i]; }
bool isSysKeyPressed(int i) { return SysKeys[i]; }
void AvoidRepeatingKey(int i) { Keys[i]=false; }
void AvoidRepeatingSysKey(int i) { SysKeys[i]=false; }
void Flip() { SwapBuffers(DC); }

};

#ifdef _WINDOWS
int WINAPI WinMain( HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
#else
int main(void)
#endif
{
try
{
Window Win;
Win.Open("[25] Press Alt-Enter to toggle fullscreen mode.",800,600,32,(MessageBox(NULL,“Would You Like To Start In Fullscreen Mode?”, “Start FullScreen?”,MB_YESNO|MB_ICONQUESTION)==IDYES));

	int Frame=0;
	while(!Win.Tick())
	{
		Frame++;
		glClearColor((Frame&1023)/1023.0f,Win.isInFullscreen()?1.0f:0.0f,0.0f,0.0f);
		glClear(GL_COLOR_BUFFER_BIT);
		Win.Flip();

		if(Win.isKeyPressed(VK_ESCAPE)

Hmm… Somehow the forum ate the last 20 lines of the code…
</font><blockquote><font size=“1” face=“Verdana, Arial”>code:</font><hr /><pre style=“font-size:x-small; font-family: monospace;”>//… continued from last message

#ifdef _WINDOWS
int WINAPI WinMain( HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
#else
int main(void)
#endif
{
try
{
Window Win;
Win.Open("[25] Press Alt-Enter to toggle fullscreen mode.",800,600,32,(MessageBox(NULL,“Would You Like To Start In Fullscreen Mode?”, “Start FullScreen?”,MB_YESNO|MB_ICONQUESTION)==IDYES));

	int Frame=0;
	while(!Win.Tick())
	{
		Frame++;
		glClearColor((Frame&1023)/1023.0f,Win.isInFullscreen()?1.0f:0.0f,0.0f,0.0f);
		glClear(GL_COLOR_BUFFER_BIT);
		Win.Flip();

		if(Win.isKeyPressed(VK_ESCAPE)

:eek: Strange. (Preview looked fine)

Before I make a complete fool of myself (too late I guess :smiley: ) here is a link to the source

[edit]
( :confused: Just to clarify: samv==Rumzeus. Yes, I was already registered and logged in under this account when I posted the first two messages :confused: )[\edit]

While playing around whith the code some more I found that destroying and recreating the rendering context seems to help. The only problem remaining is that the computer completely freezes for 5 seconds :frowning:

Is this “normal”? A crappy driver? Am I misusing the API?

My only thought for this behaviour is either that the driver does have a bug or your display properties are set for changes to occur at restart rather than immediate.

Open Display Properties dialog and verify the setting you have for Settings/Advanced/General/Compatibility is set to “Apply the new display settings without restarting”.

If that is set you should verify that you have the latest ATI drivers or Dell 8500 ATI Mobility Radeon 9000 drivers installed. And if all else fails contact Dell and/or ATI.

Wow, I didn’t actually know that setting existed. Thank you for that info. Unfortunately it is not the problem, as it is set to “Apply the new display setting without restarting”.

Could anyone who owns an ATI mobility radeon 9000 (or even any ATI card) try to compile this and test if it fails? (Alt-Enter causes CDSTest.cpp to throw an exception / CDSTest2.cpp to freeze for 5 seconds) I could also provide exe files if that’s preferred.

The strange thing is, (some) other applications/games do not have this problem…

Small update: really seems like an ATI problem. Another laptop with a radeon mobility has the same problem. (Updating the drivers slightly changed the behaviour, but didn’t fix it).

Just pretending anyone out there cares :rolleyes:

Another (non-dell) mobility radeon (9200) laptop has no problem at all with this…

A problem with dell’s drivers?

Just wondering: Does anyone know in what way / to which degree laptop manufacturers customize video drivers?

This topic was automatically closed 183 days after the last reply. New replies are no longer allowed.