HWND value woes! (Windowed-Fullscreen) **SOLVED**

Started by
3 comments, last by Spinewire 15 years, 9 months ago
Hi everyone, I'm trying to add the functionality to toggle a fullscreen/windowed mode in my current DirectX 9 project. Unfortunately, whenever I try to do this, I get an access violation. Based off of tutorials at http://www.chadvernon.com/blog/tutorials/directx9/, I build my presentation parameters as follows:

BOOL BuildPresentParameters( int width, int height )
{
    ZeroMemory( &m_pp, sizeof(m_pp) );
	D3DFORMAT adapterFormat = (m_Windowed) ? m_displayMode.Format : D3DFMT_X8R8G8B8;
    if ( SUCCEEDED( m_pD3D9->CheckDeviceFormat( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, adapterFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, D3DFMT_D24S8 ) ) )
    {
        m_pp.AutoDepthStencilFormat = D3DFMT_D24S8;
    }
    else if ( SUCCEEDED( m_pD3D9->CheckDeviceFormat( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, adapterFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, D3DFMT_D24X8 ) ) )
    {
        m_pp.AutoDepthStencilFormat = D3DFMT_D24X8;
    }
    else if ( SUCCEEDED( m_pD3D9->CheckDeviceFormat( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, adapterFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, D3DFMT_D16 ) ) )
    {
        m_pp.AutoDepthStencilFormat = D3DFMT_D16;
    }
	else
	{
        SHOWERROR( "Unable to find valid depth format", __FILE__, __LINE__ );
		return FALSE;
	}

	m_pp.BackBufferWidth            = (m_Windowed) ? 0 : width;   //m_displayMode.Width;
	m_pp.BackBufferHeight           = (m_Windowed) ? 0 : height;  //m_displayMode.Height;
    m_pp.BackBufferFormat           = adapterFormat;
    m_pp.BackBufferCount            = 1;
    m_pp.MultiSampleType            = D3DMULTISAMPLE_NONE;
    m_pp.MultiSampleQuality         = 0;
    m_pp.SwapEffect                 = D3DSWAPEFFECT_DISCARD; 
    m_pp.hDeviceWindow              = m_hWnd;
    m_pp.Windowed                   = m_Windowed;
    m_pp.EnableAutoDepthStencil     = true; 
	m_pp.FullScreen_RefreshRateInHz = (m_Windowed) ? 0 : m_displayMode.RefreshRate;
    m_pp.PresentationInterval       = D3DPRESENT_INTERVAL_IMMEDIATE;

	return TRUE;
} // BuildPresentParameters()







At that point, when I later call "m_pDevice->Reset( &m_pp );" I get that access violation. Now, I'm not throwing everything into your lap here. I've done some debugging of my own, and I think I've narrowed down the problem to the "hDeviceWindow" setting in the present parameters, and, more specifically, my m_hWnd value. This is the code I use to create it:

BOOL Initialize( LPSTR title, HINSTANCE hInstance, int width, int height, BOOL windowed )
{
    m_hInstance    = hInstance;
    m_WindowWidth  = width;
    m_WindowHeight = height;

    // Define the window
    WNDCLASSEX wcex;
    wcex.cbSize         = sizeof( WNDCLASSEX ); 
    wcex.style          = CS_DBLCLKS;
    wcex.lpfnWndProc    = (WNDPROC)IFramework::StaticWndProc;
    wcex.cbClsExtra     = 0;
    wcex.cbWndExtra     = 0;
    wcex.hInstance      = hInstance;
    wcex.hIcon          = LoadIcon( hInstance, MAKEINTRESOURCE( IDI_CGPICON ) );
    wcex.hCursor        = LoadCursor( NULL, IDC_ARROW );
    wcex.hbrBackground  = (HBRUSH) GetStockObject( BLACK_BRUSH );
    wcex.lpszMenuName   = NULL;
    wcex.lpszClassName  = title;
    wcex.hIconSm        = LoadIcon( hInstance, MAKEINTRESOURCE( IDI_CGPICON_SMALL ) );

    // Register the window
    RegisterClassEx( &wcex );

    // Create the window
    m_hWnd = CreateWindowEx( NULL,
			  title, 
		           title,  
			  windowed ? ( WS_OVERLAPPEDWINDOW & ( ~( WS_THICKFRAME | WS_MAXIMIZEBOX ) ) ) : WS_EX_TOPMOST, 
			  CW_USEDEFAULT, 
                             CW_USEDEFAULT, 
			  width, 
			  height, 
			  NULL, 
			  NULL, 
			  hInstance,
			  this );
    
    // Adjust to desired size
    RECT rect = { 0, 0, width, height };
    AdjustWindowRect( &rect, GetWindowLong( m_hWnd, GWL_STYLE ), FALSE );
    SetWindowPos( m_hWnd, HWND_TOP, 0, 0, rect.right - rect.left, rect.bottom - rect.top, 
        SWP_NOZORDER | SWP_NOMOVE  );

    // ... Unimportant code here.

} // Initialize()





When I debug that code, I find that my hWnd's "unused" value is undefined (with the code CXX0030), even right after it's set by CreateWindowEx(). I know from comparing it to previous projects, which have that unused value set to zero, something is wrong here. I've also noticed that the access violation is also always in the address equal to the hexidecimal value of that unused value. My question to you all is what I could be doing for this unused value to be set to something other than zero, and if that value is undefined the entire time, why does my game only crash when I try to reset the device, rather than when I initialize it for the first time? I also could be completely off-base, and the access violation when resetting could be from something entirely different, but this is my hunch. Any help would be appreciated! Thank you! [Edited by - Spinewire on July 10, 2008 7:01:34 PM]
Advertisement
My guess is that you've deleted the class that contains the device and present params. Failing that, your device pointer is null.
The HWND's unused value isn't anything useful to look at at all, it's only there to prevent you assigning a HBRUSH to a HWND or whatever (Since all Win32 handle types are the size of a pointer).

Your application shouldn't crash when dealing with invalid window handles, all the Win32 functions will return an error instead of crash when given a bad handle, and the same with the D3D functions.
Hm. No, I've been debugging the values that go into the presentation parameters and the only glaringly invalid value is the strange uninitialized-looking "unused" value for the hWnd, which flags the CXX0030 error in VS08 (and, I had thought, the subsequent access violation trying to modify memory at address 0x00000030, or are they unrelated?). The device pointer is valid, and points to the same area in memory that it does then the device is created. Same for the present parameters. They all show more or less valid values.

My only other idea is that the device is being reset multiple times for just one switch between fullscreen and windowed mode, which is consistent with what I've seen while setting breakpoints. Are there any messages, such as WM_SIZE that would be dispatched inadvertently during an operation like this that my WndProc function might be responding to? Or is the device lost during the transition between the two modes? I'm not 100% sure what's happening behind the scenes when I reset the device like this, and my research hasn't been completely informative.

This is the actual Reset function in the class containing it:

HRESULT Reset( int width, int height ){    if ( m_pDevice )    {        if ( !BuildPresentParameters( width, height ) )        {            return E_FAIL;        }        return m_pDevice->Reset( &m_pp );    }    return E_ABORT;} // Reset()


This is the WM_SIZE section of my WndProc (again, as per the tutorials I mentioned earlier):

    case WM_SIZE:        if ( wParam == SIZE_MINIMIZED )        {            // Disable application on minimized            m_Active = FALSE;        }         else        {            m_Active       = TRUE;            m_WindowWidth  = LOWORD( lParam );            m_WindowHeight = HIWORD( lParam );            if ( m_pGraphics->GetDevice() )            {                OnLostDevice();                // Reset() is where the present parameters are made and the device                // is reset, as per the code above                m_pGraphics->Reset( m_WindowWidth, m_WindowHeight );                OnResetDevice();                OnUpdateFrame();                OnRenderFrame();            }        }        return 0;


I've really been boggling over this. Any more guidance would be wonderful!
Quote:Original post by Spinewire
Hm. No, I've been debugging the values that go into the presentation parameters and the only glaringly invalid value is the strange uninitialized-looking "unused" value for the hWnd, which flags the CXX0030 error in VS08 (and, I had thought, the subsequent access violation trying to modify memory at address 0x00000030, or are they unrelated?). The device pointer is valid, and points to the same area in memory that it does then the device is created. Same for the present parameters. They all show more or less valid values.
The only relevant thing for the HWND is the value of the pointer, not the unused parameter. For instance, I see:
m_hWnd 0x000c13ae {unused=??? }
Which means 0x000c13ae is the HWND value. The unused member is unused, it's just a debugging aid to stop you from assigning a HBRUSH to a HWND or whatever. You can completely ignore it.

Quote:Original post by Spinewire
My only other idea is that the device is being reset multiple times for just one switch between fullscreen and windowed mode, which is consistent with what I've seen while setting breakpoints. Are there any messages, such as WM_SIZE that would be dispatched inadvertently during an operation like this that my WndProc function might be responding to? Or is the device lost during the transition between the two modes? I'm not 100% sure what's happening behind the scenes when I reset the device like this, and my research hasn't been completely informative.
Yes, during a reset, your window will receive messages. WM_SIZE is pretty likely to be received. From the Documentation:
Quote:Direct3D 9 applications can expect messages to be sent to them during this call (for example, before this call is returned); applications should take precautions not to call into Direct3D at this time.
So that's quite possibly causing problems. If in doubt, set a bool somewhere that indicates your device is being reset, and don't call into D3D if that bool is set.
Quote:Original post by Evil Steve
So that's quite possibly causing problems. If in doubt, set a bool somewhere that indicates your device is being reset, and don't call into D3D if that bool is set.


I missed that in the documentation! That would have saved me a major headache. Anyway, that was the issue, my WM_PAINT message response in my WndProc function called Reset() independant of my method used for toggling the fullscreen/windowed mode. Now I have a boolean check that takes care of that. It toggles modes like a charm. Thank you so much for the help. You've saved my neck twice now! (**SOLVED**)

This topic is closed to new replies.

Advertisement