add /IGNORE:4216 to HAL link step, add writing and directory listing to the FAT32 driver, add the concept of current working directory to the VFS, add writing to the VFS, more operations in the shell, rename KeCurrentThread to KeGetCurrentThread and add KeGetCurrentProcess, add STATUS_NO_MORE_FILES, change KeFault* to KePanic, add syscalls for writing to files, add a proper syscall to writing to the console, move Screen.Clear to after memory status debug print, add ObjectTypeDir to OBJECT_TYPE, extend kernel32 by file operations and upgrade user32 (and add gdi32) to match windows a bit more closely, change CreateProcessA to accept the first argument as NULL.

This commit is contained in:
maksw committed 2026-05-04 16:27:49 +02:00
1 parent a5f0acfac8
commit 8c7564d5e1
33 files changed
+2343 -429

No files matched your search

+83
View File
@@ -0,0 +1,83 @@
// gdi32.c - Win32 Graphics Device Interface stubs
#include <stdint.h>
#include <stddef.h>
// ---------------------------------------------------------------------------
// Syscall stubs (from syscall.dll)
// ---------------------------------------------------------------------------
extern void SysScreenBlit(int x, int y, int w, int h, const uint32_t* pixels);
// ---------------------------------------------------------------------------
// Win32 Base Types
// ---------------------------------------------------------------------------
typedef void* HDC;
typedef unsigned long DWORD;
typedef unsigned short WORD;
typedef unsigned int UINT;
typedef long LONG;
typedef int BOOL;
#define TRUE 1
#define FALSE 0
// StretchDIBits Constants
#define BI_RGB 0L
#define DIB_RGB_COLORS 0
#define SRCCOPY (DWORD)0x00CC0020
// ---------------------------------------------------------------------------
// GDI Structs
// ---------------------------------------------------------------------------
typedef struct tagBITMAPINFOHEADER {
DWORD biSize;
LONG biWidth;
LONG biHeight;
WORD biPlanes;
WORD biBitCount;
DWORD biCompression;
DWORD biSizeImage;
LONG biXPelsPerMeter;
LONG biYPelsPerMeter;
DWORD biClrUsed;
DWORD biClrImportant;
} BITMAPINFOHEADER;
typedef struct tagRGBQUAD {
unsigned char rgbBlue;
unsigned char rgbGreen;
unsigned char rgbRed;
unsigned char rgbReserved;
} RGBQUAD;
typedef struct tagBITMAPINFO {
BITMAPINFOHEADER bmiHeader;
RGBQUAD bmiColors[1];
} BITMAPINFO;
// ---------------------------------------------------------------------------
// GDI Exports
// ---------------------------------------------------------------------------
__declspec(dllexport) int StretchDIBits(
HDC hdc,
int xDest, int yDest, int DestWidth, int DestHeight,
int xSrc, int ySrc, int SrcWidth, int SrcHeight,
const void *lpBits, const BITMAPINFO *lpbmi,
UINT iUsage, DWORD rop)
{
(void)hdc; (void)xSrc; (void)ySrc; (void)SrcWidth; (void)SrcHeight;
(void)lpbmi; (void)iUsage; (void)rop;
// Direct mapping to kernel screen blit
SysScreenBlit(xDest, yDest, DestWidth, DestHeight, (const uint32_t*)lpBits);
// Return the number of scanlines copied
return DestHeight;
}
__declspec(dllexport) BOOL BitBlt(HDC hdcDest, int xDest, int yDest, int w, int h,
HDC hdcSrc, int xSrc, int ySrc, DWORD rop) {
(void)hdcDest; (void)xDest; (void)yDest; (void)w; (void)h;
(void)hdcSrc; (void)xSrc; (void)ySrc; (void)rop;
// Stubbed. Applications manipulating pixels directly will use StretchDIBits.
return TRUE;
}
+440 -46
View File
@@ -33,6 +33,12 @@ extern void* SysRealloc(void* ptr, size_t newSize);
extern uint32_t SysOpenFile(const char* path, uint32_t* handleOut);
extern uint32_t SysReadFile(uint32_t handle, void* buf, size_t size, size_t* bytesReadOut);
extern uint32_t SysWriteFile(uint32_t handle, const void* buf,
size_t size, size_t* bytesWrittenOut);
extern uint32_t SysCreateFile(const char* path, uint32_t* handleOut);
extern uint32_t SysDeleteFile(const char* path);
extern uint32_t SysTruncateFile(uint32_t handle, uint64_t newSize);
extern uint64_t SysGetFilePos(uint32_t handle);
extern uint32_t SysSeekFile(uint32_t handle, uint64_t offset);
extern uint64_t SysGetFileSize(uint32_t handle);
extern void SysCloseHandle(uint32_t handle);
@@ -54,6 +60,13 @@ extern void SysSleep(uint32_t ms);
extern uint64_t SysGetTick(void);
extern void SysDebugPrint(const char* str);
// Console & directory & CWD stubs (syscall.dll)
extern void SysWriteConsole(const char* buf, size_t len);
extern uint32_t SysOpenDir(const char* dirPath, uint32_t* handleOut);
extern uint32_t SysReadDir(uint32_t handle, void* entryOut);
extern uint32_t SysSetCwd(const char* path);
extern uint32_t SysGetCwd(char* buf, size_t size);
// ---------------------------------------------------------------------------
// Types
// ---------------------------------------------------------------------------
@@ -61,16 +74,41 @@ typedef void* HANDLE;
typedef unsigned long DWORD;
typedef int BOOL;
#define MAX_PATH 260
#define TRUE 1
#define FALSE 0
#define INVALID_HANDLE_VALUE ((HANDLE)(uintptr_t)0)
#define INVALID_HANDLE_VALUE ((HANDLE)(intptr_t)-1)
// File-find structures
typedef struct _FILETIME {
DWORD dwLowDateTime;
DWORD dwHighDateTime;
} FILETIME;
typedef struct _WIN32_FIND_DATAA {
DWORD dwFileAttributes;
FILETIME ftCreationTime;
FILETIME ftLastAccessTime;
FILETIME ftLastWriteTime;
DWORD nFileSizeHigh;
DWORD nFileSizeLow;
DWORD dwReserved0;
DWORD dwReserved1;
char cFileName[260]; // MAX_PATH
char cAlternateFileName[14];
} WIN32_FIND_DATAA;
// CreateFileA disposition / access flags (subset used by Bink and similar)
#define GENERIC_READ 0x80000000UL
#define GENERIC_WRITE 0x40000000UL
#define GENERIC_READ 0x80000000UL
#define GENERIC_WRITE 0x40000000UL
#define OPEN_EXISTING 3
#define OPEN_ALWAYS 4
#define CREATE_ALWAYS 2
#define CREATE_NEW 1
#define TRUNCATE_EXISTING 5
#define FILE_BEGIN 0
#define FILE_CURRENT 1
#define FILE_END 2
@@ -200,41 +238,90 @@ __declspec(dllexport) DWORD GetOEMCP(void) { return 437; } // DOS Latin US
// File I/O
// ---------------------------------------------------------------------------
// CreateFileA - open an existing file for reading.
// Write access, CREATE_ALWAYS and other modes return INVALID_HANDLE_VALUE
// because the VFS has no write path yet.
// CreateFileA - opens or creates a file.
// Supported modes:
// OPEN_EXISTING + GENERIC_READ -> open existing, read-only
// OPEN_EXISTING + GENERIC_WRITE -> open existing, read-write
// OPEN_EXISTING + GENERIC_READ|GENERIC_WRITE -> open existing, read-write
// CREATE_ALWAYS + GENERIC_WRITE -> create/truncate, write
// OPEN_ALWAYS + GENERIC_WRITE -> create if absent, write
// TRUNCATE_EXISTING + GENERIC_WRITE -> open & truncate to zero
__declspec(dllexport) HANDLE CreateFileA(const char* name,
DWORD access, DWORD share,
void* sa, DWORD disposition,
DWORD flags, void* templ) {
(void)share; (void)sa; (void)flags; (void)templ;
// Only OPEN_EXISTING + read supported for now.
if (disposition != OPEN_EXISTING || (access & GENERIC_WRITE)) {
gLastError = 5; // ERROR_ACCESS_DENIED
return INVALID_HANDLE_VALUE;
int wantWrite = (access & GENERIC_WRITE) != 0;
if (disposition == OPEN_EXISTING || disposition == TRUNCATE_EXISTING) {
// Open the file via the read path (it must already exist).
uint32_t kh = 0;
uint32_t s = SysOpenFile(name, &kh);
if (s != 0) { gLastError = 2; return INVALID_HANDLE_VALUE; }
if (disposition == TRUNCATE_EXISTING && wantWrite) {
// Immediately truncate to zero.
uint32_t ts = SysTruncateFile(kh, 0);
if (ts != 0) {
SysCloseHandle(kh);
gLastError = 5;
return INVALID_HANDLE_VALUE;
}
}
return KH_TO_HANDLE(kh);
}
uint32_t kh = 0;
uint32_t s = SysOpenFile(name, &kh);
if (s != 0 /* STATUS_SUCCESS */) {
gLastError = 2; // ERROR_FILE_NOT_FOUND
return INVALID_HANDLE_VALUE;
if (disposition == CREATE_ALWAYS && wantWrite) {
// Create-or-replace: try to create; if the file already exists,
// open it and truncate it to zero instead.
uint32_t kh = 0;
uint32_t s = SysCreateFile(name, &kh);
if (s != 0) {
// File may already exist - open and truncate.
s = SysOpenFile(name, &kh);
if (s != 0) { gLastError = 5; return INVALID_HANDLE_VALUE; }
SysTruncateFile(kh, 0);
}
return KH_TO_HANDLE(kh);
}
return KH_TO_HANDLE(kh);
if (disposition == OPEN_ALWAYS && wantWrite) {
// Open if exists, create if not.
uint32_t kh = 0;
if (SysOpenFile(name, &kh) != 0) {
if (SysCreateFile(name, &kh) != 0) {
gLastError = 5;
return INVALID_HANDLE_VALUE;
}
}
return KH_TO_HANDLE(kh);
}
if (disposition == CREATE_NEW && wantWrite) {
// Fail if the file already exists (we can't check atomically,
// but SysCreateFile returns NAME_COLLISION for existing files).
uint32_t kh = 0;
uint32_t s = SysCreateFile(name, &kh);
if (s != 0) { gLastError = 80; return INVALID_HANDLE_VALUE; } // ERROR_FILE_EXISTS
return KH_TO_HANDLE(kh);
}
// Any other combination (e.g. read-only CREATE_ALWAYS) is not supported.
gLastError = 87; // ERROR_INVALID_PARAMETER
return INVALID_HANDLE_VALUE;
}
// GetFileSize - fills optional high-DWORD pointer, returns low DWORD.
// Returns 0xFFFFFFFF on error, matching Win32 behaviour.
__declspec(dllexport) DWORD GetFileSize(HANDLE hFile, DWORD* fileSizeHigh) {
if (!hFile) { gLastError = 6; return 0xFFFFFFFFUL; } // ERROR_INVALID_HANDLE
if (!hFile) { gLastError = 6; return 0xFFFFFFFFUL; }
uint64_t sz = SysGetFileSize(HANDLE_TO_KH(hFile));
if (fileSizeHigh) *fileSizeHigh = (DWORD)(sz >> 32);
return (DWORD)(sz & 0xFFFFFFFFULL);
}
// ReadFile - sequential read at the file's current position.
// Overlapped is not supported (must be NULL).
__declspec(dllexport) BOOL ReadFile(HANDLE hFile, void* buf, DWORD toRead,
DWORD* bytesRead, void* overlapped) {
(void)overlapped;
@@ -242,36 +329,73 @@ __declspec(dllexport) BOOL ReadFile(HANDLE hFile, void* buf, DWORD toRead,
size_t got = 0;
uint32_t s = SysReadFile(HANDLE_TO_KH(hFile), buf, (size_t)toRead, &got);
if (bytesRead) *bytesRead = (DWORD)got;
if (s != 0) { gLastError = 1; return FALSE; } // ERROR_INVALID_FUNCTION
if (s != 0) { gLastError = 1; return FALSE; }
return TRUE;
}
// SetFilePointer - seek to an absolute or relative position.
// WriteFile - sequential write at the file's current position.
// Extends the file if writing past EOF. Overlapped I/O is not supported.
__declspec(dllexport) BOOL WriteFile(HANDLE hFile, const void* buf, DWORD toWrite,
DWORD* bytesWritten, void* overlapped) {
(void)overlapped;
if (!hFile || !buf) { gLastError = 6; return FALSE; }
size_t written = 0;
uint32_t s = SysWriteFile(HANDLE_TO_KH(hFile), buf, (size_t)toWrite, &written);
if (bytesWritten) *bytesWritten = (DWORD)written;
if (s != 0) { gLastError = 29; return FALSE; } // ERROR_WRITE_FAULT
return TRUE;
}
// SetFilePointer - seek to an absolute, relative, or end-relative position.
// Returns new position low DWORD, or 0xFFFFFFFF on error.
__declspec(dllexport) DWORD SetFilePointer(HANDLE hFile, long dist,
long* distHigh, DWORD method) {
if (!hFile) { gLastError = 6; return 0xFFFFFFFFUL; }
uint32_t kh = HANDLE_TO_KH(hFile);
uint64_t offset = 0;
int64_t delta = distHigh
? ((int64_t)(uint64_t)(uint32_t)*distHigh << 32) | (uint32_t)dist
: (int64_t)dist;
if (method == FILE_BEGIN) {
offset = (uint64_t)(int64_t)dist;
if (distHigh) offset |= (uint64_t)(uint32_t)*distHigh << 32;
} else if (method == FILE_CURRENT || method == FILE_END) {
// FILE_CURRENT and FILE_END require knowing the current offset or
// the file size; expose as unsupported for now.
gLastError = 1; // ERROR_INVALID_FUNCTION
return 0xFFFFFFFFUL;
offset = (uint64_t)delta;
} else if (method == FILE_CURRENT) {
uint64_t cur = SysGetFilePos(kh);
if (cur == (uint64_t)-1) { gLastError = 6; return 0xFFFFFFFFUL; }
offset = (uint64_t)((int64_t)cur + delta);
} else if (method == FILE_END) {
uint64_t sz = SysGetFileSize(kh);
offset = (uint64_t)((int64_t)sz + delta);
} else {
gLastError = 87; // ERROR_INVALID_PARAMETER
return 0xFFFFFFFFUL;
gLastError = 87; return 0xFFFFFFFFUL;
}
uint32_t s = SysSeekFile(HANDLE_TO_KH(hFile), offset);
uint32_t s = SysSeekFile(kh, offset);
if (s != 0) { gLastError = 1; return 0xFFFFFFFFUL; }
if (distHigh) *distHigh = (long)(offset >> 32);
if (distHigh) *distHigh = (long)(int32_t)(offset >> 32);
return (DWORD)(offset & 0xFFFFFFFFULL);
}
// SetEndOfFile - truncate or extend the file to the current seek position.
__declspec(dllexport) BOOL SetEndOfFile(HANDLE hFile) {
if (!hFile) { gLastError = 6; return FALSE; }
uint32_t kh = HANDLE_TO_KH(hFile);
uint64_t pos = SysGetFilePos(kh);
if (pos == (uint64_t)-1) { gLastError = 6; return FALSE; }
uint32_t s = SysTruncateFile(kh, pos);
if (s != 0) { gLastError = 1; return FALSE; }
return TRUE;
}
// DeleteFileA - delete a file by name; no open handle required.
__declspec(dllexport) BOOL DeleteFileA(const char* lpFileName) {
if (!lpFileName) { gLastError = 87; return FALSE; }
uint32_t s = SysDeleteFile(lpFileName);
if (s != 0) { gLastError = 2; return FALSE; } // ERROR_FILE_NOT_FOUND
return TRUE;
}
// CloseHandle - unified close for files, mutexes, semaphores, events, queues.
__declspec(dllexport) BOOL CloseHandle(HANDLE hObject) {
if (!hObject) { gLastError = 6; return FALSE; }
@@ -279,15 +403,6 @@ __declspec(dllexport) BOOL CloseHandle(HANDLE hObject) {
return TRUE;
}
// WriteFile stub - no write VFS support yet.
__declspec(dllexport) BOOL WriteFile(HANDLE hFile, const void* buf, DWORD toWrite,
DWORD* bytesWritten, void* overlapped) {
(void)hFile; (void)buf; (void)toWrite; (void)overlapped;
if (bytesWritten) *bytesWritten = 0;
gLastError = 1; // ERROR_INVALID_FUNCTION
return FALSE;
}
// ===========================================================================
// Extended shims - funcs.txt additions
// All functions here return plausible values; no real implementation exists
@@ -474,21 +589,35 @@ __declspec(dllexport) BOOL CreateProcessA(
(void)bInheritHandles; (void)dwCreationFlags; (void)lpEnvironment;
(void)lpCurrentDirectory; (void)lpStartupInfo;
if (!lpApplicationName || !lpProcessInformation) {
// lpProcessInformation is mandatory
if (!lpProcessInformation) {
gLastError = 87; // ERROR_INVALID_PARAMETER
return FALSE;
}
uint32_t kh = 0;
uint32_t s = SysCreateProcess(lpApplicationName, &kh);
if (s != 0 || kh == 0) {
gLastError = 2; // ERROR_FILE_NOT_FOUND / generic launch failure
// Standard Win32 behavior: use lpCommandLine if lpApplicationName is NULL
const char* targetPath = lpApplicationName;
if (!targetPath) {
targetPath = lpCommandLine;
}
// If both are NULL, then it's truly an invalid parameter
if (!targetPath) {
gLastError = 87;
return FALSE;
}
lpProcessInformation->hProcess = KH_TO_HANDLE(kh);
lpProcessInformation->hThread = INVALID_HANDLE_VALUE;
lpProcessInformation->dwProcessId = 0;
uint32_t kh = 0;
// Call the syscall.dll stub
uint32_t s = SysCreateProcess(targetPath, &kh);
if (s != 0 || kh == 0) {
gLastError = 2; // ERROR_FILE_NOT_FOUND
return FALSE;
}
lpProcessInformation->hProcess = KH_TO_HANDLE(kh);
lpProcessInformation->hThread = INVALID_HANDLE_VALUE;
lpProcessInformation->dwProcessId = 0;
lpProcessInformation->dwThreadId = 0;
return TRUE;
}
@@ -581,6 +710,271 @@ __declspec(dllexport) BOOL ReadConsoleA(HANDLE hConsoleInput,
return TRUE;
}
// WriteConsoleA: write nNumberOfCharsToWrite characters from lpBuffer to the
// console as white-on-black text via SYS_WRITE_CONSOLE.
__declspec(dllexport) BOOL WriteConsoleA(HANDLE hConsoleOutput,
const void* lpBuffer,
DWORD nNumberOfCharsToWrite,
DWORD* lpNumberOfCharsWritten,
void* lpReserved) {
(void)hConsoleOutput; (void)lpReserved;
if (!lpBuffer || nNumberOfCharsToWrite == 0) {
if (lpNumberOfCharsWritten) *lpNumberOfCharsWritten = 0;
return TRUE;
}
SysWriteConsole((const char*)lpBuffer, (size_t)nNumberOfCharsToWrite);
if (lpNumberOfCharsWritten) *lpNumberOfCharsWritten = nNumberOfCharsToWrite;
return TRUE;
}
// ---------------------------------------------------------------------------
// Directory enumeration (FindFirstFileA / FindNextFileA / FindClose)
// ---------------------------------------------------------------------------
// KDIR_ENTRY layout must exactly match the definition in io_file.h.
#define KDIR_NAME_MAX 260
typedef struct {
char Name[KDIR_NAME_MAX];
uint8_t Attr;
uint32_t FileSize;
} KDIR_ENTRY;
// FIND_HANDLE is a user-side wrapper: it stores the kernel dir handle and
// the wildcard pattern so FindNextFileA can filter subsequent entries.
// We return a pointer to this struct cast to HANDLE; it is NOT a kernel
// handle, so FindClose must NOT go through CloseHandle/SysCloseHandle.
typedef struct {
uint32_t kh; // kernel DIR_OBJECT handle (raw pointer)
char pattern[MAX_PATH]; // wildcard pattern, e.g. "*" or "*.txt"
} FIND_HANDLE;
// Minimal wildcard match: supports '*' (any sequence) and '?' (any char).
// Case-insensitive to match FAT32/Windows behaviour.
static int WildMatch(const char* pat, const char* name) {
while (*pat && *name) {
if (*pat == '*') {
// Skip consecutive stars
while (*pat == '*') pat++;
if (!*pat) return 1; // trailing * matches everything
// Try matching the rest of the pattern at every position
while (*name) {
if (WildMatch(pat, name)) return 1;
name++;
}
return 0;
}
char p = (*pat >= 'A' && *pat <= 'Z') ? *pat + 32 : *pat;
char n = (*name >= 'A' && *name <= 'Z') ? *name + 32 : *name;
if (*pat != '?' && p != n) return 0;
pat++; name++;
}
// Consume trailing stars in the pattern
while (*pat == '*') pat++;
return (*pat == '\0' && *name == '\0');
}
// Split a FindFirstFileA-style search path into directory and pattern parts.
// "apps\\*" -> dir="apps" pat="*"
// "*.txt" -> dir="" pat="*.txt"
// "*" -> dir="" pat="*"
// "apps\\" -> dir="apps" pat="*"
static void SplitFindPath(const char* searchPath,
char* dirOut, size_t dirSize,
char* patOut, size_t patSize) {
// Find last backslash or forward-slash
const char* last = NULL;
for (const char* p = searchPath; *p; p++)
if (*p == '\\' || *p == '/') last = p;
if (!last) {
// No separator: whole string is the pattern, dir is CWD
if (dirOut && dirSize) dirOut[0] = '\0';
if (patOut && patSize) {
size_t len = strlen(searchPath);
if (len + 1 > patSize) len = patSize - 1;
memcpy(patOut, searchPath, len);
patOut[len] = '\0';
}
} else {
// Everything before the last separator is the directory
if (dirOut) {
size_t len = (size_t)(last - searchPath);
if (len + 1 > dirSize) len = dirSize - 1;
memcpy(dirOut, searchPath, len);
dirOut[len] = '\0';
}
// Everything after the last separator is the pattern
if (patOut) {
const char* p = last + 1;
size_t len = strlen(p);
if (len + 1 > patSize) len = patSize - 1;
memcpy(patOut, p, len);
patOut[len] = '\0';
}
}
// Empty pattern defaults to "*"
if (patOut && patOut[0] == '\0') {
patOut[0] = '*'; patOut[1] = '\0';
}
}
// Fill a WIN32_FIND_DATAA from a KDIR_ENTRY.
#define FILE_ATTRIBUTE_DIRECTORY 0x00000010UL
#define FILE_ATTRIBUTE_ARCHIVE 0x00000020UL
#define FILE_ATTRIBUTE_NORMAL 0x00000080UL
static void KdirToFindData(const KDIR_ENTRY* ke, WIN32_FIND_DATAA* fd) {
// Zero the entire struct (covers all FILETIME and reserved fields)
unsigned char* p = (unsigned char*)fd;
for (size_t i = 0; i < sizeof(*fd); i++) p[i] = 0;
fd->dwFileAttributes = ke->Attr;
if (!(fd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
!(fd->dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE))
fd->dwFileAttributes |= FILE_ATTRIBUTE_NORMAL;
fd->nFileSizeLow = ke->FileSize;
fd->nFileSizeHigh = 0;
size_t nameLen = strlen(ke->Name);
if (nameLen >= MAX_PATH) nameLen = MAX_PATH - 1;
memcpy(fd->cFileName, ke->Name, nameLen);
fd->cFileName[nameLen] = '\0';
}
__declspec(dllexport) HANDLE FindFirstFileA(const char* lpFileName,
WIN32_FIND_DATAA* lpFindFileData) {
if (!lpFileName || !lpFindFileData) {
gLastError = 87; // ERROR_INVALID_PARAMETER
return INVALID_HANDLE_VALUE;
}
// Split path into directory and wildcard pattern
char dir[MAX_PATH];
char pat[MAX_PATH];
SplitFindPath(lpFileName, dir, sizeof(dir), pat, sizeof(pat));
// Open the kernel directory iterator
uint32_t kh = 0;
uint32_t s = SysOpenDir(dir[0] ? dir : NULL, &kh);
if (s != 0 || kh == 0) {
gLastError = 2; // ERROR_FILE_NOT_FOUND
return INVALID_HANDLE_VALUE;
}
// Allocate our user-side FIND_HANDLE wrapper
FIND_HANDLE* fh = (FIND_HANDLE*)HeapAlloc(NULL, 0, sizeof(FIND_HANDLE));
if (!fh) {
SysCloseHandle(kh);
gLastError = 8; // ERROR_NOT_ENOUGH_MEMORY
return INVALID_HANDLE_VALUE;
}
fh->kh = kh;
size_t patLen = strlen(pat);
if (patLen >= MAX_PATH) patLen = MAX_PATH - 1;
memcpy(fh->pattern, pat, patLen);
fh->pattern[patLen] = '\0';
// Read the first entry that matches the pattern
KDIR_ENTRY ke;
for (;;) {
uint32_t rs = SysReadDir(kh, &ke);
if (rs != 0) {
// Directory exhausted or error
SysCloseHandle(kh);
HeapFree(NULL, 0, fh);
gLastError = 18; // ERROR_NO_MORE_FILES
return INVALID_HANDLE_VALUE;
}
if (WildMatch(fh->pattern, ke.Name)) {
KdirToFindData(&ke, lpFindFileData);
return (HANDLE)fh;
}
}
}
__declspec(dllexport) BOOL FindNextFileA(HANDLE hFindFile,
WIN32_FIND_DATAA* lpFindFileData) {
if (hFindFile == INVALID_HANDLE_VALUE || !lpFindFileData) {
gLastError = 6; // ERROR_INVALID_HANDLE
return FALSE;
}
FIND_HANDLE* fh = (FIND_HANDLE*)hFindFile;
KDIR_ENTRY ke;
for (;;) {
uint32_t rs = SysReadDir(fh->kh, &ke);
if (rs != 0) {
gLastError = 18; // ERROR_NO_MORE_FILES
return FALSE;
}
if (WildMatch(fh->pattern, ke.Name)) {
KdirToFindData(&ke, lpFindFileData);
return TRUE;
}
}
}
__declspec(dllexport) BOOL FindClose(HANDLE hFindFile) {
if (hFindFile == INVALID_HANDLE_VALUE) {
gLastError = 6;
return FALSE;
}
FIND_HANDLE* fh = (FIND_HANDLE*)hFindFile;
SysCloseHandle(fh->kh);
HeapFree(NULL, 0, fh);
return TRUE;
}
// ---------------------------------------------------------------------------
// Current Working Directory
// ---------------------------------------------------------------------------
__declspec(dllexport) BOOL SetCurrentDirectoryA(const char* lpPathName) {
if (!lpPathName) { gLastError = 87; return FALSE; }
uint32_t s = SysSetCwd(lpPathName);
if (s != 0) { gLastError = 2; return FALSE; }
return TRUE;
}
__declspec(dllexport) DWORD GetCurrentDirectoryA(DWORD nBufferLength, char* lpBuffer) {
if (!lpBuffer || nBufferLength == 0) {
// Return required size (including NUL). Max CWD is 512 bytes + "C:\".
return 515;
}
// Retrieve the raw relative CWD from the kernel (e.g. "" or "apps\\data")
char raw[512];
uint32_t s = SysGetCwd(raw, sizeof(raw));
if (s != 0) { gLastError = 1; return 0; }
// Prepend the Windows-style drive letter so callers see "C:\apps\data"
// rather than just "apps\data".
char full[515];
if (raw[0] == '\0') {
// Root
full[0] = 'C'; full[1] = ':'; full[2] = '\\'; full[3] = '\0';
} else {
// "C:\<raw>"
full[0] = 'C'; full[1] = ':'; full[2] = '\\';
size_t rawLen = strlen(raw);
if (rawLen + 4 > sizeof(full)) rawLen = sizeof(full) - 4;
memcpy(full + 3, raw, rawLen);
full[3 + rawLen] = '\0';
}
size_t needed = strlen(full) + 1;
if ((DWORD)needed > nBufferLength) {
gLastError = 122; // ERROR_INSUFFICIENT_BUFFER
return (DWORD)needed;
}
memcpy(lpBuffer, full, needed);
return (DWORD)(needed - 1); // length without NUL, matching Win32
}
// ---------------------------------------------------------------------------
__declspec(dllexport) HANDLE CreateMutexA(void* lpMutexAttributes, BOOL bInitialOwner,
+33 -53
View File
@@ -1,62 +1,53 @@
// user32.c - Win32 user interface stubs (no window manager yet)
// user32.c - Win32 User Interface
#include <stdint.h>
#include <stddef.h>
// ---------------------------------------------------------------------------
// Syscall stubs (from syscall.dll)
// ---------------------------------------------------------------------------
extern void SysScreenBlit(int x, int y, int w, int h, const uint32_t* pixels);
extern void SysYield(void);
extern void SysDebugPrint(const char* str);
extern uint32_t SysKbPoll(void);
// ---------------------------------------------------------------------------
// Types
// ---------------------------------------------------------------------------
typedef void* HWND;
typedef void* HDC;
typedef long LONG;
typedef int BOOL;
#define IDOK 1
#define IDCANCEL 2
typedef struct _RECT { LONG left, top, right, bottom; } RECT;
typedef struct tagPAINTSTRUCT {
HDC hdc; BOOL fErase; RECT rcPaint; BOOL fRestore; BOOL fIncUpdate; char res[32];
} PAINTSTRUCT;
// ---------------------------------------------------------------------------
// Keyboard
// ---------------------------------------------------------------------------
// GetAsyncKeyState: returns non-zero if a key is available in the input
// buffer. We have no per-key state, so the vKey argument is ignored and
// the high bit (key-down) is set whenever SysKbPoll reports data waiting.
__declspec(dllexport) short GetAsyncKeyState(int vKey) {
(void)vKey;
// High bit (0x8000 / INT16_MIN) = key is down.
// Low bit = key pressed since last call; we have no per-key history to
// track, so it is left clear.
return SysKbPoll() ? (short)(-32768) : 0;
// --- Painting Functions ---
__declspec(dllexport) HDC BeginPaint(HWND hwnd, PAINTSTRUCT* lpPaint) {
(void)hwnd;
if (lpPaint) {
lpPaint->hdc = (HDC)1;
lpPaint->rcPaint.right = 1920; lpPaint->rcPaint.bottom = 1080;
}
return (HDC)1;
}
// ---------------------------------------------------------------------------
// Screen output
// ---------------------------------------------------------------------------
__declspec(dllexport) BOOL EndPaint(HWND hwnd, const PAINTSTRUCT* lp) { (void)hwnd; (void)lp; return 1; }
// BitBlt is the only graphical primitive available at this stage.
__declspec(dllexport) void BitBlt(int x, int y, int w, int h, const uint32_t* pixels) {
SysScreenBlit(x, y, w, h, pixels);
// --- Message Loop Stubs ---
__declspec(dllexport) int GetMessage(void* m, HWND h, uint32_t f, uint32_t l) {
(void)m; (void)h; (void)f; (void)l; SysYield(); return 0;
}
// ---------------------------------------------------------------------------
// Message loop (stubs - always return 0 / no messages)
// ---------------------------------------------------------------------------
__declspec(dllexport) int GetMessage(void* msg, HWND hwnd,
unsigned int min, unsigned int max) {
(void)msg; (void)hwnd; (void)min; (void)max;
SysYield();
__declspec(dllexport) int PeekMessage(void* m, HWND h, uint32_t f, uint32_t l, uint32_t r) {
(void)m; (void)h; (void)f; (void)l; (void)r;
return 0;
}
__declspec(dllexport) int DispatchMessage(const void* m) { (void)m; return 0; }
__declspec(dllexport) int TranslateMessage(const void* m) { (void)m; return 0; }
__declspec(dllexport) int DispatchMessage(const void* msg) { (void)msg; return 0; }
// --- Dialogs & UI ---
__declspec(dllexport) int MessageBoxA(HWND h, const char* txt, const char* cap, uint32_t type) {
(void)h; (void)cap; (void)type;
SysDebugPrint("USER32: MessageBoxA: ");
SysDebugPrint(txt);
SysDebugPrint("\n");
return 1; // IDOK
}
// ---------------------------------------------------------------------------
// Window queries (stubs - no WM exists yet, all return NULL / 0)
// ---------------------------------------------------------------------------
// --- Window Queries ---
__declspec(dllexport) HWND GetDesktopWindow(void) { return (HWND)0; }
__declspec(dllexport) HWND GetActiveWindow(void) { return (HWND)0; }
__declspec(dllexport) HWND GetTopWindow(HWND hwnd){ (void)hwnd; return (HWND)0; }
@@ -78,14 +69,3 @@ __declspec(dllexport) unsigned long GetWindowThreadProcessId(HWND hwnd, unsigned
if (pid) *pid = 1;
return 1; // Thread ID
}
// ---------------------------------------------------------------------------
// Dialogs
// ---------------------------------------------------------------------------
__declspec(dllexport) int MessageBoxA(HWND hwnd, const char* text,
const char* caption, unsigned int type) {
(void)hwnd; (void)text; (void)caption; (void)type;
// No UI available, console
SysDebugPrint(text);
return IDOK;
}