endlich habe ich mal wieder Zeit gefunden, mich meinem kleinen Spielchen zu widmen. Dazu musste ich mich mal wieder in meinen Code einarbeiten und bin bei bei meiner Fensterimplementation auf ein Konstrukt gestossen,
zu welchem ich eine Frage habe. Aber zuerst mal mein zusammengefasster Fenstercode:
Code: Alles auswählen
#include <exception>
#include <string>
#include <utility>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#define WIN32_LEAN_AND_MEAN
#define STRICT
#define NOGDICAPMASKS // - CC_*, LC_*, PC_*, CP_*, TC_*, RC_
#define NOSYSMETRICS // - SM_*
#define NOMENUS // - MF_*
#define NOKEYSTATES // - MK_*
#define NORASTEROPS // - Binary and Tertiary raster ops
#define OEMRESOURCE // - OEM Resource values
#define NOATOM // - Atom Manager routines
#define NOCLIPBOARD // - Clipboard routines
#define NOCOLOR // - Screen colors
#define NOCTLMGR // - Control and Dialog routines
#define NODRAWTEXT // - DrawText() and DT_*
#define NOKERNEL // - All KERNEL defines and routines
#define NOMEMMGR // - GMEM_*, LMEM_*, GHND, LHND, associated routines
#define NOMETAFILE // - typedef METAFILEPICT
#define NOMINMAX // - Macros min(a,b) and max(a,b)
#define NOOPENFILE // - OpenFile(), OemToAnsi, AnsiToOem, and OF_*
#define NOSCROLL // - SB_* and scrolling routines
#define NOSERVICE // - All Service Controller routines, SERVICE_ equates, etc.
#define NOSOUND // - Sound driver routines
#define NOTEXTMETRIC // - typedef TEXTMETRIC and associated routines
#define NOWH // - SetWindowsHook and WH_*
#define NOCOMM // - COMM driver routines
#define NOKANJI // - Kanji support stuff.
#define NOHELP // - Help engine interface.
#define NOPROFILER // - Profiler interface.
#define NODEFERWINDOWPOS // - DeferWindowPos routines
#define NOMCX // - Modem Configuration Extensions
// #define NOVIRTUALKEYCODES // - VK_*
// #define NOWINMESSAGES // - WM_*, EM_*, LB_*, CB_*
// #define NOWINSTYLES // - WS_*, CS_*, ES_*, LBS_*, SBS_*, CBS_*
// #define NOICONS // - IDI_*
// #define NOSYSCOMMANDS // - SC_*
// #define NOSHOWWINDOW // - SW_*
// #define NOGDI // - All GDI defines and routines
// #define NOUSER // - All USER defines and routines
// #define NONLS // - All NLS defines and routines
// #define NOMB // - MB_* and MessageBox()
// #define NOMSG // - typedef MSG and associated routines
// #define NOWINOFFSETS // - GWL_*, GCL_*, associated routines
#include <Windows.h>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#if defined _M_IX86
#pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"")
#elif defined _M_IA64
#pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='ia64' publicKeyToken='6595b64144ccf1df' language='*'\"")
#elif defined _M_X64
#pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"")
#else
#pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
#endif
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
namespace Tutorial
{
class INonCopyAssignable
{
protected:
INonCopyAssignable()
{
return;
}
private:
INonCopyAssignable(INonCopyAssignable const & /* itsInstanceToCopy */);
INonCopyAssignable & operator = (INonCopyAssignable const & /* itsInstanceToAssign */);
};
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
namespace Tutorial
{
namespace Windows
{
::std::string CreateUTF8String(::std::wstring const & itsWideStringToConvert)
{
auto const sizeOfWideStringToConvert = static_cast<int>(itsWideStringToConvert.size());
if (0 == sizeOfWideStringToConvert)
{
return std::string();
}
//
// Die Grösse des zu erstellenden UTF8 Strings ermitteln.
//
auto const sizeOfStringToCreate = ::WideCharToMultiByte(
CP_UTF8,
0,
&itsWideStringToConvert[0],
sizeOfWideStringToConvert,
nullptr,
0,
nullptr,
nullptr);
if (0 == sizeOfStringToCreate)
{
throw std::exception("::WideCharToMultiByte() failed.");
}
//
// Den UTF8 String erstellen und initialisieren.
//
::std::string stringToCreate(sizeOfStringToCreate, 0);
auto const numberOfCharsWritten = ::WideCharToMultiByte(
CP_UTF8,
0,
&itsWideStringToConvert[0],
sizeOfWideStringToConvert,
&stringToCreate[0],
sizeOfStringToCreate,
nullptr,
nullptr);
if (0 == numberOfCharsWritten)
{
throw std::exception("::WideCharToMultiByte() failed.");
}
return stringToCreate;
}
::std::wstring CreateUTF16WideString(::std::string const & itsStringToConvert)
{
auto const sizeOfStringToConvert = static_cast<int>(itsStringToConvert.size());
if (0 == sizeOfStringToConvert)
{
return std::wstring();
}
//
// Die Grösse des zu erstellenden UTF16 Widestrings ermitteln.
//
auto const sizeOfWideStringToCreate = ::MultiByteToWideChar(
CP_UTF8,
0,
&itsStringToConvert[0],
sizeOfStringToConvert,
nullptr,
0);
if (0 == sizeOfWideStringToCreate)
{
throw std::exception("::MultiByteToWideChar() failed.");
}
//
// Den UTF16 Widestring erstellen und initialisieren.
//
::std::wstring wideStringToCreate(sizeOfWideStringToCreate, 0);
auto const numberOfWideCharsWritten = ::MultiByteToWideChar(
CP_UTF8,
0,
&itsStringToConvert[0],
sizeOfStringToConvert,
&wideStringToCreate[0],
sizeOfWideStringToCreate);
if (0 == numberOfWideCharsWritten)
{
throw std::exception("::MultiByteToWideChar() failed.");
}
return wideStringToCreate;
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
namespace Tutorial
{
namespace Windows
{
typedef ::std::pair<::size_t, ::size_t> UnsignedSizeType;
UnsignedSizeType GetWindowClientSize(::HWND const itsWindow)
{
if (nullptr == itsWindow)
{
return UnsignedSizeType();
}
::RECT clientRectangle;
::GetClientRect(itsWindow, &clientRectangle);
return UnsignedSizeType(
static_cast<::size_t>(clientRectangle.right),
static_cast<::size_t>(clientRectangle.bottom));
}
void SetWindowClientSize(::HWND const itsWindow, UnsignedSizeType const itsClientSize)
{
if (nullptr == itsWindow)
{
return;
}
//
// Die neue Fenstergrösse anhand des gesetzten Fensterstils und der neuen Klientgrösse
// berechnen und setzen.
//
::RECT windowRectangle =
{
0,
0,
static_cast<::LONG>(itsClientSize.first),
static_cast<::LONG>(itsClientSize.second),
};
::AdjustWindowRectEx(
&windowRectangle,
static_cast<::DWORD>(::GetWindowLongPtrW(itsWindow, GWL_STYLE)),
FALSE,
static_cast<::DWORD>(::GetWindowLongPtrW(itsWindow, GWL_EXSTYLE)));
::SetWindowPos(
itsWindow,
nullptr,
0,
0,
static_cast<int>(windowRectangle.right - windowRectangle.left),
static_cast<int>(windowRectangle.bottom - windowRectangle.top),
SWP_NOMOVE |
SWP_NOZORDER |
SWP_NOACTIVATE);
return;
}
namespace ScreenArea
{
enum Type
{
//
// Entspricht dem Desktop minus des Taskleiste.
//
Workspace,
//
// Entspricht dem Desktop mitsamt der Taskleiste.
//
Desktop
};
}
void CenterWindowAtNearestScreen(::HWND const itsWindow, ScreenArea::Type const itsScreenAreaArea)
{
if (nullptr == itsWindow)
{
return;
}
//
// Als erstes das nächtsgelegen Anzeigegerät und dessen Eigenschaften ermitteln.
//
::RECT windowRectangle;
::GetWindowRect(itsWindow, &windowRectangle);
auto const nearestScreen = ::MonitorFromRect(&windowRectangle, MONITOR_DEFAULTTONEAREST);
::MONITORINFO screenInfo;
screenInfo.cbSize = sizeof(::MONITORINFO);
::GetMonitorInfoW(nearestScreen, &screenInfo);
//
// Das Fenster anhand des gewünschten Bereiches zentrieren.
//
auto const screenRectangle = (ScreenArea::Desktop == itsScreenAreaArea) ?
screenInfo.rcMonitor :
screenInfo.rcWork;
auto const screenAreaWidth = static_cast<int>(screenRectangle.right);
auto const screenAreaHeight = static_cast<int>(screenRectangle.bottom);
auto const windowWidth = static_cast<int>(windowRectangle.right - windowRectangle.left);
auto const windowHeight = static_cast<int>(windowRectangle.bottom - windowRectangle.top);
::SetWindowPos(
itsWindow,
nullptr,
static_cast<int>((screenAreaWidth - windowWidth) * 0.5),
static_cast<int>((screenAreaHeight - windowHeight) * 0.5),
0,
0,
SWP_NOSIZE |
SWP_NOZORDER |
SWP_NOACTIVATE);
return;
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
namespace Tutorial
{
namespace Windows
{
class IWindowListener
{
public:
virtual bool MessageHandler(
::HWND const itsWindow,
::UINT const itsMessage,
::WPARAM const itsWordParameter,
::LPARAM const itsLongParameter) = 0;
};
void SetWindowListener(::HWND const itsWindow, IWindowListener const * toItsWindowListener)
{
if (nullptr == itsWindow)
{
return;
}
::SetWindowLongPtrW(itsWindow, GWLP_USERDATA, reinterpret_cast<::LONG_PTR>(toItsWindowListener));
return;
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
namespace Tutorial
{
namespace Windows
{
namespace Internal
{
static ::LRESULT CALLBACK WindowProcedure(
::HWND itsWindow,
::UINT itsMessage,
::WPARAM itsWordParameter,
::LPARAM itsLongParameter)
{
auto processMessage = true;
//
// Prüfen, ob ein Fensterbeobachter gesetzt worden ist und wenn ja, dessen
// Nachrichtenhandler aufrufen.
//
auto const toWindowListener = reinterpret_cast<IWindowListener *>(
::GetWindowLongPtrW(itsWindow, GWLP_USERDATA));
if (nullptr != toWindowListener)
{
processMessage = toWindowListener->MessageHandler(
itsWindow,
itsMessage,
itsWordParameter,
itsLongParameter);
}
//
// WM_CLOSE nicht weiterverarbeiten da ansonsten ::DestroyWindow() aufgerufen werden würde.
// Dies aber erledigt bereits der Destruktor der betreffenden Fensterinstanz.
//
if (WM_CLOSE == itsMessage || !processMessage)
{
return 0;
}
return ::DefWindowProcW(itsWindow, itsMessage, itsWordParameter, itsLongParameter);
}
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
namespace Tutorial
{
namespace Windows
{
class WindowClass : private INonCopyAssignable
{
public:
WindowClass(
::std::string const & itsClassName,
::HINSTANCE const itsModuleInstance,
::HICON const itsWindowIcon,
::HCURSOR const itsWindowCursor,
::HBRUSH const itsWindowBackgroundColor,
::UINT const itsClassStyle)
: myClassName(CreateUTF16WideString(itsClassName))
, myModuleInstance(itsModuleInstance)
{
::WNDCLASSEXW const classDescription =
{
sizeof(::WNDCLASSEXW),
itsClassStyle,
&Internal::WindowProcedure,
0,
0,
myModuleInstance,
itsWindowIcon,
itsWindowCursor,
itsWindowBackgroundColor,
nullptr,
myClassName.data(),
itsWindowIcon
};
if (0 == ::RegisterClassExW(&classDescription))
{
throw std::exception("::RegisterClassExW() failed.");
}
return;
}
WindowClass(
::std::string const & itsClassName,
::std::string const & itsMenuName,
::HINSTANCE const itsModuleInstance,
::HICON const itsWindowIcon,
::HCURSOR const itsWindowCursor,
::HBRUSH const itsWindowBackgroundColor,
::UINT const itsClassStyle)
: myClassName(CreateUTF16WideString(itsClassName))
, myModuleInstance(itsModuleInstance)
{
auto const menuName = CreateUTF16WideString(itsMenuName);
::WNDCLASSEXW const classDescription =
{
sizeof(::WNDCLASSEXW),
itsClassStyle,
&Internal::WindowProcedure,
0,
0,
myModuleInstance,
itsWindowIcon,
itsWindowCursor,
itsWindowBackgroundColor,
menuName.data(),
myClassName.data(),
itsWindowIcon
};
if (0 == ::RegisterClassExW(&classDescription))
{
throw std::exception("::RegisterClassExW() failed.");
}
return;
}
~WindowClass()
{
::UnregisterClassW(myClassName.data(), myModuleInstance);
return;
}
private:
::std::wstring const myClassName;
::HINSTANCE const myModuleInstance;
};
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
namespace Tutorial
{
namespace Windows
{
class Window : private INonCopyAssignable
{
public:
Window(
::std::string const & itsWindowClassName,
::std::string const & itsWindowName,
::DWORD const itsWindowStyle,
::DWORD const itsExtendedWindowStyle,
::HINSTANCE const itsModuleInstance,
::HMENU const itsMenu,
::HWND const itsParentWindow)
{
auto const windowClassName = CreateUTF16WideString(itsWindowClassName);
auto const windowName = CreateUTF16WideString(itsWindowName);
myWindow = ::CreateWindowExW(
itsExtendedWindowStyle,
windowClassName.data(),
windowName.data(),
itsWindowStyle,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
itsParentWindow,
itsMenu,
itsModuleInstance,
nullptr);
if (nullptr == myWindow)
{
throw std::exception("::CreateWindowExW() failed.");
}
return;
}
~Window()
{
//
// Den Benutzerbereich des Fensters freigeben damit auf dessen Daten nicht mehr
// zugegriffen werden kann da nun das Fenster nicht mehr gültig ist.
//
::SetWindowLongPtrW(myWindow, GWLP_USERDATA, reinterpret_cast<::LONG_PTR>(nullptr));
::DestroyWindow(myWindow);
return;
}
::HWND GetHandle() const
{
return myWindow;
}
private:
::HWND myWindow;
};
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
namespace Tutorial
{
class Application : private INonCopyAssignable, private Windows::IWindowListener
{
public:
explicit Application(::HINSTANCE const itsModuleInstance)
//
// Bevor ein Fenster erstellt werden kann, muss bereits eine entsprechende
// Fensterklasse registriert worden sein.
//
: myWindowClass(
"RenderWindow",
itsModuleInstance,
::LoadIconW(nullptr, IDI_APPLICATION),
::LoadCursorW(nullptr, IDC_ARROW),
reinterpret_cast<::HBRUSH>(::GetStockObject(BLACK_BRUSH)),
CS_DBLCLKS)
, myWindow(
"RenderWindow",
"Tutorial",
WS_OVERLAPPEDWINDOW,
WS_EX_OVERLAPPEDWINDOW,
itsModuleInstance,
nullptr,
nullptr)
, myIsRunningState(true)
, myHasEndedNormallyState(true)
{
auto const window = myWindow.GetHandle();
//
// Dem Fenster die eigene Instanz übergeben damit der Nachrichtenhandler
// aufgerufen werden kann.
//
Windows::SetWindowListener(window, this);
Windows::SetWindowClientSize(window, Windows::UnsignedSizeType(1280, 720));
Windows::CenterWindowAtNearestScreen(window, Windows::ScreenArea::Workspace);
::ShowWindow(window, SW_SHOWNORMAL);
::SetForegroundWindow(window);
return;
}
void RunMessageLoop()
{
//
// Sicherstellen, dass nach einer Ausnhame die Nachrichtenschleife nicht erneut
// ausgeführt werden kann.
//
if (!myHasEndedNormallyState)
{
return;
}
myHasEndedNormallyState = false;
::MSG message = { 0 };
while (myIsRunningState)
{
if (::PeekMessageW(&message, nullptr, 0, 0, PM_REMOVE))
{
::TranslateMessage(&message);
::DispatchMessageW(&message);
}
else
{
//
// Render();
//
}
}
myHasEndedNormallyState = true;
return;
}
private:
bool MessageHandler(
::HWND const /* itsWindow */,
::UINT const itsMessage,
::WPARAM const /* itsWordParameter */,
::LPARAM const /* itsLongParameter */) final override
{
if (WM_CLOSE == itsMessage)
{
myIsRunningState = false;
}
return true;
}
private:
Windows::WindowClass const myWindowClass;
Windows::Window const myWindow;
bool myIsRunningState;
bool myHasEndedNormallyState;
};
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int WINAPI WinMain(
_In_ ::HINSTANCE itsModuleInstance,
_In_opt_ ::HINSTANCE /* itsPreviousModuleInstance */,
_In_ ::LPSTR /* toItsCommandLine */,
_In_ int /* itsShowCommand */)
{
using namespace ::Tutorial;
try
{
try
{
Application application(itsModuleInstance);
application.RunMessageLoop();
}
catch (std::exception const & exception)
{
auto const message = Windows::CreateUTF16WideString(exception.what());
auto const caption = Windows::CreateUTF16WideString("Tutorial - Exception");
::MessageBoxW(nullptr, message.data(), caption.data(), MB_ICONERROR | MB_SETFOREGROUND);
}
}
catch (...)
{
//
// Alles im Popo.
//
::MessageBoxA(nullptr, "System exception.", "Tutorial - Exception", MB_ICONERROR | MB_SETFOREGROUND);
}
return 0;
}
Besten Dank schon mal im Voraus