Reputation: 4240
I have a c# program that calls a C dll which in turn calls java dll( built using jet excelsior a 3rd party program). I am passing an xml string from the c# into the java and the java then returns the string to the the c# to process.
This works on the first iteration, but then on the second iteration I get the following exception...
Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
Here is what I would class as the relevant code but if you require anything else please let me know.
C# Calls to 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 is throwing the 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 the C# code that actually causes the 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 here is where env is declared
#include <jni.h>
#include <windows.h>
JNIEnv *env;
JavaVM *jvm;
HANDLE hUserDll;
jclass jClass;
char* dllname;
And here is how it is initialised.
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);
}
This is in response to Joes comment about initialisation...
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 has pointed out the following link potential answer
I am however not sure how to modify my current code to accomodate this solution.
As I say it works once then crashes on the second iteration.
Upvotes: 4
Views: 1221
Reputation: 16841
I'm not sure why it's working the first time, but you're passing a class object (hClass
) into request
instead of an instance of that class.
rs = DllCall.request(hClass, xmlInput); //The error is thrown on this line
See if this fixes the problem:
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;
}
If this fixes the problem, you should probably then refactor it and pull out the newClassInstance
call to an earlier initialization method.
Upvotes: 1