Хотя существует много отображений, которые будут работать (любая 32-битная структура с правильными методами, используемыми для извлечения значений), канонический способ отобразить это напрямую - использовать класс JNA Union . Союз будет иметь три элемента; либо byte
, либо структуру RGB
, которую вы можете определить (для внутреннего класса Union это нормально), либо структуру Indexed
, которую вы определите (опять же, внутренний класс).
Union
выделит достаточно памяти на собственной стороне для самого большого элемента (32-битного), и с учетом опций структуры вам гарантировано, что первые 8 бит результирующей 32-битной памяти на стороне C будут содержать поле type
; на основании этого значения вы будете знать, что содержится в оставшихся 24 битах.
Если вы посмотрите на исходный код класса VNAant JNA , который отображает объединенный тег VARIANT , вы увидите, что это реализовано в несколько более сложном масштабе. Класс _VARIANT
содержит эти пять элементов, аналогично трем элементам в вашем союзе:
public VARTYPE vt;
public short wReserved1;
public short wReserved2;
public short wReserved3;
public __VARIANT __variant;
Для Союза допустимо только одно значение __variant
. В этом случае тип задается здесь:
public void setVarType(short vt) {
this._variant.vt = new VARTYPE(vt);
}
В более общем смысле вы можете посмотреть на внешний класс VARIANT
, который использует метод Union class setType()
, чтобы определить, существует ли даже допустимое значение: он устанавливает строку, соответствующую активному полю (в данном случае "_variant"
), который устанавливается в конструкторе. (Вы также можете установить использование класса вместо String.)
В вашем случае вы захотите выполнить инициализацию на основе значения типа, поэтому вы начнете с type
в качестве значения по умолчанию, прочитаете его значение и затем переключитесь.
Вы можете определить свой союз следующим образом:
public class VTermColor extends Union {
public class RGB extends Structure {
public byte type;
public byte red;
public byte green;
public byte blue;
}
public class Indexed extends Structure {
public byte type;
public byte idx;
}
public byte type;
public RGB rgb;
public Indexed indexed;
public VTermColor() {
// initialize knowing only the type, read its value
this.setType("type");
this.read();
// switch union based on type, re-read
if ((this.type & VTERM_COLOR_TYPE_MASK) == VTERM_COLOR_RGB) {
this.setType("rgb");
} else {
this.setType("indexed");
}
this.read();
}
public VTermColor(Pointer p) {
super(p);
// same remaining code as above
}
}
Возможно, вы захотите создать несколько других методов получения, чтобы проверять значение type
перед возвратом соответствующих полей.
Как упоминалось в начале, любая 32-битная структура данных будет работать. Несколько хакерская альтернатива (жертвуя удобочитаемостью и безопасностью типов для намного меньшего количества кода) может просто всегда использовать 4-байтовую структуру RGB
, как определено выше. Метод получения для type
всегда будет работать, в то время как методы получения для red
, green
и blue
будут работать, если они действительны, в противном случае вы можете создать метод получения для idx
, который просто читает значение red
.