#java #kotlin #jna #openvr
#java #kotlin #jna #openvr
Вопрос:
Я пытаюсь создать порт kotlin для привязки openvr java, а также обновить его до версии 1.0.3
Я получил на этапе написания IVRSystem
структуры / класса
Я написал все методы вручную, чтобы быть уверенным, что не будет никакой ошибки от автоматического переводчика в Intellij
Я избавился от всех ошибок, поступающих из другого количества полей из getFieldOrder()
, но теперь я все еще получаю ошибку:
Exception in thread "main" java.lang.IllegalStateException: Pointer native@0xffffffff already mapped to Proxy interface to native function@0xffffffff (IVRSystem$GetEyeToHeadTransform_callback).
Native code may be re-using a default function pointer, in which case you may need to use a common Callback class wherever the function pointer is reused.
at com.sun.jna.CallbackReference.getCallback(CallbackReference.java:124)
at com.sun.jna.CallbackReference.getCallback(CallbackReference.java:107)
at com.sun.jna.Pointer.getValue(Pointer.java:430)
at com.sun.jna.Structure.readField(Structure.java:705)
at com.sun.jna.Structure.read(Structure.java:565)
at IVRSystem.<init>(vr.kt:2091)
at VrKt.VR_Init(vr.kt:2116)
at VrKt.main(vr.kt:2133)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)
Согласно этому комментарию, похоже, что существует несколько вызовов определенного обратного вызова ( GetEyeToHeadTransform_callback
?), Но это не так, я проверил и дважды проверил код, есть одна и только одна ссылка на этот обратный вызов..
Что еще это может быть?
Редактировать:
во-первых, это происходит, когда я read()
в IVRSysten
классе, но я не могу этого избежать…
во-вторых, я вижу, что здесь все предыдущие методы получают реальные адреса, такие как native@0x7fee4bebfd0
, только GetEyeToHeadTransform
получает всегда native@0xffffffff
…
Правка2:
исследуем исходный код
dprintf("GetRecommendedRenderTargetSize %pn", amp;vr::IVRSystem::GetRecommendedRenderTargetSize);
dprintf("GetProjectionMatrix %pn", amp;vr::IVRSystem::GetProjectionMatrix);
dprintf("GetProjectionRaw %pn", amp;vr::IVRSystem::GetProjectionRaw);
dprintf("ComputeDistortion %pn", amp;vr::IVRSystem::ComputeDistortion);
dprintf("GetEyeToHeadTransform %pn", amp;vr::IVRSystem::GetEyeToHeadTransform);
dprintf("GetTimeSinceLastVsync %pn", amp;vr::IVRSystem::GetTimeSinceLastVsync);
dprintf("GetD3D9AdapterIndex %pn", amp;vr::IVRSystem::GetD3D9AdapterIndex);
dprintf("GetDXGIOutputInfo %pn", amp;vr::IVRSystem::GetDXGIOutputInfo);
dprintf("IsDisplayOnDesktop %pn", amp;vr::IVRSystem::IsDisplayOnDesktop);
dprintf("SetDisplayVisibility %pn", amp;vr::IVRSystem::SetDisplayVisibility);
dprintf("GetDeviceToAbsoluteTrackingPose %pn", amp;vr::IVRSystem::GetDeviceToAbsoluteTrackingPose);
dprintf("ResetSeatedZeroPose %pn", amp;vr::IVRSystem::ResetSeatedZeroPose);
dprintf("GetSeatedZeroPoseToStandingAbsoluteTrackingPose %pn", amp;vr::IVRSystem::GetSeatedZeroPoseToStandingAbsoluteTrackingPose);
выводит
GetRecommendedRenderTargetSize 0109871D
GetProjectionMatrix 0109AACC
GetProjectionRaw 0109AAD1
ComputeDistortion 0109AAF9
GetEyeToHeadTransform 0109AAC2
GetTimeSinceLastVsync 0109AAE5
GetD3D9AdapterIndex 0109AAF4
GetDXGIOutputInfo 0109AADB
IsDisplayOnDesktop 0109AAEA
SetDisplayVisibility 0109AAE0
GetDeviceToAbsoluteTrackingPose 0109AAEF
ResetSeatedZeroPose 0109AAD6
GetSeatedZeroPoseToStandingAbsoluteTrackingPose 0109AAC7
GetEyeToHeadTransform
и GetSeatedZeroPoseToStandingAbsoluteTrackingPose
имеют разные указатели..
Ответ №1:
Машинный код использует «волшебное» значение -1
для более чем одной подписи обратного вызова. Когда этот код обратного вызова для JNA был написан, предполагалось, что сопоставление одного и того же указателя функции двум разным сигнатурам должно быть ошибкой.
Я предполагаю, что -1
значение означает что-то вроде «использовать обратный вызов по умолчанию» (когда, возможно, могло бы хватить просто нулевого указателя, если библиотека не использует NULL для указания не вызывать обратный вызов).
Вы могли бы обойти это, переопределив Structure.read()
или Structure.readField()
, чтобы вернуть магическое значение или постоянный объект обратного вызова, когда вы видите -1
значение, например
public void read() {
Memory old = getPointer();
Memory m = autoAllocate(size());
// horribly inefficient, but it'll do
m.write(0, old.getByteArray(0, size()), 0, size());
useMemory(m);
// Zero out the problematic callbacks
for (field : problematic_fields) {
m.setPointer(field_offset, null);
}
super.read();
useMemory(old);
}
Комментарии:
1. Спасибо, Тимоти, я решил следующим образом, но теперь я получаю еще два поля с
0xfa0
и еще пару полей с другим таким же указателем… Это никак не может быть ошибкой на стороне jna, не так ли? В любом случае, я открыл проблему на valve openvr github, давайте посмотрим, в чем дело..2. Вполне возможно, что
openvr
просто повторно используется обратный вызов, или это может быть другое магическое значение (0xfa0 не выглядит как действительный указатель на функцию). Если вам на самом деле не нужно устанавливать или вызывать данный обратный вызов, просто определите его какPointer
.3. Я решил! Каким-то образом вы были правы, я создавал экземпляр,
IVRSystem
используя"IVRSystem_012"
вместо"FnTable:IVRSystem_012"
, поэтому библиотека возвращала указатели обратного вызова, которые были бесполезны для меня .. спасибо!
Ответ №2:
Несмотря на то, что это старый вопрос, я хотел бы поделиться своим опытом. В моем случае у меня есть собственный объект, который передается Java в виде структуры с сопоставленными прокси-методами. Объект представляет собой некоторый сеанс, который реализует метод close, который должен удалить сам собственный объект. Как только вызывается close и собственный объект удаляется, генерируется аналогичное исключение. Проблема в том, что после вызова функции JNA повторно синхронизирует удаленный собственный объект. Это можно решить, установив для автоматического чтения значение false.
public void close(Handler handler) {
setAutoRead(false);
close.invoke(this, handler);
setAutoWrite(false);
}