JNI global COM Interface memory problem...

I'm trying to use a COM object globally in my JNI DLL and running into problems when the DLL is unloaded. Specifically I have a global smart pointer to one of the interfaces defined in my COM object. I call CreateInstance and get a valid interface object which I use in multiple DLL function calls. Everything works beautifully up until the DLL is unloaded. At that point the Visual Studio C++ debugger tells me I have a memory leak and my COM interace pointer is now pointing to garbage which causes an exception. Does anyone out there know what could be wrong with this?

By the way. I've created another DLL which has the same exact code, except not JNI, and tested it on a straight C++ client. No problems whatsoever. It must be something that Java is doing... sigh...

The following code (important parts) is from my JNI DLL:

=========================================

// Import the typelibrary for the COM component //

/////////////////////////////////////////////////////////

#import"PaymentProcessorComponent.tlb" no_namespace

#define kProgID"PaymentProcessorComponent.PaymentProcessor"

// Globals

//////////

struct InitOle

{

InitOle(){ ::CoInitialize(NULL);}

~InitOle(){::CoUninitialize();}

} _init_InitOle_;

IPaymentServerPtr gspPaymentServer;

// JNI functions

/////////////////

JNIEXPORTvoid JNICALL

Java_PPCWrapper_Init(JNIEnv *env, jobject obj)

{

DebugMsg("PPCWrapper::Init()");

HRESULT hr;

try

{

hr = gspPaymentServer.CreateInstance(kProgID);

if (hr != ERROR_SUCCESS)

{

ThrowJavaException(env, hr);

}

}

catch (_com_error err)

{

ThrowJavaException(env, err);

}

}

JNIEXPORTvoid JNICALL

Java_PPCWrapper_Connect(JNIEnv *env, jobject obj, jstring strIP, jint nPort, jint nTimeout)

{

DebugMsg("PPCWrapper::Connect()");

try

{

constchar *str = env->GetStringUTFChars(strIP, 0);

HRESULT hr = gspPaymentServer->Connect(str, nPort, nTimeout);

if (hr != ERROR_SUCCESS)

{

ThrowJavaException(env, hr);

}

env->ReleaseStringUTFChars(strIP, str);

}

catch (_com_error err)

{

ThrowJavaException(env, err);

}

}

JNIEXPORTvoid JNICALL

Java_PPCWrapper_Disconnect(JNIEnv *env, jobject obj)

{

DebugMsg("PPCWrapper::Disconnect()");

try

{

HRESULT hr = gspPaymentServer->Disconnect();

if (hr != ERROR_SUCCESS)

ThrowJavaException(env, hr);

}

catch (_com_error err)

{

ThrowJavaException(env, err);

}

}

[4398 byte] By [brandoneggar] at [2007-9-26 4:48:39]
# 1

One possible problem:

Your method converts an input string using GetStringUTFChars, passing a "0" as the second argument. Maybe you know exactly what happens in the platform you are using, but the book says that the second arg should be a pointer to a boolean (isCopy), and that the string should then be released only if isCopy is true.

(May have nothing to do with what is happening to you.)

bschauwe at 2007-6-29 18:39:01 > top of Java-index,Core,Core APIs...
# 2
Sorry, that doesn't seem to be the problem. You can pass a NULL value to the *isCopy member. Thanks anyway :)
brandoneggar at 2007-6-29 18:39:01 > top of Java-index,Core,Core APIs...
# 3

It seems the reason that my global COM interface pointer is getting trashed in my C++ JNI code has something to do with finalization. I added the "System.runFinalizersOnExit(true)" function to the beginning of my tester program and my COM interface doesn't get trashed and it can release in a normal fashion and can release itself on exiting. I'm a little confused in how this all works?!*&?

I noticed the "runFinalizersOnExit" method has been deprecated. Is there any other way I can go about fixing my problem?

Thanks in advance...

public class Test

{

public static void main (String[] args)

{

System.runFinalizersOnExit(true);

PPCWrapper ppc = new PPCWrapper();

ppc.Init();

ppc.Connect();

// Do some stuff here...

ppc.Disconnect();

}

}

brandoneggar at 2007-6-29 18:39:01 > top of Java-index,Core,Core APIs...
# 4

Try to release your smart pointer (even if it is a "smart pointer") in JNI method:

JNIEXPORT void JNICALL Java_PPCWrapper_Close(JNIEnv *env, jobject obj) {

if (NULL != gspPaymentServer) {

gspPaymentServer.Release();

}

}

Call this method before exit from your Java program.

veis78 at 2007-6-29 18:39:01 > top of Java-index,Core,Core APIs...