ShowWindow неверный дескриптор окна
Недавно я пытался создать класс окна, используя Windows API в C++. Однако всякий раз, когда я пытаюсь вызвать ShowWindow, функция устанавливает последнюю ошибку на 1400 (ERROR_INVALID_WINDOW_HANDLE). Попробовав некоторое время, я наткнулся на следующий пример: http://blogs.msdn.com/b/oldnewthing/archive/2005/04/22/410773.aspx
Даже создав новый проект (я использую MSVC Express 2008) и точно скопировав код (что мне не хочется делать), я обнаружил, что, хотя код успешно создал окно, функция ShowWindow по-прежнему сообщает об ошибке 1400. Вот выдержка из код найден по ссылке выше:
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;
}
(Полный код можно найти по ссылке выше)
Если у кого-то есть идеи о том, как использовать дескриптор окна в качестве переменной-члена класса без получения ошибки 1400 в ShowWindow, я был бы очень признателен за помощь.
2 ответа
ShowWindow(prw->GetHWND(), nShowCmd);
int error = GetLastError();
Это не правильный код. Единственный раз, когда допустимо вызывать GetLastError(), это когда функция winapi не работает. Если вы используете GetLastError(), когда они не потерпели неудачу, вы получите совершенно случайное число. ShowWindow() немного отличается тем, что вообще не выдает код ошибки, поэтому использование GetLastError() никогда не бывает правильным.
Общий шаблон примерно:
if (!SomeWinapiFunction(...)) {
int error = GetLastError();
CrashAndBurn(error);
}
Но проверьте документацию MSDN, чтобы увидеть, какое возвращаемое значение указывает на ошибку и подходит ли GetLastError(). Например, это не относится к функциям GDI. Обязательно исправьте это и в других частях вашего кода. Правильная обработка ошибок очень важна, когда вы используете сырой API. В частности, обратите внимание, что ваш метод RootWindow::Create() не имеет хорошего способа указать на неудачу при создании окна. Это должно быть исправлено. Исключения, конечно, очень хороший способ сделать это.
У меня такая же проблема. Решением было переместить DefWindowProc() из значения по умолчанию в конец WndProc ().
До:
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;
}
После:
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);;
}