我试图将一个字符串从C函数返回到一个C#程序,我得到一个AccessViolationException,我不明白为什么?这是我的C代码:
__declspec(dllexport) void DoLuceneRequest(byte *xmlin, int datasize, char *xmlout){
JNIEnv *env;
if (jvm == NULL){
JavaVMOption* options = new JavaVMOption[1];
JavaVMInitArgs vm_args; /* JDK/JRE 6 VM initialization arguments */
options[0].optionString = "-Djava.class.path=LuceneServlet.jar;lucene-core-2.9.4.jar;lucene-spellchecker-2.9.4.jar;servlet-api.jar";
vm_args.version = JNI_VERSION_1_6;
vm_args.nOptions = 1;
vm_args.options = options;
vm_args.ignoreUnrecognized = false;
/* load and initialize a Java VM, return a JNI interface
* pointer in env */
JNI_CreateJavaVM(&jvm, (void**)&globalenv, &vm_args);
delete options;
}
jvm->AttachCurrentThread((void **)&env, NULL);
jobject obj;
jclass cls = env->FindClass("lucene/LuceneServlet");
if (cls != NULL){
jmethodID constructor = env->GetMethodID(cls, "<init>", "()V");
if (constructor != NULL){
obj = env->NewObject(cls, constructor);
if (obj != NULL){
jmethodID processRequest = env->GetMethodID(cls, "processRequest", "([B)Ljava/lang/String;");
if (processRequest != NULL){
jbyte *jbytes = (jbyte*) xmlin;
jbyteArray jba = env->NewByteArray(datasize);
env->SetByteArrayRegion(jba, 0, datasize, jbytes);
jstring results = (jstring)env->CallObjectMethod(obj, processRequest, jba);
MessageBox(NULL, "call successful, returning values", "", MB_OK);
const char *cresults = env->GetStringUTFChars(results, NULL);
strcpy_s(xmlout, strlen(cresults) + 1, cresults);
for (int i=0; i <= strlen(cresults); i++){
if (cresults[i] == '\0'){
MessageBox(NULL, "Has null terminator", "", MB_OK);
}
}
MessageBox(NULL, cresults, "", MB_OK);
MessageBox(NULL, xmlout, "", MB_OK);
env->ReleaseStringUTFChars(results, cresults);
//env->ReleaseByteArrayElements(jba, jbytes, 0);
}else{
MessageBox(NULL, "method not found", "", MB_OK);
}
}
}
}
//jvm->DestroyJavaVM();
jvm->DetachCurrentThread();
}
消息框显示正确的字符串。
这是我的C#代码:
[DllImport("LuceneHandler.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void DoLuceneRequest(byte[] xmlin, int datasize, StringBuilder xmlout);
StringBuilder sbRsltXml = new StringBuilder();
//DisplayHelloFromDLL("hello", sbRsltXml);
//MessageBox.Show(sbRsltXml.ToString());
byte[] ubytes = Encoding.UTF8.GetBytes("<test></test>");
DoLuceneRequest(ubytes, ubytes.Length, sbRsltXml);
MessageBox.Show(sbRsltXml.ToString());
如果我使用新的StringBuilder(99999),那么它可以工作,但我不知道提前返回数据的大小,所以我不想这样做。关于我做错什么的任何想法?
答案 0 :(得分:0)
让它工作,这是代码:
__declspec(dllexport) char* DoLuceneRequest(byte *xmlin, int datasize){
JNIEnv *env;
char* returnedString = NULL;
if (jvm == NULL){
JavaVMOption* options = new JavaVMOption[1];
JavaVMInitArgs vm_args; /* JDK/JRE 6 VM initialization arguments */
options[0].optionString = "-Djava.class.path=LuceneServlet.jar;lucene-core-2.9.4.jar;lucene-spellchecker-2.9.4.jar;servlet-api.jar";
vm_args.version = JNI_VERSION_1_6;
vm_args.nOptions = 1;
vm_args.options = options;
vm_args.ignoreUnrecognized = false;
/* load and initialize a Java VM, return a JNI interface
* pointer in env */
JNI_CreateJavaVM(&jvm, (void**)&globalenv, &vm_args);
delete options;
}
jvm->AttachCurrentThread((void **)&env, NULL);
jobject obj;
jclass cls = env->FindClass("lucene/LuceneServlet");
if (cls != NULL){
jmethodID constructor = env->GetMethodID(cls, "<init>", "()V");
if (constructor != NULL){
obj = env->NewObject(cls, constructor);
if (obj != NULL){
jmethodID processRequest = env->GetMethodID(cls, "processRequest", "([B)Ljava/lang/String;");
if (processRequest != NULL){
jbyte *jbytes = (jbyte*) xmlin;
jbyteArray jba = env->NewByteArray(datasize);
env->SetByteArrayRegion(jba, 0, datasize, jbytes);
jstring results = (jstring)env->CallObjectMethod(obj, processRequest, jba);
const char *cresults = env->GetStringUTFChars(results, NULL);
returnedString = (char*)CoTaskMemAlloc(strlen(cresults) + 1);
strcpy_s(returnedString, strlen(cresults) + 1, cresults);
env->ReleaseStringUTFChars(results, cresults);
//env->ReleaseByteArrayElements(jba, jbytes, 0);
}else{
MessageBox(NULL, "method not found", "", MB_OK);
}
}
}
}
//jvm->DestroyJavaVM();
jvm->DetachCurrentThread();
return returnedString;
}