From 37c8705674b78ac3f5f09cbd4672ef84e8191282 Mon Sep 17 00:00:00 2001 From: Charles Hu Date: Wed, 9 Jul 2025 11:20:10 -0700 Subject: [PATCH 1/2] Bin compat: use Platform.getFullExecutablePath instead of CommandLine.arguments.first for ProcessInfo.processName. The original NSProcessInfo implementation calls _CFProcessPath for processName, which Platform.getFullExecutablePath internally calls. We should maintain the same behavior for binary compatibility. --- Sources/FoundationEssentials/ProcessInfo/ProcessInfo.swift | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Sources/FoundationEssentials/ProcessInfo/ProcessInfo.swift b/Sources/FoundationEssentials/ProcessInfo/ProcessInfo.swift index 1caa04bfb..acb94408e 100644 --- a/Sources/FoundationEssentials/ProcessInfo/ProcessInfo.swift +++ b/Sources/FoundationEssentials/ProcessInfo/ProcessInfo.swift @@ -597,10 +597,7 @@ extension _ProcessInfo { } private static func _getProcessName() -> String { - guard let processPath = CommandLine.arguments.first else { - return "" - } - return processPath.lastPathComponent + return Platform.getFullExecutablePath()?.lastPathComponent ?? "" } #if os(macOS) From 9a01f2c1d49c579308ce39a7e6c39b6e272cdf9d Mon Sep 17 00:00:00 2001 From: Charles Hu Date: Thu, 10 Jul 2025 11:25:35 -0700 Subject: [PATCH 2/2] Update Platform.getFullExecutablePath implementation for Windows to match _CFProcessPath --- Sources/FoundationEssentials/Platform.swift | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/Sources/FoundationEssentials/Platform.swift b/Sources/FoundationEssentials/Platform.swift index 1e39051b8..7e9800ab7 100644 --- a/Sources/FoundationEssentials/Platform.swift +++ b/Sources/FoundationEssentials/Platform.swift @@ -355,17 +355,14 @@ extension Platform { return try? FileManager.default.destinationOfSymbolicLink( atPath: "/proc/self/exe").standardizingPath #elseif os(Windows) - let hFile = GetModuleHandleW(nil) - let dwLength: DWORD = GetFinalPathNameByHandleW(hFile, nil, 0, FILE_NAME_NORMALIZED) - guard dwLength > 0 else { return nil } - return withUnsafeTemporaryAllocation(of: WCHAR.self, capacity: Int(dwLength)) { lpBuffer in - guard GetFinalPathNameByHandleW(hFile, lpBuffer.baseAddress, dwLength, FILE_NAME_NORMALIZED) == dwLength - 1 else { + return withUnsafeTemporaryAllocation(of: WCHAR.self, capacity: Int(MAX_PATH)) { lpBuffer in + let actualLength = GetModuleFileNameW(nil, lpBuffer.baseAddress!, DWORD(lpBuffer.count)) + // Windows Documentation: + // If the function fails, the return value is 0 (zero). + // To get extended error information, call GetLastError. + guard actualLength > 0 else { return nil } - - // The `GetFinalPathNameByHandleW` function will normalise the path - // for us as part of the query. This allows us to avoid having to - // standardize the path ourselves. return String(decodingCString: lpBuffer.baseAddress!, as: UTF16.self) } #else