From 8330f274796b04697f28325f36dda9dd7275e303 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Thu, 2 Oct 2025 09:47:41 -0600 Subject: [PATCH] Add CreatePipe, CON* support for CreateFileA, more for cygwin --- CMakeLists.txt | 1 + common.h | 1 + dll/advapi32.cpp | 4 ++ dll/advapi32/securitybaseapi.cpp | 44 ++++++++++++++ dll/advapi32/securitybaseapi.h | 3 + dll/kernel32.cpp | 7 +++ dll/kernel32/fibersapi.h | 1 - dll/kernel32/fileapi.cpp | 61 ++++++++++++++++++++ dll/kernel32/ioapiset.cpp | 3 +- dll/kernel32/ioapiset.h | 3 +- dll/kernel32/namedpipeapi.cpp | 98 ++++++++++++++++++++++++++++++++ dll/kernel32/namedpipeapi.h | 10 ++++ dll/kernel32/processenv.cpp | 4 +- dll/kernel32/winbase.cpp | 10 ++-- dll/kernel32/winbase.h | 4 +- dll/kernel32/wincon.cpp | 6 ++ dll/kernel32/wincon.h | 1 + dll/kernel32/winnt.cpp | 1 - dll/kernel32/winnt.h | 1 - dll/user32.cpp | 10 ++++ 20 files changed, 257 insertions(+), 16 deletions(-) create mode 100644 dll/kernel32/namedpipeapi.cpp create mode 100644 dll/kernel32/namedpipeapi.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 14f5432..630c8f1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -50,6 +50,7 @@ add_executable(wibo dll/kernel32/interlockedapi.cpp dll/kernel32/ioapiset.cpp dll/kernel32/libloaderapi.cpp + dll/kernel32/namedpipeapi.cpp dll/kernel32/memoryapi.cpp dll/kernel32/processenv.cpp dll/kernel32/processthreadsapi.cpp diff --git a/common.h b/common.h index e602f77..e6a239b 100644 --- a/common.h +++ b/common.h @@ -43,6 +43,7 @@ using HLOCAL = HANDLE; using HRSRC = HANDLE; using LPHANDLE = HANDLE *; using PHANDLE = HANDLE *; +using HKL = HANDLE; using PVOID = void *; using LPVOID = void *; using LPCVOID = const void *; diff --git a/dll/advapi32.cpp b/dll/advapi32.cpp index afa460c..fd509ba 100644 --- a/dll/advapi32.cpp +++ b/dll/advapi32.cpp @@ -33,6 +33,10 @@ void *resolveByName(const char *name) { return (void *)advapi32::DuplicateTokenEx; if (strcmp(name, "CopySid") == 0) return (void *)advapi32::CopySid; + if (strcmp(name, "InitializeSid") == 0) + return (void *)advapi32::InitializeSid; + if (strcmp(name, "EqualSid") == 0) + return (void *)advapi32::EqualSid; if (strcmp(name, "GetSecurityDescriptorDacl") == 0) return (void *)advapi32::GetSecurityDescriptorDacl; if (strcmp(name, "SetKernelObjectSecurity") == 0) diff --git a/dll/advapi32/securitybaseapi.cpp b/dll/advapi32/securitybaseapi.cpp index 7191993..958ed73 100644 --- a/dll/advapi32/securitybaseapi.cpp +++ b/dll/advapi32/securitybaseapi.cpp @@ -359,6 +359,50 @@ BOOL WIN_FUNC CopySid(DWORD nDestinationSidLength, PSID pDestinationSid, PSID pS return TRUE; } +BOOL WIN_FUNC InitializeSid(PSID sid, PSID_IDENTIFIER_AUTHORITY pIdentifierAuthority, BYTE nSubAuthorityCount) { + DEBUG_LOG("InitializeSid(%p, %p, %u)\n", sid, pIdentifierAuthority, nSubAuthorityCount); + if (!sid || !pIdentifierAuthority) { + wibo::lastError = ERROR_INVALID_PARAMETER; + return FALSE; + } + if (nSubAuthorityCount > SID_MAX_SUB_AUTHORITIES) { + wibo::lastError = ERROR_INVALID_SID; + return FALSE; + } + auto *sidStruct = reinterpret_cast(sid); + sidStruct->Revision = SID_REVISION; + sidStruct->SubAuthorityCount = nSubAuthorityCount; + sidStruct->IdentifierAuthority = *pIdentifierAuthority; + if (nSubAuthorityCount > 0) { + std::memset(sidStruct->SubAuthority, 0, sizeof(DWORD) * nSubAuthorityCount); + } + wibo::lastError = ERROR_SUCCESS; + return TRUE; +} + +BOOL WIN_FUNC EqualSid(PSID pSid1, PSID pSid2) { + DEBUG_LOG("EqualSid(%p, %p)\n", pSid1, pSid2); + if (!pSid1 || !pSid2) { + wibo::lastError = ERROR_INVALID_SID; + return FALSE; + } + const auto *sid1 = reinterpret_cast(pSid1); + const auto *sid2 = reinterpret_cast(pSid2); + if (sid1->SubAuthorityCount > SID_MAX_SUB_AUTHORITIES || sid2->SubAuthorityCount > SID_MAX_SUB_AUTHORITIES) { + wibo::lastError = ERROR_INVALID_SID; + return FALSE; + } + bool equal = + sid1->Revision == sid2->Revision && + std::memcmp(&sid1->IdentifierAuthority, &sid2->IdentifierAuthority, sizeof(SidIdentifierAuthority)) == 0 && + sid1->SubAuthorityCount == sid2->SubAuthorityCount; + if (equal && sid1->SubAuthorityCount > 0) { + equal = std::memcmp(sid1->SubAuthority, sid2->SubAuthority, sizeof(DWORD) * sid1->SubAuthorityCount) == 0; + } + wibo::lastError = ERROR_SUCCESS; + return equal ? TRUE : FALSE; +} + BOOL WIN_FUNC SetKernelObjectSecurity(HANDLE Handle, SECURITY_INFORMATION SecurityInformation, PSECURITY_DESCRIPTOR SecurityDescriptor) { DEBUG_LOG("STUB: SetKernelObjectSecurity(%p, 0x%x, %p)\n", Handle, SecurityInformation, SecurityDescriptor); diff --git a/dll/advapi32/securitybaseapi.h b/dll/advapi32/securitybaseapi.h index 23ed624..0563ce6 100644 --- a/dll/advapi32/securitybaseapi.h +++ b/dll/advapi32/securitybaseapi.h @@ -53,6 +53,7 @@ constexpr BYTE ACL_REVISION = ACL_REVISION2; constexpr BYTE ACL_REVISION_DS = ACL_REVISION4; constexpr BYTE ACCESS_ALLOWED_ACE_TYPE = 0x00; constexpr BYTE SID_MAX_SUB_AUTHORITIES = 15; +constexpr BYTE SID_REVISION = 1; struct TOKEN_PRIVILEGES; using PTOKEN_PRIVILEGES = TOKEN_PRIVILEGES *; @@ -92,6 +93,8 @@ BOOL WIN_FUNC ImpersonateLoggedOnUser(HANDLE hToken); BOOL WIN_FUNC DuplicateTokenEx(HANDLE hExistingToken, DWORD dwDesiredAccess, void *lpTokenAttributes, DWORD ImpersonationLevel, DWORD TokenType, PHANDLE phNewToken); BOOL WIN_FUNC CopySid(DWORD nDestinationSidLength, PSID pDestinationSid, PSID pSourceSid); +BOOL WIN_FUNC InitializeSid(PSID sid, PSID_IDENTIFIER_AUTHORITY pIdentifierAuthority, BYTE nSubAuthorityCount); +BOOL WIN_FUNC EqualSid(PSID pSid1, PSID pSid2); BOOL WIN_FUNC GetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR pSecurityDescriptor, LPBOOL lpbDaclPresent, PACL *pDacl, LPBOOL lpbDaclDefaulted); BOOL WIN_FUNC SetKernelObjectSecurity(HANDLE Handle, SECURITY_INFORMATION SecurityInformation, diff --git a/dll/kernel32.cpp b/dll/kernel32.cpp index 134652f..2f64916 100644 --- a/dll/kernel32.cpp +++ b/dll/kernel32.cpp @@ -9,6 +9,7 @@ #include "kernel32/interlockedapi.h" #include "kernel32/ioapiset.h" #include "kernel32/libloaderapi.h" +#include "kernel32/namedpipeapi.h" #include "kernel32/memoryapi.h" #include "kernel32/processenv.h" #include "kernel32/processthreadsapi.h" @@ -192,6 +193,10 @@ void *resolveByName(const char *name) { if (strcmp(name, "Sleep") == 0) return (void *)kernel32::Sleep; + // namedpipeapi.h + if (strcmp(name, "CreatePipe") == 0) + return (void *)kernel32::CreatePipe; + // winbase.h if (strcmp(name, "GlobalAlloc") == 0) return (void *)kernel32::GlobalAlloc; @@ -289,6 +294,8 @@ void *resolveByName(const char *name) { return (void *)kernel32::GetConsoleMode; if (strcmp(name, "SetConsoleMode") == 0) return (void *)kernel32::SetConsoleMode; + if (strcmp(name, "GetConsoleCP") == 0) + return (void *)kernel32::GetConsoleCP; if (strcmp(name, "SetConsoleCtrlHandler") == 0) return (void *)kernel32::SetConsoleCtrlHandler; if (strcmp(name, "GetConsoleScreenBufferInfo") == 0) diff --git a/dll/kernel32/fibersapi.h b/dll/kernel32/fibersapi.h index 32af1f3..58d705e 100644 --- a/dll/kernel32/fibersapi.h +++ b/dll/kernel32/fibersapi.h @@ -13,4 +13,3 @@ PVOID WIN_FUNC FlsGetValue(DWORD dwFlsIndex); BOOL WIN_FUNC FlsSetValue(DWORD dwFlsIndex, PVOID lpFlsData); } // namespace kernel32 - diff --git a/dll/kernel32/fileapi.cpp b/dll/kernel32/fileapi.cpp index 86ba717..4dce0aa 100644 --- a/dll/kernel32/fileapi.cpp +++ b/dll/kernel32/fileapi.cpp @@ -220,6 +220,53 @@ bool initializeEnumeration(const std::filesystem::path &parent, const std::strin return nextMatch(handle, firstMatch); } +std::optional stdHandleForConsoleDevice(const std::string &name, DWORD desiredAccess) { + std::string lowered = stringToLower(name); + if (lowered == "conin$") { + return STD_INPUT_HANDLE; + } + if (lowered == "conout$") { + return STD_OUTPUT_HANDLE; + } + if (lowered == "conerr$") { + return STD_ERROR_HANDLE; + } + if (lowered == "con") { + if ((desiredAccess & GENERIC_WRITE) != 0) { + return STD_OUTPUT_HANDLE; + } + return STD_INPUT_HANDLE; + } + return std::nullopt; +} + +bool tryOpenConsoleDevice(DWORD dwDesiredAccess, DWORD dwShareMode, DWORD dwCreationDisposition, + DWORD dwFlagsAndAttributes, HANDLE &outHandle, const std::string &originalName) { + (void)dwShareMode; + (void)dwCreationDisposition; + (void)dwFlagsAndAttributes; + auto stdHandleKind = stdHandleForConsoleDevice(originalName, dwDesiredAccess); + if (!stdHandleKind) { + return false; + } + HANDLE baseHandle = files::getStdHandle(*stdHandleKind); + auto *baseFile = files::fileHandleFromHandle(baseHandle); + if (!baseFile) { + wibo::lastError = ERROR_INVALID_HANDLE; + outHandle = INVALID_HANDLE_VALUE; + return true; + } + HANDLE duplicated = files::duplicateFileHandle(baseFile, false); + if (!duplicated) { + wibo::lastError = ERROR_INVALID_HANDLE; + outHandle = INVALID_HANDLE_VALUE; + return true; + } + wibo::lastError = ERROR_SUCCESS; + outHandle = duplicated; + return true; +} + } // namespace namespace kernel32 { @@ -548,6 +595,13 @@ HANDLE WIN_FUNC CreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwSh wibo::lastError = ERROR_INVALID_PARAMETER; return INVALID_HANDLE_VALUE; } + HANDLE consoleHandle = INVALID_HANDLE_VALUE; + if (tryOpenConsoleDevice(dwDesiredAccess, dwShareMode, dwCreationDisposition, dwFlagsAndAttributes, consoleHandle, + std::string(lpFileName))) { + DEBUG_LOG("CreateFileA(console=%s, desiredAccess=0x%x, shareMode=%u, flags=0x%x) -> %p\n", lpFileName, + dwDesiredAccess, dwShareMode, dwFlagsAndAttributes, consoleHandle); + return consoleHandle; + } std::string path = files::pathFromWindows(lpFileName); DEBUG_LOG("CreateFileA(filename=%s (%s), desiredAccess=0x%x, shareMode=%u, securityAttributes=%p, " "creationDisposition=%u, flagsAndAttributes=%u)\n", @@ -629,6 +683,13 @@ HANDLE WIN_FUNC CreateFileW(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwS return INVALID_HANDLE_VALUE; } std::string lpFileNameA = wideStringToString(lpFileName); + HANDLE consoleHandle = INVALID_HANDLE_VALUE; + if (tryOpenConsoleDevice(dwDesiredAccess, dwShareMode, dwCreationDisposition, dwFlagsAndAttributes, consoleHandle, + lpFileNameA)) { + DEBUG_LOG("CreateFileW(console=%s, desiredAccess=0x%x, shareMode=%u, flags=0x%x) -> %p\n", lpFileNameA.c_str(), + dwDesiredAccess, dwShareMode, dwFlagsAndAttributes, consoleHandle); + return consoleHandle; + } return CreateFileA(lpFileNameA.c_str(), dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); } diff --git a/dll/kernel32/ioapiset.cpp b/dll/kernel32/ioapiset.cpp index 8d5d064..fab6a24 100644 --- a/dll/kernel32/ioapiset.cpp +++ b/dll/kernel32/ioapiset.cpp @@ -6,7 +6,7 @@ namespace kernel32 { BOOL WIN_FUNC GetOverlappedResult(HANDLE hFile, LPOVERLAPPED lpOverlapped, LPDWORD lpNumberOfBytesTransferred, - BOOL bWait) { + BOOL bWait) { DEBUG_LOG("GetOverlappedResult(%p, %p, %p, %d)\n", hFile, lpOverlapped, lpNumberOfBytesTransferred, bWait); (void)hFile; if (!lpOverlapped) { @@ -46,4 +46,3 @@ BOOL WIN_FUNC GetOverlappedResult(HANDLE hFile, LPOVERLAPPED lpOverlapped, LPDWO } } // namespace kernel32 - diff --git a/dll/kernel32/ioapiset.h b/dll/kernel32/ioapiset.h index 9fa4ea4..3b08f77 100644 --- a/dll/kernel32/ioapiset.h +++ b/dll/kernel32/ioapiset.h @@ -6,7 +6,6 @@ namespace kernel32 { BOOL WIN_FUNC GetOverlappedResult(HANDLE hFile, LPOVERLAPPED lpOverlapped, LPDWORD lpNumberOfBytesTransferred, - BOOL bWait); + BOOL bWait); } // namespace kernel32 - diff --git a/dll/kernel32/namedpipeapi.cpp b/dll/kernel32/namedpipeapi.cpp new file mode 100644 index 0000000..68a25e1 --- /dev/null +++ b/dll/kernel32/namedpipeapi.cpp @@ -0,0 +1,98 @@ +#include "namedpipeapi.h" + +#include "errors.h" +#include "fileapi.h" +#include "files.h" +#include "handles.h" +#include "internal.h" + +#include +#include +#include +#include + +namespace kernel32 { + +namespace { + +void configureInheritability(int fd, bool inherit) { + if (fd < 0) { + return; + } + int flags = fcntl(fd, F_GETFD); + if (flags == -1) { + return; + } + if (inherit) { + flags &= ~FD_CLOEXEC; + } else { + flags |= FD_CLOEXEC; + } + fcntl(fd, F_SETFD, flags); +} + +} // namespace + +BOOL WIN_FUNC CreatePipe(PHANDLE hReadPipe, PHANDLE hWritePipe, LPSECURITY_ATTRIBUTES lpPipeAttributes, DWORD nSize) { + DEBUG_LOG("CreatePipe(%p, %p, %p, %u)\n", hReadPipe, hWritePipe, lpPipeAttributes, nSize); + if (!hReadPipe || !hWritePipe) { + wibo::lastError = ERROR_INVALID_PARAMETER; + return FALSE; + } + *hReadPipe = nullptr; + *hWritePipe = nullptr; + + int pipeFds[2]; + if (pipe(pipeFds) != 0) { + setLastErrorFromErrno(); + return FALSE; + } + + bool inheritHandles = lpPipeAttributes && lpPipeAttributes->bInheritHandle; + configureInheritability(pipeFds[0], inheritHandles); + configureInheritability(pipeFds[1], inheritHandles); + + if (nSize != 0) { + // Best-effort adjustment; ignore failures as recommended by docs. + fcntl(pipeFds[0], F_SETPIPE_SZ, static_cast(nSize)); + fcntl(pipeFds[1], F_SETPIPE_SZ, static_cast(nSize)); + } + + FILE *readStream = fdopen(pipeFds[0], "rb"); + if (!readStream) { + int savedErrno = errno ? errno : EINVAL; + close(pipeFds[0]); + close(pipeFds[1]); + errno = savedErrno; + setLastErrorFromErrno(); + return FALSE; + } + FILE *writeStream = fdopen(pipeFds[1], "wb"); + if (!writeStream) { + int savedErrno = errno ? errno : EINVAL; + fclose(readStream); + close(pipeFds[1]); + errno = savedErrno; + setLastErrorFromErrno(); + return FALSE; + } + + setvbuf(readStream, nullptr, _IONBF, 0); + setvbuf(writeStream, nullptr, _IONBF, 0); + + HANDLE readHandle = files::allocFpHandle(readStream, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, true); + HANDLE writeHandle = files::allocFpHandle(writeStream, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, true); + if (!readHandle || !writeHandle) { + fclose(readStream); + fclose(writeStream); + wibo::lastError = ERROR_NOT_ENOUGH_MEMORY; + return FALSE; + } + + *hReadPipe = readHandle; + *hWritePipe = writeHandle; + wibo::lastError = ERROR_SUCCESS; + return TRUE; +} + +} // namespace kernel32 diff --git a/dll/kernel32/namedpipeapi.h b/dll/kernel32/namedpipeapi.h new file mode 100644 index 0000000..3ce1bae --- /dev/null +++ b/dll/kernel32/namedpipeapi.h @@ -0,0 +1,10 @@ +#pragma once + +#include "common.h" +#include "minwinbase.h" + +namespace kernel32 { + +BOOL WIN_FUNC CreatePipe(PHANDLE hReadPipe, PHANDLE hWritePipe, LPSECURITY_ATTRIBUTES lpPipeAttributes, DWORD nSize); + +} // namespace kernel32 diff --git a/dll/kernel32/processenv.cpp b/dll/kernel32/processenv.cpp index 70178a5..95fdf6f 100644 --- a/dll/kernel32/processenv.cpp +++ b/dll/kernel32/processenv.cpp @@ -53,12 +53,12 @@ LPWSTR WIN_FUNC GetCommandLineW() { } HANDLE WIN_FUNC GetStdHandle(DWORD nStdHandle) { - DEBUG_LOG("GetStdHandle(%u)\n", nStdHandle); + DEBUG_LOG("GetStdHandle(%d)\n", nStdHandle); return files::getStdHandle(nStdHandle); } BOOL WIN_FUNC SetStdHandle(DWORD nStdHandle, HANDLE hHandle) { - DEBUG_LOG("SetStdHandle(%u, %p)\n", nStdHandle, hHandle); + DEBUG_LOG("SetStdHandle(%d, %p)\n", nStdHandle, hHandle); return files::setStdHandle(nStdHandle, hHandle); } diff --git a/dll/kernel32/winbase.cpp b/dll/kernel32/winbase.cpp index bba33ef..da55d3c 100644 --- a/dll/kernel32/winbase.cpp +++ b/dll/kernel32/winbase.cpp @@ -9,8 +9,8 @@ #include #include #include -#include #include +#include #include #include #include @@ -171,10 +171,10 @@ UINT WIN_FUNC SetHandleCount(UINT uNumber) { return handles::MAX_HANDLES; } -DWORD WIN_FUNC FormatMessageA(DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, DWORD dwLanguageId, - LPSTR lpBuffer, DWORD nSize, va_list *Arguments) { - DEBUG_LOG("FormatMessageA(%u, %p, %u, %u, %p, %u, %p)\n", dwFlags, lpSource, dwMessageId, dwLanguageId, - lpBuffer, nSize, Arguments); +DWORD WIN_FUNC FormatMessageA(DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, DWORD dwLanguageId, LPSTR lpBuffer, + DWORD nSize, va_list *Arguments) { + DEBUG_LOG("FormatMessageA(%u, %p, %u, %u, %p, %u, %p)\n", dwFlags, lpSource, dwMessageId, dwLanguageId, lpBuffer, + nSize, Arguments); if (dwFlags & 0x00000100) { // FORMAT_MESSAGE_ALLOCATE_BUFFER diff --git a/dll/kernel32/winbase.h b/dll/kernel32/winbase.h index 48e87ba..776f8c6 100644 --- a/dll/kernel32/winbase.h +++ b/dll/kernel32/winbase.h @@ -9,8 +9,8 @@ namespace kernel32 { BOOL WIN_FUNC IsBadReadPtr(LPCVOID lp, UINT_PTR ucb); BOOL WIN_FUNC IsBadWritePtr(LPVOID lp, UINT_PTR ucb); UINT WIN_FUNC SetHandleCount(UINT uNumber); -DWORD WIN_FUNC FormatMessageA(DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, DWORD dwLanguageId, - LPSTR lpBuffer, DWORD nSize, va_list *Arguments); +DWORD WIN_FUNC FormatMessageA(DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, DWORD dwLanguageId, LPSTR lpBuffer, + DWORD nSize, va_list *Arguments); PVOID WIN_FUNC EncodePointer(PVOID Ptr); PVOID WIN_FUNC DecodePointer(PVOID Ptr); BOOL WIN_FUNC SetDllDirectoryA(LPCSTR lpPathName); diff --git a/dll/kernel32/wincon.cpp b/dll/kernel32/wincon.cpp index 701b3f8..de337cc 100644 --- a/dll/kernel32/wincon.cpp +++ b/dll/kernel32/wincon.cpp @@ -25,6 +25,12 @@ BOOL WIN_FUNC SetConsoleMode(HANDLE hConsoleHandle, DWORD dwMode) { return TRUE; } +UINT WIN_FUNC GetConsoleCP() { + DEBUG_LOG("STUB: GetConsoleCP() -> 65001\n"); + wibo::lastError = ERROR_SUCCESS; + return 65001; // UTF-8 +} + UINT WIN_FUNC GetConsoleOutputCP() { DEBUG_LOG("STUB: GetConsoleOutputCP() -> 65001\n"); wibo::lastError = ERROR_SUCCESS; diff --git a/dll/kernel32/wincon.h b/dll/kernel32/wincon.h index 99edf47..b99a9c7 100644 --- a/dll/kernel32/wincon.h +++ b/dll/kernel32/wincon.h @@ -30,6 +30,7 @@ namespace kernel32 { BOOL WIN_FUNC GetConsoleMode(HANDLE hConsoleHandle, LPDWORD lpMode); BOOL WIN_FUNC SetConsoleMode(HANDLE hConsoleHandle, DWORD dwMode); +UINT WIN_FUNC GetConsoleCP(); UINT WIN_FUNC GetConsoleOutputCP(); BOOL WIN_FUNC SetConsoleCtrlHandler(PHANDLER_ROUTINE HandlerRoutine, BOOL Add); BOOL WIN_FUNC GetConsoleScreenBufferInfo(HANDLE hConsoleOutput, CONSOLE_SCREEN_BUFFER_INFO *lpConsoleScreenBufferInfo); diff --git a/dll/kernel32/winnt.cpp b/dll/kernel32/winnt.cpp index fd4e9ed..2f3eba4 100644 --- a/dll/kernel32/winnt.cpp +++ b/dll/kernel32/winnt.cpp @@ -10,4 +10,3 @@ void WIN_FUNC RtlUnwind(PVOID TargetFrame, PVOID TargetIp, PEXCEPTION_RECORD Exc } } // namespace kernel32 - diff --git a/dll/kernel32/winnt.h b/dll/kernel32/winnt.h index 46c0b87..ac3786f 100644 --- a/dll/kernel32/winnt.h +++ b/dll/kernel32/winnt.h @@ -8,4 +8,3 @@ namespace kernel32 { void WIN_FUNC RtlUnwind(PVOID TargetFrame, PVOID TargetIp, PEXCEPTION_RECORD ExceptionRecord, PVOID ReturnValue); } // namespace kernel32 - diff --git a/dll/user32.cpp b/dll/user32.cpp index 29b4e97..9c30d14 100644 --- a/dll/user32.cpp +++ b/dll/user32.cpp @@ -1,8 +1,10 @@ #include "common.h" +#include "errors.h" #include "strutil.h" namespace user32 { constexpr uint32_t RT_STRING_ID = 6; + constexpr uintptr_t kDefaultKeyboardLayout = 0x04090409; int WIN_FUNC LoadStringA(void* hInstance, unsigned int uID, char* lpBuffer, int cchBufferMax) { DEBUG_LOG("LoadStringA(%p, %u, %p, %d)\n", hInstance, uID, lpBuffer, cchBufferMax); @@ -109,6 +111,13 @@ namespace user32 { fflush(stdout); return 1; } + + HKL WIN_FUNC GetKeyboardLayout(DWORD idThread) { + DEBUG_LOG("GetKeyboardLayout(%u)\n", idThread); + (void)idThread; + wibo::lastError = ERROR_SUCCESS; + return reinterpret_cast(kDefaultKeyboardLayout); + } } @@ -116,6 +125,7 @@ static void *resolveByName(const char *name) { if (strcmp(name, "LoadStringA") == 0) return (void *) user32::LoadStringA; if (strcmp(name, "LoadStringW") == 0) return (void *) user32::LoadStringW; if (strcmp(name, "MessageBoxA") == 0) return (void *) user32::MessageBoxA; + if (strcmp(name, "GetKeyboardLayout") == 0) return (void *) user32::GetKeyboardLayout; return nullptr; }