访问冲突异常
本文关键字:异常 访问冲突 | 更新日期: 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
调用。