2012-12-25 2 views
4

저는 NeHe gamedev 튜토리얼을 따르고 있습니다. (OO로 변경하면서) CreateWindowEx 데모 (http://nehe.gamedev.net/tutorial/creating_an_opengl_window_(win32)에서 문제가 발생했습니다./13001 /). (여기에 자세히 설명 : http://web.archive.org/web/20051125022758/www.rpi.edu/~pudeyo/articles/wndproc/) CreateWindowEx가 실패했습니다.

은 내가 lpParam를 통해 내 윈도우 객체에의 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

장부 이름 공간의 헤더 파일에 정적 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을 제거하는 것 뿐이므로 유효한 솔루션이 아니기 때문에 lpParam이 필요합니다. –

+0

문제의 원인을 추적하는 데 도움이되는 경우 더 많은 코드를 추가했습니다. – Brandon

관련 문제