Split kernel32 into separate files (part 1)

This commit is contained in:
Luke Street 2025-10-01 18:18:13 -06:00
parent c099a1b577
commit 9ea5b24b67
11 changed files with 1255 additions and 1079 deletions

View File

@ -36,6 +36,12 @@ add_executable(wibo
dll/bcrypt.cpp
dll/crt.cpp
dll/kernel32.cpp
dll/kernel32/errhandlingapi.cpp
dll/kernel32/fibersapi.cpp
dll/kernel32/processthreadsapi.cpp
dll/kernel32/sysinfoapi.cpp
dll/kernel32/synchapi.cpp
dll/kernel32/wow64apiset.cpp
dll/lmgr.cpp
dll/mscoree.cpp
dll/msvcrt.cpp

View File

@ -48,6 +48,8 @@ typedef ULONG *PULONG;
typedef int64_t LARGE_INTEGER;
typedef LARGE_INTEGER *PLARGE_INTEGER;
typedef uintptr_t ULONG_PTR;
typedef ULONG_PTR DWORD_PTR;
typedef DWORD_PTR *PDWORD_PTR;
typedef char *LPSTR;
typedef const char *LPCSTR;
typedef uint16_t *LPWSTR;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,56 @@
#include "common.h"
#include "kernel32.h"
namespace {
LPTOP_LEVEL_EXCEPTION_FILTER g_topLevelExceptionFilter = nullptr;
UINT g_processErrorMode = 0;
} // namespace
namespace kernel32 {
DWORD WIN_FUNC GetLastError() {
DEBUG_LOG("GetLastError() -> %u\n", wibo::lastError);
return wibo::lastError;
}
void WIN_FUNC SetLastError(DWORD dwErrCode) {
DEBUG_LOG("SetLastError(%u)\n", dwErrCode);
wibo::lastError = dwErrCode;
}
void WIN_FUNC RaiseException(DWORD dwExceptionCode, DWORD dwExceptionFlags, DWORD nNumberOfArguments,
const ULONG_PTR *lpArguments) {
DEBUG_LOG("RaiseException(0x%x, 0x%x, %u, %p)\n", dwExceptionCode, dwExceptionFlags, nNumberOfArguments,
lpArguments);
(void)dwExceptionFlags;
(void)nNumberOfArguments;
(void)lpArguments;
exit(static_cast<int>(dwExceptionCode));
}
PVOID WIN_FUNC AddVectoredExceptionHandler(ULONG First, PVECTORED_EXCEPTION_HANDLER Handler) {
DEBUG_LOG("STUB: AddVectoredExceptionHandler(%u, %p)\n", First, Handler);
return reinterpret_cast<PVOID>(Handler);
}
LPTOP_LEVEL_EXCEPTION_FILTER WIN_FUNC
SetUnhandledExceptionFilter(LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter) {
DEBUG_LOG("STUB: SetUnhandledExceptionFilter(%p)\n", lpTopLevelExceptionFilter);
LPTOP_LEVEL_EXCEPTION_FILTER previous = g_topLevelExceptionFilter;
g_topLevelExceptionFilter = lpTopLevelExceptionFilter;
return previous;
}
LONG WIN_FUNC UnhandledExceptionFilter(PEXCEPTION_POINTERS ExceptionInfo) {
DEBUG_LOG("STUB: UnhandledExceptionFilter(%p)\n", ExceptionInfo);
return EXCEPTION_EXECUTE_HANDLER;
}
UINT WIN_FUNC SetErrorMode(UINT uMode) {
DEBUG_LOG("STUB: SetErrorMode(%u)\n", uMode);
UINT previous = g_processErrorMode;
g_processErrorMode = uMode;
return previous;
}
} // namespace kernel32

View File

@ -0,0 +1,63 @@
#include "common.h"
#include "errors.h"
#include "kernel32.h"
namespace kernel32 {
constexpr size_t MAX_FLS_VALUES = 0x100;
static bool flsValuesUsed[MAX_FLS_VALUES] = {false};
static void *flsValues[MAX_FLS_VALUES];
DWORD WIN_FUNC FlsAlloc(PFLS_CALLBACK_FUNCTION lpCallback) {
DEBUG_LOG("FlsAlloc(%p)", lpCallback);
// If the function succeeds, the return value is an FLS index initialized to zero.
for (size_t i = 0; i < MAX_FLS_VALUES; i++) {
if (flsValuesUsed[i] == false) {
flsValuesUsed[i] = true;
flsValues[i] = nullptr;
DEBUG_LOG(" -> %d\n", i);
return i;
}
}
DEBUG_LOG(" -> -1\n");
wibo::lastError = 1;
return FLS_OUT_OF_INDEXES;
}
BOOL WIN_FUNC FlsFree(DWORD dwFlsIndex) {
DEBUG_LOG("FlsFree(%u)\n", dwFlsIndex);
if (dwFlsIndex >= 0 && dwFlsIndex < MAX_FLS_VALUES && flsValuesUsed[dwFlsIndex]) {
flsValuesUsed[dwFlsIndex] = false;
return TRUE;
} else {
wibo::lastError = 1;
return FALSE;
}
}
PVOID WIN_FUNC FlsGetValue(DWORD dwFlsIndex) {
VERBOSE_LOG("FlsGetValue(%u)\n", dwFlsIndex);
PVOID result = nullptr;
if (dwFlsIndex >= 0 && dwFlsIndex < MAX_FLS_VALUES && flsValuesUsed[dwFlsIndex]) {
result = flsValues[dwFlsIndex];
// See https://learn.microsoft.com/en-us/windows/win32/api/fibersapi/nf-fibersapi-flsgetvalue
wibo::lastError = ERROR_SUCCESS;
} else {
wibo::lastError = 1;
}
// DEBUG_LOG(" -> %p\n", result);
return result;
}
BOOL WIN_FUNC FlsSetValue(DWORD dwFlsIndex, PVOID lpFlsData) {
VERBOSE_LOG("FlsSetValue(%u, %p)\n", dwFlsIndex, lpFlsData);
if (dwFlsIndex >= 0 && dwFlsIndex < MAX_FLS_VALUES && flsValuesUsed[dwFlsIndex]) {
flsValues[dwFlsIndex] = lpFlsData;
return TRUE;
} else {
wibo::lastError = 1;
return FALSE;
}
}
} // namespace kernel32

54
dll/kernel32/internal.h Normal file
View File

@ -0,0 +1,54 @@
#pragma once
#include "kernel32.h"
#include <pthread.h>
namespace kernel32 {
struct ThreadObject {
pthread_t thread;
bool finished = false;
bool joined = false;
bool detached = false;
bool synthetic = false;
DWORD exitCode = 0;
int refCount = 1;
pthread_mutex_t mutex;
pthread_cond_t cond;
unsigned int suspendCount = 0;
};
struct MutexObject {
pthread_mutex_t mutex;
bool ownerValid = false;
pthread_t owner = 0;
unsigned int recursionCount = 0;
std::u16string name;
int refCount = 1;
};
struct EventObject {
pthread_mutex_t mutex;
pthread_cond_t cond;
bool manualReset = false;
bool signaled = false;
std::u16string name;
int refCount = 1;
};
struct SemaphoreObject {
pthread_mutex_t mutex;
pthread_cond_t cond;
LONG count = 0;
LONG maxCount = 0;
std::u16string name;
int refCount = 1;
};
void releaseMutexObject(MutexObject *obj);
void releaseEventObject(EventObject *obj);
void releaseSemaphoreObject(SemaphoreObject *obj);
void resetOverlappedEvent(OVERLAPPED *ov);
void signalOverlappedEvent(OVERLAPPED *ov);
} // namespace kernel32

193
dll/kernel32/kernel32.h Normal file
View File

@ -0,0 +1,193 @@
#pragma once
#include "common.h"
// errhandlingapi.h
constexpr DWORD EXCEPTION_MAXIMUM_PARAMETERS = 15;
struct EXCEPTION_RECORD {
DWORD ExceptionCode;
DWORD ExceptionFlags;
EXCEPTION_RECORD *ExceptionRecord;
PVOID ExceptionAddress;
DWORD NumberParameters;
ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
};
using PEXCEPTION_RECORD = EXCEPTION_RECORD *;
using PCONTEXT = void *;
struct EXCEPTION_POINTERS {
PEXCEPTION_RECORD ExceptionRecord;
PCONTEXT ContextRecord;
};
using PEXCEPTION_POINTERS = EXCEPTION_POINTERS *;
using PVECTORED_EXCEPTION_HANDLER = LONG(WIN_FUNC *)(PEXCEPTION_POINTERS ExceptionInfo);
using LPTOP_LEVEL_EXCEPTION_FILTER = LONG(WIN_FUNC *)(PEXCEPTION_POINTERS ExceptionInfo);
constexpr LONG EXCEPTION_CONTINUE_EXECUTION = static_cast<LONG>(-1);
constexpr LONG EXCEPTION_CONTINUE_SEARCH = 0;
constexpr LONG EXCEPTION_EXECUTE_HANDLER = 1;
// synchapi.h constants
constexpr DWORD WAIT_OBJECT_0 = 0x00000000;
constexpr DWORD WAIT_ABANDONED = 0x00000080;
constexpr DWORD WAIT_TIMEOUT = 0x00000102;
constexpr DWORD WAIT_FAILED = 0xFFFFFFFF;
constexpr DWORD INFINITE = 0xFFFFFFFF;
// minwinbase.h
struct SECURITY_ATTRIBUTES {
DWORD nLength;
LPVOID lpSecurityDescriptor;
BOOL bInheritHandle;
};
using PSECURITY_ATTRIBUTES = SECURITY_ATTRIBUTES *;
using LPSECURITY_ATTRIBUTES = SECURITY_ATTRIBUTES *;
// sysinfoapi.h
struct SYSTEM_INFO {
union {
DWORD dwOemId;
struct {
WORD wProcessorArchitecture;
WORD wReserved;
};
};
DWORD dwPageSize;
LPVOID lpMinimumApplicationAddress;
LPVOID lpMaximumApplicationAddress;
DWORD_PTR dwActiveProcessorMask;
DWORD dwNumberOfProcessors;
DWORD dwProcessorType;
DWORD dwAllocationGranularity;
WORD wProcessorLevel;
WORD wProcessorRevision;
};
using LPSYSTEM_INFO = SYSTEM_INFO *;
// processthreadsapi.h
struct PROCESS_INFORMATION {
HANDLE hProcess;
HANDLE hThread;
DWORD dwProcessId;
DWORD dwThreadId;
};
using PPROCESS_INFORMATION = PROCESS_INFORMATION *;
using LPPROCESS_INFORMATION = PROCESS_INFORMATION *;
struct STARTUPINFOA {
DWORD cb;
LPSTR lpReserved;
LPSTR lpDesktop;
LPSTR lpTitle;
DWORD dwX;
DWORD dwY;
DWORD dwXSize;
DWORD dwYSize;
DWORD dwXCountChars;
DWORD dwYCountChars;
DWORD dwFillAttribute;
DWORD dwFlags;
WORD wShowWindow;
WORD cbReserved2;
unsigned char *lpReserved2;
HANDLE hStdInput;
HANDLE hStdOutput;
HANDLE hStdError;
};
using LPSTARTUPINFOA = STARTUPINFOA *;
struct STARTUPINFOW {
DWORD cb;
LPWSTR lpReserved;
LPWSTR lpDesktop;
LPWSTR lpTitle;
DWORD dwX;
DWORD dwY;
DWORD dwXSize;
DWORD dwYSize;
DWORD dwXCountChars;
DWORD dwYCountChars;
DWORD dwFillAttribute;
DWORD dwFlags;
WORD wShowWindow;
WORD cbReserved2;
unsigned char *lpReserved2;
HANDLE hStdInput;
HANDLE hStdOutput;
HANDLE hStdError;
};
using LPSTARTUPINFOW = STARTUPINFOW *;
// fibersapi.h
using PFLS_CALLBACK_FUNCTION = void (*)(void *);
constexpr DWORD FLS_OUT_OF_INDEXES = 0xFFFFFFFF;
namespace kernel32 {
// fibersapi.h
DWORD WIN_FUNC FlsAlloc(PFLS_CALLBACK_FUNCTION lpCallback);
BOOL WIN_FUNC FlsFree(DWORD dwFlsIndex);
PVOID WIN_FUNC FlsGetValue(DWORD dwFlsIndex);
BOOL WIN_FUNC FlsSetValue(DWORD dwFlsIndex, PVOID lpFlsData);
// errhandlingapi.h
DWORD WIN_FUNC GetLastError();
void WIN_FUNC SetLastError(DWORD dwErrCode);
void WIN_FUNC RaiseException(DWORD dwExceptionCode, DWORD dwExceptionFlags, DWORD nNumberOfArguments,
const ULONG_PTR *lpArguments);
PVOID WIN_FUNC AddVectoredExceptionHandler(ULONG First, PVECTORED_EXCEPTION_HANDLER Handler);
LPTOP_LEVEL_EXCEPTION_FILTER WIN_FUNC
SetUnhandledExceptionFilter(LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter);
LONG WIN_FUNC UnhandledExceptionFilter(PEXCEPTION_POINTERS ExceptionInfo);
UINT WIN_FUNC SetErrorMode(UINT uMode);
// wow64apiset.h
BOOL WIN_FUNC Wow64DisableWow64FsRedirection(PVOID *OldValue);
BOOL WIN_FUNC Wow64RevertWow64FsRedirection(PVOID OldValue);
BOOL WIN_FUNC IsWow64Process(HANDLE hProcess, PBOOL Wow64Process);
// sysinfoapi.h
void WIN_FUNC GetSystemInfo(LPSYSTEM_INFO lpSystemInfo);
// processthreadsapi.h
HANDLE WIN_FUNC GetCurrentProcess();
DWORD WIN_FUNC GetCurrentProcessId();
DWORD WIN_FUNC GetCurrentThreadId();
BOOL WIN_FUNC GetProcessAffinityMask(HANDLE hProcess, PDWORD_PTR lpProcessAffinityMask, PDWORD_PTR lpSystemAffinityMask);
BOOL WIN_FUNC SetProcessAffinityMask(HANDLE hProcess, DWORD_PTR dwProcessAffinityMask);
void WIN_FUNC ExitProcess(UINT uExitCode);
BOOL WIN_FUNC TerminateProcess(HANDLE hProcess, UINT uExitCode);
BOOL WIN_FUNC GetExitCodeProcess(HANDLE hProcess, LPDWORD lpExitCode);
BOOL WIN_FUNC CreateProcessA(LPCSTR lpApplicationName, LPSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags,
LPVOID lpEnvironment, LPCSTR lpCurrentDirectory, LPSTARTUPINFOA lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation);
BOOL WIN_FUNC CreateProcessW(LPCWSTR lpApplicationName, LPWSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags,
LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation);
// synchapi.h
HANDLE WIN_FUNC CreateMutexA(LPSECURITY_ATTRIBUTES lpMutexAttributes, BOOL bInitialOwner, LPCSTR lpName);
HANDLE WIN_FUNC CreateMutexW(LPSECURITY_ATTRIBUTES lpMutexAttributes, BOOL bInitialOwner, LPCWSTR lpName);
BOOL WIN_FUNC ReleaseMutex(HANDLE hMutex);
HANDLE WIN_FUNC CreateEventA(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState, LPCSTR lpName);
HANDLE WIN_FUNC CreateEventW(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState, LPCWSTR lpName);
BOOL WIN_FUNC SetEvent(HANDLE hEvent);
BOOL WIN_FUNC ResetEvent(HANDLE hEvent);
HANDLE WIN_FUNC CreateSemaphoreA(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, LONG lInitialCount, LONG lMaximumCount,
LPCSTR lpName);
HANDLE WIN_FUNC CreateSemaphoreW(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, LONG lInitialCount, LONG lMaximumCount,
LPCWSTR lpName);
BOOL WIN_FUNC ReleaseSemaphore(HANDLE hSemaphore, LONG lReleaseCount, PLONG lpPreviousCount);
DWORD WIN_FUNC WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds);
} // namespace kernel32

View File

@ -0,0 +1,259 @@
#include "common.h"
#include "errors.h"
#include "handles.h"
#include "kernel32.h"
#include "processes.h"
#include "strutil.h"
#include <cerrno>
#include <csignal>
#include <cstdlib>
#include <cstring>
#include <limits>
#include <pthread.h>
#include <string>
#include <unistd.h>
#include <vector>
namespace {
DWORD_PTR computeSystemAffinityMask() {
long reported = sysconf(_SC_NPROCESSORS_ONLN);
if (reported <= 0) {
reported = 1;
}
const auto bitCount = static_cast<unsigned int>(std::numeric_limits<DWORD_PTR>::digits);
const auto usable = static_cast<unsigned int>(reported);
if (usable >= bitCount) {
return static_cast<DWORD_PTR>(~static_cast<DWORD_PTR>(0));
}
return (static_cast<DWORD_PTR>(1) << usable) - 1;
}
DWORD_PTR g_processAffinityMask = 0;
bool g_processAffinityMaskInitialized = false;
} // namespace
namespace kernel32 {
HANDLE WIN_FUNC GetCurrentProcess() {
DEBUG_LOG("GetCurrentProcess() -> %p\n", reinterpret_cast<void *>(static_cast<uintptr_t>(-1)));
return reinterpret_cast<HANDLE>(static_cast<uintptr_t>(-1));
}
DWORD WIN_FUNC GetCurrentProcessId() {
DWORD pid = static_cast<DWORD>(getpid());
DEBUG_LOG("GetCurrentProcessId() -> %u\n", pid);
return pid;
}
DWORD WIN_FUNC GetCurrentThreadId() {
pthread_t thread = pthread_self();
const auto threadId = static_cast<DWORD>(thread);
DEBUG_LOG("GetCurrentThreadId() -> %u\n", threadId);
return threadId;
}
BOOL WIN_FUNC GetProcessAffinityMask(HANDLE hProcess, PDWORD_PTR lpProcessAffinityMask,
PDWORD_PTR lpSystemAffinityMask) {
DEBUG_LOG("GetProcessAffinityMask(%p, %p, %p)\n", hProcess, lpProcessAffinityMask, lpSystemAffinityMask);
if (!lpProcessAffinityMask || !lpSystemAffinityMask) {
wibo::lastError = ERROR_INVALID_PARAMETER;
return FALSE;
}
uintptr_t rawHandle = reinterpret_cast<uintptr_t>(hProcess);
bool isPseudoHandle = rawHandle == static_cast<uintptr_t>(-1);
if (!isPseudoHandle) {
auto data = handles::dataFromHandle(hProcess, false);
if (data.type != handles::TYPE_PROCESS || data.ptr == nullptr) {
wibo::lastError = ERROR_INVALID_HANDLE;
return FALSE;
}
}
DWORD_PTR systemMask = computeSystemAffinityMask();
if (!g_processAffinityMaskInitialized) {
g_processAffinityMask = systemMask;
g_processAffinityMaskInitialized = true;
}
DWORD_PTR processMask = g_processAffinityMask & systemMask;
if (processMask == 0) {
processMask = systemMask == 0 ? 1 : systemMask;
}
*lpProcessAffinityMask = processMask;
*lpSystemAffinityMask = systemMask == 0 ? 1 : systemMask;
wibo::lastError = ERROR_SUCCESS;
return TRUE;
}
BOOL WIN_FUNC SetProcessAffinityMask(HANDLE hProcess, DWORD_PTR dwProcessAffinityMask) {
DEBUG_LOG("SetProcessAffinityMask(%p, 0x%lx)\n", hProcess, static_cast<unsigned long>(dwProcessAffinityMask));
if (dwProcessAffinityMask == 0) {
wibo::lastError = ERROR_INVALID_PARAMETER;
return FALSE;
}
uintptr_t rawHandle = reinterpret_cast<uintptr_t>(hProcess);
bool isPseudoHandle = rawHandle == static_cast<uintptr_t>(-1);
if (!isPseudoHandle) {
auto data = handles::dataFromHandle(hProcess, false);
if (data.type != handles::TYPE_PROCESS) {
wibo::lastError = ERROR_INVALID_HANDLE;
return FALSE;
}
}
DWORD_PTR systemMask = computeSystemAffinityMask();
if ((dwProcessAffinityMask & systemMask) == 0 || (dwProcessAffinityMask & ~systemMask) != 0) {
wibo::lastError = ERROR_INVALID_PARAMETER;
return FALSE;
}
g_processAffinityMask = dwProcessAffinityMask & systemMask;
g_processAffinityMaskInitialized = true;
wibo::lastError = ERROR_SUCCESS;
return TRUE;
}
void WIN_FUNC ExitProcess(UINT uExitCode) {
DEBUG_LOG("ExitProcess(%u)\n", uExitCode);
std::exit(static_cast<int>(uExitCode));
}
BOOL WIN_FUNC TerminateProcess(HANDLE hProcess, UINT uExitCode) {
DEBUG_LOG("TerminateProcess(%p, %u)\n", hProcess, uExitCode);
if (hProcess == reinterpret_cast<HANDLE>(static_cast<uintptr_t>(-1))) {
ExitProcess(uExitCode);
}
auto data = handles::dataFromHandle(hProcess, false);
if (data.type != handles::TYPE_PROCESS || data.ptr == nullptr) {
wibo::lastError = ERROR_INVALID_HANDLE;
return FALSE;
}
auto *process = reinterpret_cast<processes::Process *>(data.ptr);
if (kill(process->pid, SIGKILL) != 0) {
int err = errno;
DEBUG_LOG("TerminateProcess: kill(%d) failed: %s\n", process->pid, strerror(err));
switch (err) {
case ESRCH:
case EPERM:
wibo::lastError = ERROR_ACCESS_DENIED;
break;
default:
wibo::lastError = ERROR_INVALID_PARAMETER;
break;
}
return FALSE;
}
process->forcedExitCode = uExitCode;
process->terminationRequested = true;
process->exitCode = uExitCode;
wibo::lastError = ERROR_SUCCESS;
return TRUE;
}
BOOL WIN_FUNC GetExitCodeProcess(HANDLE hProcess, LPDWORD lpExitCode) {
DEBUG_LOG("GetExitCodeProcess(%p, %p)\n", hProcess, lpExitCode);
if (!lpExitCode) {
wibo::lastError = ERROR_INVALID_PARAMETER;
return FALSE;
}
auto *process = processes::processFromHandle(hProcess, false);
if (!process) {
wibo::lastError = ERROR_INVALID_HANDLE;
return FALSE;
}
*lpExitCode = process->exitCode;
wibo::lastError = ERROR_SUCCESS;
return TRUE;
}
BOOL WIN_FUNC CreateProcessA(LPCSTR lpApplicationName, LPSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags,
LPVOID lpEnvironment, LPCSTR lpCurrentDirectory, LPSTARTUPINFOA lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation) {
DEBUG_LOG("CreateProcessA %s \"%s\" %p %p %d 0x%x %p %s %p %p\n", lpApplicationName ? lpApplicationName : "<null>",
lpCommandLine ? lpCommandLine : "<null>", lpProcessAttributes, lpThreadAttributes, bInheritHandles,
dwCreationFlags, lpEnvironment, lpCurrentDirectory ? lpCurrentDirectory : "<none>", lpStartupInfo,
lpProcessInformation);
bool useSearchPath = lpApplicationName == nullptr;
std::string application;
std::string commandLine = lpCommandLine ? lpCommandLine : "";
if (lpApplicationName) {
application = lpApplicationName;
} else {
std::vector<std::string> arguments = processes::splitCommandLine(commandLine.c_str());
if (arguments.empty()) {
wibo::lastError = ERROR_FILE_NOT_FOUND;
return FALSE;
}
application = arguments.front();
}
auto resolved = processes::resolveExecutable(application, useSearchPath);
if (!resolved) {
wibo::lastError = ERROR_FILE_NOT_FOUND;
return FALSE;
}
pid_t pid = -1;
int spawnResult = processes::spawnWithCommandLine(*resolved, commandLine, &pid);
if (spawnResult != 0) {
wibo::lastError = (spawnResult == ENOENT) ? ERROR_FILE_NOT_FOUND : ERROR_ACCESS_DENIED;
return FALSE;
}
if (lpProcessInformation) {
lpProcessInformation->hProcess = processes::allocProcessHandle(pid);
lpProcessInformation->hThread = nullptr;
lpProcessInformation->dwProcessId = static_cast<DWORD>(pid);
lpProcessInformation->dwThreadId = 0;
}
wibo::lastError = ERROR_SUCCESS;
(void)lpProcessAttributes;
(void)lpThreadAttributes;
(void)bInheritHandles;
(void)dwCreationFlags;
(void)lpEnvironment;
(void)lpCurrentDirectory;
(void)lpStartupInfo;
return TRUE;
}
BOOL WIN_FUNC CreateProcessW(LPCWSTR lpApplicationName, LPWSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags,
LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation) {
std::string applicationUtf8;
if (lpApplicationName) {
applicationUtf8 = wideStringToString(lpApplicationName);
}
std::string commandUtf8;
if (lpCommandLine) {
commandUtf8 = wideStringToString(lpCommandLine);
}
std::string directoryUtf8;
if (lpCurrentDirectory) {
directoryUtf8 = wideStringToString(lpCurrentDirectory);
}
DEBUG_LOG("CreateProcessW %s \"%s\" %p %p %d 0x%x %p %s %p %p\n",
applicationUtf8.empty() ? "<null>" : applicationUtf8.c_str(),
commandUtf8.empty() ? "<null>" : commandUtf8.c_str(), lpProcessAttributes, lpThreadAttributes,
bInheritHandles, dwCreationFlags, lpEnvironment, directoryUtf8.empty() ? "<none>" : directoryUtf8.c_str(),
lpStartupInfo, lpProcessInformation);
std::vector<char> commandBuffer;
if (!commandUtf8.empty()) {
commandBuffer.assign(commandUtf8.begin(), commandUtf8.end());
commandBuffer.push_back('\0');
}
LPSTR commandPtr = commandBuffer.empty() ? nullptr : commandBuffer.data();
LPCSTR applicationPtr = applicationUtf8.empty() ? nullptr : applicationUtf8.c_str();
LPCSTR directoryPtr = directoryUtf8.empty() ? nullptr : directoryUtf8.c_str();
return CreateProcessA(applicationPtr, commandPtr, lpProcessAttributes, lpThreadAttributes, bInheritHandles,
dwCreationFlags, lpEnvironment, directoryPtr, nullptr /* TODO: lpStartupInfo */,
lpProcessInformation);
}
} // namespace kernel32

506
dll/kernel32/synchapi.cpp Normal file
View File

@ -0,0 +1,506 @@
#include "common.h"
#include "errors.h"
#include "handles.h"
#include "internal.h"
#include "kernel32.h"
#include "processes.h"
#include "strutil.h"
#include <cerrno>
#include <mutex>
#include <pthread.h>
#include <string>
#include <sys/wait.h>
#include <unistd.h>
#include <unordered_map>
#include <vector>
namespace {
std::u16string makeMutexName(LPCWSTR name) {
if (!name) {
return {};
}
size_t len = wstrlen(reinterpret_cast<const uint16_t *>(name));
return {reinterpret_cast<const char16_t *>(name), len};
}
void makeWideNameFromAnsi(LPCSTR ansiName, std::vector<uint16_t> &outWide) {
outWide.clear();
if (!ansiName) {
return;
}
outWide = stringToWideString(ansiName);
}
} // namespace
namespace kernel32 {
namespace {
std::mutex mutexRegistryLock;
std::unordered_map<std::u16string, MutexObject *> namedMutexes;
std::mutex eventRegistryLock;
std::unordered_map<std::u16string, EventObject *> namedEvents;
std::mutex semaphoreRegistryLock;
std::unordered_map<std::u16string, SemaphoreObject *> namedSemaphores;
EventObject *eventObjectFromHandle(HANDLE hEvent) {
auto data = handles::dataFromHandle(hEvent, false);
if (data.type != handles::TYPE_EVENT || data.ptr == nullptr) {
return nullptr;
}
return reinterpret_cast<EventObject *>(data.ptr);
}
SemaphoreObject *semaphoreObjectFromHandle(HANDLE hSemaphore) {
auto data = handles::dataFromHandle(hSemaphore, false);
if (data.type != handles::TYPE_SEMAPHORE || data.ptr == nullptr) {
return nullptr;
}
return reinterpret_cast<SemaphoreObject *>(data.ptr);
}
MutexObject *mutexObjectFromHandle(HANDLE hMutex) {
auto data = handles::dataFromHandle(hMutex, false);
if (data.type != handles::TYPE_MUTEX || data.ptr == nullptr) {
return nullptr;
}
return reinterpret_cast<MutexObject *>(data.ptr);
}
bool setEventSignaledState(HANDLE hEvent, bool signaled) {
EventObject *obj = eventObjectFromHandle(hEvent);
if (!obj) {
return false;
}
pthread_mutex_lock(&obj->mutex);
obj->signaled = signaled;
if (signaled) {
if (obj->manualReset) {
pthread_cond_broadcast(&obj->cond);
} else {
pthread_cond_signal(&obj->cond);
}
}
pthread_mutex_unlock(&obj->mutex);
return true;
}
} // namespace
void releaseMutexObject(MutexObject *obj) {
if (!obj) {
return;
}
std::lock_guard<std::mutex> lock(mutexRegistryLock);
obj->refCount--;
if (obj->refCount == 0) {
if (!obj->name.empty()) {
namedMutexes.erase(obj->name);
}
pthread_mutex_destroy(&obj->mutex);
delete obj;
}
}
void releaseEventObject(EventObject *obj) {
if (!obj) {
return;
}
std::lock_guard<std::mutex> lock(eventRegistryLock);
obj->refCount--;
if (obj->refCount == 0) {
if (!obj->name.empty()) {
namedEvents.erase(obj->name);
}
pthread_cond_destroy(&obj->cond);
pthread_mutex_destroy(&obj->mutex);
delete obj;
}
}
void releaseSemaphoreObject(SemaphoreObject *obj) {
if (!obj) {
return;
}
std::lock_guard<std::mutex> lock(semaphoreRegistryLock);
obj->refCount--;
if (obj->refCount == 0) {
if (!obj->name.empty()) {
namedSemaphores.erase(obj->name);
}
pthread_cond_destroy(&obj->cond);
pthread_mutex_destroy(&obj->mutex);
delete obj;
}
}
HANDLE WIN_FUNC CreateMutexW(LPSECURITY_ATTRIBUTES lpMutexAttributes, BOOL bInitialOwner, LPCWSTR lpName) {
std::string nameLog;
if (lpName) {
nameLog = wideStringToString(reinterpret_cast<const uint16_t *>(lpName));
} else {
nameLog = "<unnamed>";
}
DEBUG_LOG("CreateMutexW(%p, %d, %s)\n", lpMutexAttributes, bInitialOwner, nameLog.c_str());
(void)lpMutexAttributes;
std::u16string name = makeMutexName(lpName);
MutexObject *obj = nullptr;
bool alreadyExists = false;
{
std::lock_guard<std::mutex> lock(mutexRegistryLock);
if (!name.empty()) {
auto it = namedMutexes.find(name);
if (it != namedMutexes.end()) {
obj = it->second;
obj->refCount++;
alreadyExists = true;
}
}
if (!obj) {
obj = new MutexObject();
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&obj->mutex, &attr);
pthread_mutexattr_destroy(&attr);
obj->name = name;
if (!name.empty()) {
namedMutexes[name] = obj;
}
}
}
if (!alreadyExists && bInitialOwner) {
pthread_mutex_lock(&obj->mutex);
obj->owner = pthread_self();
obj->ownerValid = true;
obj->recursionCount = 1;
}
HANDLE handle = handles::allocDataHandle({handles::TYPE_MUTEX, obj, 0});
wibo::lastError = alreadyExists ? ERROR_ALREADY_EXISTS : ERROR_SUCCESS;
return handle;
}
HANDLE WIN_FUNC CreateMutexA(LPSECURITY_ATTRIBUTES lpMutexAttributes, BOOL bInitialOwner, LPCSTR lpName) {
DEBUG_LOG("CreateMutexA -> ");
std::vector<uint16_t> wideName;
makeWideNameFromAnsi(lpName, wideName);
return CreateMutexW(lpMutexAttributes, bInitialOwner,
lpName ? reinterpret_cast<LPCWSTR>(wideName.data()) : nullptr);
}
BOOL WIN_FUNC ReleaseMutex(HANDLE hMutex) {
DEBUG_LOG("ReleaseMutex(%p)\n", hMutex);
MutexObject *obj = mutexObjectFromHandle(hMutex);
if (!obj) {
wibo::lastError = ERROR_INVALID_HANDLE;
return FALSE;
}
pthread_t self = pthread_self();
pthread_mutex_lock(&obj->mutex);
if (!obj->ownerValid || !pthread_equal(obj->owner, self) || obj->recursionCount == 0) {
pthread_mutex_unlock(&obj->mutex);
wibo::lastError = ERROR_NOT_OWNER;
return FALSE;
}
obj->recursionCount--;
if (obj->recursionCount == 0) {
obj->ownerValid = false;
}
pthread_mutex_unlock(&obj->mutex);
wibo::lastError = ERROR_SUCCESS;
return TRUE;
}
HANDLE WIN_FUNC CreateEventW(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState,
LPCWSTR lpName) {
std::string nameLog;
if (lpName) {
nameLog = wideStringToString(reinterpret_cast<const uint16_t *>(lpName));
} else {
nameLog = "<unnamed>";
}
DEBUG_LOG("CreateEventW(name=%s, manualReset=%d, initialState=%d)\n", nameLog.c_str(), bManualReset, bInitialState);
(void)lpEventAttributes;
std::u16string name = makeMutexName(lpName);
EventObject *obj = nullptr;
bool alreadyExists = false;
{
std::lock_guard<std::mutex> lock(eventRegistryLock);
if (!name.empty()) {
auto it = namedEvents.find(name);
if (it != namedEvents.end()) {
obj = it->second;
obj->refCount++;
alreadyExists = true;
}
}
if (!obj) {
obj = new EventObject();
pthread_mutex_init(&obj->mutex, nullptr);
pthread_cond_init(&obj->cond, nullptr);
obj->manualReset = bManualReset;
obj->signaled = bInitialState;
obj->name = name;
if (!name.empty()) {
namedEvents[name] = obj;
}
}
}
HANDLE handle = handles::allocDataHandle({handles::TYPE_EVENT, obj, 0});
wibo::lastError = alreadyExists ? ERROR_ALREADY_EXISTS : ERROR_SUCCESS;
return handle;
}
HANDLE WIN_FUNC CreateEventA(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState,
LPCSTR lpName) {
DEBUG_LOG("CreateEventA -> ");
std::vector<uint16_t> wideName;
makeWideNameFromAnsi(lpName, wideName);
return CreateEventW(lpEventAttributes, bManualReset, bInitialState,
lpName ? reinterpret_cast<LPCWSTR>(wideName.data()) : nullptr);
}
HANDLE WIN_FUNC CreateSemaphoreW(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, LONG lInitialCount, LONG lMaximumCount,
LPCWSTR lpName) {
DEBUG_LOG("CreateSemaphoreW(%p, %ld, %ld, %ls)\n", lpSemaphoreAttributes, static_cast<long>(lInitialCount),
static_cast<long>(lMaximumCount), lpName ? reinterpret_cast<const wchar_t *>(lpName) : L"<null>");
(void)lpSemaphoreAttributes;
std::u16string name = makeMutexName(lpName);
SemaphoreObject *obj = nullptr;
bool alreadyExists = false;
{
std::lock_guard<std::mutex> lock(semaphoreRegistryLock);
if (!name.empty()) {
auto it = namedSemaphores.find(name);
if (it != namedSemaphores.end()) {
obj = it->second;
obj->refCount++;
alreadyExists = true;
}
}
if (!obj) {
if (lMaximumCount <= 0 || lInitialCount < 0 || lInitialCount > lMaximumCount) {
wibo::lastError = ERROR_INVALID_PARAMETER;
return nullptr;
}
obj = new SemaphoreObject();
pthread_mutex_init(&obj->mutex, nullptr);
pthread_cond_init(&obj->cond, nullptr);
obj->count = lInitialCount;
obj->maxCount = lMaximumCount;
obj->name = name;
if (!name.empty()) {
namedSemaphores[name] = obj;
}
}
}
HANDLE handle = handles::allocDataHandle({handles::TYPE_SEMAPHORE, obj, 0});
wibo::lastError = alreadyExists ? ERROR_ALREADY_EXISTS : ERROR_SUCCESS;
return handle;
}
HANDLE WIN_FUNC CreateSemaphoreA(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, LONG lInitialCount, LONG lMaximumCount,
LPCSTR lpName) {
DEBUG_LOG("CreateSemaphoreA -> ");
std::vector<uint16_t> wideName;
makeWideNameFromAnsi(lpName, wideName);
return CreateSemaphoreW(lpSemaphoreAttributes, lInitialCount, lMaximumCount,
lpName ? reinterpret_cast<LPCWSTR>(wideName.data()) : nullptr);
}
BOOL WIN_FUNC ReleaseSemaphore(HANDLE hSemaphore, LONG lReleaseCount, PLONG lpPreviousCount) {
DEBUG_LOG("ReleaseSemaphore(%p, %ld, %p)\n", hSemaphore, static_cast<long>(lReleaseCount), lpPreviousCount);
if (lReleaseCount <= 0) {
wibo::lastError = ERROR_INVALID_PARAMETER;
return FALSE;
}
SemaphoreObject *obj = semaphoreObjectFromHandle(hSemaphore);
if (!obj) {
wibo::lastError = ERROR_INVALID_HANDLE;
return FALSE;
}
pthread_mutex_lock(&obj->mutex);
if (lpPreviousCount) {
*lpPreviousCount = obj->count;
}
if (lReleaseCount > obj->maxCount - obj->count) {
pthread_mutex_unlock(&obj->mutex);
wibo::lastError = ERROR_INVALID_PARAMETER;
return FALSE;
}
obj->count += lReleaseCount;
pthread_mutex_unlock(&obj->mutex);
pthread_cond_broadcast(&obj->cond);
wibo::lastError = ERROR_SUCCESS;
return TRUE;
}
BOOL WIN_FUNC SetEvent(HANDLE hEvent) {
DEBUG_LOG("SetEvent(%p)\n", hEvent);
if (!setEventSignaledState(hEvent, true)) {
wibo::lastError = ERROR_INVALID_HANDLE;
return FALSE;
}
wibo::lastError = ERROR_SUCCESS;
return TRUE;
}
BOOL WIN_FUNC ResetEvent(HANDLE hEvent) {
DEBUG_LOG("ResetEvent(%p)\n", hEvent);
if (!setEventSignaledState(hEvent, false)) {
wibo::lastError = ERROR_INVALID_HANDLE;
return FALSE;
}
wibo::lastError = ERROR_SUCCESS;
return TRUE;
}
DWORD WIN_FUNC WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds) {
DEBUG_LOG("WaitForSingleObject(%p, %u)\n", hHandle, dwMilliseconds);
handles::Data data = handles::dataFromHandle(hHandle, false);
switch (data.type) {
case handles::TYPE_PROCESS: {
if (dwMilliseconds != INFINITE) {
DEBUG_LOG("WaitForSingleObject: timeout for process not supported\n");
wibo::lastError = ERROR_NOT_SUPPORTED;
return WAIT_FAILED;
}
auto *process = reinterpret_cast<processes::Process *>(data.ptr);
int status = 0;
for (;;) {
if (waitpid(process->pid, &status, 0) == -1) {
if (errno == EINTR) {
continue;
}
if (errno == ECHILD && process->terminationRequested) {
process->exitCode = process->forcedExitCode;
break;
}
DEBUG_LOG("WaitForSingleObject: waitpid(%d) failed: %s\n", process->pid, strerror(errno));
wibo::lastError = ERROR_INVALID_HANDLE;
return WAIT_FAILED;
}
break;
}
if (process->terminationRequested) {
process->exitCode = process->forcedExitCode;
} else if (WIFEXITED(status)) {
process->exitCode = static_cast<DWORD>(WEXITSTATUS(status));
} else {
DEBUG_LOG("WaitForSingleObject: child process exited abnormally - returning exit code 1\n");
process->exitCode = 1;
}
process->terminationRequested = false;
wibo::lastError = ERROR_SUCCESS;
return WAIT_OBJECT_0;
}
case handles::TYPE_EVENT: {
EventObject *obj = reinterpret_cast<EventObject *>(data.ptr);
if (dwMilliseconds != INFINITE) {
DEBUG_LOG("WaitForSingleObject: timeout for event not supported\n");
wibo::lastError = ERROR_NOT_SUPPORTED;
return WAIT_FAILED;
}
pthread_mutex_lock(&obj->mutex);
while (!obj->signaled) {
pthread_cond_wait(&obj->cond, &obj->mutex);
}
if (!obj->manualReset) {
obj->signaled = false;
}
pthread_mutex_unlock(&obj->mutex);
wibo::lastError = ERROR_SUCCESS;
return WAIT_OBJECT_0;
}
case handles::TYPE_THREAD: {
ThreadObject *obj = reinterpret_cast<ThreadObject *>(data.ptr);
if (dwMilliseconds != INFINITE) {
DEBUG_LOG("WaitForSingleObject: timeout for thread not supported\n");
wibo::lastError = ERROR_NOT_SUPPORTED;
return WAIT_FAILED;
}
pthread_mutex_lock(&obj->mutex);
while (!obj->finished) {
pthread_cond_wait(&obj->cond, &obj->mutex);
}
bool needJoin = !obj->joined && !obj->detached;
pthread_t thread = obj->thread;
if (needJoin) {
obj->joined = true;
}
pthread_mutex_unlock(&obj->mutex);
if (needJoin) {
pthread_join(thread, nullptr);
}
wibo::lastError = ERROR_SUCCESS;
return WAIT_OBJECT_0;
}
case handles::TYPE_SEMAPHORE: {
SemaphoreObject *obj = reinterpret_cast<SemaphoreObject *>(data.ptr);
if (dwMilliseconds != INFINITE) {
DEBUG_LOG("WaitForSingleObject: timeout for semaphore not supported\n");
wibo::lastError = ERROR_NOT_SUPPORTED;
return WAIT_FAILED;
}
pthread_mutex_lock(&obj->mutex);
while (obj->count == 0) {
pthread_cond_wait(&obj->cond, &obj->mutex);
}
obj->count--;
pthread_mutex_unlock(&obj->mutex);
wibo::lastError = ERROR_SUCCESS;
return WAIT_OBJECT_0;
}
case handles::TYPE_MUTEX: {
MutexObject *obj = reinterpret_cast<MutexObject *>(data.ptr);
if (dwMilliseconds != INFINITE) {
DEBUG_LOG("WaitForSingleObject: timeout for mutex not supported\n");
wibo::lastError = ERROR_NOT_SUPPORTED;
return WAIT_FAILED;
}
pthread_mutex_lock(&obj->mutex);
pthread_t self = pthread_self();
if (obj->ownerValid && pthread_equal(obj->owner, self)) {
obj->recursionCount++;
} else {
obj->owner = self;
obj->ownerValid = true;
obj->recursionCount = 1;
}
wibo::lastError = ERROR_SUCCESS;
return WAIT_OBJECT_0;
}
default:
DEBUG_LOG("WaitForSingleObject: unsupported handle type %d\n", data.type);
wibo::lastError = ERROR_INVALID_HANDLE;
return WAIT_FAILED;
}
}
void resetOverlappedEvent(OVERLAPPED *ov) {
if (!ov || !ov->hEvent) {
return;
}
setEventSignaledState(ov->hEvent, false);
}
void signalOverlappedEvent(OVERLAPPED *ov) {
if (!ov || !ov->hEvent) {
return;
}
setEventSignaledState(ov->hEvent, true);
}
} // namespace kernel32

View File

@ -0,0 +1,58 @@
#include "common.h"
#include "kernel32.h"
#include <cstring>
namespace {
constexpr WORD PROCESSOR_ARCHITECTURE_INTEL = 0;
constexpr DWORD PROCESSOR_INTEL_PENTIUM = 586;
DWORD_PTR computeSystemProcessorMask(unsigned int cpuCount) {
const auto maskWidth = static_cast<unsigned int>(sizeof(DWORD_PTR) * 8);
if (cpuCount >= maskWidth) {
return static_cast<DWORD_PTR>(~static_cast<DWORD_PTR>(0));
}
DWORD_PTR mask = (static_cast<DWORD_PTR>(1) << cpuCount) - 1;
return mask == 0 ? 1 : mask;
}
} // namespace
namespace kernel32 {
void WIN_FUNC GetSystemInfo(LPSYSTEM_INFO lpSystemInfo) {
DEBUG_LOG("GetSystemInfo(%p)\n", lpSystemInfo);
if (!lpSystemInfo) {
return;
}
std::memset(lpSystemInfo, 0, sizeof(*lpSystemInfo));
lpSystemInfo->wProcessorArchitecture = PROCESSOR_ARCHITECTURE_INTEL;
lpSystemInfo->dwOemId = lpSystemInfo->wProcessorArchitecture;
lpSystemInfo->dwProcessorType = PROCESSOR_INTEL_PENTIUM;
lpSystemInfo->wProcessorLevel = 6; // Pentium
long pageSize = sysconf(_SC_PAGESIZE);
if (pageSize <= 0) {
pageSize = 4096;
}
lpSystemInfo->dwPageSize = static_cast<DWORD>(pageSize);
lpSystemInfo->lpMinimumApplicationAddress = reinterpret_cast<LPVOID>(0x00010000);
if (sizeof(void *) == 4) {
lpSystemInfo->lpMaximumApplicationAddress = reinterpret_cast<LPVOID>(0x7FFEFFFF);
} else {
lpSystemInfo->lpMaximumApplicationAddress = reinterpret_cast<LPVOID>(0x00007FFFFFFEFFFFull);
}
unsigned int cpuCount = 1;
long reported = sysconf(_SC_NPROCESSORS_ONLN);
if (reported > 0) {
cpuCount = static_cast<unsigned int>(reported);
}
lpSystemInfo->dwNumberOfProcessors = cpuCount;
lpSystemInfo->dwActiveProcessorMask = computeSystemProcessorMask(cpuCount);
lpSystemInfo->dwAllocationGranularity = 0x10000;
}
} // namespace kernel32

View File

@ -0,0 +1,50 @@
#include "common.h"
#include "errors.h"
#include "handles.h"
#include "kernel32.h"
namespace kernel32 {
BOOL WIN_FUNC Wow64DisableWow64FsRedirection(PVOID *OldValue) {
DEBUG_LOG("STUB: Wow64DisableWow64FsRedirection(%p)\n", OldValue);
if (OldValue) {
*OldValue = nullptr;
}
wibo::lastError = ERROR_SUCCESS;
return TRUE;
}
BOOL WIN_FUNC Wow64RevertWow64FsRedirection(PVOID OldValue) {
DEBUG_LOG("STUB: Wow64RevertWow64FsRedirection(%p)\n", OldValue);
(void)OldValue;
wibo::lastError = ERROR_SUCCESS;
return TRUE;
}
BOOL WIN_FUNC IsWow64Process(HANDLE hProcess, PBOOL Wow64Process) {
DEBUG_LOG("IsWow64Process(%p, %p)\n", hProcess, Wow64Process);
if (!Wow64Process) {
wibo::lastError = ERROR_INVALID_PARAMETER;
return FALSE;
}
const auto rawHandle = reinterpret_cast<uintptr_t>(hProcess);
bool isPseudoHandle = rawHandle == static_cast<uintptr_t>(-1);
if (!isPseudoHandle) {
if (!hProcess) {
wibo::lastError = ERROR_INVALID_HANDLE;
return FALSE;
}
auto data = handles::dataFromHandle(hProcess, false);
if (data.type != handles::TYPE_PROCESS || data.ptr == nullptr) {
wibo::lastError = ERROR_INVALID_HANDLE;
return FALSE;
}
}
*Wow64Process = FALSE;
wibo::lastError = ERROR_SUCCESS;
return TRUE;
}
} // namespace kernel32