Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

error code

102 views
Skip to first unread message

rahul

unread,
Jan 5, 2010, 6:00:34 AM1/5/10
to
I am creating window with CreateEx function.
But it fails (and returns zero ) so no window is created.
When I call GetLastError just after CreatEx call return 0 means no
ERROR. Why??
Doesn't failure of CreateEx function set the error code??
Which functions set the error code (which is retrived by
GetLastError) ??

David Wilkinson

unread,
Jan 5, 2010, 7:02:18 AM1/5/10
to

The documentation of CWnd::CreateEx() does not say that it sets the error state.

Run under the debugger and step into the CreateEx() code.

Or post your code here.

--
David Wilkinson
Visual C++ MVP

Giovanni Dicanio

unread,
Jan 5, 2010, 7:18:41 AM1/5/10
to
"rahul" <hyra...@gmail.com> ha scritto nel messaggio
news:1d4431cf-e9bf-452a...@k19g2000yqc.googlegroups.com...

> I am creating window with CreateEx function.
> But it fails (and returns zero ) so no window is created.
> When I call GetLastError just after CreatEx call return 0 means no
> ERROR. Why??

It makes sense to call GetLastError after calling raw Win32 API
::CreateWindowEx, not after CWnd::CreateEx.

For example, if CreateWindowEx call (inside CWnd::CreateEx body) fails,
other functions are called before CWnd::CreateEx returns FALSE.

In fact, in CWnd::CreateEx implementation in wincore.cpp (VS2008 SP1), I can
read:

<code>
...
if (!AfxUnhookWindowCreate())
PostNcDestroy(); // cleanup if CreateWindowEx fails too soon

if (hWnd == NULL)
return FALSE;

</code>

So, if CreateWindowEx failed, AfxUnhookWindowCreate is called, and
PostNcDestroy could be called, before CWnd::CreateEx returns FALSE.
I think these functions may alter the error state, making GetLastError calls
after CWnd::CreateEx meaningless.

Giovanni

Goran

unread,
Jan 5, 2010, 9:08:58 AM1/5/10
to

As explained by Giovanni, last error is probably eaten by cleanup
code. A quick inspection of ::CreateEx shows that you can see
GetLastError() in _DEBUG builds.

My guess is that the MFC people thinking goes like this: there's two
reasons for CreateEx to fail, either there is a resource shortage, in
which case result FALSE means OutOfResources, either there is a bug in
client code, in which case it's enough to show last error only in
_DEBUG builds.

Of course, that's not very nice. It's better to employ scope guard^^^^
and preserve original error code, e.g.

void ___RestoreLastError(DWORD e)
{ SetLastError(e); }

void ___UnhookWindowCreate(CWnd& wnd)
{
if (AfxUnhookWindowCreate())
wnd.PostNcDestroy();
}

BOOL CWnd::CreateEx(....)
{
.......

DWORD dwLastError=NOERROR;
ScopeGuard GuardLastError = MakeGuard(&__RestoreLastError, ByRef
(dwLastError));

AfxHookWindowCreate(this); // wincore.cpp, line 705 (VS2008 MFC
sources)
ON_BLOCK_EXIT(&___UnhookWindowCreate, *this);

if (::AfxCtxCreateWindowEx(cs.dwExStyle, cs.lpszClass,
cs.lpszName, cs.style, cs.x, cs.y, cs.cx, cs.cy,
cs.hwndParent, cs.hMenu, cs.hInstance, cs.lpCreateParams) == NULL)
{
dwLastCreationError = GetLastError();
return FALSE;
}
ASSERT(hWnd == m_hWnd); // should have been set in send msg hook

GuardLastError.dismiss(); // Creation worked, don't touch last
error.
return TRUE;
}

Goran.

P.S. (^^^^) he who knows not of ScopeGuard, Google it; if you know C+
+, it will forever change the way you code, and for the better.

P.P.S How does the above work? (Provided it does, since it's compiled
with head-compiler and debugged with head-debugger). In short: we
register last error just after the failed call to
AfxCtxCreateWindowEx. GuardLastError object forces a call to
SetLastError. Call to SetLastError happens just before CWnd::CreateEx
exits, during the destruction of GuardLastError object. One has to be
a crafty bastard and place GuardLastError in a good place so that it
this is indeed last to be destroyed, which I am (crafty bastard, that
is). If creation works, GuardLastError is "dismissed" (in scope guard
parlance), that is, we don't touch last error value on success. Call
to AfxHookWindowCreate is matched with Unhook/PostDestroy in lines
718/719. That's assured through ON_BLOCK_EXIT with
___UnhookWindowCreate.

P.P.P.S. This seems complicated, and indeed it is in a simple
situation like this. However, judicious application of scope guard in
anything a more complicated easily makes for simpler code. And when
exceptions are present (and they are even if you don't see any throw
statements), code gets unwieldy even easier. For example, just ask
yourself how would correct code look like if AfxCtxCreateWindowEx
could throw. (BTW, I guess it can't; if it can, CWnd:::CreateEx does
not satisfy "Basic exception safety" from
http://en.wikipedia.org/wiki/Exception_handling#Exception_safety. That
wouldn't be a surprise, though; quick glance at MFC sources shows that
MFC is all but exception safe. But luckily for MFC, next contender,
Qt, ain't any better in that regard either).

Joseph M. Newcomer

unread,
Jan 5, 2010, 8:49:29 PM1/5/10
to
As pointed out, CWnd::CreateEx does not set the error code. I consider this a serious
defect, and have reported it numerous times over the years, but hey, why should we be told
why something fails, when the perfect MFC design means that this information is not
necessary...

[Sorry, I get tired of seeing the same bugs come back year after year, even though they
are reasonbly trivial for Microsoft to fix]

As pointed out, single-stepping into the code helps. Note also that there are a number of
places where, instead of ASSERT statements, MFC just prints out English-language messages
about problems (often with decimal values displayed in hex, because hex is so much
cooler), so be sure to look in your output window.

But ultimately, the most effective procedure is to single-step through CWnd::CreateEx with
the step-into function (F11 default shortcut) to see what is happening. Closing your eyes
and saying "MFC is perfect, I don't need to look into it" is not a viable approach to this
kind of debugging.
joe

Joseph M. Newcomer [MVP]
email: newc...@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm

0 new messages