Support for wchar, minor opts in interop runtime (#641)
This commit is contained in:
@@ -76,6 +76,18 @@ object nativeMemUtils {
|
|||||||
unsafe.copyMemory(source, baseOffset, null, dest.address, length.toLong())
|
unsafe.copyMemory(source, baseOffset, null, dest.address, length.toLong())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getCharArray(source: NativePointed, dest: CharArray, length: Int) {
|
||||||
|
val clazz = CharArray::class.java
|
||||||
|
val baseOffset = unsafe.arrayBaseOffset(clazz).toLong();
|
||||||
|
unsafe.copyMemory(null, source.address, dest, baseOffset, length.toLong() * 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun putCharArray(source: CharArray, dest: NativePointed, length: Int) {
|
||||||
|
val clazz = CharArray::class.java
|
||||||
|
val baseOffset = unsafe.arrayBaseOffset(clazz).toLong();
|
||||||
|
unsafe.copyMemory(source, baseOffset, null, dest.address, length.toLong() * 2)
|
||||||
|
}
|
||||||
|
|
||||||
fun zeroMemory(dest: NativePointed, length: Int): Unit = unsafe.setMemory(dest.address, length.toLong(), 0)
|
fun zeroMemory(dest: NativePointed, length: Int): Unit = unsafe.setMemory(dest.address, length.toLong(), 0)
|
||||||
|
|
||||||
internal class NativeAllocated(override val rawPtr: NativePtr) : NativePointed
|
internal class NativeAllocated(override val rawPtr: NativePtr) : NativePointed
|
||||||
|
|||||||
@@ -147,10 +147,11 @@ inline fun <reified T : CPointer<*>>
|
|||||||
NativePlacement.allocArrayOf(elements: List<T?>): CArrayPointer<CPointerVarOf<T>> {
|
NativePlacement.allocArrayOf(elements: List<T?>): CArrayPointer<CPointerVarOf<T>> {
|
||||||
|
|
||||||
val res = allocArray<CPointerVarOf<T>>(elements.size)
|
val res = allocArray<CPointerVarOf<T>>(elements.size)
|
||||||
elements.forEachIndexed { index, value ->
|
var index = 0
|
||||||
res[index] = value
|
while (index < elements.size) {
|
||||||
|
res[index] = elements[index]
|
||||||
|
++index
|
||||||
}
|
}
|
||||||
|
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,8 +164,9 @@ fun NativePlacement.allocArrayOf(elements: ByteArray): CArrayPointer<ByteVar> {
|
|||||||
fun NativePlacement.allocArrayOf(vararg elements: Float): CArrayPointer<FloatVar> {
|
fun NativePlacement.allocArrayOf(vararg elements: Float): CArrayPointer<FloatVar> {
|
||||||
val res = allocArray<FloatVar>(elements.size)
|
val res = allocArray<FloatVar>(elements.size)
|
||||||
var index = 0
|
var index = 0
|
||||||
for (element in elements) {
|
while (index < elements.size) {
|
||||||
res[index++] = element
|
res[index] = elements[index]
|
||||||
|
++index
|
||||||
}
|
}
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
@@ -287,8 +289,6 @@ fun <T : CPointed> Array<CPointer<T>?>.toCValues() = cValuesOf(*this)
|
|||||||
fun <T : CPointed> List<CPointer<T>?>.toCValues() = this.toTypedArray().toCValues()
|
fun <T : CPointed> List<CPointer<T>?>.toCValues() = this.toTypedArray().toCValues()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO: should the name of the function reflect the encoding?
|
|
||||||
*
|
|
||||||
* @return the value of zero-terminated UTF-8-encoded C string constructed from given [kotlin.String].
|
* @return the value of zero-terminated UTF-8-encoded C string constructed from given [kotlin.String].
|
||||||
*/
|
*/
|
||||||
val String.cstr: CValues<ByteVar>
|
val String.cstr: CValues<ByteVar>
|
||||||
@@ -307,6 +307,21 @@ val String.cstr: CValues<ByteVar>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val String.wcstr: CValues<ShortVar>
|
||||||
|
get() {
|
||||||
|
val chars = CharArray(this.length, { i -> this.get(i)})
|
||||||
|
return object : CValues<ShortVar>() {
|
||||||
|
override val size get() = chars.size + 1
|
||||||
|
|
||||||
|
override fun getPointer(placement: NativePlacement): CPointer<ShortVar> {
|
||||||
|
val result = placement.allocArray<ShortVar>(chars.size + 1)
|
||||||
|
nativeMemUtils.putCharArray(chars, result.pointed, chars.size)
|
||||||
|
result[chars.size] = 0.toShort()
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO: should the name of the function reflect the encoding?
|
* TODO: should the name of the function reflect the encoding?
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -33,24 +33,50 @@ object nativeMemUtils {
|
|||||||
// TODO: optimize
|
// TODO: optimize
|
||||||
fun getByteArray(source: NativePointed, dest: ByteArray, length: Int) {
|
fun getByteArray(source: NativePointed, dest: ByteArray, length: Int) {
|
||||||
val sourceArray = source.reinterpret<ByteVar>().ptr
|
val sourceArray = source.reinterpret<ByteVar>().ptr
|
||||||
for (index in 0 .. length - 1) {
|
var index = 0
|
||||||
|
while (index < length) {
|
||||||
dest[index] = sourceArray[index]
|
dest[index] = sourceArray[index]
|
||||||
|
++index
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: optimize
|
// TODO: optimize
|
||||||
fun putByteArray(source: ByteArray, dest: NativePointed, length: Int) {
|
fun putByteArray(source: ByteArray, dest: NativePointed, length: Int) {
|
||||||
val destArray = dest.reinterpret<ByteVar>().ptr
|
val destArray = dest.reinterpret<ByteVar>().ptr
|
||||||
for (index in 0 .. length - 1) {
|
var index = 0
|
||||||
|
while (index < length) {
|
||||||
destArray[index] = source[index]
|
destArray[index] = source[index]
|
||||||
|
++index
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: optimize
|
||||||
|
fun getCharArray(source: NativePointed, dest: CharArray, length: Int) {
|
||||||
|
val sourceArray = source.reinterpret<ShortVar>().ptr
|
||||||
|
var index = 0
|
||||||
|
while (index < length) {
|
||||||
|
dest[index] = sourceArray[index].toChar()
|
||||||
|
++index
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: optimize
|
||||||
|
fun putCharArray(source: CharArray, dest: NativePointed, length: Int) {
|
||||||
|
val destArray = dest.reinterpret<ShortVar>().ptr
|
||||||
|
var index = 0
|
||||||
|
while (index < length) {
|
||||||
|
destArray[index] = source[index].toShort()
|
||||||
|
++index
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: optimize
|
// TODO: optimize
|
||||||
fun zeroMemory(dest: NativePointed, length: Int): Unit {
|
fun zeroMemory(dest: NativePointed, length: Int): Unit {
|
||||||
val destArray = dest.reinterpret<ByteVar>().ptr
|
val destArray = dest.reinterpret<ByteVar>().ptr
|
||||||
for (index in 0 .. length - 1) {
|
var index = 0
|
||||||
|
while (index < length) {
|
||||||
destArray[index] = 0
|
destArray[index] = 0
|
||||||
|
++index
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+23
@@ -60,6 +60,8 @@ class StubGenerator(
|
|||||||
"true", "try", "typealias", "val", "var", "when", "while"
|
"true", "try", "typealias", "val", "var", "when", "while"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val platformWStringTypes = setOf("LPCWSTR")
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For this identifier constructs the string to be parsed by Kotlin as `SimpleName`
|
* For this identifier constructs the string to be parsed by Kotlin as `SimpleName`
|
||||||
* defined [here](https://kotlinlang.org/docs/reference/grammar.html#SimpleName).
|
* defined [here](https://kotlinlang.org/docs/reference/grammar.html#SimpleName).
|
||||||
@@ -516,12 +518,24 @@ class StubGenerator(
|
|||||||
return pointeeType
|
return pointeeType
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun Type.isAliasOf(names: Set<String>): Boolean {
|
||||||
|
var type = this
|
||||||
|
while (type is Typedef) {
|
||||||
|
if (names.contains(type.def.name)) return true
|
||||||
|
type = type.def.aliased
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
fun representCFunctionParameterAsString(type: Type): Boolean {
|
fun representCFunctionParameterAsString(type: Type): Boolean {
|
||||||
val unwrappedType = type.unwrapTypedefs()
|
val unwrappedType = type.unwrapTypedefs()
|
||||||
return unwrappedType is PointerType && unwrappedType.pointeeIsConst &&
|
return unwrappedType is PointerType && unwrappedType.pointeeIsConst &&
|
||||||
unwrappedType.pointeeType.unwrapTypedefs() == CharType
|
unwrappedType.pointeeType.unwrapTypedefs() == CharType
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We take this approach as generic 'const short*' shall not be used as String.
|
||||||
|
fun representCFunctionParameterAsWString(type: Type)= type.isAliasOf(platformWStringTypes)
|
||||||
|
|
||||||
fun getCFunctionParamBinding(type: Type): OutValueBinding {
|
fun getCFunctionParamBinding(type: Type): OutValueBinding {
|
||||||
if (representCFunctionParameterAsString(type)) {
|
if (representCFunctionParameterAsString(type)) {
|
||||||
return OutValueBinding(
|
return OutValueBinding(
|
||||||
@@ -532,6 +546,15 @@ class StubGenerator(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (representCFunctionParameterAsWString(type)) {
|
||||||
|
return OutValueBinding(
|
||||||
|
kotlinType = "String?", // TODO: mention the C type (e.g. with annotation).
|
||||||
|
kotlinConv = { name -> "$name?.wcstr?.getPointer(memScope).rawValue" },
|
||||||
|
memScoped = true,
|
||||||
|
kotlinJniBridgeType = "NativePtr"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
representCFunctionParameterAsValuesRef(type)?.let {
|
representCFunctionParameterAsValuesRef(type)?.let {
|
||||||
val pointeeMirror = mirror(it)
|
val pointeeMirror = mirror(it)
|
||||||
return OutValueBinding(
|
return OutValueBinding(
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
import win32.*
|
||||||
|
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
MessageBoxW(null, "Konan говорит:\nЗДРАВСТВУЙ МИР!\n",
|
||||||
|
"Заголовок окна", MB_YESNOCANCEL or MB_ICONQUESTION)
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
@echo off
|
||||||
|
setlocal
|
||||||
|
set DIR=.
|
||||||
|
set "PATH=..\..\dist\bin;..\..\bin;%PATH%"
|
||||||
|
if "%TARGET%" == "" set TARGET=mingw
|
||||||
|
|
||||||
|
set "LFLAGS=-Wl,--subsystem,windows"
|
||||||
|
|
||||||
|
call cinterop -def "%DIR%\win32.def" -target "%TARGET%" -o win32 || exit /b
|
||||||
|
call konanc -target "%TARGET%" "%DIR%\MessageBox.kt" -library win32 -linkerOpts "%LFLAGS%" -opt -o MessageBox || exit /b
|
||||||
|
|
||||||
|
copy MessageBox.kexe MessageBox.exe
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
headers = windows.h
|
||||||
|
headerFilter = win**.h
|
||||||
|
compilerOpts = -DUNICODE -Wno-incompatible-pointer-types -Wno-deprecated-declarations
|
||||||
Reference in New Issue
Block a user