Why does CreateWindowW fail?

Started by
27 comments, last by MarkS_ 11 years, 6 months ago
I'm just doing a little practice with C++11 and using something I enjoy, DirectX11, to make it fun. And I decided to write a Win32 Window wrapper class to eliminate the need to rewrite Win32 window initialization code over and over every time I just want to make a simple DirectX11 program. But all of a sudden CreateWindowW just starts failing when I use my class's static method Window::Create, even though the Window initialization code is almost exactly the same as it was prior to creating the class -- which worked perfectly... I cannot figure out why but it keeps on returning a null HWND handle... Here is the code:

gamewnd.h

[source lang="cpp"]
#pragma region Description
/* gamewnd.h ::
* Implements a game window class for DirectX applications.
*
* Copyright © ATCWARE 2010, All Rights Reserved.
*/
#pragma endregion

/*----------------------------------
* INCLUDE DIRECTIVES ::
*----------------------------------*/

#pragma once
#define WIN32_LEAN_AND_MEAN

#include <atc_standards.h>
#include <Windows.h>
#include <stdexcept>

using namespace std;

/*----------------------------------
* PREPROCESSOR DIRECTIVES ::
*----------------------------------*/

#define WND_CLASS_NAME_W L"GameWndClass"
#define MAX_WINDOW_WIDTH 0x1000
#define MAX_WINDOW_HEIGHT 0x1000

/*-----------------------------------------------------------------------------*
* GLOBAL VARIABLES ::
*-----------------------------------------------------------------------------*/



/*-----------------------------------------------------------------------------*
* PROTOTYPES & FORWARD DECLARATIONS ::
*-----------------------------------------------------------------------------*/

enum WndState
{
DEFAULT = 0x00,
MAXIMIZED = 0x01,
MINIMIZED = 0x02,
};

class Window
{
public:
virtual void Show( );
virtual void Hide( );
virtual void Close( );

static void ClientToAbsSize( Int32* const pWidth, Int32* const pHeight );
static Window* Create( Int32 width, Int32 height, wstring title, HINSTANCE hInstance );

protected:
Window( );

HWND hWnd;
HINSTANCE hInstance;

virtual LRESULT WndProc( UInt32 msg, WPARAM wParam, LPARAM lParam );

private:
static LRESULT CALLBACK MsgRouter(
HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam);
};


/*-----------------------------------------------------------------------------*
*******************************************************************************
*-----------------------------------------------------------------------------*/
[/source]

gamewnd.cpp

[source lang="cpp"]
#pragma region Description
/* gamewnd.cpp ::
*
*
* Copyright © ATCWARE 2010, All Rights Reserved.
*/
#pragma endregion

/*----------------------------------
* INCLUDE DIRECTIVES ::
*----------------------------------*/

#include "gamewnd.h"

/*----------------------------------
* PREPROCESSOR DIRECTIVES ::
*----------------------------------*/



/*-----------------------------------------------------------------------------*
* GLOBAL VARIABLES ::
*-----------------------------------------------------------------------------*/



/*-----------------------------------------------------------------------------*
* GameWndBase Implementation ::
*-----------------------------------------------------------------------------*/

Window::Window( ) {
this->hInstance = 0x00;
this->hWnd = 0x00;
}

void Window::Show( ) {
ShowWindow( this->hWnd, SHOW_OPENWINDOW );
}

void Window::Hide( ) {
ShowWindow( this->hWnd, HIDE_WINDOW );
}

void Window::Close( ) {
CloseWindow( this->hWnd );
}

void Window::ClientToAbsSize( Int32* const pWidth, Int32* const pHeight ) {

RECT rc = { 0, 0, *pWidth, *pHeight };

AdjustWindowRect( &rc, WS_OVERLAPPEDWINDOW, FALSE );
*pWidth = (rc.right - rc.left);
*pHeight = (rc.bottom - rc.top);
}

Window* Window::Create( Int32 width, Int32 height, wstring title, HINSTANCE hInstance ) {

#if DEBUG || PERFORM_CHECKS //! Validate arguments
if( (width < 0) || (width > MAX_WINDOW_WIDTH) )
throw new invalid_argument( "Specified Window width out of range." );

if( (height < 0) || (height > MAX_WINDOW_HEIGHT) )
throw new invalid_argument( "Specified Window width out of range." );

if( !(title.data()) || (title.length() < 1) )
throw new invalid_argument( "Invalid Window title parameter." );

if( !hInstance )
throw new invalid_argument( "HINSTANCE parameter is NULL." );
#endif

Window* pWindow = new Window;

// Create & register window class ::
WNDCLASSEX wndClass = { 0 };
wndClass.cbSize = sizeof( WNDCLASSEX );
wndClass.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
wndClass.lpfnWndProc = Window::MsgRouter;
wndClass.hCursor = LoadCursor( null, IDC_ARROW );
wndClass.style = (CS_VREDRAW | CS_HREDRAW);
wndClass.hInstance = hInstance;
wndClass.lpszMenuName = null;
wndClass.lpszClassName = WND_CLASS_NAME_W;

if( !RegisterClassEx( &wndClass ) )
throw new runtime_error( "Window registration failed!" );

// Calculate absolute window size ::
Int32 abs_width = width, abs_height = height;
ClientToAbsSize( &abs_width, &abs_height );

// Create the Win32 window ::
HWND hWnd = CreateWindowW( WND_CLASS_NAME_W, title.data(), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
abs_width, abs_height, null, null, hInstance, static_cast<LPVOID>( pWindow ) );

// Show the game window ::
if( !hWnd )
throw new runtime_error( "Window creation failed!" );

pWindow->hWnd = hWnd;
pWindow->hInstance = hInstance; //! Store handles

return pWindow;
}

LRESULT Window::WndProc( UInt32 msg, WPARAM wParam, LPARAM lParam ) {

HDC hDC;
PAINTSTRUCT paintStruct;

switch( msg )
{
case WM_PAINT:
hDC = BeginPaint( this->hWnd, &paintStruct );
EndPaint( this->hWnd, &paintStruct );
break;

case WM_DESTROY:
PostQuitMessage( 0x00 );
break;

default:
return DefWindowProc( this->hWnd, msg, wParam, lParam );
}

return static_cast<LRESULT>( 0x00 );
}

// Routes messages to Window instances:
LRESULT CALLBACK Window::MsgRouter(HWND hWnd, UINT msg,
WPARAM wParam, LPARAM lParam) {

Window* Wnd = (Window *)0x00;

if( msg == WM_NCCREATE ) {
SetWindowLongPtr( hWnd, GWLP_USERDATA,
reinterpret_cast<LONG_PTR>( (LPCREATESTRUCT(lParam))->lpCreateParams) );
}

else
{
Wnd = reinterpret_cast<Window *>( GetWindowLongPtr( hWnd, GWLP_USERDATA ) );

if( !Wnd )
throw new runtime_error( "No Window instance associated with HWND!" );

return Wnd->WndProc( msg, wParam, lParam );
}
}

/*-----------------------------------------------------------------------------*
*******************************************************************************
*-----------------------------------------------------------------------------*/
[/source]

...for some reason CreateWindowW always returns null (0x00000000)! At first I thought maybe it was some invalid parameters, but I've stepped through in debug mode and cannot see anything wrong with them. I even switched some of the custom parameters to hard-coded values that I already know work in regular Win32 applications (e.g., the original version of this project) but it still fails.

For example, I just hard-coded the window title to L"MyWindow", changed the width/height params to 1024 and 768, changed the last parameter to NULL, etc... Still doesn't work, still returns a null HWND... :'(

Any idea what's going on here?

Thanks,

--ATC--

P.S. -- Just getting back into C++ to resharpen my old skills, so if you see any other coding problems or bad practices that don't have anything to do with the actual issue I welcome your corrections and suggestions...
_______________________________________________________________________________
CEO & Lead Developer at ATCWARE™
"Project X-1"; a 100% managed, platform-agnostic game & simulation engine

Please visit our new forums and help us test them and break the ice!
___________________________________________________________________________________
Advertisement
NOTE::

I just call Window::Create in my wWinMain function like so:

Window* pWindow = Window::Create( 1024, 768, L"DirectX11 Tutorial", hInstance );
_______________________________________________________________________________
CEO & Lead Developer at ATCWARE™
"Project X-1"; a 100% managed, platform-agnostic game & simulation engine

Please visit our new forums and help us test them and break the ice!
___________________________________________________________________________________
From MSDN for CreateWindow:

If the function fails, the return value is NULL. To get extended error information, call GetLastError.[/quote]

Have you tried calling GetLastError to get more info?
Your Window::MsgRouter function doesn't have a return statement for the code path when the WM_NCCREATE message is passed. Your compiler should have complained about that.

Chances are that the function happens to return zero, which is the response to the NCCREATE message to abort the window creation and return a null handle.
ERROR_INVALID_WINDOW_HANDLE
1400 (0x578)
Invalid window handle.
_______________________________________________________________________________
CEO & Lead Developer at ATCWARE™
"Project X-1"; a 100% managed, platform-agnostic game & simulation engine

Please visit our new forums and help us test them and break the ice!
___________________________________________________________________________________
@ Brother Bob:

Ahhh, good eye... I didn't notice that. But I changed it to this:

[source lang="cpp"]// Routes messages to Window instances:
LRESULT CALLBACK Window::MsgRouter(HWND hWnd, UINT msg,
WPARAM wParam, LPARAM lParam) {

Window* Wnd = (Window *)0x00;

if( msg == WM_NCCREATE ) {
SetWindowLongPtr( hWnd, GWLP_USERDATA,
reinterpret_cast<LONG_PTR>( (LPCREATESTRUCT(lParam))->lpCreateParams) );

return ::DefWindowProc( hWnd, msg, wParam, lParam );
}

else
{
Wnd = reinterpret_cast<Window *>( GetWindowLongPtr( hWnd, GWLP_USERDATA ) );

if( !Wnd )
throw new runtime_error( "No Window instance associated with HWND!" );

return Wnd->WndProc( msg, wParam, lParam );
}
}[/source]

...now the code does not crash but I don't get a proper window. I just get a borderless square on the screen without any control buttons/boxes or anything. Just a blank square client area it appears.

EDIT:

It appears this is happening because my window never recieves a WM_PAINT... every time WndProc is invoked it seems that msg == 0x00... ?

EDIT 2:

Or is the above happening (no WM_PAINT) because the window is occluded/minimized as I debug the application?

EDIT 3 (lol):

Yes, that's why... so the window IS getting WM_PAINT, leaving me with no idea why it's all screwed up... tongue.png

BTW, this is a very odd Windows behavior if you ask me...
_______________________________________________________________________________
CEO & Lead Developer at ATCWARE™
"Project X-1"; a 100% managed, platform-agnostic game & simulation engine

Please visit our new forums and help us test them and break the ice!
___________________________________________________________________________________
I see an ambiguity, but I am not sure how compilers handle this, so I could be wrong.

You mean to set the hInstance of the window class to the argument from Window::Create. However, you also have a NULL hInstance member variable. If the NULL variable is being substituted for the function argument, then you'll see issues.

Try changing the variable names to remove the ambiguity or move "pWindow->hInstance = hInstance;" immediately prior to setting up wndClass.

Again, I could be wrong, but this is the only thing that jumps out at me.

I see an ambiguity, but I am not sure how compilers handle this, so I could be wrong.

You mean to set the hInstance of the window class to the argument from Window::Create. However, you also have a NULL hInstance member variable. If the NULL variable is being substituted for the function argument, then you'll see issues.

Try changing the variable names to remove the ambiguity or move "pWindow->hInstance = hInstance;" immediately prior to setting up wndClass.

Again, I could be wrong, but this is the only thing that jumps out at me.

Name resolution is well defined. Function parameters have higher priority than members, so that is not a problem.

Anyway, I have copied your code and I truly cannot see how your code flow is different from mine, yet mine works and your behaves just as you describe. I will see if I can spend some more time later and investigate some more if you haven't found a solution. My observation so far is that the window becomes OK after a while, you just need to, for example, minimize and maximize the window and it starts behaving as expected.

Name resolution is well defined. Function parameters have higher priority than members, so that is not a problem.



Thanks for the clarification.
You (OP) have a problem everybody seems to run into when doing this at some point.
You call CreateWindow: this->hwnd == NULL
CreateWindow sends WM_NCCreate - you set the window data, this->hwnd still == NULL
CreateWindow sends the other messages it sends - you call Wnd->WndProc, you pass this->hwnd to DefWindowProc but this->hwnd is still NULL
CreateWindow finally returns, after a check only now is this->hwnd set to a valid value

Long story short, you handle who knows how many messages by passing a NULL hwnd to DefWindowProc or to Begin/EndPaint.
The easiest way to fix it is to assign this->hwnd in WM_NCCreate.

This topic is closed to new replies.

Advertisement