#include <windows.h>
#include <string>
#include <stdexcept>
namespace{
LRESULT CALLBACK MainWindowProc(HWND, UINT, WPARAM, LPARAM);
}
class App
{
public:
App(HINSTANCE instance_exe);
App(const App &) = delete;
App& operator=(const App &) = delete;
public:
~App();
public:
void Shutdown(bool throw_exceptions = false);
void SetupMainWindow();
void CloseMainWindow();
bool PumpMessages();
private:
HINSTANCE instance_exe_;
HWINSTA old_winsta_;
HDESK old_desk_;
HWINSTA winsta_;
HDESK desk_;
bool shutdown_;
HWND wnd_;
std::wstring wndclass_name_;
};
namespace global{
App *app {};
}
App::App(HINSTANCE instance_exe):
instance_exe_{instance_exe},
old_winsta_ {},
old_desk_ {},
winsta_ {},
desk_ {},
shutdown_ {},
wnd_{},
wndclass_name_{}
{
global::app = this;
old_winsta_ = GetProcessWindowStation();
if(old_winsta_ == nullptr){
throw std::runtime_error(
"GetProcessWindowStation failed :" +
std::to_string(GetLastError()));
}
old_desk_ = GetThreadDesktop(GetCurrentThreadId());
if(old_desk_ == nullptr){
throw std::runtime_error(
"GetThreadDesktop failed :" +
std::to_string(GetLastError()));
}
winsta_ = OpenWindowStation("winsta0", false,
WINSTA_ACCESSCLIPBOARD |
WINSTA_ACCESSGLOBALATOMS |
WINSTA_CREATEDESKTOP |
WINSTA_ENUMDESKTOPS |
WINSTA_ENUMERATE |
WINSTA_EXITWINDOWS |
WINSTA_READATTRIBUTES |
WINSTA_READSCREEN |
WINSTA_WRITEATTRIBUTES);
if(winsta_ == nullptr){
throw std::runtime_error(
"OpenWindowStation (winsta0) failed :" +
std::to_string(GetLastError()));
}
if(!SetProcessWindowStation(winsta_)){
throw std::runtime_error(
"SetProcessWindowStation (winsta0) failed :" +
std::to_string(GetLastError()));
}
HDESK test_desk = GetThreadDesktop(GetCurrentThreadId());
if(test_desk == nullptr){
throw std::runtime_error(
"Test desktop failed :" +
std::to_string(GetLastError()));
}
desk_ = OpenDesktop(
"default", 0, false,
DESKTOP_CREATEMENU |
DESKTOP_SWITCHDESKTOP |
DESKTOP_READOBJECTS |
DESKTOP_JOURNALPLAYBACK |
DESKTOP_JOURNALRECORD |
DESKTOP_WRITEOBJECTS |
DESKTOP_CREATEWINDOW |
READ_CONTROL |
WRITE_DAC
);
if(desk_ == nullptr){
throw std::runtime_error(
"OpenDesktop (default) failed :" +
std::to_string(GetLastError()));
}
if(!SetThreadDesktop(desk_)){
throw std::runtime_error(
"SetThreadDesktop (default) failed :" +
std::to_string(GetLastError()));
}
}
App::~App()
{
if(!shutdown_){
Shutdown(false);
}
global::app = nullptr;
}
void App::CloseMainWindow()
{
ClipCursor(nullptr);
DestroyWindow(wnd_);
UnregisterClassW(wndclass_name_.c_str(), instance_exe_);
}
void App::Shutdown(bool throw_exceptions)
{
if(winsta_)
{
if(!SetProcessWindowStation(old_winsta_)){
if(throw_exceptions){
throw std::runtime_error(
"SetProcessWindowStation (reset) failed :" +
std::to_string(GetLastError()));
}
}
CloseWindowStation(winsta_);
winsta_ = nullptr;
}
if(old_desk_){
if(!SetThreadDesktop(old_desk_)){
if(throw_exceptions){
throw std::runtime_error(
"SetThreadDesktop (reset) failed :" +
std::to_string(GetLastError()));
}
}
CloseDesktop(desk_);
desk_ = nullptr;
}
shutdown_ = true;
}
bool App::PumpMessages()
{
MSG msg {};
while(PeekMessageW(&msg, nullptr, 0, 0, PM_NOREMOVE))
{
if(GetMessageW(&msg, nullptr, 0, 0) <= 0)
{
return false;
}
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
return true;
}
void App::SetupMainWindow()
{
static const auto wndclass_name = [&]() -> const wchar_t*
{
WNDCLASSEXW wcx {};
wcx.cbSize = sizeof(WNDCLASSEXW);
wcx.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
wcx.hInstance = instance_exe_;
wcx.lpfnWndProc = MainWindowProc;
wcx.lpszClassName = L"MainWindowClass";
wcx.hbrBackground = static_cast<HBRUSH>(
GetStockObject(WHITE_BRUSH));
wcx.hIcon = reinterpret_cast<HICON>(
LoadImage(
nullptr,
IDI_APPLICATION,
IMAGE_ICON,
0,0,
LR_DEFAULTSIZE | LR_SHARED));
wcx.hCursor = reinterpret_cast<HCURSOR>(
LoadImage(
nullptr,
IDC_ARROW,
IMAGE_CURSOR,
0,0,
LR_DEFAULTSIZE | LR_SHARED));
ATOM result = RegisterClassExW(&wcx);
if(!result){
throw std::runtime_error("Failed to register main window class");
}
return wcx.lpszClassName;
}();
wndclass_name_ = wndclass_name;
///////////////////////////////////////////
RECT r {};
r.bottom = 480; // height
r.right = 640; // width
AdjustWindowRect(
&r,
WS_OVERLAPPEDWINDOW,
false);
int width = r.right - r.left;
int height = r.bottom - r.top;
//////////////////////////////////////////
auto wnd = CreateWindowExW(
0,
wndclass_name,
L"test...",
WS_OVERLAPPEDWINDOW,
0 , 0, width, height,
nullptr,
nullptr,
instance_exe_,
nullptr);
if(!wnd){
throw std::runtime_error("Failed to create main window");
}
ShowWindow(wnd, SW_SHOW);
UpdateWindow(wnd);
GetClientRect(wnd, &r);
///////////////////////////////////////////
POINT upper_left;
upper_left.x = r.left;
upper_left.y = r.top;
POINT lower_right;
lower_right.x = r.right;
lower_right.y = r.bottom;
MapWindowPoints(wnd, nullptr, &upper_left, 1);
MapWindowPoints(wnd, nullptr, &lower_right, 1);
r.left = upper_left.x;
r.top = upper_left.y;
r.right = lower_right.x;
r.bottom = lower_right.y;
///////////////////////////////////////////
ClipCursor(&r);
wnd_ = wnd;
}
int WINAPI WinMain(
HINSTANCE instance_exe,
HINSTANCE,
LPSTR,
int)
{
try{
App app{instance_exe};
app.SetupMainWindow();
while(true)
{
if(!app.PumpMessages()){
break;
}
}
app.Shutdown(true);
}
catch(const std::exception &e){
MessageBoxA(nullptr, e.what(), "", MB_ICONSTOP);
}
return EXIT_SUCCESS;
}
namespace{
LRESULT CALLBACK MainWindowProc(
HWND wnd,
UINT msg,
WPARAM wparam,
LPARAM lparam)
{
LRESULT result {};
switch(msg)
{
case WM_CLOSE:
global::app->CloseMainWindow();
break;
case WM_CHAR:
{
if(wparam == VK_ESCAPE){
global::app->CloseMainWindow();
}
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
result = DefWindowProcW(wnd, msg, wparam, lparam);
break;
}
return result;
}
}
So bleibt man im Fenster des späteren "Graphplotters". Aber das hantieren mit dem Desktop-Zeugs...wow
Das einzige Problem ist nur der doofe Fehlercode: 170.
Ich muss irgendein GDI-Zeugs noch aktiv haben...aber ich weiß nicht wo.
Der Fehler tritt wie schon erwähnt hier auf
SetThreadDesktop(old_desk_)
Das hat doch sicher schon jemand mal gemacht...bütte, bütte...