|
-
July 26th, 2003, 08:38 AM
#1
CreateWindowEx(): "Cannot find the file specified"
Hello,
Since hours I try to get my code running which is supposed to create a standard window using CreateWindowEx(). However, the returned handle is always NULL.
I called GetLastError() and received the error string. It reads:
"The system cannot find the file specified."
Uh, which file? The only files I'm implicitly dealing with are icon and cursor files. But I use default icons and I checked their handles in the debugger and everything seems to be okay. To be 100% sure I even created my own icons and loaded them using MAKEINTRESOURCE, but nope, still get this confusing error message. I couldn't create an own cursor file, but I tried to use other values like IDC_HAND, but again the same error.
I think I better post some code now:
Code:
HRESULT CMyApp::InitInstance()
{
HRESULT hr = 0;
WNDCLASSEX wc;
ZeroMemory( &wc, sizeof( WNDCLASSEX ) );
static TCHAR szClassName[] = _T("def_w32_app");
wc.cbSize = sizeof( WNDCLASSEX );
wc.hbrBackground = (HBRUSH) GetStockObject( COLOR_WINDOW );
wc.hCursor = LoadCursor( NULL, IDC_ARROW );
wc.hIcon = LoadIcon( NULL, IDI_APPLICATION );
wc.hIconSm = wc.hIcon;
wc.lpszMenuName = NULL;
wc.hInstance = GetInstance();
wc.lpfnWndProc = ::WindowProc;
wc.lpszClassName = szClassName;
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
hr = RegisterClassEx( &wc );
if( FAILED( hr ) )
{
CError e;
e.Display();
return E_FAIL;
}
DWORD dwStyle = WS_OVERLAPPEDWINDOW | WS_VISIBLE;
DWORD dwExStyle = NULL;
m_hWnd = CreateWindowEx( dwExStyle, szClassName, "Test Window", dwStyle, 100, 100, 800, 600, NULL, NULL, GetInstance(), NULL );
if( m_hWnd == NULL )
{
CError e;
e.Display();
return E_FAIL;
}
return S_OK;
}
There you go, the whole function as it is now. GetInstance() returns a handle to the instance of the running program. I checked the value, it's okay. The CError class will only call GetLastError() and display a message box. Everything else should be self explanatory.
Any idea what's going wrong here?
- Matthias
"C makes it easy to shoot yourself in the foot; C++ makes it harder, but when you do it blows your whole leg off." - Bjarne Stroustrup
-
July 26th, 2003, 08:55 AM
#2
Youre code seems OK. I just want to know if this code is in DLL. If so, try add the CS_GLOBALCLASS to your wc.style
Code:
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC | CS_GLOBALCLASS;
Hope it will help you
-
July 26th, 2003, 09:32 AM
#3
No, the code is in local *.cpp files.
- Matthias
"C makes it easy to shoot yourself in the foot; C++ makes it harder, but when you do it blows your whole leg off." - Bjarne Stroustrup
-
July 26th, 2003, 09:58 AM
#4
When I got a valid HWND and still set the breakpoint to get the last error, I got this error that you are saying. Is this the real code you're working, or you removed some parts between CreateWindowEx and the if statement?
-
July 26th, 2003, 10:29 AM
#5
Nope, it's the full code.
What exactly did you do to reproduce the error?
- Matthias
"C makes it easy to shoot yourself in the foot; C++ makes it harder, but when you do it blows your whole leg off." - Bjarne Stroustrup
-
July 26th, 2003, 10:34 AM
#6
I don't really know what you mean with "when I got a valid HWND", because I never get a valid HWND.
m_hWnd is always 0. So something seems to fail during the call of CreateWindowEx.
Odd is that I pasted in the code from a win32 app created with the wizard, and it still didn't work. The problem must be located elsewhere. Besides, I still don't have a clue why the program complains about a missing file... I mean, WHAT FILE? Is there a way to check which file the error handler is talking about?
- Matthias
"C makes it easy to shoot yourself in the foot; C++ makes it harder, but when you do it blows your whole leg off." - Bjarne Stroustrup
-
July 27th, 2003, 03:34 AM
#7
Haha, it becomes even more odd now:
I have taken the part of the code from which I thought would cause the trouble and put it in one file, in the WinMain(). And it still doesn't work!
Here's the code as it is now:
Code:
#include <windows.h>
#include <tchar.h>
//--------------------------------------------------------------------------------------------------
// METHOD NAME: WindowProc
// RETURN TYPE: LRESULT
// DESCRIPTION: Callback function for handling Windows messages
//--------------------------------------------------------------------------------------------------
LRESULT CALLBACK WindowProc( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam )
{
return 0L;
}
//--------------------------------------------------------------------------------------------------
// METHOD NAME: WinMain
// RETURN TYPE: int
// DESCRIPTION: Entry point of each Win32 application
//--------------------------------------------------------------------------------------------------
int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
HRESULT hr = 0;
WNDCLASSEX wc;
ZeroMemory( &wc, sizeof( WNDCLASSEX ) );
static TCHAR szClassName[] = _T("def_w32_app");
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = ::WindowProc;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)GetStockObject(COLOR_WINDOW);
wc.lpszClassName = szClassName;
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
RegisterClassEx( &wc );
DWORD dwStyle = WS_OVERLAPPEDWINDOW | WS_VISIBLE;
DWORD dwExStyle = NULL;
HWND hWnd = CreateWindowEx( dwExStyle, szClassName, "Test Window", dwStyle, 0, 0, 800, 600, NULL, NULL, hInstance, NULL);
return 0;
}
This is the whole code, I changed nothing. Funny ain't it? And hWnd is still always NULL and checking for the error returns a "The system cannot find the file specified".
I'm getting desperate, please help!
- Matthias
"C makes it easy to shoot yourself in the foot; C++ makes it harder, but when you do it blows your whole leg off." - Bjarne Stroustrup
-
July 27th, 2003, 04:57 AM
#8
Hah, I've found the error! I can't say I really understand it, but...
I had to fill something into the message handler WindowProc(). I first only returned 0 because I didn't even manage to create the window so I didn't really care about handling messages... However, the application seems to verify the message handler in some way (at least I believe that) before creating the window using the WNDCLASS I passed the message handler to.
Instead of just returning 0, I now wrote some basic code in its body:
Code:
LRESULT CALLBACK WindowProc( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam )
{
switch (nMsg)
{
case WM_COMMAND:
break;
case WM_PAINT:
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
break;
}
return DefWindowProc(hWnd, nMsg, wParam, lParam);
}
Hard to believe... But it works =)
If someone here has an idea why the heck I have to write a function which isn't even called before my window even EXISTS, I would appreciate any explanation...
I don't know why this produced a "file not found" error either and I'm 100% sure that VS6 didn't have this problem. Perhaps it's a bug in the compiler? I don't know.
- Matthias
"C makes it easy to shoot yourself in the foot; C++ makes it harder, but when you do it blows your whole leg off." - Bjarne Stroustrup
-
July 27th, 2003, 12:42 PM
#9
I think you found ur problem, when used WindowProc, except for dialog box. I think u need to add
DefWindowProc(...) function; in default area;
example :
LRESULT CALLBACK WndProc(HWND ...)
{
switch(msg)
{
case ... :
default : return DefWindowProc(hWnd,...);
}
}
-
July 27th, 2003, 01:07 PM
#10
Originally posted by matthias_k
Hah, I've found the error! I can't say I really understand it, but...
Without DefWindowProc() you are sending messages
that need to be handled by Windows to never-never land.
Windows is expecting you to use the message, and then send it
to Windows, but you failed to do so. Remember, every message
is sent to your Window procedure, including ones you would
never expect to receive, but must handle correctly.
Undoubtedly, one of these messages could have been something
to do with file handling, who knows. But whatever it was, you
screwed up the smooth processing of the message by not
completing the DefWindowProc step. I'm surprised your program
didn't show other erratic behavior by leaving out DefWindowProc.
Regards,
Paul McKenzie
-
July 27th, 2003, 08:30 PM
#11
Originally posted by matthias_k
I don't really know what you mean with "when I got a valid HWND", because I never get a valid HWND
What I mean is, In my case, I get a valid handle in calling CreateWindowEx. But even I got a valid handle I tried to call GetLastError and if I do that I got the error 2 that you're saying. I found out that this error is generated internally by RegisterClassEx so I asked you if you have any code between the CreateWindowEx and the if statement that might change the HWND and I'm sorry that I did not assumed you step into it.
Originally posted by matthias_k
Hard to believe... But it works =)
If someone here has an idea why the heck I have to write a function which isn't even called before my window even EXISTS, I would appreciate any explanation...
I don't know why this produced a "file not found" error either and I'm 100% sure that VS6 didn't have this problem. Perhaps it's a bug in the compiler? I don't know.
When we call CreateWindowEx, it will create the window. Before returning, it will send 3 messages to our WindowProc specifically WM_NCCREATE, WM_NCCALCSIZE, and WM_CREATE in that order. With WM_NCCALCSIZE and WM_CREATE, it's fine when you return 0 to the system. But in case of WM_NCCREATE, we must return TRUE so that the HWND will be valid. In your case, however, you returned FALSE that make CreateWindowEx to return 0.
Summing up everything, the GetLastError of 2 was generated by RegisterClassEx internally in registering the window class. CreateWindowEx succeeded in creating your window, so the system error of 2 is not touched, and it's ready to return a valid handle. CreateWindowEx sent you WM_NCCREATE, expecting you to return TRUE but you returned 0, and because of that it set its return value to NULL. You recieved NULL and because of that, you called GetLastError, because CreateWindowEx did not touch the error value, you still get the value set by RegisterClassEx. That's the whole story, AFAIK.
As Paul said, you must let the default window procedure process those messages you don't handle.
Hope it will clarify your concerns
-
July 27th, 2003, 11:45 PM
#12
Kind of unrelated, but I believe that other graphical, event-driven
operating systems do not work the same as Windows in terms of
message handling. You have to tell the OS what messages you
want to handle, as opposed to Windows sending you everything
but the kitchen sink. I believe X-Windows works this way (but I
may be wrong).
This is sort of like how MFC does things -- you have to explicitly
state what messages you want by defining them in your
message map.
Regards,
Paul McKenzie
-
July 28th, 2003, 03:21 AM
#13
Ahh, thanks for the explanation.
That given, I thought it might be the best way to implement the WndProc like this:
Code:
LRESULT CALLBACK WndProc( ... )
{
switch(message)
{
case WM_WHATEVER:
// handle the message or not...
break;
}
return DefWindowProc(...);
}
With this code, empty case blocks would not lead to an error, right? Because I always break to the end and return the default procedure. I have seen this approach in a sample code.
I'm currently only returning the default procedure when entering the 'default' case in the switch statement, otherwise I always return 0L. As far as I know, returning 0 tells the program that I handled a message successfully, therefor I'm a bit confused that rxbagain said CreateWindowEx failed because I always returned FALSE (0) in my Window Proc.
Can you clarify this?
- Matthias
"C makes it easy to shoot yourself in the foot; C++ makes it harder, but when you do it blows your whole leg off." - Bjarne Stroustrup
-
July 28th, 2003, 03:39 AM
#14
Originally posted by matthias_k
As far as I know, returning 0 tells the program that I handled a message successfully, therefor I'm a bit confused that rxbagain said CreateWindowEx failed because I always returned FALSE (0) in my Window Proc.
Can you clarify this?
Most messages we handle are generally handled this way (returning 0 means that there is no error). But for some messages, returning 0 means are error had occured. This is true in WM_NCCREATE message, which is the first message we encounter in our WindowProc when we create window. If we look at the documentation of WM_NCCREATE in MSDN, it says like this
If an application processes this message, it should return TRUE to continue creation of the window. If the application returns FALSE, the CreateWindow or CreateWindowEx function will return a NULL handle.
Usually, it's best to consult the documentation whenever we handle a specific message as to how it is handled and what we should return for it.
Hope it will clarify your concerns
Last edited by rxbagain; July 28th, 2003 at 03:41 AM.
-
July 28th, 2003, 05:02 AM
#15
- Matthias
"C makes it easy to shoot yourself in the foot; C++ makes it harder, but when you do it blows your whole leg off." - Bjarne Stroustrup
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|