/****************************************************************************************** * Chili Direct3D Engine * * Copyright 2018 PlanetChili * * * * This file is part of Chili Direct3D Engine. * * * * Chili Direct3D Engine is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, either version 3 of the License, or * * (at your option) any later version. * * * * The Chili Direct3D Engine is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with The Chili Direct3D Engine. If not, see . * ******************************************************************************************/ #include "Window.h" #include // Window Class Stuff Window::WindowClass Window::WindowClass::wndClass; Window::WindowClass::WindowClass() noexcept : hInst( GetModuleHandle( nullptr ) ) { WNDCLASSEX wc = { 0 }; wc.cbSize = sizeof( wc ); wc.style = CS_OWNDC; wc.lpfnWndProc = HandleMsgSetup; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = GetInstance(); wc.hIcon = nullptr; wc.hCursor = nullptr; wc.hbrBackground = nullptr; wc.lpszMenuName = nullptr; wc.lpszClassName = GetName(); wc.hIconSm = nullptr; RegisterClassEx( &wc ); } Window::WindowClass::~WindowClass() { UnregisterClass( wndClassName,GetInstance() ); } const char* Window::WindowClass::GetName() noexcept { return wndClassName; } HINSTANCE Window::WindowClass::GetInstance() noexcept { return wndClass.hInst; } // Window Stuff Window::Window( int width,int height,const char* name ) { // calculate window size based on desired client region size RECT wr; wr.left = 100; wr.right = width + wr.left; wr.top = 100; wr.bottom = height + wr.top; if (FAILED(AdjustWindowRect(&wr, WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU, FALSE))) { throw CHWND_LAST_EXCEPT(); }; // create window & get hWnd hWnd = CreateWindow( WindowClass::GetName(),name, WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU, CW_USEDEFAULT,CW_USEDEFAULT,wr.right - wr.left,wr.bottom - wr.top, nullptr,nullptr,WindowClass::GetInstance(),this // this 用来将该Window的实例和WinAPI连接起来 ); // check for error if (hWnd == nullptr) { throw CHWND_LAST_EXCEPT(); } // show window ShowWindow( hWnd,SW_SHOWDEFAULT ); } Window::~Window() { DestroyWindow( hWnd ); } LRESULT CALLBACK Window::HandleMsgSetup( HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam ) noexcept { // use create parameter passed in from CreateWindow() to store window class pointer at WinAPI side if( msg == WM_NCCREATE ) { // extract ptr to window class from creation data // 使用CREATESTRUCT函数的第一个参数lpCreateParams,通过reinterpret_cast,获取到CREATESTRUCT函数的指针 // lpCreateParams的指针和CREATESTRUCT的指针指向同一个物理地址,只是寻址对象不同 const CREATESTRUCTW* const pCreate = reinterpret_cast(lParam); // 取得指向Window的指针 Window* const pWnd = static_cast(pCreate->lpCreateParams); // 将Window类,存储到WinAPI // set WinAPI-managed user data to store ptr to window class SetWindowLongPtr( hWnd,GWLP_USERDATA,reinterpret_cast(pWnd) ); // set message proc to normal (non-setup) handler now that setup is finished SetWindowLongPtr( hWnd,GWLP_WNDPROC,reinterpret_cast(&Window::HandleMsgThunk) ); // forward message to window class handler return pWnd->HandleMsg( hWnd,msg,wParam,lParam ); } // if we get a message before the WM_NCCREATE message, handle with default handler return DefWindowProc( hWnd,msg,wParam,lParam ); } LRESULT CALLBACK Window::HandleMsgThunk( HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam ) noexcept { // retrieve ptr to window class Window* const pWnd = reinterpret_cast(GetWindowLongPtr( hWnd,GWLP_USERDATA )); // forward message to window class handler return pWnd->HandleMsg( hWnd,msg,wParam,lParam ); } LRESULT Window::HandleMsg( HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam ) noexcept { switch( msg ) { // we don't want the DefProc to handle this message because // we want our destructor to destroy the window, so return 0 instead of break case WM_CLOSE: PostQuitMessage( 0 ); return 0; } return DefWindowProc( hWnd,msg,wParam,lParam ); } // Window Exception Stuff Window::Exception::Exception(int line, const char* file, HRESULT hr) noexcept : ChiliException(line, file), hr(hr) {} const char* Window::Exception::what() const noexcept { std::ostringstream oss; oss << GetType() << std::endl << "[Error Code] " << GetErrorCode() << std::endl << "[Description] " << GetErrorString() << std::endl << GetOriginString(); whatBuffer = oss.str(); return whatBuffer.c_str(); } const char* Window::Exception::GetType() const noexcept { return "Chili Window Exception"; } std::string Window::Exception::TranslateErrorCode(HRESULT hr) noexcept { char* pMsgBuf = nullptr; // windows will allocate memory for err string and make our pointer point to it DWORD nMsgLen = FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, hr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), reinterpret_cast(&pMsgBuf), 0, nullptr ); // 0 string length returned indicates a failure if (nMsgLen == 0) { return "Unidentified error code"; } // copy error string from windows-allocated buffer to std::string std::string errorString = pMsgBuf; // free windows buffer LocalFree(pMsgBuf); return errorString; } HRESULT Window::Exception::GetErrorCode() const noexcept { return hr; } std::string Window::Exception::GetErrorString() const noexcept { return TranslateErrorCode(hr); }