我需要使用JNI从C ++调用Java API。我正在尝试通过byte*
,如下所示:
Java
void OperateData(byte[] data, int dataLength)
{
//Some Implementation
}
C ++
void OperateData(byte* data, int dataLength)
{
JavaMethod* methodObj = getMethod(_T("OperateData"));
JNIEnv* jniEnv = JvmManager::GetInstance()->GetJNIEnv();
jobject jBuffer = jniEnv->CallObjectMethod(m_javaObject->getJObject(), methodObj->getJMethodID(), (jobject)data, (jint)dataLength);
}
这不起作用。它引发了异常。您能告诉我我在做什么错吗?
更新:我根据建议修改了C ++代码,如下所示。我仍然有同样的问题。还是有问题吗?
void OperateData(byte* data, int dataLength)
{
JavaMethod* methodObj = getMethod(_T("OperateData"));
JNIEnv* jniEnv = JvmManager::GetInstance()->GetJNIEnv();
jbyteArray jBuff = jniEnv->NewByteArray(dataLength);
jniEnv->SetByteArrayRegion(jBuff, 0, dataLength, (jbyte*)data);
jobject jBuffer = jniEnv->CallObjectMethod(m_javaObject->getJObject(), methodObj->getJMethodID(), jBuff, (jint)dataLength);
jniEnv->ReleaseByteArrayElements(jBuff,(jbyte*)data, 0);
}
答案 0 :(得分:4)
JavaMethod* methodObj = getMethod(_T("OperateData"));
// ...
jobject jBuffer = jniEnv->CallObjectMethod(m_javaObject->getJObject(), methodObj->getJMethodID(), (jobject)data,(jint)dataLength);
// ...
jniEnv->ReleaseByteArrayElements(jBuff,(jbyte*)data, 0);
这些都没有道理。
javap -s
的输出所给。因此,Java方法的JNI签名绝对不只是"OperateData"
。 methodObj
必须为空,或包含为零的jmethodID
,仅此一项就足以解释您的问题。void
,因此它不会返回jobject
。void
,因此您应该使用CallVoidMethod()
。char *data
将C ++ jbytearray
数组转换为NewByteArray()
,并使用适当的JNI Array Methods进行填充。ReleaseByteArrayElements()
。您不需要在这里完全调用它,但是当您调用它时,将使用通过GetByteArrayElements()
获得的指针来调用它。没有您自己的数据。jbytearray
。答案 1 :(得分:4)
您不能简单地将原始C / C ++ byte*
指针类型转换为表示Java字节数组的jobject
。您需要use JNI functions进行以下操作:
通过NewByteArray()
在JVM的内存中分配一个新的Java字节数组。
然后通过以下任一方式将原始字节复制到该Java数组的内存中:
然后将该Java数组传递给目标Java方法。
然后最终通过DeleteLocalRef()
释放Java数组。
例如:
void OperateData(byte* data, int dataLength)
{
JavaMethod* methodObj = getMethod(_T("OperateData"));
if (!methodObj) return;
JNIEnv* jniEnv = JvmManager::GetInstance()->GetJNIEnv();
if (!jniEnv) return;
jbyteArray jData = jniEnv->NewByteArray((jsize)dataLength);
if (!jData) return;
jniEnv->SetByteArrayRegion(jData, 0, (jsize)dataLength, (jbyte*)data);
jniEnv->CallVoidMethod(m_javaObject->getJObject(), methodObj->getJMethodID(), jData, (jint)dataLength);
jniEnv->DeleteLocalRef(jData);
}
更新:在注释中,您说您更改了Java代码以返回byte[]
而不是void
。如果是这样,则需要相应地调整C ++代码,例如:
void OperateData(byte* data, int dataLength)
{
JavaMethod* methodObj = getMethod(_T("OperateData"));
if (!methodObj) return;
JNIEnv* jniEnv = JvmManager::GetInstance()->GetJNIEnv();
if (!jniEnv) return;
jbyteArray jData = jniEnv->NewByteArray((jsize)dataLength);
if (!jData) return;
jniEnv->SetByteArrayRegion(jData, 0, (jsize)dataLength, (jbyte*)data);
jobject jBuffer = jniEnv->CallObjectMethod(m_javaObject->getJObject(), methodObj->getJMethodID(), jData, (jint)dataLength);
if (jBuffer) jniEnv->DeleteLocalRef(jBuffer);
jniEnv->DeleteLocalRef(jData);
}