Straightforward native interfacing from Kotlin
compile group: 'org.jire.arrowhead', name: 'arrowhead', version: '1.3.3'
<dependency>
<groupId>org.jire.arrowhead</groupId>
<artifactId>arrowhead</artifactId>
<version>1.3.3</version>
</dependency>
Sources are native references that can be read from and written to through Arrowhead.
Process
and Module
are the two sources available.
You can acquire a process using a name (executable file name):
val process = processByName("process.exe")!!
You can also acquire by process ID (PID):
val process123 = processByID(123)!!
You can use .modules
off a process for a map of the module name to the Module
.
val module = process.modules["module.dll"]!!
You can use the implicit data type to read from an address:
val someByte: Byte = process[0x123]
val someInt: Int = process[0x123]
val someFloat: Float = process[0x123]
val someBoolean: Boolean = process[0x123]
The implicit type also works when passing arguments or using if expressions.
if (process[0x321]) // Boolean type inferred
Math.sin(process[0x555]) // Double type inferred
Sometimes it's easier or necessary to use explicit types, and we have you covered:
val someByte = process.byte(0x123)
val someInt = process.int(0x123)
val someFloat = process.float(0x123)
val someBoolean = process.boolean(0x123)
Writing to a source is just as easy as reading.
You can use "implicit" writing with the set operator.
something[0x123] = 1.toByte()
something[0x123] = 1
something[0x123] = 1F
something[0x123] = true
There are no "explicit" writes, as the "implicit" writes are simply method overloads.
Defining structures is the same as in JNA,
except you should extend Struct
(of org.jire.arrowhead
) instead of JNA's Structure
(of com.sun.jna
)
to take advantage of the reuse ("caching") system and other enhancements like automatic field order.
For JNA and Arrowhead to detect fields correctly, make sure to annotate them with
@JvmField
.
The easiest way to get a struct is by referring to its class type and using the get
extension function.
val struct = MyStruct::class.get()
If you have a constructor for your struct type, you can use the get operator to pass the arguments in:
val struct = MyStruct::class["abc", 1, 2, 3]
To read into a struct you can use its read function, which takes the address to read and the source to read from:
struct.read(address = 0x123, source = something)
To write the struct to a source you can use its write function, which is similar to reading:
struct.write(address = 0x123, source = something)
After you're done using a struct you should release it back into the caching pool:
struct.release()