Pārlūkot izejas kodu

Static init priority changes, Platform hooking

Brian Fiete 8 mēneši atpakaļ
vecāks
revīzija
1de07d0ee4

+ 1 - 1
BeefLibs/corlib/src/FFI/Function.bf

@@ -1,6 +1,6 @@
 namespace System.FFI
 namespace System.FFI
 {
 {
-	[CRepr, StaticInitPriority(100)]
+	[CRepr, StaticInitPriority(200)]
 	struct FFIType
 	struct FFIType
 	{
 	{
 		public enum TypeKind : uint16
 		public enum TypeKind : uint16

+ 15 - 13
BeefLibs/corlib/src/IO/Directory.bf

@@ -135,7 +135,7 @@ namespace System.IO
 				bfpFlags |= .Directories;
 				bfpFlags |= .Directories;
 			if (flags.HasFlag(.Files))
 			if (flags.HasFlag(.Files))
 				bfpFlags |= .Files;
 				bfpFlags |= .Files;
-			let findFileData = Platform.BfpFindFileData_FindFirstFile(useStr, bfpFlags, null);
+			let findFileData = Platform.Hook.BfpFindFileData_FindFirstFile(useStr, bfpFlags, null);
 			return FileEnumerator(useStr, findFileData);
 			return FileEnumerator(useStr, findFileData);
 		}
 		}
 
 
@@ -206,7 +206,7 @@ namespace System.IO
 		{
 		{
 			get
 			get
 			{
 			{
-				return Platform.BfpFindFileData_GetFileAttributes(mFindFileData).HasFlag(.Directory);
+				return Platform.Hook.BfpFindFileData_GetFileAttributes(mFindFileData).HasFlag(.Directory);
 			}
 			}
 		}
 		}
 
 
@@ -214,7 +214,7 @@ namespace System.IO
 		{
 		{
 			Platform.GetStrHelper(outFileName, scope (outPtr, outSize, outResult) =>
 			Platform.GetStrHelper(outFileName, scope (outPtr, outSize, outResult) =>
 				{
 				{
-					Platform.BfpFindFileData_GetFileName(mFindFileData, outPtr, outSize, (Platform.BfpFileResult*)outResult);
+					Platform.Hook.BfpFindFileData_GetFileName(mFindFileData, outPtr, outSize, (Platform.BfpFileResult*)outResult);
 				});
 				});
 		}
 		}
 
 
@@ -228,43 +228,45 @@ namespace System.IO
 
 
 		public DateTime GetLastWriteTime()
 		public DateTime GetLastWriteTime()
 		{
 		{
-			return DateTime.FromFileTime((int64)Platform.BfpFindFileData_GetTime_LastWrite(mFindFileData));
+			return DateTime.FromFileTime((int64)Platform.Hook.BfpFindFileData_GetTime_LastWrite(mFindFileData));
 		}
 		}
 
 
 		public DateTime GetLastWriteTimeUtc()
 		public DateTime GetLastWriteTimeUtc()
 		{
 		{
-			return DateTime.FromFileTimeUtc((int64)Platform.BfpFindFileData_GetTime_LastWrite(mFindFileData));
+			return DateTime.FromFileTimeUtc((int64)Platform.Hook.BfpFindFileData_GetTime_LastWrite(mFindFileData));
 		}
 		}
 
 
 		public DateTime GetCreatedTime()
 		public DateTime GetCreatedTime()
 		{
 		{
-			return DateTime.FromFileTime((int64)Platform.BfpFindFileData_GetTime_Created(mFindFileData));
+			return DateTime.FromFileTime((int64)Platform.Hook.BfpFindFileData_GetTime_Created(mFindFileData));
 		}
 		}
 
 
 		public DateTime GetCreatedTimeUtc()
 		public DateTime GetCreatedTimeUtc()
 		{
 		{
-			return DateTime.FromFileTimeUtc((int64)Platform.BfpFindFileData_GetTime_Created(mFindFileData));
+			return DateTime.FromFileTimeUtc((int64)Platform.Hook.BfpFindFileData_GetTime_Created(mFindFileData));
 		}
 		}
 
 
 		public DateTime GetAccessedTime()
 		public DateTime GetAccessedTime()
 		{
 		{
-			return DateTime.FromFileTime((int64)Platform.BfpFindFileData_GetTime_Access(mFindFileData));
+			return DateTime.FromFileTime((int64)Platform.Hook.BfpFindFileData_GetTime_Access(mFindFileData));
 		}
 		}
 
 
 		public DateTime GetAccessedTimeUtc()
 		public DateTime GetAccessedTimeUtc()
 		{
 		{
-			return DateTime.FromFileTimeUtc((int64)Platform.BfpFindFileData_GetTime_Access(mFindFileData));
+			return DateTime.FromFileTimeUtc((int64)Platform.Hook.BfpFindFileData_GetTime_Access(mFindFileData));
 		}
 		}
 
 
 		public int64 GetFileSize()
 		public int64 GetFileSize()
 		{
 		{
-			return Platform.BfpFindFileData_GetFileSize(mFindFileData);
+			return Platform.Hook.BfpFindFileData_GetFileSize(mFindFileData);
 		}
 		}
 
 
 		public Platform.BfpFileAttributes GetFileAttributes()
 		public Platform.BfpFileAttributes GetFileAttributes()
 		{
 		{
-			return Platform.BfpFindFileData_GetFileAttributes(mFindFileData);
+			return Platform.Hook.BfpFindFileData_GetFileAttributes(mFindFileData);
 		}
 		}
+
+		public static bool operator implicit (Self self) => self.mFindFileData != null;
 	}
 	}
 
 
 	struct FileEnumerator : IEnumerator<FileFindEntry>, IDisposable
 	struct FileEnumerator : IEnumerator<FileFindEntry>, IDisposable
@@ -292,7 +294,7 @@ namespace System.IO
 		{
 		{
 			delete mSearchStr;
 			delete mSearchStr;
 			if (mFindFileData != null)
 			if (mFindFileData != null)
-				Platform.BfpFindFileData_Release(mFindFileData);
+				Platform.Hook.BfpFindFileData_Release(mFindFileData);
 		}
 		}
 
 
 		public bool MoveNext() mut 
 		public bool MoveNext() mut 
@@ -301,7 +303,7 @@ namespace System.IO
 			if (mIdx == 0)
 			if (mIdx == 0)
 				return mFindFileData != null;
 				return mFindFileData != null;
 
 
-			return Platform.BfpFindFileData_FindNextFile(mFindFileData);
+			return Platform.Hook.BfpFindFileData_FindNextFile(mFindFileData);
 		}
 		}
 
 
 		public Result<FileFindEntry> GetNext() mut
 		public Result<FileFindEntry> GetNext() mut

+ 44 - 9
BeefLibs/corlib/src/IO/File.bf

@@ -141,13 +141,13 @@ namespace System.IO
 
 
 		public static bool Exists(StringView fileName)
 		public static bool Exists(StringView fileName)
 		{
 		{
-			return Platform.BfpFile_Exists(fileName.ToScopeCStr!());
+			return Platform.Hook.BfpFile_Exists(fileName.ToScopeCStr!());
 		}
 		}
 
 
 		public static Result<void, Platform.BfpFileResult> Delete(StringView fileName)
 		public static Result<void, Platform.BfpFileResult> Delete(StringView fileName)
 		{
 		{
 			Platform.BfpFileResult result = default;
 			Platform.BfpFileResult result = default;
-			Platform.BfpFile_Delete(fileName.ToScopeCStr!(), &result);
+			Platform.Hook.BfpFile_Delete(fileName.ToScopeCStr!(), &result);
 			if ((result != .Ok) && (result != .NotFound))
 			if ((result != .Ok) && (result != .NotFound))
 				return .Err(result);
 				return .Err(result);
 			return .Ok;
 			return .Ok;
@@ -156,7 +156,7 @@ namespace System.IO
 		public static Result<void, Platform.BfpFileResult> Move(StringView fromPath, StringView toPath)
 		public static Result<void, Platform.BfpFileResult> Move(StringView fromPath, StringView toPath)
 		{
 		{
 			Platform.BfpFileResult result = default;
 			Platform.BfpFileResult result = default;
-			Platform.BfpFile_Rename(fromPath.ToScopeCStr!(), toPath.ToScopeCStr!(), &result);
+			Platform.Hook.BfpFile_Rename(fromPath.ToScopeCStr!(), toPath.ToScopeCStr!(), &result);
 			if (result != .Ok)
 			if (result != .Ok)
 				return .Err(result);
 				return .Err(result);
 			return .Ok;
 			return .Ok;
@@ -165,7 +165,7 @@ namespace System.IO
 		public static Result<void, Platform.BfpFileResult> Copy(StringView fromPath, StringView toPath)
 		public static Result<void, Platform.BfpFileResult> Copy(StringView fromPath, StringView toPath)
 		{
 		{
 			Platform.BfpFileResult result = default;
 			Platform.BfpFileResult result = default;
-			Platform.BfpFile_Copy(fromPath.ToScopeCStr!(), toPath.ToScopeCStr!(), .Always, &result);
+			Platform.Hook.BfpFile_Copy(fromPath.ToScopeCStr!(), toPath.ToScopeCStr!(), .Always, &result);
 			if (result != .Ok)
 			if (result != .Ok)
 				return .Err(result);
 				return .Err(result);
 			return .Ok;
 			return .Ok;
@@ -174,7 +174,7 @@ namespace System.IO
 		public static Result<void, Platform.BfpFileResult> CopyIfNewer(StringView fromPath, StringView toPath)
 		public static Result<void, Platform.BfpFileResult> CopyIfNewer(StringView fromPath, StringView toPath)
 		{
 		{
 			Platform.BfpFileResult result = default;
 			Platform.BfpFileResult result = default;
-			Platform.BfpFile_Copy(fromPath.ToScopeCStr!(), toPath.ToScopeCStr!(), .IfNewer, &result);
+			Platform.Hook.BfpFile_Copy(fromPath.ToScopeCStr!(), toPath.ToScopeCStr!(), .IfNewer, &result);
 			if (result != .Ok)
 			if (result != .Ok)
 				return .Err(result);
 				return .Err(result);
 			return .Ok;
 			return .Ok;
@@ -183,7 +183,7 @@ namespace System.IO
 		public static Result<void, Platform.BfpFileResult> Copy(StringView fromPath, StringView toPath, bool overwrite)
 		public static Result<void, Platform.BfpFileResult> Copy(StringView fromPath, StringView toPath, bool overwrite)
 		{
 		{
 			Platform.BfpFileResult result = default;
 			Platform.BfpFileResult result = default;
-			Platform.BfpFile_Copy(fromPath.ToScopeCStr!(), toPath.ToScopeCStr!(), overwrite ? .Always : .IfNotExists, &result);
+			Platform.Hook.BfpFile_Copy(fromPath.ToScopeCStr!(), toPath.ToScopeCStr!(), overwrite ? .Always : .IfNotExists, &result);
 			if (result != .Ok)
 			if (result != .Ok)
 				return .Err(result);
 				return .Err(result);
 			return .Ok;
 			return .Ok;
@@ -192,7 +192,7 @@ namespace System.IO
 		public static Result<void, Platform.BfpFileResult> SetAttributes(StringView path, FileAttributes attr)
 		public static Result<void, Platform.BfpFileResult> SetAttributes(StringView path, FileAttributes attr)
 		{
 		{
 			Platform.BfpFileResult result = default;
 			Platform.BfpFileResult result = default;
-			Platform.BfpFile_SetAttributes(path.ToScopeCStr!(), (Platform.BfpFileAttributes)attr, &result);
+			Platform.Hook.BfpFile_SetAttributes(path.ToScopeCStr!(), (Platform.BfpFileAttributes)attr, &result);
 			if (result != .Ok)
 			if (result != .Ok)
 				return .Err(result);
 				return .Err(result);
 			return .Ok;
 			return .Ok;
@@ -200,12 +200,47 @@ namespace System.IO
 
 
 		public static Result<DateTime> GetLastWriteTime(StringView fullPath)
 		public static Result<DateTime> GetLastWriteTime(StringView fullPath)
 		{
 		{
-			return DateTime.FromFileTime((int64)Platform.BfpFile_GetTime_LastWrite(fullPath.ToScopeCStr!()));
+			return DateTime.FromFileTime((int64)Platform.Hook.BfpFile_GetTime_LastWrite(fullPath.ToScopeCStr!()));
 		}
 		}
 
 
 		public static Result<DateTime> GetLastWriteTimeUtc(StringView fullPath)
 		public static Result<DateTime> GetLastWriteTimeUtc(StringView fullPath)
 		{
 		{
-			return DateTime.FromFileTimeUtc((int64)Platform.BfpFile_GetTime_LastWrite(fullPath.ToScopeCStr!()));
+			return DateTime.FromFileTimeUtc((int64)Platform.Hook.BfpFile_GetTime_LastWrite(fullPath.ToScopeCStr!()));
 		}
 		}
 	}
 	}
+
+	class FileInfo
+	{
+		FileFindEntry mFileFindEntry;
+
+		public this(StringView path)
+		{
+			let findFileData = Platform.Hook.BfpFindFileData_FindFirstFile(path.ToScopeCStr!(), .Files, null);
+			if (findFileData == null)
+				return;
+			mFileFindEntry = .(new .(path), findFileData);
+		}
+
+		public ~this()
+		{
+			if (mFileFindEntry.[Friend]mSearchStr != null)
+			{
+				delete mFileFindEntry.[Friend]mSearchStr;
+				Platform.Hook.BfpFindFileData_Release(mFileFindEntry.[Friend]mFindFileData);
+			}
+		}
+
+		public bool Exists => mFileFindEntry;
+		public bool IsDirectory => mFileFindEntry ? mFileFindEntry.IsDirectory : default;
+		public void GetFileName(String outFileName) { if (mFileFindEntry) mFileFindEntry.GetFileName(outFileName); }
+		public void GetFilePath(String outPath) { if (mFileFindEntry) mFileFindEntry.GetFilePath(outPath); }
+		public DateTime GetLastWriteTime() => mFileFindEntry ? mFileFindEntry.GetLastWriteTime() : default;
+		public DateTime GetLastWriteTimeUtc() => mFileFindEntry ? mFileFindEntry.GetLastWriteTimeUtc() : default;
+		public DateTime GetCreatedTime() => mFileFindEntry ? mFileFindEntry.GetCreatedTime() : default;
+		public DateTime GetCreatedTimeUtc() => mFileFindEntry ? mFileFindEntry.GetCreatedTimeUtc() : default;
+		public DateTime GetAccessedTime() => mFileFindEntry ? mFileFindEntry.GetAccessedTime() : default;
+		public DateTime GetAccessedTimeUtc() => mFileFindEntry ? mFileFindEntry.GetAccessedTimeUtc() : default;
+		public int64 GetFileSize() => mFileFindEntry ? mFileFindEntry.GetFileSize() : default;
+		public Platform.BfpFileAttributes GetFileAttributes() => mFileFindEntry ? mFileFindEntry.GetFileAttributes() : default;
+	}
 }
 }

+ 26 - 26
BeefLibs/corlib/src/IO/FileStream.bf

@@ -12,12 +12,12 @@ namespace System.IO
 		{
 		{
 			get
 			get
 			{
 			{
-				return Platform.BfpFile_Seek(mBfpFile, 0, .Relative);
+				return Platform.Hook.BfpFile_Seek(mBfpFile, 0, .Relative);
 			}
 			}
 
 
 			set
 			set
 			{
 			{
-				Platform.BfpFile_Seek(mBfpFile, value, .Absolute);
+				Platform.Hook.BfpFile_Seek(mBfpFile, value, .Absolute);
 			}
 			}
 		}
 		}
 
 
@@ -25,7 +25,7 @@ namespace System.IO
 		{
 		{
 			get
 			get
 			{
 			{
-				return Platform.BfpFile_GetFileSize(mBfpFile);
+				return Platform.Hook.BfpFile_GetFileSize(mBfpFile);
 			}
 			}
 		}
 		}
 
 
@@ -35,7 +35,7 @@ namespace System.IO
 			{
 			{
 				if (mBfpFile == null)
 				if (mBfpFile == null)
 					return 0;
 					return 0;
-				return Platform.BfpFile_GetSystemHandle(mBfpFile);
+				return Platform.Hook.BfpFile_GetSystemHandle(mBfpFile);
 			}
 			}
 		}
 		}
 
 
@@ -46,7 +46,7 @@ namespace System.IO
 
 
 		public override Result<void> Seek(int64 pos, SeekKind seekKind = .Absolute)
 		public override Result<void> Seek(int64 pos, SeekKind seekKind = .Absolute)
 		{
 		{
-			int64 newPos = Platform.BfpFile_Seek(mBfpFile, pos, (Platform.BfpFileSeekKind)seekKind);
+			int64 newPos = Platform.Hook.BfpFile_Seek(mBfpFile, pos, (Platform.BfpFileSeekKind)seekKind);
 			// Ensure position is what was requested
 			// Ensure position is what was requested
 			if ((seekKind == .Absolute) && (newPos != pos))
 			if ((seekKind == .Absolute) && (newPos != pos))
 				return .Err;
 				return .Err;
@@ -56,7 +56,7 @@ namespace System.IO
 		public override Result<int> TryRead(Span<uint8> data)
 		public override Result<int> TryRead(Span<uint8> data)
 		{
 		{
 			Platform.BfpFileResult result = .Ok;
 			Platform.BfpFileResult result = .Ok;
-			int numBytesRead = Platform.BfpFile_Read(mBfpFile, data.Ptr, data.Length, -1, &result);
+			int numBytesRead = Platform.Hook.BfpFile_Read(mBfpFile, data.Ptr, data.Length, -1, &result);
 			if ((result != .Ok) && (result != .PartialData))
 			if ((result != .Ok) && (result != .PartialData))
 				return .Err;
 				return .Err;
 			return numBytesRead;
 			return numBytesRead;
@@ -65,7 +65,7 @@ namespace System.IO
 		public override Result<int, FileError> TryRead(Span<uint8> data, int timeoutMS)
 		public override Result<int, FileError> TryRead(Span<uint8> data, int timeoutMS)
 		{
 		{
 			Platform.BfpFileResult result = .Ok;
 			Platform.BfpFileResult result = .Ok;
-			int numBytesRead = Platform.BfpFile_Read(mBfpFile, data.Ptr, data.Length, timeoutMS, &result);
+			int numBytesRead = Platform.Hook.BfpFile_Read(mBfpFile, data.Ptr, data.Length, timeoutMS, &result);
 			if ((result != .Ok) && (result != .PartialData))
 			if ((result != .Ok) && (result != .PartialData))
 			{
 			{
 				switch (result)
 				switch (result)
@@ -84,7 +84,7 @@ namespace System.IO
 		public override Result<int> TryWrite(Span<uint8> data)
 		public override Result<int> TryWrite(Span<uint8> data)
 		{
 		{
 			Platform.BfpFileResult result = .Ok;
 			Platform.BfpFileResult result = .Ok;
-			int numBytesWritten = Platform.BfpFile_Write(mBfpFile, data.Ptr, data.Length, -1, &result);
+			int numBytesWritten = Platform.Hook.BfpFile_Write(mBfpFile, data.Ptr, data.Length, -1, &result);
 			if ((result != .Ok) && (result != .PartialData))
 			if ((result != .Ok) && (result != .PartialData))
 				return .Err;
 				return .Err;
 			return numBytesWritten;
 			return numBytesWritten;
@@ -93,7 +93,7 @@ namespace System.IO
 		public override Result<void> Close()
 		public override Result<void> Close()
 		{
 		{
 			if (mBfpFile != null)
 			if (mBfpFile != null)
-				Platform.BfpFile_Release(mBfpFile);
+				Platform.Hook.BfpFile_Release(mBfpFile);
 			mBfpFile = null;
 			mBfpFile = null;
 			return .Ok;
 			return .Ok;
 		}
 		}
@@ -101,7 +101,7 @@ namespace System.IO
 		public override Result<void> Flush()
 		public override Result<void> Flush()
 		{
 		{
 			if (mBfpFile != null)
 			if (mBfpFile != null)
-				Platform.BfpFile_Flush(mBfpFile);
+				Platform.Hook.BfpFile_Flush(mBfpFile);
 			return .Ok;
 			return .Ok;
 		}
 		}
 
 
@@ -159,7 +159,7 @@ namespace System.IO
 		public Result<void, FileOpenError> OpenStd(Platform.BfpFileStdKind stdKind)
 		public Result<void, FileOpenError> OpenStd(Platform.BfpFileStdKind stdKind)
 		{
 		{
 			Platform.BfpFileResult fileResult = .Ok;
 			Platform.BfpFileResult fileResult = .Ok;
-			mBfpFile = Platform.BfpFile_GetStd(stdKind, &fileResult);
+			mBfpFile = Platform.Hook.BfpFile_GetStd(stdKind, &fileResult);
 			mFileAccess = .ReadWrite;
 			mFileAccess = .ReadWrite;
 
 
 			if ((mBfpFile == null) || (fileResult != .Ok))
 			if ((mBfpFile == null) || (fileResult != .Ok))
@@ -218,7 +218,7 @@ namespace System.IO
 			Platform.BfpFileAttributes fileFlags = .Normal;
 			Platform.BfpFileAttributes fileFlags = .Normal;
 			
 			
 			Platform.BfpFileResult fileResult = .Ok;
 			Platform.BfpFileResult fileResult = .Ok;
-			mBfpFile = Platform.BfpFile_Create(path.ToScopeCStr!(128), createKind, createFlags, fileFlags, &fileResult);
+			mBfpFile = Platform.Hook.BfpFile_Create(path.ToScopeCStr!(128), createKind, createFlags, fileFlags, &fileResult);
 
 
 			if ((mBfpFile == null) || (fileResult != .Ok))
 			if ((mBfpFile == null) || (fileResult != .Ok))
 			{
 			{
@@ -261,7 +261,7 @@ namespace System.IO
 				Seek(length);
 				Seek(length);
 
 
 			Platform.BfpFileResult result = .Ok;
 			Platform.BfpFileResult result = .Ok;
-			Platform.BfpFile_Truncate(mBfpFile, &result);
+			Platform.Hook.BfpFile_Truncate(mBfpFile, &result);
 			if (result != .Ok)
 			if (result != .Ok)
 			{
 			{
 				Seek(pos);
 				Seek(pos);
@@ -297,7 +297,7 @@ namespace System.IO
 			{
 			{
 				if (mBfpFile == null)
 				if (mBfpFile == null)
 					return 0;
 					return 0;
-				return Platform.BfpFile_GetSystemHandle(mBfpFile);
+				return Platform.Hook.BfpFile_GetSystemHandle(mBfpFile);
 			}
 			}
 		}
 		}
 
 
@@ -321,7 +321,7 @@ namespace System.IO
 		{
 		{
 			set
 			set
 			{
 			{
-				// Matches the behavior of Platform.BfpFile_Seek(mBfpFile, value, .Absolute);
+				// Matches the behavior of Platform.Hook.BfpFile_Seek(mBfpFile, value, .Absolute);
 				mPos = Math.Max(value, 0);
 				mPos = Math.Max(value, 0);
 			}
 			}
 		}
 		}
@@ -355,7 +355,7 @@ namespace System.IO
 		public Result<void, FileOpenError> OpenStd(Platform.BfpFileStdKind stdKind)
 		public Result<void, FileOpenError> OpenStd(Platform.BfpFileStdKind stdKind)
 		{
 		{
 			Platform.BfpFileResult fileResult = .Ok;
 			Platform.BfpFileResult fileResult = .Ok;
-			mBfpFile = Platform.BfpFile_GetStd(stdKind, &fileResult);
+			mBfpFile = Platform.Hook.BfpFile_GetStd(stdKind, &fileResult);
 			mFileAccess = .ReadWrite;
 			mFileAccess = .ReadWrite;
 
 
 			if ((mBfpFile == null) || (fileResult != .Ok))
 			if ((mBfpFile == null) || (fileResult != .Ok))
@@ -413,7 +413,7 @@ namespace System.IO
 			Platform.BfpFileAttributes fileFlags = .Normal;
 			Platform.BfpFileAttributes fileFlags = .Normal;
 			
 			
 			Platform.BfpFileResult fileResult = .Ok;
 			Platform.BfpFileResult fileResult = .Ok;
-			mBfpFile = Platform.BfpFile_Create(path.ToScopeCStr!(128), createKind, createFlags, fileFlags, &fileResult);
+			mBfpFile = Platform.Hook.BfpFile_Create(path.ToScopeCStr!(128), createKind, createFlags, fileFlags, &fileResult);
 
 
 			if ((mBfpFile == null) || (fileResult != .Ok))
 			if ((mBfpFile == null) || (fileResult != .Ok))
 			{
 			{
@@ -467,7 +467,7 @@ namespace System.IO
 				newPos = mPos + pos;
 				newPos = mPos + pos;
 			}
 			}
 
 
-			// Matches the behaviour of Platform.BfpFile_Seek(mBfpFile, value, .Absolute);
+			// Matches the behaviour of Platform.Hook.BfpFile_Seek(mBfpFile, value, .Absolute);
 			mPos = Math.Max(newPos, 0);
 			mPos = Math.Max(newPos, 0);
 			if (seekKind == .Absolute && newPos < 0)
 			if (seekKind == .Absolute && newPos < 0)
 				return .Err;
 				return .Err;
@@ -479,7 +479,7 @@ namespace System.IO
 		{
 		{
 			let ret = base.Close();
 			let ret = base.Close();
 			if (mBfpFile != null)
 			if (mBfpFile != null)
-				Platform.BfpFile_Release(mBfpFile);
+				Platform.Hook.BfpFile_Release(mBfpFile);
 
 
 			mBfpFile = null;
 			mBfpFile = null;
 			mFileAccess = default;
 			mFileAccess = default;
@@ -489,12 +489,12 @@ namespace System.IO
 
 
 		protected override void UpdateLength()
 		protected override void UpdateLength()
 		{
 		{
-			mUnderlyingLength = Platform.BfpFile_GetFileSize(mBfpFile);
+			mUnderlyingLength = Platform.Hook.BfpFile_GetFileSize(mBfpFile);
 		}
 		}
 
 
 		protected Result<void, FileError> SeekUnderlying(int64 offset, Platform.BfpFileSeekKind seekKind = .Absolute)
 		protected Result<void, FileError> SeekUnderlying(int64 offset, Platform.BfpFileSeekKind seekKind = .Absolute)
 		{
 		{
-			int64 newPos = Platform.BfpFile_Seek(mBfpFile, offset, seekKind);
+			int64 newPos = Platform.Hook.BfpFile_Seek(mBfpFile, offset, seekKind);
 			Result<void, FileError> result = ((seekKind == .Absolute) && (newPos != offset)) ? .Err(.SeekError) : .Ok;
 			Result<void, FileError> result = ((seekKind == .Absolute) && (newPos != offset)) ? .Err(.SeekError) : .Ok;
 			if (result case .Ok)
 			if (result case .Ok)
 				mBfpFilePos = newPos;
 				mBfpFilePos = newPos;
@@ -507,7 +507,7 @@ namespace System.IO
 				Try!(SeekUnderlying(pos));
 				Try!(SeekUnderlying(pos));
 
 
 			Platform.BfpFileResult result = .Ok;
 			Platform.BfpFileResult result = .Ok;
-			int numBytesRead = Platform.BfpFile_Read(mBfpFile, data.Ptr, data.Length, -1, &result);
+			int numBytesRead = Platform.Hook.BfpFile_Read(mBfpFile, data.Ptr, data.Length, -1, &result);
 			if ((result != .Ok) && (result != .PartialData))
 			if ((result != .Ok) && (result != .PartialData))
 				return .Err;
 				return .Err;
 			mBfpFilePos += numBytesRead;
 			mBfpFilePos += numBytesRead;
@@ -520,7 +520,7 @@ namespace System.IO
 				Try!(SeekUnderlying(pos));
 				Try!(SeekUnderlying(pos));
 
 
 			Platform.BfpFileResult result = .Ok;
 			Platform.BfpFileResult result = .Ok;
-			int numBytesRead = Platform.BfpFile_Write(mBfpFile, data.Ptr, data.Length, -1, &result);
+			int numBytesRead = Platform.Hook.BfpFile_Write(mBfpFile, data.Ptr, data.Length, -1, &result);
 			if ((result != .Ok) && (result != .PartialData))
 			if ((result != .Ok) && (result != .PartialData))
 				return .Err;
 				return .Err;
 			mBfpFilePos += numBytesRead;
 			mBfpFilePos += numBytesRead;
@@ -533,7 +533,7 @@ namespace System.IO
 				Try!(SeekUnderlying(mPos));
 				Try!(SeekUnderlying(mPos));
 
 
 			Platform.BfpFileResult result = .Ok;
 			Platform.BfpFileResult result = .Ok;
-			int numBytesRead = Platform.BfpFile_Read(mBfpFile, data.Ptr, data.Length, timeoutMS, &result);
+			int numBytesRead = Platform.Hook.BfpFile_Read(mBfpFile, data.Ptr, data.Length, timeoutMS, &result);
 			if ((result != .Ok) && (result != .PartialData))
 			if ((result != .Ok) && (result != .PartialData))
 			{
 			{
 				switch (result)
 				switch (result)
@@ -560,7 +560,7 @@ namespace System.IO
 			}
 			}
 
 
 			Platform.BfpFileResult result = .Ok;
 			Platform.BfpFileResult result = .Ok;
-			Platform.BfpFile_Truncate(mBfpFile, &result);
+			Platform.Hook.BfpFile_Truncate(mBfpFile, &result);
 			if (result != .Ok)
 			if (result != .Ok)
 			{
 			{
 				Try!(SeekUnderlying(pos));
 				Try!(SeekUnderlying(pos));
@@ -585,7 +585,7 @@ namespace System.IO
 		{
 		{
 			var result = base.Flush();
 			var result = base.Flush();
 			if (mBfpFile != null)
 			if (mBfpFile != null)
-				Platform.BfpFile_Flush(mBfpFile);
+				Platform.Hook.BfpFile_Flush(mBfpFile);
 			return result;
 			return result;
 		}
 		}
 	}
 	}

+ 94 - 0
BeefLibs/corlib/src/IO/MemoryStream.bf

@@ -116,4 +116,98 @@ namespace System.IO
 			mPosition = 0;
 			mPosition = 0;
 		}
 		}
 	}
 	}
+
+	class FixedMemoryStream : Stream
+	{
+		Span<uint8> mMemory;
+		int mPosition = 0;
+
+		public override int64 Position
+		{
+			get
+			{
+				return mPosition;
+			}
+
+			set
+			{
+				mPosition = (.)value;
+			}
+		}
+
+		public override int64 Length
+		{
+			get
+			{
+				return mMemory.Length;
+			}
+		}
+
+		public override bool CanRead
+		{
+			get
+			{
+				return true;
+			}
+		}
+
+		public override bool CanWrite
+		{
+			get
+			{
+				return true;
+			}
+		}
+
+
+		public this(Span<uint8> memory)
+		{
+			mMemory = memory;
+		}
+
+		public Span<uint8> Memory => mMemory;
+
+		public override Result<int> TryRead(Span<uint8> data)
+		{
+			let count = data.Length;
+			if (count == 0)
+				return .Ok(0);
+			int readBytes = Math.Min(count, mMemory.Length - mPosition);
+			if (readBytes <= 0)
+				return .Ok(readBytes);
+
+			Internal.MemCpy(data.Ptr, &mMemory[mPosition], readBytes);
+			mPosition += readBytes;
+			return .Ok(readBytes);
+		}
+
+		public override Result<int> TryWrite(Span<uint8> data)
+		{
+			let count = data.Length;
+			if (count == 0)
+				return .Ok(0);
+			int growSize = mPosition + count - mMemory.Length;
+			if (growSize > 0)
+				return .Err;
+			Internal.MemCpy(&mMemory[mPosition], data.Ptr, count);
+			mPosition += count;
+			return .Ok(count);
+		}
+
+		public override Result<void> Close()
+		{
+			return .Ok;
+		}
+		
+		public override Result<void> SetLength(int64 length)
+	    {
+			return .Err;
+	    }
+
+		public void Clear()
+		{
+			mMemory.Clear();
+			mPosition = 0;
+		}
+	}
 }
 }

+ 2 - 2
BeefLibs/corlib/src/IO/Pipe.bf

@@ -46,7 +46,7 @@ namespace System.IO
 			Platform.BfpFileAttributes fileFlags = .Normal;
 			Platform.BfpFileAttributes fileFlags = .Normal;
 
 
 			Platform.BfpFileResult fileResult = .Ok;
 			Platform.BfpFileResult fileResult = .Ok;
-			mBfpFile = Platform.BfpFile_Create(path, createKind, createFlags, fileFlags, &fileResult);
+			mBfpFile = Platform.Hook.BfpFile_Create(path, createKind, createFlags, fileFlags, &fileResult);
 
 
 			if ((mBfpFile == null) || (fileResult != .Ok))
 			if ((mBfpFile == null) || (fileResult != .Ok))
 			{
 			{
@@ -83,7 +83,7 @@ namespace System.IO
 			Platform.BfpFileAttributes fileFlags = .Normal;
 			Platform.BfpFileAttributes fileFlags = .Normal;
 
 
 			Platform.BfpFileResult fileResult = .Ok;
 			Platform.BfpFileResult fileResult = .Ok;
-			mBfpFile = Platform.BfpFile_Create(path, createKind, createFlags, fileFlags, &fileResult);
+			mBfpFile = Platform.Hook.sBfpFile_Create(path, createKind, createFlags, fileFlags, &fileResult);
 
 
 			if ((mBfpFile == null) || (fileResult != .Ok))
 			if ((mBfpFile == null) || (fileResult != .Ok))
 			{
 			{

+ 49 - 30
BeefLibs/corlib/src/Platform.bf

@@ -66,6 +66,11 @@ namespace System
 			TempFileError = (int)Result.TempFileError
 			TempFileError = (int)Result.TempFileError
 		}
 		}
 
 
+		[StaticHook(typeof(SelfOuter))]
+		public static struct Hook
+		{
+		}
+
 #if !BF_RUNTIME_DISABLE
 #if !BF_RUNTIME_DISABLE
 		[CallingConvention(.Stdcall), CLink]
 		[CallingConvention(.Stdcall), CLink]
 		public static extern uint32 BfpSystem_TickCount();
 		public static extern uint32 BfpSystem_TickCount();
@@ -565,47 +570,47 @@ namespace System
 		}
 		}
 
 
 #if !BF_RUNTIME_DISABLE
 #if !BF_RUNTIME_DISABLE
-		[CallingConvention(.Stdcall), CLink]
+		[CallingConvention(.Stdcall), CLink, StaticHook]
 		public static extern BfpFile* BfpFile_Create(char8* name, BfpFileCreateKind createKind, BfpFileCreateFlags createFlags, BfpFileAttributes createdFileAttrs, BfpFileResult* outResult);
 		public static extern BfpFile* BfpFile_Create(char8* name, BfpFileCreateKind createKind, BfpFileCreateFlags createFlags, BfpFileAttributes createdFileAttrs, BfpFileResult* outResult);
-		[CallingConvention(.Stdcall), CLink]
+		[CallingConvention(.Stdcall), CLink, StaticHook]
 		public static extern BfpFile* BfpFile_GetStd(BfpFileStdKind kind, BfpFileResult* outResult);
 		public static extern BfpFile* BfpFile_GetStd(BfpFileStdKind kind, BfpFileResult* outResult);
-		[CallingConvention(.Stdcall), CLink]
+		[CallingConvention(.Stdcall), CLink, StaticHook]
 		public static extern int BfpFile_GetSystemHandle(BfpFile* file);
 		public static extern int BfpFile_GetSystemHandle(BfpFile* file);
-		[CallingConvention(.Stdcall), CLink]
+		[CallingConvention(.Stdcall), CLink, StaticHook]
 		public static extern void BfpFile_Release(BfpFile* file);
 		public static extern void BfpFile_Release(BfpFile* file);
-		[CallingConvention(.Stdcall), CLink]
+		[CallingConvention(.Stdcall), CLink, StaticHook]
 		public static extern int BfpFile_Write(BfpFile* file, void* buffer, int size, int timeoutMS, BfpFileResult* outResult);
 		public static extern int BfpFile_Write(BfpFile* file, void* buffer, int size, int timeoutMS, BfpFileResult* outResult);
-		[CallingConvention(.Stdcall), CLink]
+		[CallingConvention(.Stdcall), CLink, StaticHook]
 		public static extern int BfpFile_Read(BfpFile* file, void* buffer, int size, int timeoutMS, BfpFileResult* outResult);
 		public static extern int BfpFile_Read(BfpFile* file, void* buffer, int size, int timeoutMS, BfpFileResult* outResult);
-		[CallingConvention(.Stdcall), CLink]
+		[CallingConvention(.Stdcall), CLink, StaticHook]
 		public static extern void BfpFile_Flush(BfpFile* file);
 		public static extern void BfpFile_Flush(BfpFile* file);
-		[CallingConvention(.Stdcall), CLink]
+		[CallingConvention(.Stdcall), CLink, StaticHook]
 		public static extern int64 BfpFile_GetFileSize(BfpFile* file);
 		public static extern int64 BfpFile_GetFileSize(BfpFile* file);
-		[CallingConvention(.Stdcall), CLink]
+		[CallingConvention(.Stdcall), CLink, StaticHook]
 		public static extern int64 BfpFile_Seek(BfpFile* file, int64 offset, BfpFileSeekKind seekKind);
 		public static extern int64 BfpFile_Seek(BfpFile* file, int64 offset, BfpFileSeekKind seekKind);
-		[CallingConvention(.Stdcall), CLink]
+		[CallingConvention(.Stdcall), CLink, StaticHook]
 		public static extern void BfpFile_Truncate(BfpFile* file, BfpFileResult* outResult);
 		public static extern void BfpFile_Truncate(BfpFile* file, BfpFileResult* outResult);
-		[CallingConvention(.Stdcall), CLink]
+		[CallingConvention(.Stdcall), CLink, StaticHook]
 		public static extern BfpTimeStamp BfpFile_GetTime_LastWrite(char8* path);
 		public static extern BfpTimeStamp BfpFile_GetTime_LastWrite(char8* path);
-		[CallingConvention(.Stdcall), CLink]
+		[CallingConvention(.Stdcall), CLink, StaticHook]
 		public static extern BfpFileAttributes BfpFile_GetAttributes(char8* path, BfpFileResult* outResult);
 		public static extern BfpFileAttributes BfpFile_GetAttributes(char8* path, BfpFileResult* outResult);
-		[CallingConvention(.Stdcall), CLink]
+		[CallingConvention(.Stdcall), CLink, StaticHook]
 		public static extern void BfpFile_SetAttributes(char8* path, BfpFileAttributes attribs, BfpFileResult* outResult);
 		public static extern void BfpFile_SetAttributes(char8* path, BfpFileAttributes attribs, BfpFileResult* outResult);
-		[CallingConvention(.Stdcall), CLink]
+		[CallingConvention(.Stdcall), CLink, StaticHook]
 		public static extern void BfpFile_Copy(char8* oldPath, char8* newPath, BfpFileCopyKind copyKind, BfpFileResult* outResult);
 		public static extern void BfpFile_Copy(char8* oldPath, char8* newPath, BfpFileCopyKind copyKind, BfpFileResult* outResult);
-		[CallingConvention(.Stdcall), CLink]
+		[CallingConvention(.Stdcall), CLink, StaticHook]
 		public static extern void BfpFile_Rename(char8* oldPath, char8* newPath, BfpFileResult* outResult);
 		public static extern void BfpFile_Rename(char8* oldPath, char8* newPath, BfpFileResult* outResult);
-		[CallingConvention(.Stdcall), CLink]
+		[CallingConvention(.Stdcall), CLink, StaticHook]
 		public static extern void BfpFile_Delete(char8* path, BfpFileResult* outResult);
 		public static extern void BfpFile_Delete(char8* path, BfpFileResult* outResult);
-		[CallingConvention(.Stdcall), CLink]
+		[CallingConvention(.Stdcall), CLink, StaticHook]
 		public static extern bool BfpFile_Exists(char8* path);
 		public static extern bool BfpFile_Exists(char8* path);
-		[CallingConvention(.Stdcall), CLink]
+		[CallingConvention(.Stdcall), CLink, StaticHook]
 		public static extern void BfpFile_GetTempPath(char8* outPath, int32* inOutPathSize, BfpFileResult* outResult);
 		public static extern void BfpFile_GetTempPath(char8* outPath, int32* inOutPathSize, BfpFileResult* outResult);
-		[CallingConvention(.Stdcall), CLink]
+		[CallingConvention(.Stdcall), CLink, StaticHook]
 		public static extern void BfpFile_GetTempFileName(char8* outName, int32* inOutNameSize, BfpFileResult* outResult);
 		public static extern void BfpFile_GetTempFileName(char8* outName, int32* inOutNameSize, BfpFileResult* outResult);
-		[CallingConvention(.Stdcall), CLink]
+		[CallingConvention(.Stdcall), CLink, StaticHook]
 		public static extern void BfpFile_GetFullPath(char8* inPath, char8* outPath, int32* inOutPathSize, BfpFileResult* outResult);
 		public static extern void BfpFile_GetFullPath(char8* inPath, char8* outPath, int32* inOutPathSize, BfpFileResult* outResult);
-		[CallingConvention(.Stdcall), CLink]
+		[CallingConvention(.Stdcall), CLink, StaticHook]
 		public static extern void BfpFile_GetActualPath(char8* inPath, char8* outPath, int32* inOutPathSize, BfpFileResult* outResult);
 		public static extern void BfpFile_GetActualPath(char8* inPath, char8* outPath, int32* inOutPathSize, BfpFileResult* outResult);
 #else
 #else
 		
 		
@@ -660,23 +665,23 @@ namespace System
 		};
 		};
 
 
 #if !BF_RUNTIME_DISABLE
 #if !BF_RUNTIME_DISABLE
-		[CallingConvention(.Stdcall), CLink]
+		[CallingConvention(.Stdcall), CLink, StaticHook]
 		public static extern BfpFindFileData* BfpFindFileData_FindFirstFile(char8* path, BfpFindFileFlags flags, BfpFileResult* outResult);
 		public static extern BfpFindFileData* BfpFindFileData_FindFirstFile(char8* path, BfpFindFileFlags flags, BfpFileResult* outResult);
-		[CallingConvention(.Stdcall), CLink]
+		[CallingConvention(.Stdcall), CLink, StaticHook]
 		public static extern bool BfpFindFileData_FindNextFile(BfpFindFileData* findData);
 		public static extern bool BfpFindFileData_FindNextFile(BfpFindFileData* findData);
-		[CallingConvention(.Stdcall), CLink]
+		[CallingConvention(.Stdcall), CLink, StaticHook]
 		public static extern void BfpFindFileData_GetFileName(BfpFindFileData* findData, char8* outName, int32* inOutNameSize, BfpFileResult* outResult);
 		public static extern void BfpFindFileData_GetFileName(BfpFindFileData* findData, char8* outName, int32* inOutNameSize, BfpFileResult* outResult);
-		[CallingConvention(.Stdcall), CLink]
+		[CallingConvention(.Stdcall), CLink, StaticHook]
 		public static extern BfpTimeStamp BfpFindFileData_GetTime_LastWrite(BfpFindFileData* findData);
 		public static extern BfpTimeStamp BfpFindFileData_GetTime_LastWrite(BfpFindFileData* findData);
-		[CallingConvention(.Stdcall), CLink]
+		[CallingConvention(.Stdcall), CLink, StaticHook]
 		public static extern BfpTimeStamp BfpFindFileData_GetTime_Created(BfpFindFileData* findData);
 		public static extern BfpTimeStamp BfpFindFileData_GetTime_Created(BfpFindFileData* findData);
-		[CallingConvention(.Stdcall), CLink]
+		[CallingConvention(.Stdcall), CLink, StaticHook]
 		public static extern BfpTimeStamp BfpFindFileData_GetTime_Access(BfpFindFileData* findData);
 		public static extern BfpTimeStamp BfpFindFileData_GetTime_Access(BfpFindFileData* findData);
-		[CallingConvention(.Stdcall), CLink]
+		[CallingConvention(.Stdcall), CLink, StaticHook]
 		public static extern BfpFileAttributes BfpFindFileData_GetFileAttributes(BfpFindFileData* findData);
 		public static extern BfpFileAttributes BfpFindFileData_GetFileAttributes(BfpFindFileData* findData);
-		[CallingConvention(.Stdcall), CLink]
+		[CallingConvention(.Stdcall), CLink, StaticHook]
 		public static extern int64 BfpFindFileData_GetFileSize(BfpFindFileData* findData);
 		public static extern int64 BfpFindFileData_GetFileSize(BfpFindFileData* findData);
-		[CallingConvention(.Stdcall), CLink]
+		[CallingConvention(.Stdcall), CLink, StaticHook]
 		public static extern void BfpFindFileData_Release(BfpFindFileData* findData);
 		public static extern void BfpFindFileData_Release(BfpFindFileData* findData);
 #else
 #else
 		
 		
@@ -714,6 +719,20 @@ namespace System
 			Documents
 			Documents
 		}
 		}
 
 
+		public static bool SetStrHelper(StringView str, char8* outStr, int32* inOutSize, Result* outResult)
+		{
+			if (str.Length > *inOutSize + 1)
+			{
+				*inOutSize = (.)str.Length + 1;
+				*outResult = .InsufficientBuffer;
+				return false;
+			}
+			*inOutSize = (.)str.Length + 1;
+			Internal.MemCpy(outStr, str.Ptr, str.Length);
+			outStr[str.Length] = 0;
+			return true;
+		}
+
 		public static Result<void, Platform.Result> GetStrHelper(String outStr, delegate void (char8* outPtr, int32* outSize, Result* outResult) func)
 		public static Result<void, Platform.Result> GetStrHelper(String outStr, delegate void (char8* outPtr, int32* outSize, Result* outResult) func)
 		{
 		{
 			let initSize = 4096;
 			let initSize = 4096;

+ 1 - 1
BeefLibs/corlib/src/Random.bf

@@ -21,7 +21,7 @@ namespace System
 	using System.Threading;
 	using System.Threading;
 
 
 	// This class is thread-safe for random results, but not deterministically thread-safe
 	// This class is thread-safe for random results, but not deterministically thread-safe
-	[StaticInitPriority(100)]
+	[StaticInitPriority(200)]
 	public class Random
 	public class Random
 	{
 	{
       //
       //

+ 2 - 1
BeefLibs/corlib/src/Runtime.bf

@@ -14,7 +14,7 @@ namespace System
 		public bool AVX, AVX2, AVX512;
 		public bool AVX, AVX2, AVX512;
 	}
 	}
 
 
-	[StaticInitPriority(101)]
+	[StaticInitPriority(201)]
 	static class Runtime
 	static class Runtime
 	{
 	{
 		const int32 cVersion = 10;
 		const int32 cVersion = 10;
@@ -484,6 +484,7 @@ namespace System
 
 
 		public static function ErrorHandlerResult(AssertError.Kind kind, String error, String filePath, int lineNum) CheckAssertError;
 		public static function ErrorHandlerResult(AssertError.Kind kind, String error, String filePath, int lineNum) CheckAssertError;
 		public static function int32(char8* kind, char8* arg1, char8* arg2, int arg3) CheckErrorHandler;
 		public static function int32(char8* kind, char8* arg1, char8* arg2, int arg3) CheckErrorHandler;
+		public static function void*(char8* filePath) LibraryLoadCallback;
 
 
 		static ErrorHandlerResult CheckAssertError_Impl(AssertError.Kind kind, String error, String filePath, int lineNum)
 		static ErrorHandlerResult CheckAssertError_Impl(AssertError.Kind kind, String error, String filePath, int lineNum)
 		{
 		{

+ 90 - 0
BeefLibs/corlib/src/StaticHookAttribute.bf

@@ -0,0 +1,90 @@
+namespace System;
+
+[AttributeUsage(.Types | .Method, .AlwaysIncludeTarget)]
+public struct StaticHookAttribute : Attribute, IOnTypeInit
+{
+	Type mSrcType;
+	Type mDestType;
+
+	public this()
+	{
+		mSrcType = null;
+		mDestType = null;
+	}
+
+	public this(Type srcType)
+	{
+		mSrcType = srcType;
+		mDestType = null;
+	}
+
+	public this(Type srcType, Type destType)
+	{
+		mSrcType = srcType;
+		mDestType = destType;
+	}
+
+	[Comptime]
+	public void OnTypeInit(Type type, Self* prev)
+	{
+		var emitStr = scope String();
+
+		if (mDestType != null)
+		{
+			var hookAttr = mSrcType.GetCustomAttribute<Self>().Value;
+
+			for (var methodInfo in mDestType.GetMethods(.Static))
+			{
+				if (!methodInfo.HasCustomAttribute<StaticHookAttribute>())
+					continue;
+				emitStr.AppendF($"public static function {methodInfo.ReturnType}");
+				emitStr.Append("(");
+				methodInfo.GetParamsDecl(emitStr);
+				emitStr.AppendF($") s{methodInfo.Name};\n");
+			}
+			emitStr.Append("\n");
+
+			emitStr.Append("static this\n{\n");
+			for (var methodInfo in mDestType.GetMethods(.Static))
+			{
+				if (!methodInfo.HasCustomAttribute<StaticHookAttribute>())
+					continue;
+
+				emitStr.AppendF($"\ts{methodInfo.Name} = {mSrcType}.s{methodInfo.Name} ?? => {hookAttr.mSrcType}.{methodInfo.Name};\n");
+				emitStr.AppendF($"\t{mSrcType}.s{methodInfo.Name} = => {mDestType}.{methodInfo.Name};\n");
+			}
+			emitStr.Append("}\n");
+		}
+		else
+		{
+			if (mSrcType == null)
+				return;
+
+			emitStr.Append("#pragma warning disable\n");
+			for (var methodInfo in mSrcType.GetMethods(.Static))
+			{
+				if (!methodInfo.HasCustomAttribute<StaticHookAttribute>())
+					continue;
+
+				emitStr.AppendF($"public static function {methodInfo.ReturnType}");
+				emitStr.Append("(");
+				methodInfo.GetParamsDecl(emitStr);
+				emitStr.AppendF($") s{methodInfo.Name};\n");
+
+				emitStr.AppendF($"public static {methodInfo.ReturnType} {methodInfo.Name}");
+				emitStr.Append("(");
+				methodInfo.GetParamsDecl(emitStr);
+				emitStr.Append(")\n");
+				emitStr.Append("{\n");
+				emitStr.AppendF($"\tif (s{methodInfo.Name} != null)\n");
+				emitStr.AppendF($"\t\treturn s{methodInfo.Name}(");
+				methodInfo.GetArgsList(emitStr);
+				emitStr.AppendF($");\n\treturn {mSrcType}.{methodInfo.Name}(");
+				methodInfo.GetArgsList(emitStr);
+				emitStr.Append(");\n}\n\n");
+			}
+		}
+
+		Compiler.EmitTypeBody(type, emitStr);
+	}
+}

+ 1 - 1
BeefLibs/corlib/src/Text/Encoding.bf

@@ -2,7 +2,7 @@ using System.Diagnostics;
 using System.Threading;
 using System.Threading;
 namespace System.Text
 namespace System.Text
 {
 {
-	[StaticInitPriority(100)]
+	[StaticInitPriority(200)]
 	abstract class Encoding
 	abstract class Encoding
 	{
 	{
 		public enum DecodeError
 		public enum DecodeError

+ 2 - 2
BeefLibs/corlib/src/Threading/Thread.bf

@@ -8,7 +8,7 @@ namespace System.Threading
     public delegate void ThreadStart();
     public delegate void ThreadStart();
     public delegate void ParameterizedThreadStart(Object obj);
     public delegate void ParameterizedThreadStart(Object obj);
 
 
-	[StaticInitPriority(100)]
+	[StaticInitPriority(200)]
     public sealed class Thread
     public sealed class Thread
     {
     {
         private int mInternalThread;
         private int mInternalThread;
@@ -28,7 +28,7 @@ namespace System.Threading
 
 
 		public static Thread sMainThread ~ delete _;
 		public static Thread sMainThread ~ delete _;
 
 
-        [StaticInitPriority(102)]
+        [StaticInitPriority(202)]
         struct RuntimeThreadInit
         struct RuntimeThreadInit
         {
         {
             static Object Thread_Alloc()
             static Object Thread_Alloc()

+ 1 - 1
BeefLibs/corlib/src/TimeZoneInfo.bf

@@ -53,7 +53,7 @@ namespace System {
         NoThrowOnInvalidTime      = 2
         NoThrowOnInvalidTime      = 2
     }
     }
 
 
-	[StaticInitPriority(100)]
+	[StaticInitPriority(200)]
     sealed public class TimeZoneInfo : IEquatable<TimeZoneInfo>
     sealed public class TimeZoneInfo : IEquatable<TimeZoneInfo>
 	{
 	{
         // ---- SECTION:  members supporting exposed properties -------------*
         // ---- SECTION:  members supporting exposed properties -------------*