mirror of
https://github.com/mirkobrombin/raven.git
synced 2026-10-28 21:25:06 +00:00
124 lines
5.6 KiB
C
124 lines
5.6 KiB
C
#define WIN32_LEAN_AND_MEAN
|
|
#include <windows.h>
|
|
|
|
/* Window state read back right after it changes, including from inside the messages the change sends, whether the runtime or the
|
|
program answers the reads. */
|
|
|
|
static int size_seen, size_failed;
|
|
|
|
static LRESULT CALLBACK message_filter(int code, WPARAM wparam, LPARAM lparam)
|
|
{
|
|
return code == 0x1234 ? 77 : 0;
|
|
}
|
|
|
|
static LRESULT CALLBACK procedure(HWND window, UINT message, WPARAM wparam, LPARAM lparam)
|
|
{
|
|
if (message == WM_SIZE) {
|
|
RECT client;
|
|
++size_seen;
|
|
if (!GetClientRect(window, &client) || client.left || client.top || client.right != LOWORD(lparam) || client.bottom != HIWORD(lparam))
|
|
size_failed = 1;
|
|
if (GetWindowLongPtrW(window, GWLP_USERDATA) != 0x1234 && GetWindowLongPtrW(window, GWLP_USERDATA) != 0)
|
|
size_failed = 1;
|
|
}
|
|
return DefWindowProcW(window, message, wparam, lparam);
|
|
}
|
|
|
|
int raven_entry(void)
|
|
{
|
|
WNDCLASSW type = {0};
|
|
type.lpfnWndProc = procedure;
|
|
type.hInstance = GetModuleHandleW(NULL);
|
|
type.lpszClassName = L"RavenWindowState";
|
|
type.cbWndExtra = 16;
|
|
if (!RegisterClassW(&type))
|
|
return 1;
|
|
HWND window = CreateWindowExW(0, L"RavenWindowState", L"state", WS_OVERLAPPEDWINDOW, 10, 20, 300, 200, NULL, NULL, type.hInstance, NULL);
|
|
if (!window || !IsWindow(window) || !IsWindowUnicode(window))
|
|
return 2;
|
|
if (GetWindowLongPtrW(window, GWLP_WNDPROC) != (LONG_PTR)procedure || GetWindowLongPtrW(window, GWLP_HINSTANCE) != (LONG_PTR)type.hInstance)
|
|
return 3;
|
|
/* Every read follows the write before it. */
|
|
for (LONG_PTR value = 1; value < 40; ++value) {
|
|
SetWindowLongPtrW(window, GWLP_USERDATA, value);
|
|
SetWindowLongPtrW(window, 8, value * 3);
|
|
SetWindowLongW(window, 4, (LONG)value * 5);
|
|
if (GetWindowLongPtrW(window, GWLP_USERDATA) != value || GetWindowLongPtrW(window, 8) != value * 3 || GetWindowLongW(window, 4) != value * 5 ||
|
|
GetWindowLongW(window, -21) != (LONG)value)
|
|
return 4;
|
|
}
|
|
SetWindowLongPtrW(window, GWLP_USERDATA, 0x1234);
|
|
/* Indexes past the extra bytes fail as before. */
|
|
SetLastError(0);
|
|
if (GetWindowLongPtrW(window, 12) != 0 || GetLastError() != ERROR_INVALID_INDEX)
|
|
return 5;
|
|
if ((GetWindowLongW(window, GWL_STYLE) & WS_OVERLAPPEDWINDOW) != WS_OVERLAPPEDWINDOW)
|
|
return 6;
|
|
SetWindowLongW(window, GWL_STYLE, GetWindowLongW(window, GWL_STYLE) | WS_CLIPCHILDREN);
|
|
if (!(GetWindowLongW(window, GWL_STYLE) & WS_CLIPCHILDREN))
|
|
return 7;
|
|
/* Properties named by an atom, set and removed. */
|
|
if (GetPropW(window, (LPCWSTR)(ULONG_PTR)0xc123) || !SetPropW(window, (LPCWSTR)(ULONG_PTR)0xc123, (HANDLE)0x55))
|
|
return 8;
|
|
if (GetPropW(window, (LPCWSTR)(ULONG_PTR)0xc123) != (HANDLE)0x55 || GetPropW(window, (LPCWSTR)(ULONG_PTR)0xc124))
|
|
return 9;
|
|
RemovePropW(window, (LPCWSTR)(ULONG_PTR)0xc123);
|
|
if (GetPropW(window, (LPCWSTR)(ULONG_PTR)0xc123))
|
|
return 10;
|
|
/* Rectangles after a move, and inside the size message the move sends. */
|
|
size_seen = 0;
|
|
if (!MoveWindow(window, 30, 40, 420, 330, TRUE) || !size_seen || size_failed)
|
|
return 11;
|
|
RECT outer, client;
|
|
if (!GetWindowRect(window, &outer) || outer.left != 30 || outer.top != 40 || outer.right != 450 || outer.bottom != 370)
|
|
return 12;
|
|
if (!GetClientRect(window, &client) || client.right <= 0 || client.right > 420 || client.bottom <= 0 || client.bottom > 330)
|
|
return 13;
|
|
/* Ancestry, focus and resolution. */
|
|
HWND child = CreateWindowExW(0, L"RavenWindowState", L"child", WS_CHILD, 0, 0, 50, 50, window, NULL, type.hInstance, NULL);
|
|
HWND grandchild = CreateWindowExW(0, L"RavenWindowState", L"grandchild", WS_CHILD, 0, 0, 10, 10, child, NULL, type.hInstance, NULL);
|
|
HWND other = CreateWindowExW(0, L"RavenWindowState", L"other", WS_OVERLAPPEDWINDOW, 0, 0, 50, 50, NULL, NULL, type.hInstance, NULL);
|
|
if (!child || !grandchild || !other)
|
|
return 15;
|
|
if (!IsChild(window, child) || !IsChild(window, grandchild) || !IsChild(child, grandchild) || IsChild(grandchild, window) ||
|
|
IsChild(window, window) || IsChild(window, other) || IsChild(NULL, child) || IsChild(window, NULL))
|
|
return 16;
|
|
SetFocus(child);
|
|
if (GetFocus() != child)
|
|
return 17;
|
|
SetFocus(other);
|
|
if (GetFocus() != other)
|
|
return 18;
|
|
if (!AllowSetForegroundWindow(GetCurrentProcessId()) || !SetForegroundWindow(window) || GetForegroundWindow() != window ||
|
|
!AllowSetForegroundWindow(ASFW_ANY))
|
|
return 40;
|
|
SetLastError(0);
|
|
if (AllowSetForegroundWindow(0) || GetLastError() != ERROR_INVALID_PARAMETER || GetForegroundWindow() != window)
|
|
return 41;
|
|
if (GetDpiForWindow(window) != 96)
|
|
return 19;
|
|
/* The message loop's helpers on messages they leave alone. */
|
|
MSG message = {window, WM_MOUSEMOVE, 0, 0, 0, {0, 0}};
|
|
for (int round = 0; round < 3; ++round) {
|
|
if (TranslateMessage(&message) || CallMsgFilterW(&message, 0x1234) || !GetDesktopWindow() || GetDesktopWindow() != GetDesktopWindow())
|
|
return 20;
|
|
}
|
|
HHOOK hook = SetWindowsHookExW(WH_MSGFILTER, message_filter, NULL, GetCurrentThreadId());
|
|
if (!hook || CallMsgFilterW(&message, 0x1234) != 77 || !UnhookWindowsHookEx(hook) || CallMsgFilterW(&message, 0x1234))
|
|
return 21;
|
|
ACCEL keys[] = {{FVIRTKEY | FCONTROL, 'S', 900}};
|
|
HACCEL table = CreateAcceleratorTableW(keys, 1);
|
|
SetLastError(0);
|
|
if (!table || TranslateAcceleratorW(window, table, &message) || GetLastError())
|
|
return 22;
|
|
if (!DestroyAcceleratorTable(table) || TranslateAcceleratorW(window, table, &message) || GetLastError() != ERROR_INVALID_WINDOW_HANDLE)
|
|
return 23;
|
|
SetLastError(0);
|
|
if (TranslateAcceleratorW(window, NULL, &message) || GetLastError() != ERROR_INVALID_WINDOW_HANDLE)
|
|
return 24;
|
|
DestroyWindow(other);
|
|
if (!DestroyWindow(window) || IsWindow(window) || GetWindowLongPtrW(window, GWLP_USERDATA) || GetLastError() != ERROR_INVALID_WINDOW_HANDLE)
|
|
return 14;
|
|
return 0;
|
|
}
|