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).
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<Window*>(reinterpret_cast<CREATESTRUCT*>(lParam)->lpCreateParams);
//::SetWindowLong(Wnd,GWL_USERDATA,reinterpret_cast<LONG_PTR>(Win));
::SetWindowLongPtr(Wnd,GWLP_USERDATA,reinterpret_cast<LONG_PTR>(Win));
}
else
{
Win=reinterpret_cast<Window*>(GetWindowLongPtr(Wnd,GWLP_USERDATA));
}
switch(Msg)
{
case WM_ACTIVATE:
{
Win->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->Keys[wParam]=true;
return 0;
}
case WM_KEYUP:
{
Win->Keys[wParam]=false;
return 0;
}
case WM_SYSKEYDOWN:
{
Win->SysKeys[wParam]=true;
return 0;
}
case WM_SYSKEYUP:
{
Win->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->Width=Width;
this->Height=Height;
this->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); // <-- 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)