mirror of
https://github.com/mirkobrombin/raven.git
synced 2026-10-28 21:25:06 +00:00
86 lines
3.0 KiB
C
86 lines
3.0 KiB
C
#define WIN32_LEAN_AND_MEAN
|
|
#include <windows.h>
|
|
|
|
/* Screen contexts are reused while clean, but a leased context belongs to one caller. */
|
|
|
|
static HDC held[4];
|
|
static volatile LONG ready;
|
|
|
|
static DWORD WINAPI screen_worker(void *argument)
|
|
{
|
|
const unsigned index = (unsigned)(UINT_PTR)argument;
|
|
HFONT font = CreateFontW(-30, 0, 0, 0, FW_BOLD, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, L"Arial");
|
|
held[index] = GetDC(NULL);
|
|
InterlockedIncrement(&ready);
|
|
while (InterlockedCompareExchange(&ready, 4, 4) != 4)
|
|
Sleep(0);
|
|
DWORD error = !held[index] || !font;
|
|
for (unsigned other = 0; other < 4; ++other)
|
|
if (other != index && held[index] == held[other])
|
|
error = 1;
|
|
if (!error && (!SelectObject(held[index], font) || GetCurrentObject(held[index], OBJ_FONT) != font))
|
|
error = 2;
|
|
if (held[index] && ReleaseDC(NULL, held[index]) != 1)
|
|
error = 3;
|
|
if (font)
|
|
DeleteObject(font);
|
|
return error;
|
|
}
|
|
|
|
static int screen_caps_hold(HDC dc)
|
|
{
|
|
return GetDeviceCaps(dc, LOGPIXELSX) == 96 && GetDeviceCaps(dc, LOGPIXELSY) == 96 && GetDeviceCaps(dc, BITSPIXEL) == 32 &&
|
|
GetDeviceCaps(dc, HORZRES) == GetSystemMetrics(SM_CXSCREEN) && GetDeviceCaps(dc, VERTRES) == GetSystemMetrics(SM_CYSCREEN) &&
|
|
GetDeviceCaps(dc, TECHNOLOGY) == DT_RASDISPLAY;
|
|
}
|
|
|
|
int raven_entry(void)
|
|
{
|
|
HDC first = GetDC(NULL);
|
|
if (!first || !screen_caps_hold(first) || ReleaseDC(NULL, first) != 1)
|
|
return 1;
|
|
HDC again = GetDC(NULL);
|
|
if (!again || !screen_caps_hold(again) || ReleaseDC(NULL, again) != 1)
|
|
return 2;
|
|
HDC third = GetDC(NULL);
|
|
if (third != again || ReleaseDC(NULL, third) != 1)
|
|
return 3;
|
|
/* A context somebody holds is not handed out twice. */
|
|
HDC held = GetDC(NULL), other = GetDC(NULL);
|
|
if (!held || !other || held == other || !screen_caps_hold(other))
|
|
return 4;
|
|
if (ReleaseDC(NULL, held) != 1 || ReleaseDC(NULL, other) != 1)
|
|
return 5;
|
|
/* A context whose state a call changed is released by the runtime, and the next one starts clean. */
|
|
HFONT font = CreateFontW(-30, 0, 0, 0, FW_BOLD, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, L"Arial");
|
|
HDC changed = GetDC(NULL);
|
|
if (!changed || !SelectObject(changed, font) || ReleaseDC(NULL, changed) != 1)
|
|
return 6;
|
|
HDC clean = GetDC(NULL);
|
|
if (!clean || GetCurrentObject(clean, OBJ_FONT) == font || ReleaseDC(NULL, clean) != 1)
|
|
return 6;
|
|
DeleteObject(font);
|
|
/* A memory context still answers for its own bitmap. */
|
|
HDC memory = CreateCompatibleDC(NULL);
|
|
if (!memory || GetDeviceCaps(memory, TECHNOLOGY) == DT_RASDISPLAY || !DeleteDC(memory))
|
|
return 7;
|
|
for (unsigned round = 0; round < 16; ++round) {
|
|
HANDLE workers[4];
|
|
ready = 0;
|
|
for (unsigned index = 0; index < 4; ++index) {
|
|
workers[index] = CreateThread(NULL, 0, screen_worker, (void *)(UINT_PTR)index, 0, NULL);
|
|
if (!workers[index])
|
|
return 8;
|
|
}
|
|
if (WaitForMultipleObjects(4, workers, TRUE, 5000) != WAIT_OBJECT_0)
|
|
return 9;
|
|
for (unsigned index = 0; index < 4; ++index) {
|
|
DWORD code = 0;
|
|
if (!GetExitCodeThread(workers[index], &code) || code)
|
|
return 10;
|
|
CloseHandle(workers[index]);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|