У меня есть программа на c #, которая вызывает C dll, которая, в свою очередь, вызывает java dll (созданная с использованием jet excelsior сторонней программы). Я передаю строку 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;
}
В ответе Даниилу вот где объявляется 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);
}
Это ответ Джоса на комментарий об инициализации ...
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);
}
Ганс указал на следующую ссылку потенциальный ответ
Однако я не уверен, как изменить мой текущий код, чтобы приспособить это решение.
Как я уже сказал, он работает один раз, а затем падает на второй итерации.