I have a C # program that calls C dll, which in turn calls java dll (built using a third-party jet excelsior program). I pass the xml string from C # to java, and java then returns the string to C # for processing.
This works on the first iteration, but then on the second iteration I get the following exception ...
Attempted to read or write protected memory. It is often that other memory is corrupted.
Here is what I would call the appropriate code, but if you need anything else, let me know.
C # Call for 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(); }
Method in C dll that throws an error
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; }
As requested, here is a C # code that actually throws an exception.
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; }
In response to Daniel, env is declared here
#include <jni.h> #include <windows.h> JNIEnv *env; JavaVM *jvm; HANDLE hUserDll; jclass jClass; char* dllname;
And this is how it is initialized.
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; } 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); } 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); }
This is in response to Jos's initialization comment ...
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); }
Hans pointed to the following link potential response
However, I am not sure how to change the current code to host this solution.
As I said, it works once, and then falls on the second iteration.