将字符串从c dll返回到c#

时间:2014-05-13 13:34:19

标签: c# c interop

我试图将一个字符串从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),那么它可以工作,但我不知道提前返回数据的大小,所以我不想这样做。关于我做错什么的任何想法?

1 个答案:

答案 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;
}