WindowsApiException

This commit is contained in:
Andrew Golovashevich 2025-09-04 22:43:01 +03:00
parent 6c52ff9fd2
commit 10ea159606
7 changed files with 123 additions and 1 deletions

6
.gitmodules vendored Normal file
View File

@ -0,0 +1,6 @@
[submodule "lib/closeable-state"]
path = lib/closeable-state
url = https://git.landgrafhomyak.ru/LanguageUtilities/closeable-state.kt
[submodule "lib/highlevel-try-finally"]
path = lib/highlevel-try-finally
url = https://git.landgrafhomyak.ru/xomrk/highlevel-try-finally.kt

View File

@ -11,6 +11,8 @@ repositories {
}
kotlin {
explicitApi()
mingwX64()
linuxX64()
@ -23,6 +25,7 @@ kotlin {
sourceSets {
commonMain {
dependencies {
implementation("ru.landgrafhomyak.utility:highlevel-try-finally:0.6")
implementation("ru.landgrafhomyak.utility:closeable-state-1:1.1")
}
}

1
lib/closeable-state Submodule

@ -0,0 +1 @@
Subproject commit bdb1fe56fa79e50850e8072db0b857955d48b479

@ -0,0 +1 @@
Subproject commit 6cfa6bddd04a041ae02ec8098c478762313c71de

View File

@ -1,2 +1,4 @@
rootProject.name = "kotlin-native-stdlib-1"
rootProject.name = "kotlin-native-interop-stdlib-0"
includeBuild("lib/closeable-state")
includeBuild("lib/highlevel-try-finally")

View File

@ -0,0 +1,10 @@
package ru.landgrafhomyak.utility.kotlin_native_interop_stdlib_0
public abstract class OsException : RuntimeException {
public constructor() : super()
public constructor(message: String?) : super(message)
public constructor(message: String?, cause: Throwable?) : super(message, cause)
public constructor(cause: Throwable?) : super(cause)
abstract override fun toString(): String
}

View File

@ -0,0 +1,99 @@
package ru.landgrafhomyak.utility.kotlin_native_interop_stdlib_0
import kotlinx.cinterop.ByteVar
import kotlinx.cinterop.CPointerVar
import kotlinx.cinterop.ExperimentalForeignApi
import kotlinx.cinterop.alloc
import kotlinx.cinterop.memScoped
import kotlinx.cinterop.ptr
import kotlinx.cinterop.reinterpret
import kotlinx.cinterop.toKString
import kotlinx.cinterop.value
import platform.windows.FORMAT_MESSAGE_ALLOCATE_BUFFER
import platform.windows.FORMAT_MESSAGE_FROM_SYSTEM
import platform.windows.FORMAT_MESSAGE_IGNORE_INSERTS
import platform.windows.FormatMessageA
import platform.windows.GetLastError
import platform.windows.LocalFree
import ru.landgrafhomyak.utility.highlevel_try_finally.safeAutoClose1
public class WindowsApiException : OsException {
private val errno: UInt
private val nativeMessage: String?
public constructor(errno: UInt, nativeMessage: String?) : super() {
this.errno = errno
this.nativeMessage = nativeMessage
}
public constructor(errno: UInt, nativeMessage: String?, customMessage: String?) : super(customMessage) {
this.errno = errno
this.nativeMessage = nativeMessage
}
public constructor(errno: UInt, nativeMessage: String?, customMessage: String?, cause: Throwable?) : super(customMessage, cause) {
this.errno = errno
this.nativeMessage = nativeMessage
}
public constructor(errno: UInt, nativeMessage: String?, cause: Throwable?) : super(cause) {
this.errno = errno
this.nativeMessage = nativeMessage
}
override fun toString(): String =
"<windows api exception errno=${this.errno}>"
public companion object {
public fun throwFromLastWindowsErr(): Nothing {
throw this.formatFromLastWindowsErr()
}
public fun throwFromWindowsErrCode(code: UInt): Nothing {
throw this.formatFromWindowsErrCode(code)
}
public fun formatFromLastWindowsErr(): WindowsApiException = this.formatFromWindowsErrCode(GetLastError())
public fun formatFromWindowsErrCode(code: UInt): WindowsApiException {
var err = WindowsApiException(errno = code, nativeMessage = null, customMessage = "[errno=${code}]")
try {
val nativeMessage = this.getNativeMessageByErrno(code)
err = WindowsApiException(errno = code, nativeMessage = nativeMessage, "[errno=${err}] ${nativeMessage}")
} catch (newErr: Throwable) {
err.addSuppressed(newErr)
}
return err
}
@OptIn(ExperimentalForeignApi::class)
public fun getNativeMessageByErrno(code: UInt): String {
memScoped {
var buffer = alloc<CPointerVar<ByteVar>>()
val result = FormatMessageA(
FORMAT_MESSAGE_ALLOCATE_BUFFER.toUInt() or FORMAT_MESSAGE_FROM_SYSTEM.toUInt() or FORMAT_MESSAGE_IGNORE_INSERTS.toUInt(),
null,
code,
0u, // MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
buffer.ptr.reinterpret(),
0u,
null
)
if (result == 0u) {
val newErrno = GetLastError()
throw WindowsApiException(errno = newErrno, nativeMessage = null, customMessage = "[errno=${newErrno}]")
}
safeAutoClose1(
action = {
return buffer.value!!.toKString() // todo handle nullablity
},
finally = {
LocalFree(buffer.value)
}
)
}
}
}
}