Log in

View Full Version : ChangeDisplaySettings


TJM
07-01-2003, 04:42 AM
Originally posted by LordKronos
ChangeDisplaySettings is what I use. Its a core Win32 API function, and exists on all Win32 platforms.

Originally posted by Scorpio
Yeah, I actually used ChangeDisplaySettings when I first added full-screen support...but I didn't get the "free" handling of alt+tab, etc. so I went the DDraw route in the end.
-Scorpio

I'm trying to find information about how implement ChangeDisplaySettings. Can you recommend some sites/links that would have source code or detailed information?

Also, with this function, are you able to change display settings from within your program and then change the display back upon exiting your program?

I'm trying up upgrade all my old games to DirectX but I thought the ChangeDisplaySettings might be a temporary quick fix to get the appropriate display for the games.

LordKronos
07-01-2003, 05:23 AM
The documentation for ChangeDisplaySettings is here:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/devcons_7gz7.asp

All you do is pass it a structure (explained in the documentation) that tells it the resolution, bit depth, refresh rate, etc. As I recall, the flag I pass as the second parameter is CDS_FULLSCREEN. To restore the resolution when you game exits, call ChangeDisplaySettings(NULL,0);

If you want to find out what resolutions are supported, call EnumDisplaySettings.

TJM
07-01-2003, 05:56 AM
Thank you very much.

Scorpio
07-01-2003, 06:12 AM
From my experience with implementing both, they were both equally easy to implement, and only a page of code (or so) for each method.

Additional concerns I had with ChangeDisplaySettings is that if your app crashes, you hose the user and leave them in a resolution other than their desktop resolution.

DDraw full-screen takes care of all of these cases...and it's guaranteed to be their on everything except Win95. Once you're in full-screen, you can still use all your GDI stuff if you're not using DDraw.

Good luck with whichever method you go with.
-Scorpio

TJM
07-01-2003, 06:18 AM
In the long run, I want to use DDraw, but in the short run to get some old games playable again for more users, I'm going to try this ChangeDisplaySettings.

Thx.

LordKronos
07-01-2003, 06:57 AM
Originally posted by Scorpio
Additional concerns I had with ChangeDisplaySettings is that if your app crashes, you hose the user and leave them in a resolution other than their desktop resolution.

Good point. I've had that happen to me more times than I would like to remember. There is a way to deal with this. In most languages, when your app is about to crash you can almost always catch the error in an exception handler, restore the resolution, and the proceed to crash. In C++, something like

try
{
//game goes here
}
catch(...)
{
if (inFullscreenMode) ChangeDisplaySettings(NULL,0);
throw;
}


This will fix the problem in all but the most severe crashes. In fact, I don't know if I've ever had a crash where the exception handler failed to execute (except for those very rare ones that hang the whole computer, but by then I guess it's not very important anymore).

bstone
07-01-2003, 06:20 PM
Posted by LordKronos
This will fix the problem in all but the most severe crashes. In fact, I don't know if I've ever had a crash where the exception handler failed to execute (except for those very rare ones that hang the whole computer, but by then I guess it's not very important anymore).C++ exception handler won’t catch structured exceptions (e.g. access violation). But handling the structured exceptions is not very difficult. You can even translate them to C++ exceptions if you wish.

LordKronos
07-02-2003, 01:31 AM
Originally posted by bstone
C++ exception handler won’t catch structured exceptions (e.g. access violation). But handling the structured exceptions is not very difficult. You can even translate them to C++ exceptions if you wish.

Oh really? The why does the following code:int main(int argc, char* argv[]){
try{
printf((const char*)392033);
}catch(...){
printf("OOPS!");
};
return 0;
}

print out "OOPS!". That's a definite access violation (I even get the standard access violation dialog if I remove the try/catch).

Where you are getting confused is that you can't selectively handle a C++ exception with structured exception handling, nor can you selectively handle a structured exception with C++ typed exception handling. However, you can unselectively handle any type of exception with a "catch(...)" block.

bstone
07-02-2003, 08:44 PM
Posted by LordKronos
Oh really? The why does the following code:


print out "OOPS!". That's a definite access violation (I even get the standard access violation dialog if I remove the try/catch).I see. What you’ve missed is that not everybody uses Microsoft C++ compiler. If you compile that code using Borland C++ or GCC (MinGW port) you’ll get your access violation anyway :) But you are right. MSVC has a limited support for handling structured exceptions the C++ way. Just that I used to messing a lot with Borland C++ in the past and now look into GCC (can’t stand the awful support for templates in MSVC).

Posted by LordKronos
Where you are getting confused is that you can't selectively handle a C++ exception with structured exception handling, nor can you selectively handle a structured exception with C++ typed exception handling. However, you can unselectively handle any type of exception with a "catch(...)" block.Actually, I do “selectively handle a structured exception with C++ typed exception handling” easily. I use a structured exceptions filter to catch and classify structured exceptions, and re-raise them as C++ ones. It’s pretty easy. You should try it :)

LordKronos
07-03-2003, 01:35 AM
I didn't realize it was a MSVC issue. I've seen many "authoratative" websites that passed that off as being a standard feature of C++. :( Myself, I love VC++ and it's great debugging tools, so I guess it's not an issue for me (I have no plans to port to other platforms at this time). Glad you pointed it out though.

Originally posted by bstone
Actually, I do “selectively handle a structured exception with C++ typed exception handling” easily. I use a structured exceptions filter to catch and classify structured exceptions, and re-raise them as C++ ones. It’s pretty easy. You should try it :) Don't need to try it. I know all about it. However, I wouldn't classify it as “selectively handle a structured exception with C++ typed exception handling”. You are handing an SE with SEH. Your handling is to just "translate" the exception to a typed one and then throw it again. I guess it depends on how you define handle, but that wasn't what I was referring to.

TJM
07-04-2003, 06:08 PM
I used ChangeDisplaySettings and have a problem with the button focus when testing the game in Windows 98. I am having to press the button on the title screen that enters the program twice before it will advance.

I searched on the Internet for information related to this problem and found a site that said:

"If you use ChangeDisplaySettings or pDirectDraw-SetDisplayMode then a couple of spurious WM_MOUSEMOVE messages get generated as the mouse settles into its new position. To complicate matters, these messages do not get sent during the mode-change call but after. There are a few possible solutions, all unpleasant: you could count down and ignore the first five WM_MOUSEMOVE messages; or you could ignore all such messages that occur within the five seconds after changing mode. It will help greatly if you use some Debug function to display a record of every single window message that gets sent to your window during the change-mode."

Anyone had any experiences with this? Or better yet, solutions for it?

LordKronos
07-05-2003, 01:40 AM
Not surprisingly, I've never noticed that problem because I ignore WM_MOUSEMOVE messages. The only reason (at least that I can think of ) to use WM_MOUSEMOVE is if you wanted to track relative movement (like in a FPS game, or if you wanted to implement mouse gestures in your UI like Opera and Mozilla do). Other than that, if you just want to know where the mouse is, I use GetCursorPos every frame and it works fine.

TJM
07-05-2003, 02:41 AM
I don't use WM_MOUSEMOVE. The problem is that I have to press twice on the OK button to get off the title screen of the game. It's either a focus problem or it takes two presses for Windows to figure out where the mouse is. I only get the problem to occur on one computer (the operating system is Windows 98); it works fine on three others.

If I move the mouse around on the screen for a few seconds before I hit the button, it works ok. So it seems like Windows can't figure out where the mouse is.

LordKronos
07-05-2003, 02:51 AM
Since the problem is that Windows is confused about the location of the mouse, I wonder what would happen if you call GetCursorPos to get the position, then call SetCursorPos to set it to the same position. I wonder if that would reset whatever code in Windows is causing the problem. Of course, this is assuming that GetCursorPos returns accurate coordinates. And if it doesn't return accurate coordinates, maybe you can just set the cursor pos to the center of the window or screen. After all, you just changed resolution, so I doubt the user would be very distracted by the cursor position changing.

TJM
07-05-2003, 06:23 AM
I tried SetCursorPos to the middle of the window. It didn't work. Note that the button that is taking two presses to response is in a dialog box.

It seems to have a problem with the window being activated. It becomes activated after the first mouse press, thus allowing the second mouse press to take affect. I tried to send it a mouse press, an activate, set focus, and a nchittest... nothing worked. Only a physical mouse press works. I need the operating system to recognize that the program is activated and the mouse is active.

Another thing that I did that caused change was to move the ChangeDisplaySettings function to a different place in my code. When I place it before the Windows initialization, it consistently takes two presses. When I move it after initializing but before the message loop, it only occurs occasionally.

Any ideas?

LordKronos
07-05-2003, 09:21 AM
That's odd. You said you tried sending it an activate. Did you try calling SetForegroundWindow followed by BringWindowToFront (or maybe in the opposite order). I don't know what else to tell you, other than trying different combinations of the other window display functions (ShowWindow, SetActiveWindow, SetWindowPos, and SetWindowPlacement). What makes this bug even more peculiar is that I can't find any mention of it on the MSDN site. Microsoft is usually very good at identifying and documenting bugs like this there.

TJM
07-06-2003, 09:56 AM
I tried all those functions. No results. The only way I got any improvement was to move the ChangeDisplaySettings to inside the dialog box routine. When its in the dialog box routine, it only happens about once every 25 times instead of once every 5 times.

I may just have to live with it. Thanks for your ideas.

Lizardsoft
07-06-2003, 10:31 AM
Hmm that's very interesting TJM. Does the button respond properly if accessed via keyboard instead of mouse? How did you send it a mouse click? Did you use messages or the mouse_event/SendInput functions?

TJM
07-06-2003, 12:27 PM
Yes, the button will respond to the keyboard at all times (even when it will not respond to the mouse). But after advancing past the title screen with the keyword, the first mouse click on the main screen will not work. It loses the first mouse press regardless.

I previously tried sending messages, but I just tried mouse_event and it worked. It's a nice workaround. Thanks a million.

But this is causing another problem. It is jumping out of the program during startup. I don't have the mouse_event in a good location in the code. I'm currently putting it in the dialog box routine which is causing problems.

Do you have a suggestion as to where to put an extraneous mouse press and release (where it will do no harm)?

TJM
07-16-2003, 06:05 PM
Did anyone ever get the alt+tab to work with ChangeDisplaySettings (where it will switch between the user's original higher resolution and the game's lower resolution) or is that impossible?

LordKronos
07-16-2003, 06:14 PM
I have it working. All you have to do is detect the WM_ACTIVATEAPP message. One of the parameters passed with this message will tell you whether your window is gaining or losing focus. If you are gaining focus, just call ChangeDisplaySettings with the resolution you want. If you are losing focus, minimize your window and call ChangeDisplaySettings(NULL,0)

Of course, the more difficult part is usually dealing with directX (reaquiring surfaces, input devices, etc). This may be easy or difficult depending on how you use DirectX (if you use D3DX, I think it might take care of a lot of that for you).

TJM
07-16-2003, 06:34 PM
Yes, that's what I'm doing (detecting the WM_ACTIVATEAPP message). But it's inconsistent. It only works part of the time. Sometimes it doesn't change out of the low res when I alt+tab. It seems to work pretty consistently if I'm alt+tabbing to Notepad or Internet Explorer, but when I'm alt+tabbing to My Computer, it messes up more. It almost always fails when I alt+tab to My Computer. I'm currently testing it on Windows 98. I'm checking on the return errors and it never has an error message, it always says it completes.

Any idea why this is happening?

Scorpio
07-16-2003, 06:40 PM
TJM, I am not sure why you are having these problems, but you might try using DirectDraw instead. The guts of it should only be a couple dozen lines of code (including error checking).

When I made the switch, it only took me about 10 minutes (since I had all the other stuff, such as removing/restoring the window border/menu/caption/etc already working).

My guess is that the time you will spend trying to get ChangeDisplaySettings() to work in all cases will be greater than the time it will take to add DDraw support via SetDisplayMode().

Good luck,
-Scorpio

TJM
07-16-2003, 07:12 PM
I didn't know that you could use DirectDraw with regular GDI. I assumed I would have to use the DirectDraw surfaces and not the regular Windows functions. All I'm wanting to do is change the resolution. I thought the ChangeDisplaySettings would be simpler, but obviously it's not. But I thought I would have to re-write the entire program since my original programs use GDI.

How do you change the resolution with DirectDraw?

Scorpio
07-16-2003, 07:22 PM
Yeah, you can use DDraw just to change the video mode and then use GDI for everything else. That's how our 3 released HipSoft games all work currently (they use our older engine).

Here's some code to help you get started, note that I removed all the error checking and clean-up code for clarity.

// Load the library
m_hLibrary = ::LoadLibrary("ddraw.dll");

// Get the DirectDrawCreate function
m_pCreateFunc = (DIRECTDRAWCREATE)GetProcAddress(m_hLibrary, "DirectDrawCreate");

// Create the direct draw object
LPDIRECTDRAW m_pDirectDraw1;
m_pCreateFunc(NULL, &m_pDirectDraw1, NULL);

// Set the cooperative level
DWORD dwFlags = DDSCL_FULLSCREEN | DDSCL_EXCLUSIVE;
m_pDirectDraw1->SetCooperativeLevel(m_hWnd, dwFlags);

// Get our current bit-depth so we can keep it the same
DDSURFACEDESC Surf;
Surf.dwSize = sizeof(Surf);
m_pDirectDraw1->GetDisplayMode(&Surf);
int nWindowDepth = Surf.ddpfPixelFormat.dwRGBBitCount;

// Set the display mode that we want
m_pDirectDraw1->SetDisplayMode(640, 480, nWindowDepth);

// Make sure we are on the GDI surface
m_pDirectDraw1->FlipToGDISurface();


Hope this helps! :)
-Scorpio

TJM
07-16-2003, 07:54 PM
Thanks a million. I got it working finally. I accomplished more in the past 15 minutes than I have in the past two weeks. I was misunderstanding how DirectDraw works. Thank you for your help.