2012-12-25 42 views
4

我遵循NeHe gamedev教程(将它们改为OO),并且遇到了CreateWindowEx演示的问题(http://nehe.gamedev.net/tutorial/creating_an_opengl_window_(win32)/13001 /)。CreateWindowEx失败

我想一个指针传递WndProc中,以通过lpParam我的Window对象(如这里详细: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); 
} 
+0

您可以发布您的静态WindProc并在头文件中的类成员的WndProc的你的宣言? – cppanda

+0

静态的WindowProc已经在那里了,但我已经在成员的WindowProc编辑现在 –

+0

你有在COG命名空间中的静态的WndProc的头文件中的声明?如果没有,请尝试在没有cpp文件 – cppanda

回答

2

莫非你要请求全屏的事实而导致问题? 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调用有顺序错误的PARAMS - 特别实例paramater。你用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) 
      ); 
     } 
    } 
} 

[编辑]的情况下,更多的代码它有助于

//------------------------------------------------------------------------------ 
//! 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_); 
} 
+0

命名空间我试图改变我的代码看起来更像你(减去统一修改),而问题一直存在。解决问题的唯一方法是删除lpParam,但我需要这样做,因此这不是一个有效的解决方案。 –

+0

我添加了一些更多的代码,以便它可以帮助您追踪问题的根源。 – Brandon