Jump to content
  • Advertisement
Sign in to follow this  
mldaalder

Strange Win32 problem

This topic is 4410 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello, first of all thank you for reading this topic. I'm currently in the progress of writing a Win32 wrapper, named OOWin32. It's shaping up nicely, considering it's my first attempt to write a wrapper for Win32. Now, I'm having a strange problem, CreateWindowEx returns an invalid handle, but doesn't set LastError code. After some research, I've found out that it's the Window Proc that's at fault, so I thought: "Doh, forgot to turn any unhandled events to DefWindowProc" but when I checked, I noticed the window proc _was DefWindowProc. So that made no sense. I wrote a quick window proc that showed a message box (and returned the result of DefWindowProc), but it didn't even show the message box. And with that, I've just eleminated the only case I found on the internet that had my specific problems, CreateWindowEx not returning a valid handled and not setting the last error. This is my initialize function (it's virtual, and it get's called in my system).
	bool Window::initialize()
	{
		WNDCLASSA wc;

		HINSTANCE hInstance = GetModuleHandle(NULL);

		this->class_name = ("OOWin32Window@" + (boost::format("%#x")%this).str()).c_str();

		wc.style         = CS_HREDRAW | CS_VREDRAW;
		wc.lpfnWndProc   = (WNDPROC)Util::WndProc;
		wc.cbClsExtra    = 0;
		wc.cbWndExtra    = 0;
		wc.hInstance     = hInstance;
		wc.hIcon         = LoadIcon(NULL, iIcon);
		wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
		wc.hbrBackground = (HBRUSH)GetStockObject(COLOR_WINDOW);
		wc.lpszMenuName  = NULL;
		wc.lpszClassName = this->class_name.c_str();


		// Register the application
		if(!RegisterClassA(&wc))
		{
			MessageBoxA(NULL, boost::lexical_cast<std::string>(GetLastError()).c_str(), "Error in RegisterClass", MB_OK);
			destroy();
			WindowManager::getInstance()->removeWindow(this);
			return false;
		}

		RECT WindowRect;
		WindowRect.left= rect.x;
		WindowRect.top = rect.y;
		WindowRect.right=rect.w;
		WindowRect.top = rect.h;

		// Find a function that can directly adjust the window
		AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle);

		//SetLastError(0);
		this->handle = 0;
		HWND hWnd = CreateWindowExA(
					dwExStyle,							// Extended Style For The Window
					this->class_name.c_str(),					// Class Name
					title.c_str(),						// Window Title
					dwStyle |							// Defined Window Style
					WS_CLIPSIBLINGS |					// Required Window Style
					WS_CLIPCHILDREN,					// Required Window Style
					WindowRect.left, WindowRect.top,	// Window Position
					WindowRect.right-WindowRect.left,	// Calculate Window Width
					WindowRect.bottom-WindowRect.top,	// Calculate Window Height
					NULL,								// No Parent Window
					NULL,								// No Menu
					hInstance,							// Instance
					NULL);								// Window Long, used to pass along for user data.
		this->handle = (void*)hWnd;
		if(!hWnd)
		{
			MessageBoxA(reinterpret_cast<HWND>(handle), ("ERROR!\n" + boost::lexical_cast<std::string>(GetLastError())).c_str(), "Window::initialize", MB_OK);
			destroy();
			WindowManager::getInstance()->removeWindow(this, false);
			return false;
		}

		return true;
	}


Some extra info, dwstyle is set to WS_OVERLAPPEDWINDOW, dwExstyle is set to: WS_EX_APPWINDOW | WS_EX_WINDOWEDGE, the bounds are 10, 10, 800, 600 (x,y,w,h format). As you can see, I've uncommented the SetLastError(0) just before the CreateWindowEx, I've done that because I could set it to anything and it wouldn't matter. If you think it's the that my window class is a WNDCLASSA and I've using the Extended version of CreateWindow, then I'm afraid I have to proof you wrong, this is a very valid thing to do. Not to mention, I've tried every combination.:P I hope you can find the culprit of the problem, I think it's going to be something small...:( Thank you for your time. [EDIT] I would also like to say that the setting the window visible is done only if this function returns true, which doesn't happen.

Share this post


Link to post
Share on other sites
Advertisement
Quote:
Original post by mldaalder
After some research, I've found out that it's the Window Proc that's at fault, so I thought: "Doh, forgot to turn any unhandled events to DefWindowProc" but when I checked, I noticed the window proc _was DefWindowProc.

No it isn't...
Quote:

wc.lpfnWndProc = (WNDPROC)Util::WndProc;

I'm guessing your window proc is misbehaving as your research suggested or that it is not a static member function and thus you end up getting garbage passed to it.

Share this post


Link to post
Share on other sites
It's the test window proc I've mentioned.

	LRESULT	CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
MessageBoxA(hWnd, "Test WndProc", "TEST!", MB_OK);
return DefWindowProc(hWnd, msg, wparam, lparam);
}



But the MessageBox is never called.

Share this post


Link to post
Share on other sites
I've read that article in the past, but it isn't quite what I'm looking for (need more widgets). Though it has been half a year ago.

The strange problem is, that _none_ of the places I have message handling routines, is being called on window creation.

I have tried some more, and it's the window creation where it get's wrong, the oter places don't get called yet (for instance, the window manager's PumpMessage routine, which basicly get's all the messages and routes them to the message handlers, but this requires created windows).


Ok, a bit more about the system.

In my main I do the following:
	OOWin32::WindowManagerPtr winManager = OOWin32::WindowManager::getInstance();

OOWin32::Window* testwindow = winManager-&gt;createWindow();
testwindow-&gt;setBounds(0,0, 800, 600);
testwindow-&gt;setTitle("OOWin32 Test Window 1");

testwindow-&gt;setstyle(WS_OVERLAPPEDWINDOW);
testwindow-&gt;setExtendedstyle(WS_EX_APPWINDOW | WS_EX_WINDOWEDGE);

testwindow-&gt;setVisible(true);

MessageBoxA(NULL, "Test", "Main", MB_OK);

return winManager-&gt;PumpMessages();


The functions up until setVisible aren't important (they can do some window work, but only if the widget is initialized, a widget can be anything, from a button to a window, to something abstract, such as a container).

setVisible does the following:
	void Window::setVisible(bool isVisible)
{
Container::setVisible(isVisible);
if(isVisible)
{
HWND hWnd = reinterpret_cast<HWND>(getHandle());
if(hWnd)
{
ShowWindow(hWnd,SW_SHOW);
SetForegroundWindow(hWnd);
SetFocus(hWnd);
}
}
}




Container::setVisible does some child layout, but it also calls the Widget::setVisible, which does the initialization (if needed).

	void Widget::setVisible(bool isVisible)
{
visible = isVisible;
if(!handle)
if(!this->initialize())
return;
if(wid_pimpl_->parent)
{
wid_pimpl_->parent->doLayout(wid_pimpl_->parent->getIterator(this));
}
}




I'm using the Pimpl idiom (aka compiler firewall, as described by the guru of the week website, since I would otherwise have a cyclic dependancy between Widget and Container (Container inherits from Widget)).

initialize is a virtual function, and brings me full circle with the function in my first post.

Share this post


Link to post
Share on other sites
Its not clear from the code but does the initialize() function get called during the winManager.createWindow() function? If so then you haven't specified the style flags before trying to create the window. At least from the main snippit you've shown.

Not critical but any reason your specifically using the ANSI versions of the Win32 API? The windows headers have macros to select the right version depending on Unicode/Ansi. i.e. use MessageBox() instead of MessageBoxA()

Share this post


Link to post
Share on other sites
Quote:
Original post by mark_dev
Its not clear from the code but does the initialize() function get called during the winManager.createWindow() function? If so then you haven't specified the style flags before trying to create the window. At least from the main snippit you've shown.

Look back at the first post, I'm using WS_OVERLAPPEDWINDOW as the dwstyle and WS_EX_APPWINDOW | WS_EX_WINDOWEDGE as the dwExstyle.

The setVisible calls initialize if it hasn't been initialized already.

Check my post above yours for the run down how it gets to initialize.


Quote:
Not critical but any reason your specifically using the ANSI versions of the Win32 API? The windows headers have macros to select the right version depending on Unicode/Ansi. i.e. use MessageBox() instead of MessageBoxA()

I know this, and I've used the Ansi function explicitly in case I wanted to switch some parts to Unicode later, which will save me some work instead of having to _T all the explicit parts and using some ugly per character wchar_t casting (haven't found the correct way of doing yet :().
Should have done it from the start, but that would break some other code as well (atleast, in the project where this library is intended for).

In a lot of other projects I've used the correct way.
But at the moment, it's no big deal.

Share this post


Link to post
Share on other sites
If I'm reading this right:
this->class_name = ("OOWin32Window@" + (boost::format("%#x")%this).str()).c_str();



Maybe you're assigning class_name to the c_str() pointer of a temporary string returned from operator+( const char*, string ).

Share this post


Link to post
Share on other sites
Quote:
Original post by Jaymar
If I'm reading this right:
*** Source Snippet Removed ***

Maybe you're assigning class_name to the c_str() pointer of a temporary string returned from operator+( const char*, string ).

Woops, was a typo.

Still, it's not the problem, since I've also tried it with a non dynamic class name.

I've fixed it now, and it's giving me the same problem.

On another forum it was suggested that it's the window rect.

After some tests, this "appears", like the best code to do this:
		long screenW = GetSystemMetrics(SM_CXSCREEN);
RECT screenRect;
SystemParametersInfo(SPI_GETWORKAREA, 0, &screenRect, 0);
long screenH = GetSystemMetrics(SM_CYSCREEN) - (GetSystemMetrics(SM_CYSCREEN)-screenRect.bottom);

RECT WindowRect;
WindowRect.left= rect.x;
WindowRect.top = rect.y;
WindowRect.right=screenW - (rect.w+rect.x);
WindowRect.bottom = screenH - (rect.h+rect.y);


It results into this after the AdjustWindowEx:
---------------------------
Test
---------------------------
-4x-26x228x150
---------------------------
OK
---------------------------

Share this post


Link to post
Share on other sites
Might I ask why you're storing a void pointer version of the returned handle when you can store the actual value (as HWND)?
What's actually happening (what does happen and what doesn't)?
Have you stepped through the program with the debugger and checked values?
Is Util::WndProc in a class or namespace?
If it's in a class is it static?
How do you know that CreateWindowEx() returning an invalid handle?

Quote:
If you think it's the that my window class is a WNDCLASSA and I've using the Extended version of CreateWindow, then I'm afraid I have to proof you wrong, this is a very valid thing to do. Not to mention, I've tried every combination.:P

Jumping to the defensive before anybody has even said anything seems quite rude and your statement also gives off the feeling that you think you're smarter than us.

Edit: With the above post, are you trying to center the window on the screen?

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!