访问冲突异常

本文关键字:异常 访问冲突 | 更新日期: 2023-09-27 18:19:27

我有一个c#程序,它调用一个c dll,而c dll又调用java dll(使用jet excelsi或第三方程序构建)。我将一个xml字符串从c#传递到java中,然后java将该字符串返回给c#进行处理。

这在第一次迭代中有效,但在第二次迭代中,我得到了以下异常。。。

尝试读取或写入受保护的内存。这通常是指示其他内存已损坏。

以下是我将分类为相关代码的内容,但如果您需要其他内容,请告诉我。

C#调用C dll

public static class DllCall
{
    [DllImport("Stubs", CallingConvention = CallingConvention.Cdecl)]
    public static extern int initDll([MarshalAs(UnmanagedType.LPStr)] string userDllName);
    [DllImport("Stubs", CallingConvention = CallingConvention.Cdecl)]
    public static extern void finalizeDll();
    [DllImport("Stubs", CallingConvention = CallingConvention.Cdecl)]
    public static extern UInt32 newClassInstance(String rootPath, String cfgPath, String logPath );
    [DllImport("Stubs", CallingConvention = CallingConvention.Cdecl)]
    public static extern String request(UInt32 hClassInst, [MarshalAs(UnmanagedType.LPStr)] String input);
    [DllImport("Stubs", CallingConvention = CallingConvention.Cdecl)]
    public static extern void close();

}

C dll中引发错误的方法

const char* request(jobject obj, char* input )
{
    jstring inputString;
    jstring outputString;
    const char *nativeString;

    jmethodID mID = (*env)->GetMethodID (env, jClass, "request", "(Ljava/lang/String;)Ljava/lang/String;");
    if (!mID){
        printf("'nError: dllClass.request() not found'n");
        return 0;
    }
    inputString = (*env)->NewStringUTF(env, input);

    outputString = (*env)->CallObjectMethod(env, obj, mID, inputString);    
    nativeString = (*env)->GetStringUTFChars(env, outputString, 0); 

    return nativeString;
}

根据请求,这里是实际导致异常的C#代码。

        public string request(string xmlInput)
{
    LogManager.logMessage("Sending request to Java. Request is - " + xmlInput);
    string rs ="";
    Console.Write("Making request");
    //this works fine
    rs = DllCall.request(hClass, xmlInput); 
    Console.Write("---> request() rs = {0}'n", rs);
    // this throws the error
    rs = DllCall.request(hClass, "<?xml version='1.0' encoding='utf-8'?><moo><request name='"Panel.Open.GetSelectionTemplate'"/></moo>"); 
    return rs;
}

作为对Daniel的回应,这里是env被声明为的地方

#include <jni.h>
#include <windows.h>
JNIEnv  *env;
JavaVM  *jvm;
HANDLE  hUserDll;
jclass  jClass;
char*  dllname;

下面是它的初始化方式。

int initDll(char* userDllName) 
{
  jClass = NULL;
  hUserDll = loadDll(userDllName); 
  dllname = userDllName;
  initJavaRT(hUserDll, &jvm, &env); 
  jClass = lookForClass(env, "XActMain/XActGeminiX3/XActGeminiX3IFX");
  return jClass ? 1 : 0;
}
/*
 * Initialize JET run-time.
 */
void initJavaRT(HANDLE myDllHandle, JavaVM** pjvm, JNIEnv** penv)
{
    int            result;
    JavaVMInitArgs args;
    JNI_GetDefaultJavaVMInitArgs_func = 
             (jint (JNICALL *) (void *args))
             GetProcAddress (myDllHandle, "JNI_GetDefaultJavaVMInitArgs");
    JNI_CreateJavaVM_func =
             (jint (JNICALL *) (JavaVM **pvm, void **penv, void *args))
             GetProcAddress (myDllHandle, "JNI_CreateJavaVM");
    if(!JNI_GetDefaultJavaVMInitArgs_func) {
        printf ("%s doesn't contain public JNI_GetDefaultJavaVMInitArgs'n", dllname);
        exit (1);
    }
    if(!JNI_CreateJavaVM_func) {
        printf ("%s doesn't contain public JNI_CreateJavaVM'n", dllname);
        exit (1);
    }
    memset (&args, 0, sizeof(args));
    args.version = JNI_VERSION_1_2;
    result = JNI_GetDefaultJavaVMInitArgs_func(&args);
    if (result != JNI_OK) {
        printf ("JNI_GetDefaultJavaVMInitArgs() failed with result %d'n", result);
        exit(1);
    }
    /*
     * NOTE: no JVM is actually created
     * this call to JNI_CreateJavaVM is intended for JET RT initialization
     */
    result = JNI_CreateJavaVM_func (pjvm, (void **)penv, &args);
    if (result != JNI_OK) {
        printf ("JNI_CreateJavaVM() failed with result %d'n", result);
        exit(1);
    }
    printf ("JET RT initialized'n");
    fflush (stdout);
}

这是对Joes关于初始化的评论的回应。。。

public class Test
 {
     public UInt32 hClass;
     public Test()
     {
        initDll();
        newClassInstance(rootConfig, config, logFile);
     }
     ........
     public void newClassInstance(string rootPath, string cfgPath, string logPath)
     {
         hClass = DllCall.newClassInstance(rootPath, cfgPath, logPath);
         Console.Write("---> hClass = {0}'n", hClass);
     }
     public void initDll()
     {
             int rc = DllCall.initDll("dllClass.dll");
             Console.Write("---> initDll() rc = {0}'n", rc);
     }

汉斯指出了以下环节的潜在答案

然而,我不确定如何修改我当前的代码来适应这个解决方案。

正如我所说,它只工作一次,然后在第二次迭代中崩溃。

访问冲突异常

我不知道为什么它第一次工作,但您将类对象(hClass)传递到request,而不是该类的实例。

rs = DllCall.request(hClass, xmlInput); //The error is thrown on this line

看看这是否解决了问题:

public string request(string xmlInput)
{
    LogManager.logMessage("Sending request to Java. Request is - " + xmlInput);
    string rs ="";
    Console.Write("Making request");
    UInt32 hClassInst = DllCall.newClassInstance(rootPath, cfgPath, logPath); // <-- New line, using your own rootPath, cfgPath, logPath variables
    rs = DllCall.request(hClassInst, xmlInput);                               // <-- Modified line, using hClassInst instead of hClass
    Console.Write("---> request() rs = {0}'n", rs);
    return rs;
}

如果这解决了问题,那么您可能应该重构它,并提取对早期初始化方法的newClassInstance调用。