Click to See Complete Forum and Search --> : Strange problem with CreateWindowEx (WndProc not called)


MLeoDaalder
September 22nd, 2006, 07:51 AM
Hello and thank you in advance for your time.


I'm currently writing a Win32 API wrapper (first time doing this, I have read various articles on this in the past), and it was shaping up nice, up until I gave it a test run to test the Window class.

The CreateWindowEx returns a not valid handle (0), but it doesn't set the LastError.
After some googling I found out that this is caused by the WndProc not handling the WM_NCREATE (and consorts) correctly. So, I zip back to my code and go to my WndProc, which happend to be a simple WndProc that just returned the result of DefWindowProc, so that wasn't the problem.

I've tried various diffrent approaches to solve it, added DefWindowProc directly, moved the wndproc to the cpp file (from the window manager cpp).
I finally added a simple MessageBox to it.
I compile, and run it. And guess what, the wndproc is never called!

I have checked if the WndProc is changed (for whatever reason) and it isn't.


The Wrapper is a bit more extensive than just a window wrapper, it's designed to also wrap buttons and the like, but I've started on the Window (seemed like the best thing to do, wouldn't you agree?) after the basic abstract classes (Widget, Container, LayoutManager).


This is what happens in the Main function:
OOWin32::WindowManagerPtr winManager = OOWin32::WindowManager::getInstance();

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

testwindow->setStyle(WS_OVERLAPPEDWINDOW);
testwindow->setExtendedStyle(WS_EX_APPWINDOW | WS_EX_WINDOWEDGE);

testwindow->setVisible(true);

return winManager->PumpMessages();


The setVisible function does this:
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 layout stuff (through the layoutmanager) and sets the children visible, if needed.

But it starts by calling the Widget::setVisible, which does this:
visible = isVisible;
if(!handle)
if(!this->initialize())
return;
if(wid_pimpl_->parent)
{
wid_pimpl_->parent->doLayout(wid_pimpl_->parent->getIterator(this));
}


Now, in initialize, my problems happen (it's a virtual function, if you hadn't deduced this already).

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

HINSTANCE hInstance = GetModuleHandle(NULL);

WNDCLASSEXA wc;
ZeroMemory(&wc, sizeof(WNDCLASSEXA));

wc.cbSize = sizeof(WNDCLASSEXA);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = &TestWndProc;//::DefWindowProcA;//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(!RegisterClassExA(&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;
ZeroMemory(&WindowRect, sizeof(RECT));
WindowRect.left= rect.x;
WindowRect.top = rect.y;
WindowRect.right=rect.w+rect.x;
WindowRect.bottom = rect.h+rect.y;

SetLastError(0);

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

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;


This function goes right all the way up untill the CreateWindowEx, which, as I've said, returns 0, but does not set the LastError to something else than the value already set (which in the current code is 0, but I could just as well have set it to 9999 or -1 and it would happily report it in the MessageBox).

This is the WndProc I'm currently using:
LRESULT CALLBACK TestWndProc(HWND hWnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
MessageBoxA(hWnd, "Test WndProc", "TEST!", MB_OK);
return DefWindowProc(hWnd, msg, wparam, lparam);
}
It has a breakpoint on the MessageBox.


I hope you can help me with this, it's seriously questioning my sanity (if I ever had any.:P).

Thank you again for your time.

MLeoDaalder

ZaccheusUK
September 23rd, 2006, 05:08 AM
I can't see anything wrong with your code.


Try outputting the WindowRect after AdjustWindowRectEx was called.

Perhaps there are some unexpected values in there?



If there is something wrong with the input parameters to CreateWindowEx, then the window can't be created and the WndProc will not be called at all.

MLeoDaalder
September 23rd, 2006, 05:23 AM
I can't see anything wrong with your code.


Try outputting the WindowRect after AdjustWindowRectEx was called.

Perhaps there are some unexpected values in there?



If there is something wrong with the input parameters to CreateWindowEx, then the window can't be created and the WndProc will not be called at all.
First of, thank you for your time.

Perhaps a bit:
---------------------------
Test
---------------------------
-4x-26x804x604
---------------------------
OK
---------------------------
That's in Left, Top, Right, Bottom.
Which I currently see as being wrong.

RECT WindowRect;
WindowRect.left= rect.x;
WindowRect.top = rect.y;
WindowRect.right=rect.w+rect.x;
WindowRect.bottom = rect.h+rect.y;
This is my current Rect calculator.

And this is what I do:
WindowRect.left, WindowRect.top, // Window Position
WindowRect.right-WindowRect.left, // Calculate Window Width
WindowRect.bottom-WindowRect.top, // Calculate Window Height



You know, I find this another design flaw in Win32, why have the programmer convert it first to a left, top, right, bottom (from an x, y, w, h) only to have to convert it back to x, y, w, h format.

So, I've changed the WindowRect calculation to this:
long screenW = GetSystemMetrics(SM_CXSCREEN);
RECT screenRect;
SystemParametersInfo(SPI_GETWORKAREA, 0, &rect, 0);
long screenH = GetSystemMetrics(SM_CYSCREEN) - (GetSystemMetrics(SM_CYSCREEN)-rect.bottom);

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


And the output is this:
---------------------------
Test
---------------------------
-4x-26x228x150
---------------------------
OK
---------------------------


Still the same error.

Zaccheus
September 23rd, 2006, 07:33 AM
I would (temporarily) hard code some numbers for x,y,width,height and see what works and what does not work.

Perhaps it cannot open a window with a negative initial left and/or top position, or something like that.

MLeoDaalder
September 23rd, 2006, 07:46 AM
I just tested that, and it isn't the negative values (besides, why wouldn't you not be able to put in negative values? You can move a window off the screen).

miteshpandey
September 23rd, 2006, 08:28 AM
There are two things that I noticed.

1. You are using GetModuleHandle(NULL) to get the instance handle. Why are you not using the instance handle passed as a parameter to the WinMain function?

2. Even if you can have negative values for the location of the window (the window will be out of sight though), you cannot have negative value or 0 for the width and height of the window. Make sure the width and height have proper values.

However I don't know if passing negative width or height causes the function to fail or just create a window with zero height and zero width.

MLeoDaalder
September 23rd, 2006, 08:31 AM
I'm not passing negative for width or height, namely, 800 and 600.


The values I've posted are after they are transformed through AdjustWindowRectEx.

miteshpandey
September 23rd, 2006, 08:47 AM
GetLastError returns an error code. And this error code should be matched with system defined error messages whose text representation will reveal what the actual error is.

The following FAQ will be helpful to you:FAQ (http://www.codeguru.com/forum/showthread.php?t=318721)

miteshpandey
September 23rd, 2006, 09:10 AM
Don't know if it is of some consequence or not


OOWin32::Window* testwindow = winManager->createWindow();

testwindow->setBounds(10,10, 800, 600);


Maybe u need to pass the location of 10, 10 and dimensions 800, 600 to the createWindow function. It seems you are setting this after the call to createWindow()

Zaccheus
September 23rd, 2006, 10:18 AM
That confused me too at first, but createWindow only creates his C++ object.

What we do know is that the register window class function succeeds and yet the window cannot be created, so logically it must be one of the parameters passed into the create window function.

Have you output each of the values passed into the CreateWindowEx function to double check that they are what you expect?

miteshpandey
September 23rd, 2006, 10:41 AM
That confused me too at first, but createWindow only creates his C++ object.


What made you believe this. I don't see any code posted by the OP suggest that createWindow is only creating the C++ object. By the way shouldn't the name of the function imply what it is going to do?

Zaccheus
September 23rd, 2006, 10:50 AM
The OP says that the call to CreateWindowEx is inside (a function called by) setVisible.

miteshpandey
September 23rd, 2006, 11:15 AM
Yup! you are right. Great insight... :thumb:

MikeAThon
September 23rd, 2006, 11:25 AM
I think that you should omit the "&" in this line
wc.lpfnWndProc = &TestWndProc;
should be
wc.lpfnWndProc = TestWndProc;
Also, I agree with the other comments here that you should postpone fancy window rectangle calculations until after you have the problem sorted out. For the time being, pass in "CW_USEDEFAULT" as the rectangle, and let Windows calculate a default for you.

Mike

MLeoDaalder
October 3rd, 2006, 04:24 AM
Sorry for not replying sooner (was expecting an e-mail, which I didn't get :().


After some intense debugging, checking all the values and ripping out parts and putting them back in, it *seems* to be that I store my extended style as a signed long. Which it expects an unsigned long. And my window worked after I changed the type to unsigned long. I came to this sollution when I changed the style to 0.




I'm now implementing widgets, and by Lo, behold, an not editable edit control.
It isn't even editable if I do it the "old" way (through drag and drop in VS2005).

Anyone knows anything about this?

Only the delete button works. And the Read Only flag _isn't_ set.
If it is, then it really is read-only.