3

I have been trying recently to create a window class using the Windows API in C++. However, whenever I attempt to call ShowWindow, the function sets the last error to 1400 (ERROR_INVALID_WINDOW_HANDLE). After trying for a while, I stumbled across the following example: http://blogs.msdn.com/b/oldnewthing/archive/2005/04/22/410773.aspx#comments

Even creating a new project (I use MSVC Express 2008) and copying the code exactly (which I hate to do), I discovered that, while the code successfully created a window, the ShowWindow function still reported error 1400. Here is an excerpt from the code found at the above link:

int PASCAL
WinMain(HINSTANCE hinst, HINSTANCE, LPSTR, int nShowCmd)
{
 g_hinst = hinst;

 if (SUCCEEDED(CoInitialize(NULL))) {
  InitCommonControls();

  RootWindow *prw = RootWindow::Create();
  if (prw) {
   ShowWindow(prw->GetHWND(), nShowCmd);
   int error = GetLastError(); //Line added by me, error gets set to 1400.
   MSG msg;
       while (GetMessage(&msg, NULL, 0, 0)) {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
   }
  }
  CoUninitialize();
 }
 return 0;
}

(The full code can be found at the above link)

If anyone has any ideas on how to have the window handle as a member variable of a class without receiving error 1400 on ShowWindow, I would greatly appreciate some help.

Mmarss
  • 178
  • 1
  • 5
  • This may sound trivial, but did you *check* the GetHWND() return value to ensure it is set to a valid window handle? I.e `if (!::IsWindow(prw->GetHWND()) { panic }` ? The code you linked (which was honestly already antiquated when it was written and time hasn't done it any favors) relies on processing WM_NCCREATE to set the member window handle. If this isn't done correctly or an error condition happened along the way, your window handle will not be valid. – WhozCraig Mar 01 '13 at 23:36
  • I tried adding in the code as suggested, but IsWindow returned 1, indicating that the window handle identifies an existing window [see microsoft.com: IsWindow() function](http://msdn.microsoft.com/en-us/library/windows/desktop/ms633528%28v=vs.85%29.aspx). – Mmarss Mar 01 '13 at 23:44

2 Answers2

6
   ShowWindow(prw->GetHWND(), nShowCmd);
   int error = GetLastError();

This is not correct code. The only time it is valid to call GetLastError() is when a winapi function failed. If you use GetLastError() when they didn't fail then you'll get a completely random number. ShowWindow() is a bit special in that it doesn't produce an error code at all so using GetLastError() is never correct.

The generic pattern is roughly:

if (!SomeWinapiFunction(...)) {
    int error = GetLastError();
    CrashAndBurn(error);
}

But do check the MSDN documentation to see what return value indicates an error and whether GetLastError() is appropriate. It is generally not on GDI functions for example. Be sure to correct this in other parts of your code as well. Getting error handling right is very important when you use the raw api. In particular note how your RootWindow::Create() method has no good way to indicate failure to create the window. That needs to be fixed. Exceptions are of course a very good way to do so.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • +1 Very nice catch, Hans. I had mistakenly assumed he had already deduced the API failed. Never crossed my mind that his "problem" was that there was no problem. – WhozCraig Mar 02 '13 at 00:51
  • Many thanks, but do you have any idea why a function that completed successfully would report that an error had occurred through GetLastError? – Mmarss Mar 02 '13 at 05:01
  • Again, it **didn't** report any error. It returned TRUE. Calling GetLastError() when there was no error gives you an arbitrary number. It is not a cryptographically secure random number however. – Hans Passant Mar 02 '13 at 10:45
  • 1
    ShowWindow doesn't return an error flag. It returns previous visibility of the window. https://msdn.microsoft.com/en-us/library/windows/desktop/ms633548(v=vs.85).aspx – Tereza Tomcova Jul 08 '16 at 21:32
0

I had the same problem. The solution was to move DefWindowProc() from default to the end of WndProc().

Before:

LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
    static HBITMAP hBitMap;
    static int cxSizeBitMap;
    static int cySizeBitMap;
    static int cxClient;
    static int cyClient;
    HDC hdc;
    BITMAP bitMap;
    PAINTSTRUCT ps;
    HDC hMem;
    HINSTANCE      hInstance ;
    switch( message ) 
    {
        case WM_CREATE:
            hInstance = ((LPCREATESTRUCT) lParam)->hInstance ;
            hBitMap = LoadBitmap( hInstance, MAKEINTRESOURCE( IDB_BRICK ) );
            GetObject( hBitMap, sizeof(BITMAP), &bitMap );
            cxSizeBitMap = bitMap.bmWidth;
            cySizeBitMap = bitMap.bmHeight;
            break;
        case WM_SIZE:
          cxClient = LOWORD (lParam) ;
          cyClient = HIWORD (lParam) ;
            break;
        case WM_PAINT:
            hdc = BeginPaint( hWnd, &ps );
            hMem = CreateCompatibleDC( hdc );
            SelectObject( hMem,  hBitMap );
            for (int y = 0 ; y < cyClient ; y += cySizeBitMap)
            for (int x = 0 ; x < cxClient ; x += cxSizeBitMap)
            {
               BitBlt (hdc, x, y, cxSizeBitMap, cySizeBitMap, hMem, 0, 0, SRCCOPY) ;
            }
            DeleteDC( hMem );
            EndPaint( hWnd, &ps );
            break;
        case WM_DESTROY:
            DeleteObject( hBitMap );
            PostQuitMessage( 0 );
            break;
        default:
            // In this cast ShowWindow() will return 1400.
            DefWindowProc(hWnd, message, wParam, lParam);
    }

    return 0;
}

After:

LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
    static HBITMAP hBitMap;
    static int cxSizeBitMap;
    static int cySizeBitMap;
    static int cxClient;
    static int cyClient;
    HDC hdc;
    BITMAP bitMap;
    PAINTSTRUCT ps;
    HDC hMem;
    HINSTANCE      hInstance ;
    switch( message ) 
    {
        case WM_CREATE:
            hInstance = ((LPCREATESTRUCT) lParam)->hInstance ;
            hBitMap = LoadBitmap( hInstance, MAKEINTRESOURCE( IDB_BRICK ) );
            GetObject( hBitMap, sizeof(BITMAP), &bitMap );
            cxSizeBitMap = bitMap.bmWidth;
            cySizeBitMap = bitMap.bmHeight;
            break;
        case WM_SIZE:
          cxClient = LOWORD (lParam) ;
          cyClient = HIWORD (lParam) ;
            break;

        case WM_PAINT:
            hdc = BeginPaint( hWnd, &ps );
            hMem = CreateCompatibleDC( hdc );

            // Было SelectObject( hdc,  hMem );
            SelectObject( hMem,  hBitMap );
            // Было BitBlt( hdc, 0, 0, cxSize, cySize, hMem, 0, 0, DIB_RGB_COLORS);
            for (int y = 0 ; y < cyClient ; y += cySizeBitMap)
            for (int x = 0 ; x < cxClient ; x += cxSizeBitMap)
            {
               BitBlt (hdc, x, y, cxSizeBitMap, cySizeBitMap, hMem, 0, 0, SRCCOPY) ;
            }


            DeleteDC( hMem );
            EndPaint( hWnd, &ps );
            break;
        case WM_DESTROY:
            DeleteObject( hBitMap );
            PostQuitMessage( 0 );
            break;
    }

    // In this case ShowWindow() will show the window.
    return DefWindowProc(hWnd, message, wParam, lParam);;
}
Daniil Vorobeyv
  • 145
  • 2
  • 2
  • 10