feat: add registry, locale and event APIs

This commit is contained in:
mirkobrombin committed 2026-10-31 19:43:27 +00:00
1 parent a948d60bec
commit 0df657bec7
4 files changed
+100 -1

No files matched your search

+7
View File
@@ -47,6 +47,13 @@ void NativeObjectAPI::register_served(ApiRegistry &registry, NativeObjects &obje
if (status) call.fail(error(status), 0);
else call.ret(1);
});
// PulseEvent: signalled for whoever waits now, and not signalled after.
registry.add("PulseEvent", 1, [&objects](ApiCall &call) {
uint32_t status=objects.set_event(call[0], true).status;
if (!status) status=objects.set_event(call[0], false).status;
if (status) call.fail(error(status), 0);
else call.ret(1);
});
}
bool NativeObjectAPI::dispatch(std::string_view name)
+41
View File
@@ -954,6 +954,47 @@ void register_registry_api(ApiRegistry &registry, KernelContext &context, Native
call.ret(0);
};
registry.add("RegGetValueW", 7, [get_value](ApiCall &call) { get_value(call, true); });
// RegQueryValue, from 16-bit Windows: the unnamed value of a subkey, always as text; a key without one reads as the empty text.
for (const bool wide : {true, false})
registry.add(wide ? "RegQueryValueW" : "RegQueryValueA", 4, [&hive, &context, text_of, view, ansi_page, wide](ApiCall &call) {
uint64_t key = call[0];
uint64_t opened = 0;
const auto subkey = call[1] ? text_of(call, call[1], wide) : std::u16string{};
if (!subkey.empty()) {
const auto status = hive.open(key, view(key, subkey, 0), opened);
if (status) {
call.ret(status);
return;
}
key = opened;
}
uint32_t type = 0;
std::vector<uint8_t> data;
const auto status = hive.query(key, u"", type, data);
if (opened) {
hive.close(opened);
context.objects.release_reserved(opened);
}
if (status && status != 2) {
call.ret(status);
return;
}
if (status || !is_text(type)) data.assign(wide ? 2 : 1, 0);
else if (!wide) data = to_ansi_bytes(data, ansi_page);
if (!call[2]) {
if (call[3]) call.store<uint32_t>(call[3], uint32_t(data.size()));
call.ret(0);
return;
}
const uint32_t capacity = call[3] ? call.load<uint32_t>(call[3]) : 0;
if (call[3]) call.store<uint32_t>(call[3], uint32_t(data.size()));
if (data.size() > capacity) {
call.ret(error_more_data);
return;
}
call.write(call[2], data);
call.ret(0);
});
registry.add("RegGetValueA", 7, [get_value](ApiCall &call) { get_value(call, false); });
// RegSetKeyValue creates the subkey when it is missing, then writes the value as RegSetValueEx does.
for (const bool wide : {true, false})
+42 -1
View File
@@ -6,6 +6,7 @@
{"ActivateActCtx", 2},
{"AddAccessAllowedAce", 4},
{"AddAccessDeniedAce", 4},
{"AddAtomA", 1},
{"AddDllDirectory", 1},
{"AddVectoredContinueHandler", 2},
{"AddVectoredExceptionHandler", 2},
@@ -89,6 +90,7 @@
{"CertFreeCertificateContext", 1},
{"CertGetCertificateChain", 8},
{"CertGetCertificateContextProperty", 4},
{"CertGetEnhancedKeyUsage", 4},
{"CertGetNameStringW", 6},
{"CertNameToStrW", 5},
{"CertOpenStore", 5},
@@ -122,7 +124,9 @@
{"CoInitializeEx", 2},
{"CoInitializeSecurity", 9},
{"CoLockObjectExternal", 3},
{"CoRegisterClassObject", 5},
{"CoRegisterMessageFilter", 2},
{"CoRevokeClassObject", 1},
{"CoTaskMemAlloc", 1},
{"CoTaskMemFree", 1},
{"CoTaskMemRealloc", 2},
@@ -138,6 +142,7 @@
{"ConnectEx", 7},
{"ConnectNamedPipe", 2},
{"ControlService", 3},
{"ConvertInterfaceGuidToLuid", 2},
{"ConvertSidToStringSidW", 2},
{"ConvertStringSidToSidW", 2},
{"CopyFileExW", 6},
@@ -291,6 +296,7 @@
{"FileTimeToSystemTime", 2},
{"FillRect", 3},
{"FillRgn", 3},
{"FindAtomA", 1},
{"FindClose", 1},
{"FindCloseChangeNotification", 1},
{"FindFirstChangeNotificationW", 3},
@@ -337,6 +343,7 @@
{"GetCaretBlinkTime", 0},
{"GetCaretPos", 1},
{"GetCharABCWidthsW", 4},
{"GetCharWidth32W", 4},
{"GetCharWidthInfo", 2},
{"GetCharWidthW", 4},
{"GetClassWord", 2},
@@ -354,9 +361,12 @@
{"GetConsoleOutputCP", 0},
{"GetCurrentActCtx", 1},
{"GetCurrentDirectoryW", 2},
{"GetCurrentInputMessageSource", 1},
{"GetCurrentProcess", 0},
{"GetCurrentProcessExplicitAppUserModelID", 1},
{"GetCurrentThread", 0},
{"GetCursor", 0},
{"GetCursorInfo", 1},
{"GetCursorPos", 1},
{"GetDCEx", 3},
{"GetDIBColorTable", 4},
@@ -375,6 +385,7 @@
{"GetDynamicTimeZoneInformation", 1},
{"GetEnvironmentStringsW", 0},
{"GetEnvironmentVariableW", 3},
{"GetErrorMode", 0},
{"GetExitCodeProcess", 2},
{"GetExitCodeThread", 2},
{"GetExtendedTcpTable", 6},
@@ -400,6 +411,7 @@
{"GetGuiResources", 2},
{"GetHandleInformation", 2},
{"GetICMProfileW", 3},
{"GetIfEntry2", 1},
{"GetIsImmersiveColorUsingHighContrast", 1},
{"GetKeyNameTextW", 3},
{"GetKeyState", 1},
@@ -507,6 +519,7 @@
{"GetSystemMenu", 2},
{"GetSystemMetrics", 1},
{"GetSystemMetricsForDpi", 2},
{"GetSystemPaletteUse", 1},
{"GetSystemPowerStatus", 1},
{"GetSystemPreferredUILanguages", 4},
{"GetSystemTime", 1},
@@ -561,6 +574,7 @@
{"GetUserNameExW", 3},
{"GetUserObjectInformationW", 5},
{"GetUserPreferredUILanguages", 4},
{"GetUserProfileDirectoryW", 3},
{"GetVersion", 0},
{"GetVersionExA", 1},
{"GetVersionExW", 1},
@@ -616,6 +630,7 @@
{"ImmGetIMEFileNameA", 3},
{"ImmGetIMEFileNameW", 3},
{"ImmGetOpenStatus", 1},
{"ImmGetProperty", 2},
{"ImmIsIME", 1},
{"ImmNotifyIME", 4},
{"ImmReleaseContext", 2},
@@ -625,6 +640,7 @@
{"ImmSetCompositionWindow", 2},
{"ImmSetOpenStatus", 2},
{"InflateRect", 3},
{"InheritWindowMonitor", 2},
{"InitOnceBeginInitialize", 4},
{"InitOnceComplete", 3},
{"InitOnceExecuteOnce", 4},
@@ -695,6 +711,7 @@
{"IsDestinationReachableW", 2},
{"IsEnclaveTypeSupported", 1},
{"IsIconic", 1},
{"IsImmersiveProcess", 1},
{"IsNetworkAlive", 1},
{"IsProcessDPIAware", 0},
{"IsProcessInJob", 3},
@@ -711,8 +728,10 @@
{"IsValidLocale", 2},
{"IsValidSecurityDescriptor", 1},
{"IsValidSid", 1},
{"IsWinEventHookInstalled", 1},
{"IsWindowArranged", 1},
{"IsWindowEnabled", 1},
{"IsWindowRedirectedForPrint", 1},
{"IsWow64Process", 2},
{"IsWow64Process2", 3},
{"IsZoomed", 1},
@@ -734,6 +753,7 @@
{"LoadImageW", 6},
{"LoadMenuA", 2},
{"LoadStringA", 4},
{"LoadUserProfileW", 2},
{"LocalAlloc", 2},
{"LocalFree", 1},
{"LocalLock", 1},
@@ -801,6 +821,8 @@
{"OleUninitialize", 0},
{"OpenClipboard", 1},
{"OpenDesktopW", 4},
{"OpenEventLogA", 2},
{"OpenEventLogW", 2},
{"OpenEventW", 3},
{"OpenFileMappingW", 3},
{"OpenJobObjectW", 3},
@@ -853,6 +875,7 @@
{"PolylineTo", 3},
{"PostMessageA", 4},
{"PostQueuedCompletionStatus", 4},
{"PowerDeterminePlatformRoleEx", 1},
{"PrefetchVirtualMemory", 4},
{"Process32First", 2},
{"Process32FirstW", 2},
@@ -860,6 +883,7 @@
{"Process32NextW", 2},
{"ProcessIdToSessionId", 2},
{"ProcessPrng", 2},
{"PulseEvent", 1},
{"QueryDepthSList", 1},
{"QueryDisplayConfig", 6},
{"QueryInformationJobObject", 5},
@@ -932,8 +956,10 @@
{"RegOpenKeyW", 3},
{"RegQueryInfoKeyA", 12},
{"RegQueryInfoKeyW", 12},
{"RegQueryValueA", 4},
{"RegQueryValueExA", 6},
{"RegQueryValueExW", 6},
{"RegQueryValueW", 4},
{"RegSetValueExA", 6},
{"RegSetValueExW", 6},
{"RegisterApplicationRestart", 2},
@@ -949,6 +975,7 @@
{"RegisterServiceCtrlHandlerExW", 3},
{"RegisterServiceCtrlHandlerW", 2},
{"RegisterSuspendResumeNotification", 2},
{"RegisterTouchHitTestingWindow", 2},
{"RegisterTouchWindow", 2},
{"RegisterTraceGuidsW", 8},
{"RegisterWaitForSingleObject", 6},
@@ -968,6 +995,7 @@
{"RemoveVectoredContinueHandler", 1},
{"RemoveVectoredExceptionHandler", 1},
{"ReplaceFileW", 6},
{"ResolveLocaleName", 3},
{"RestoreDC", 2},
{"ResumeThread", 1},
{"RevokeDragDrop", 1},
@@ -1013,12 +1041,15 @@
{"SHGetFolderPathW", 5},
{"SHGetKnownFolderPath", 4},
{"SHGetPathFromIDListW", 2},
{"SHGetSettings", 2},
{"SHGetSpecialFolderLocation", 3},
{"SHGetSpecialFolderPathW", 4},
{"SLGetWindowsInformation", 4},
{"SLGetWindowsInformationDWORD", 2},
{"SaveDC", 1},
{"ScriptApplyDigitSubstitution", 3},
{"ScriptBreak", 4},
{"ScriptGetFontProperties", 3},
{"ScriptStringAnalyse", 13},
{"ScriptStringCPtoX", 4},
{"ScriptStringFree", 1},
@@ -1085,7 +1116,9 @@
{"SetProcessDPIAware", 0},
{"SetProcessDpiAwareness", 1},
{"SetProcessDpiAwarenessContext", 1},
{"SetProcessInformation", 4},
{"SetProcessMitigationPolicy", 3},
{"SetProcessPriorityBoost", 2},
{"SetProcessShutdownParameters", 2},
{"SetProcessWindowStation", 1},
{"SetPropA", 3},
@@ -1110,15 +1143,16 @@
{"SetThreadDescription", 2},
{"SetThreadDesktop", 1},
{"SetThreadDpiAwarenessContext", 1},
{"SetThreadPreferredUILanguages", 3},
{"SetThreadErrorMode", 3},
{"SetThreadInformation", 4},
{"SetThreadLocale", 1},
{"SetThreadPreferredUILanguages", 3},
{"SetThreadPriority", 2},
{"SetThreadPriorityBoost", 2},
{"SetThreadStackGuarantee", 1},
{"SetTokenInformation", 4},
{"SetUnhandledExceptionFilter", 1},
{"SetUserObjectInformationW", 4},
{"SetViewportOrgEx", 4},
{"SetWinEventHook", 7},
{"SetWindowContextHelpId", 2},
@@ -1202,6 +1236,7 @@
{"UnhookWinEvent", 1},
{"UnhookWindowsHookEx", 1},
{"UnionRect", 3},
{"UnloadUserProfile", 2},
{"UnlockFile", 5},
{"UnlockFileEx", 5},
{"UnmapViewOfFile", 1},
@@ -1214,6 +1249,7 @@
{"UnregisterTraceGuids", 1},
{"UnregisterWait", 1},
{"UnregisterWaitEx", 2},
{"UpdateLayeredWindow", 9},
{"UpdateProcThreadAttribute", 7},
{"UrlFixupW", 3},
{"VariantClear", 1},
@@ -1222,6 +1258,7 @@
{"VerQueryValueW", 4},
{"VerSetConditionMask", 3},
{"VerifyVersionInfoW", 3},
{"VkKeyScanExW", 2},
{"VkKeyScanW", 1},
{"WSACleanup", 0},
{"WSACloseEvent", 1},
@@ -1246,8 +1283,10 @@
{"WSASocketA", 6},
{"WSASocketW", 6},
{"WSAStartup", 2},
{"WTSEnumerateSessionsW", 5},
{"WTSFreeMemory", 1},
{"WTSQuerySessionInformationW", 5},
{"WTSQueryUserToken", 2},
{"WTSRegisterSessionNotification", 2},
{"WTSUnRegisterSessionNotification", 1},
{"WaitForInputIdle", 2},
@@ -1293,6 +1332,8 @@
{"WindowsGetStringLen", 1},
{"WindowsGetStringRawBuffer", 2},
{"WindowsIsStringEmpty", 1},
{"Wow64DisableWow64FsRedirection", 1},
{"Wow64RevertWow64FsRedirection", 1},
{"WriteConsoleW", 5},
{"WriteFile", 5},
{"WritePrivateProfileStringW", 4},
+10
View File
@@ -1093,6 +1093,16 @@ void register_text_api(ApiRegistry &registry, KernelContext &context)
call.put_wide(buffer, name, size_t(capacity));
call.ret(name.size() + 1);
};
// The one locale there is answers for its own name, its language alone, and no name at all.
registry.add("ResolveLocaleName", 3, [locale_name](ApiCall &call) {
const auto name = call[0] ? call.wide(call[0], 85) : std::u16string{};
if (!name.empty() && compare_fold(name, u"en-US") != 0 && compare_fold(name, u"en") != 0) {
if (call[1] && call.i32(2) > 0) call.put_wide(call[1], u"", size_t(call.i32(2)));
call.ret(1);
return;
}
locale_name(call, call[1], call[1] ? call.i32(2) : 0);
});
registry.add("GetUserDefaultLocaleName", 2, [locale_name](ApiCall &call) { locale_name(call, call[0], call.i32(1)); });
registry.add("GetSystemDefaultLocaleName", 2, [locale_name](ApiCall &call) { locale_name(call, call[0], call.i32(1)); });
// A name the table does not know, as the culture-neutral "x-none" programs use, is not a locale. No name is the user's, the empty one