CreateWindowEx failing



我正在遵循NeHe游戏开发教程(同时将它们更改为OO),我遇到了CreateWindowEx演示(http://nehe.gamedev.net/tutorial/creating_an_opengl_window_(win32)/13001/)的问题。

我试图通过lpParam传递WndProc指针到我的窗口对象(详见这里:http://web.archive.org/web/20051125022758/www.rpi.edu/~pudeyo/articles/wndproc/),但如果我试图这样做,CreateWindowEx失败与GetLastError返回1400 - ERROR_INVALID_WINDOW_HANDLE。

我是一个完全的windows API初学者,并且已经用尽了我所知道的解决这个问题的所有方法,请您指出我在这里的错误吗?相关代码如下:

LRESULT CALLBACK cog::WindowProc(HWND window, UINT msg, WPARAM wParam, LPARAM lParam) {
    // Member method as windowproc: http://web.archive.org/web/20051125022758/www.rpi.edu/~pudeyo/articles/wndproc/
    if(msg == WM_NCCREATE) {
        LPCREATESTRUCT cs = (LPCREATESTRUCT)lParam;
        SetWindowLong(window, GWL_USERDATA, (long)cs->lpCreateParams);
    }
    cog::Window* w = (cog::Window*)GetWindowLong(window, GWL_USERDATA);
    if(w) {
        return w->windowProc(msg, wParam, lParam);
    } else {
        return DefWindowProc(window, msg, wParam, lParam);
    }
}
cog::Window::Window(int width, int height, int bits, bool fullscreen) :
fullscreen(fullscreen), appInstance(GetModuleHandle(NULL)), active(FALSE) {
    // Generate a rectangle corresponding to the window size
    RECT winRect = {0, 0, width, height};
    WNDCLASS winClass;
     winClass.style         = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;   // Redraw On Size, And Own DC For Window.
    winClass.lpfnWndProc    = (WNDPROC) cog::WindowProc;            // WndProc Handles Messages
    winClass.cbClsExtra     = 0;                                    // No Extra Window Data
    winClass.cbWndExtra     = sizeof(this);                         // Window Data - pointer to Window object
    winClass.hInstance      = this->appInstance;                    // Set The Instance
    winClass.hIcon          = LoadIcon(NULL, IDI_WINLOGO);          // Load The Default Icon
    winClass.hCursor        = LoadCursor(NULL, IDC_ARROW);          // Load The Arrow Pointer
    winClass.hbrBackground  = NULL;                                 // No Background Required For GL
    winClass.lpszMenuName   = NULL;                                 // We Don't Want A Menu
    winClass.lpszClassName  = TEXT("OpenGL");   
    if(!RegisterClass(&winClass)) {
        throw cog::WindowException(std::string("Failed to register class"));
    }
    if(this->fullscreen) {
        DEVMODE screenSettings;
        memset(&screenSettings, 0, sizeof(DEVMODE));
        screenSettings.dmSize = sizeof(DEVMODE);
        screenSettings.dmPelsWidth = width;
        screenSettings.dmPelsHeight = height;
        screenSettings.dmBitsPerPel = bits;
        screenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
        if(DISP_CHANGE_SUCCESSFUL != ChangeDisplaySettings(&screenSettings, CDS_FULLSCREEN)) {
            if(MessageBox(NULL, "Cannot start in full screen mode - start in windowed mode instead?", "OpenGL", MB_YESNO | MB_ICONEXCLAMATION)) {
                this->fullscreen = FALSE;
            } else {
                throw cog::WindowException(std::string("Refused to launch program in windowed mode"));
            }
        }
    }
    DWORD winExStyle;
    DWORD winStyle;
    if(fullscreen) {
        winExStyle = WS_EX_APPWINDOW;
        winStyle = WS_POPUP;
        ShowCursor(FALSE);
    } else {
        winExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
        winStyle = WS_OVERLAPPEDWINDOW;
    }
    AdjustWindowRectEx(&winRect, winStyle, FALSE, winExStyle);
    /*
     * !! BLOWS UP AT THIS CALL - WindowException triggered
     */
    if(!(this->window = CreateWindowEx(
    winExStyle,
    TEXT("OpenGL"),
    TEXT("OpenGL Testing"),
    winStyle,
    0, 0,
    winRect.right - winRect.left,
    winRect.bottom - winRect.top,
    NULL,
    NULL,
    this->appInstance,
    this))) {
        throw cog::WindowException(std::string("Failed to create window"));
    }
    // ... cut here ...
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE lPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
    MSG msg;
    cog::Window* w = NULL;
    try {
        w = new cog::Window(100, 100, 16, TRUE);
        // ... cut here ...
    } catch(cog::Exception e) {
        MessageBox(NULL, e.what(), "Exception Raised", MB_OK | MB_ICONEXCLAMATION);
    }
    if(w) {
        delete w;
    }
}

成员windowProc:

LRESULT CALLBACK cog::Window::windowProc(UINT msg, WPARAM wParam, LPARAM lParam) {
    switch(msg) {
    case WM_ACTIVATE:
        if(HIWORD(wParam)) {
            this->active = FALSE;
        } else {
            this->active = TRUE;
        }
        return 0;;
    case WM_SYSCOMMAND:
        switch(wParam) {
        case SC_SCREENSAVE:
        case SC_MONITORPOWER:
            return 0;
        }
        break;
    case WM_CLOSE:
        PostQuitMessage(0);
        return 0;
    case WM_KEYDOWN:
        this->keys[wParam] = TRUE;
        break;
    case WM_KEYUP:
        this->keys[wParam] = FALSE;
        break;
    case WM_SIZE:
        this->resize(LOWORD(lParam), HIWORD(lParam));
        return 0;
    default:
        break;
    }
    return DefWindowProc(this->window, msg, wParam, lParam);
}

请求全屏会导致问题吗?w = new cog::Window(100, 100, 16, TRUE);

如果它有帮助,这在我的代码库中工作:

HWND impl::window_impl::create_window_(
    window_impl* window // associated window object
) {
    auto const INSTANCE = ::GetModuleHandleW(L"");
    WNDCLASSEXW const wc = {
        sizeof(WNDCLASSEXW),
        CS_OWNDC | CS_HREDRAW | CS_VREDRAW,
        window_impl::top_level_wnd_proc_,
        0,
        0,
        INSTANCE,
        nullptr,
        ::LoadCursorW(nullptr, MAKEINTRESOURCE(IDC_ARROW)),
        nullptr,
        nullptr,
        CLASS_NAME,
        nullptr
    };
    ::RegisterClassExW(&wc); // ignore return value
    auto const result = ::CreateWindowExW(
        0,
        CLASS_NAME,
        L"window",
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT,
        CW_USEDEFAULT, CW_USEDEFAULT,
        (HWND)nullptr ,
        (HMENU)nullptr,
        INSTANCE,
        window
    );
    return result;
}

[编辑]我认为你对CreateWindowExW的调用有错误顺序的参数——特别是实例参数。你是否使用STRICT进行编译?它应该能检测到这类问题。

[编辑]没有直接关系,但是当编译为64位代码时,您的实现将无法工作,并且它不会检查可能的错误-您应该使用类似的内容:

//--------------------------------------------------------------------------
//! Get the userdata for the window given by @c hwnd (our window object).
//! @throw bklib::platform::windows_exception
//--------------------------------------------------------------------------
impl::window_impl* get_window_ptr(HWND hwnd) {
    ::SetLastError(0);
    auto const result = ::GetWindowLongPtrW(hwnd, GWLP_USERDATA);
    if (result == 0) {
        auto const e = ::GetLastError();
        if (e) {
            BOOST_THROW_EXCEPTION(bklib::platform::windows_exception()
                << bklib::platform::windows_error_code(e)
            );
        }
    }
    return reinterpret_cast<impl::window_impl*>(result);
}
//--------------------------------------------------------------------------
//! Set the userdata for the window given by @c hwnd to be our
//! window object.
//! @throw bklib::platform::windows_exception
//--------------------------------------------------------------------------
void set_window_ptr(HWND hwnd, impl::window_impl* ptr) {
    ::SetLastError(0);
    auto const result = ::SetWindowLongPtrW(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(ptr));
    if (result == 0) {
        auto const e = ::GetLastError();
        if (e) {
            BOOST_THROW_EXCEPTION(bklib::platform::windows_exception()
                << bklib::platform::windows_error_code(e)
            );
        }
    }
}

[edit]更多的代码,如果它有帮助

//------------------------------------------------------------------------------
//! Top level window procedure which forwards messages to the appropriate
//! impl::window_impl instance.
//! @throw noexcept
//!     Swallows all exceptions at the API boundary.
//------------------------------------------------------------------------------
LRESULT CALLBACK impl::window_impl::top_level_wnd_proc_(
    HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam
) try {
    // set the instance pointer for the window given by hwnd if it was just created
    if (msg == WM_NCCREATE) {
        auto const cs =
            reinterpret_cast<CREATESTRUCTW const*>(lParam);
        auto const window_ptr =
            reinterpret_cast<window_impl*>(cs->lpCreateParams);
        set_window_ptr(hwnd, window_ptr);
    }
    // the window object to forward the message to
    auto const window = get_window_ptr(hwnd);
    if (window) {
        return window->window_proc_(hwnd, msg, wParam, lParam);
    } else {
        // it's possible we will receive some messages beofre WM_NCCREATE;
        // use the default handler
        return ::DefWindowProcW(hwnd, msg, wParam, lParam);
    }
} catch (std::exception&) {
    ::PostQuitMessage(-1);
    return 0;
} catch (...) {
    ::PostQuitMessage(-1);
    return 0;
}
//------------------------------------------------------------------------------
//! Called by the top level window proc. Dispatches messages to their
//! appropriate handler function.
//------------------------------------------------------------------------------
LRESULT impl::window_impl::window_proc_(
    HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam
) {
    return ::DefWindowProcW(hwnd, msg, wParam, lParam);
}
//------------------------------------------------------------------------------
void impl::window_impl::create() {
    handle_ = create_window_(this);
}
//------------------------------------------------------------------------------
void impl::window_impl::show(bool visible) {
    ::ShowWindow(handle_, SW_SHOWDEFAULT);
    ::InvalidateRect(handle_, nullptr, FALSE);
    ::UpdateWindow(handle_);
}

最新更新