Jump to content

  • Log In with Google      Sign In   
  • Create Account

Why does CreateWindowW fail?


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
28 replies to this topic

#1 ATC   Members   -  Reputation: 551

Like
0Likes
Like

Posted 19 October 2012 - 01:54 PM

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!
___________________________________________________________________________________

Sponsor:

#2 ATC   Members   -  Reputation: 551

Like
0Likes
Like

Posted 19 October 2012 - 02:06 PM

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!
___________________________________________________________________________________

#3 DoctorGlow   Members   -  Reputation: 834

Like
0Likes
Like

Posted 19 October 2012 - 02:41 PM

From MSDN for CreateWindow:

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


Have you tried calling GetLastError to get more info?

#4 Brother Bob   Moderators   -  Reputation: 8605

Like
0Likes
Like

Posted 19 October 2012 - 02:53 PM

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.

#5 ATC   Members   -  Reputation: 551

Like
0Likes
Like

Posted 19 October 2012 - 02:54 PM

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!
___________________________________________________________________________________

#6 ATC   Members   -  Reputation: 551

Like
0Likes
Like

Posted 19 October 2012 - 03:01 PM

@ 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... Posted Image

BTW, this is a very odd Windows behavior if you ask me...

Edited by ATC, 19 October 2012 - 03:25 PM.

_______________________________________________________________________________
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!
___________________________________________________________________________________

#7 MarkS   Prime Members   -  Reputation: 887

Like
0Likes
Like

Posted 19 October 2012 - 03:26 PM

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.

#8 Brother Bob   Moderators   -  Reputation: 8605

Like
1Likes
Like

Posted 19 October 2012 - 03:48 PM

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.

#9 MarkS   Prime Members   -  Reputation: 887

Like
0Likes
Like

Posted 19 October 2012 - 03:50 PM

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


Thanks for the clarification.

#10 adeyblue   Members   -  Reputation: 518

Like
0Likes
Like

Posted 19 October 2012 - 04:07 PM

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.

Edited by adeyblue, 19 October 2012 - 04:08 PM.


#11 ATC   Members   -  Reputation: 551

Like
0Likes
Like

Posted 19 October 2012 - 04:09 PM

@ Brother Bob:

You're saying the same exact code works on your PC? Posted Image
_______________________________________________________________________________
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!
___________________________________________________________________________________

#12 ATC   Members   -  Reputation: 551

Like
0Likes
Like

Posted 19 October 2012 - 04:11 PM

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.


I tried doing that too and it didn't work, I seem to remember... And then there's the issue that you can't get the Window* on the WM_NCCreate message anyway, so not sure how you could actually do this correctly...
_______________________________________________________________________________
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!
___________________________________________________________________________________

#13 Brother Bob   Moderators   -  Reputation: 8605

Like
0Likes
Like

Posted 19 October 2012 - 04:14 PM

@ Brother Bob:

You're saying the same exact code works on your PC? Posted Image

I see how I expressed myself incorrectly. What I meant was that I compared your code with my own window code and I cannot see any difference in the basic structure of the code. When I run your code it works as you describe (in other words; doesn't work), but my own code works, so apparently there's something different that I just cannot see even when I compare the codes side by side.

#14 ATC   Members   -  Reputation: 551

Like
0Likes
Like

Posted 19 October 2012 - 04:21 PM

I see how I expressed myself incorrectly. What I meant was that I compared your code with my own window code and I cannot see any difference in the basic structure of the code. When I run your code it works as you describe (in other words; doesn't work), but my own code works, so apparently there's something different that I just cannot see even when I compare the codes side by side.


If it's not some sort of proprietary code would you mind showing me for me to examine and correct this problem?
_______________________________________________________________________________
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!
___________________________________________________________________________________

#15 Brother Bob   Moderators   -  Reputation: 8605

Like
0Likes
Like

Posted 19 October 2012 - 04:40 PM

It is by no means proprietary or closed, but it's a part of a bigger windowing system where I can't easily rip out the relevant parts without going through some editing for it to make sense by itself. Not trying to tell you to STFW, but it's probably quicker to just find some standard window tutorial code and compare to it. My way of doing it is really no different than any other code you can find. But I'll keep looking at it.

#16 Brother Bob   Moderators   -  Reputation: 8605

Like
1Likes
Like

Posted 19 October 2012 - 05:45 PM

Ok, good news and bad news... Good news is I've found a solution. Bad news is I don't know why.

Joke aside, I found a difference: you set the window pointer when you receive the NCCREATE message, but I change it on the CREATE message. The NC-messages are sent before the non-NC messages to pass non-client (NC) messages to your window before the client are is set up. It could be that the window simply don't have any storage to store your pointer at that time, or that you are not allowed to store data there yet. In any case, I don't know why this makes a difference becuase you proceed to call DefWindowProc in the same order as me as far as I can see. Simply changing the pointer setup on the CREATE message instead of on the NCCREATE message seems to work just fine. You have to write your message router a bit different though.

I do it using two separate window handlers: one for the initial NC-messages and then I change handler once the CREATE message arrives.
LRESULT CALLBACK messagehandler::WndProcNC(HWND hwnd, UINT wmsg, WPARAM wparam, LPARAM lparam)
{
	if(wmsg == WM_CREATE) {
		LPCREATESTRUCT cs = reinterpret_cast<LPCREATESTRUCT>(lparam);
		window *win = reinterpret_cast<window *>(cs->lpCreateParams);
  
		SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(win));
		SetWindowLongPtr(hwnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(WndProc));
		return WndProc(hwnd, wmsg, wparam, lparam);
	} else {
		return DefWindowProc(hwnd, wmsg, wparam, lparam);
	}
}

LRESULT CALLBACK messagehandler::WndProc(HWND hwnd, UINT wmsg, WPARAM wparam, LPARAM lparam)
{
	// handle window messages here as usual
}
The window class structure is registered with the WndProcNC function which processes NC-messages until CREATE is received. At that point, the window pointer is fetched from the create parameter and put into the window data, the window's message handler is swapped to WndProc, and finally the message is passed manually to WndProc for further processing.

This method brings me to a problem with your method. If you just change it to set the window pointer on the CREATE message instead of the NCCREATE message, you will fall through the first if-statement and call you windows message handler on a null-pointer (or rather, throw the exception in that code path). You can either use my method and use separate message handlers for windows with and without pointer data (since the pointer data is set and the window handler is changed at the same time), or add some extra logic to your own method.
LRESULT CALLBACK Window::MsgRouter(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	Window* Wnd = reinterpret_cast<Window *>( GetWindowLongPtr( hWnd, GWLP_USERDATA ) );
	if(Wnd == nullptr) {
		if( msg == WM_CREATE ) {
			SetWindowLongPtr( hWnd, GWLP_USERDATA, reinterpret_cast<LONG>( (LPCREATESTRUCT(lParam))->lpCreateParams) );
		}
	  
		return DefWindowProc(hWnd, msg, wParam, lParam);
	}
	else
	{
	    if( !Wnd )
			throw new runtime_error( "No Window instance associated with HWND!" );
		
		return Wnd->WndProc( msg, wParam, lParam );
	}
}
The idea is the same as my method, as long as the window pointer is null, then you process messages in the if-statement; otherwise you have a window pointer and you process it in the else-statement.

Edited by Brother Bob, 19 October 2012 - 05:49 PM.


#17 ATC   Members   -  Reputation: 551

Like
0Likes
Like

Posted 19 October 2012 - 07:14 PM

I can't get either of those methods to work...

The first way won't even compile because of this line:

SetWindowLongPtr(hwnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(WndProc));

WndProc is member function of type Window, and no matter what I do I cannot obtain/use its address in calling SetWindowLongPtr... doesn't make sense to me...

"Error 1 error C2440: 'reinterpret_cast' : cannot convert from 'LRESULT (__cdecl Window::* )(UInt32,WPARAM,LPARAM)' to 'LONG_PTR' C:\Users\ATC\Documents\Visual Studio 2012\Projects\D3D11Tutorial01\D3D11Tutorial01\gamewnd.cpp 142 1 D3D11Tutorial01"

The second way compiles and runs but no window is created or show at all... just a loop running and I have to click Stop Debugging to exit...

Edited by ATC, 19 October 2012 - 07:29 PM.

_______________________________________________________________________________
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!
___________________________________________________________________________________

#18 ATC   Members   -  Reputation: 551

Like
0Likes
Like

Posted 19 October 2012 - 07:52 PM

Well I think I finally got it... gonna clean my code up a little bit, double-check the results and I will post me code...
_______________________________________________________________________________
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!
___________________________________________________________________________________

#19 ATC   Members   -  Reputation: 551

Like
0Likes
Like

Posted 19 October 2012 - 08:19 PM

And here is the (now) working implementation -- though it lacks an implementation of methods to manipulate the actual window once created. This is just the "framework" of it to create a window, route messages to the proper instance and have a virtual WndProc derrived classes can override to do custom message handling... Anyways, here's the working 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 <list>#include <string>#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( ); ~Window( ); HWND hWnd; HINSTANCE hInstance; virtual LRESULT WndProc( UInt32 msg, WPARAM wParam, LPARAM lParam );private: static LRESULT CALLBACK MsgRouter( HWND hWnd, UINT Msg, 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;}Window::~Window( ) { this->Close();}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; pWindow->hInstance = hInstance; //! Store handle // 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!" ); 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 );}LRESULT CALLBACK Window::MsgRouter( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam ) {#if DEBUG || PERFORM_CHECKS if( !hWnd ) throw invalid_argument( "Null window handle!" );#endif auto wnd = (Window *)null; if( Msg == WM_NCCREATE ) { // Get the Window pointer from lpCreateParams :: wnd = reinterpret_cast<Window *>( ((LPCREATESTRUCT)lParam)->lpCreateParams ); // Save our Window pointer and the valid HWND :: SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<long>(wnd)); wnd->hWnd = hWnd; } else // Get Window pointer from our window info :: wnd = reinterpret_cast<Window *>( GetWindowLongPtrW( hWnd, GWLP_USERDATA ) ); return wnd->WndProc(Msg, wParam, lParam); //! Invoke Window::WndProc}/*-----------------------------------------------------------------------------*********************************************************************************-----------------------------------------------------------------------------*/[/source]

Enjoy! BTW, I know it says "Copyright" in the description section but that's just because my default .h, .cpp, .c, etc file templates automatically format the code files that way. So disregard the copyright notice; you're free to use this code.

Regards,

--ATC--

EDIT:

For some reason the code block feature on the forums makes anything enclosed in <> braces disappear, so it screws up C/C++ include directives and C# generics, for example. The includes for gamewnd.h are:

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

Edited by ATC, 19 October 2012 - 08:25 PM.

_______________________________________________________________________________
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!
___________________________________________________________________________________

#20 ATC   Members   -  Reputation: 551

Like
0Likes
Like

Posted 19 October 2012 - 11:07 PM

Now that I got that WndProc problem solved I've got a pretty good Window class coming along... But now I'm having a REALLY stupid problem that makes no sense at all...

The SetWindowTextW and SetWindowTextA functions flat out don't work... they do NOTHING... And just to make sure it wasn't a bad HWND handle at fault I tried this:

SetWindowPos( hWnd, null, 700, 700, width, height, null );

...and it worked exactly as expected! So I know my handle is good. But why won't SetWindowText work? I've used this function a million times in the past, even called in from C# with P/Invoke and it always worked. Why is it not working now? Even if I just hard-code something like:

SetWindowTextW( hWnd, L"WTF!?" );

...even that doesn't work! Posted Image

Any ideas?

EDIT:

Even more odd is that my Window gets the WM_SETTEXT message if I call SetWindowText, but still, nothing happens... the text remains untouched...

Edited by ATC, 19 October 2012 - 11:08 PM.

_______________________________________________________________________________
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!
___________________________________________________________________________________




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS