Sourceforge 2011706 windows memory error when exiting program with call back proxies still hooked up.

This commit is contained in:
clay_shooter
2008-07-06 12:39:04 +00:00
parent 3bb8889134
commit b7dc74c59d
4 changed files with 162 additions and 93 deletions

View File

@@ -1,5 +1,46 @@
<HTML> <HTML>
<BODY> <BODY>
<!-- --------- -->
<h2>JACOB 1.14.2</h2>
<h3>Tracked Changes</h3>
<table border="0" cellpadding="0" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111" width="100%" >
<tr>
<td width="100%" colspan="2"><b>Bugs</b></td>
</tr>
<tr>
<td width="13%" valign="top">2011706</td>
<td width="87%" valign="top">Fixed windows memory corruption unhooking
call back proxies</td>
</tr>
<tr>
<td width="13%" valign="top">&nbsp;</td>
<td width="87%" valign="top">&nbsp;</td>
</tr>
<tr>
<td width="100%" colspan="2"><b>Patches</b></td>
</tr>
<tr>
<td width="13%" valign="top">&nbsp;</td>
<td width="87%" valign="top">&nbsp;</td>
</tr>
<tr>
<td width="100%" colspan="2"><b>Feature Requests</b></td>
</tr>
<tr>
<td width="13%" valign="top">&nbsp;</td>
<td width="87%" valign="top">&nbsp;</td>
</tr>
<tr>
<td width="100%" colspan="2"><b>Known Issues</b></td>
</tr>
<tr>
<td width="13%" valign="top"></td>
<td width="87%" valign="top"></td>
</tr>
</table>
<!-- --------- --> <!-- --------- -->
<h2>JACOB 1.14.1</h2> <h2>JACOB 1.14.1</h2>
<h3>Tracked Changes</h3> <h3>Tracked Changes</h3>

View File

@@ -73,8 +73,8 @@ should be fixed in some future release, fix method and time not yet determined.
<h2>Microsoft Visual C++ library dependencies.</h2> <h2>Microsoft Visual C++ library dependencies.</h2>
Jacob 1.13 is built with VC++ 2005 that creates a dependency on msvcr80.dll. Jacob 1.13 is built with VC++ 2005 that creates a dependency on msvcr80.dll.
Windows XP and later seem to already include the necessary components. Windows XP and later seem to already include the necessary components.
NT/2000 and Server/2003 require that you download the Visual C redistributable package, NT/2000 and Server/2003 require that you download the Visual C 2005 redistributable
vcredist_x86.exe from the microsoft web site. package, vcredist_x86.exe from the microsoft web site.
Microsoft has a download available that supplies the necessary components. Microsoft has a download available that supplies the necessary components.
It is distributed as a redistributable package. It is distributed as a redistributable package.
<p> <p>

View File

@@ -60,33 +60,36 @@ EventProxy::~EventProxy()
JNIEnv *env; JNIEnv *env;
Disconnect(); Disconnect();
jint vmConnectionStatus = JNI_EVERSION ; jint vmConnectionStatus = JNI_EVERSION ;
jint attachReturnStatus = -1; // AttachCurrentThread return status.. negative numbers are failure return codes.
// attach to the current running thread -- JDK 1.4 jni.h has two param cover for 3 param call // attach to the current running thread -- JDK 1.4 jni.h has two param cover for 3 param call
vmConnectionStatus = jvm->GetEnv((void **)&env, JNI_VERSION_1_2); vmConnectionStatus = jvm->GetEnv((void **)&env, JNI_VERSION_1_2);
if (env->ExceptionOccurred()) { env->ExceptionDescribe(); env->ExceptionClear();} if ((env != NULL)&& env->ExceptionOccurred()) { env->ExceptionDescribe(); env->ExceptionClear();}
if (vmConnectionStatus == JNI_EDETACHED){ if (vmConnectionStatus == JNI_EDETACHED){
//printf("Unhook: Attaching to current thread using JNI Version 1.2 (%d)\n",vmConnectionStatus); //printf("Unhook: Attaching to current thread using JNI Version 1.2 (%d)\n",vmConnectionStatus);
JavaVMAttachArgs attachmentArgs; JavaVMAttachArgs attachmentArgs;
attachmentArgs.version = JNI_VERSION_1_2; attachmentArgs.version = JNI_VERSION_1_2;
attachmentArgs.name = NULL; attachmentArgs.name = NULL;
attachmentArgs.group = NULL; attachmentArgs.group = NULL;
jvm->AttachCurrentThread((void **)&env, &attachmentArgs); attachReturnStatus = jvm->AttachCurrentThread((void **)&env, &attachmentArgs);
if (env->ExceptionOccurred()) { env->ExceptionDescribe(); env->ExceptionClear();} if ((env != NULL) && env->ExceptionOccurred()) { env->ExceptionDescribe(); env->ExceptionClear();}
} else { } else {
// should really look for JNI_OK versus an error // should really look for JNI_OK versus an error because it could have been JNI_EVERSION
// started method hooked so no need to attach again // started method with thread hooked to VM so no need to attach again
//printf("Unhook: No need to attach because already attached %d\n",vmConnectionStatus); //printf("Unhook: No need to attach because already attached %d\n",vmConnectionStatus);
} }
// we should always have an env by this point but lets be paranoid and check
env->DeleteGlobalRef(javaSinkObj); if (env != NULL){
if (env->ExceptionOccurred()) { env->ExceptionDescribe(); env->ExceptionClear();} env->DeleteGlobalRef(javaSinkObj);
if (env->ExceptionOccurred()) { env->ExceptionDescribe(); env->ExceptionClear();}
}
if (MethNum) { if (MethNum) {
delete [] MethName; delete [] MethName;
delete [] MethID; delete [] MethID;
} }
// detach from thread // detach from thread only if we attached to it in this function
if (vmConnectionStatus == JNI_EDETACHED){ if (attachReturnStatus == 0){
jvm->DetachCurrentThread(); jvm->DetachCurrentThread();
//printf("Unhook: Detached\n"); //printf("Unhook: Detached\n");
} else { } else {

View File

@@ -11,7 +11,7 @@ import com.jacob.test.BaseTestCase;
* This test runs fine against jdk 1.4 and 1.5 * This test runs fine against jdk 1.4 and 1.5
* *
* This demonstrates the new event handling code in jacob 1.7 This example will * This demonstrates the new event handling code in jacob 1.7 This example will
* open up IE and print out some of the events it listens to as it havigates to * open up IE and print out some of the events it listens to as it navigates to
* web sites. contributed by Niels Olof Bouvin mailto:n.o.bouvin@daimi.au.dk and * web sites. contributed by Niels Olof Bouvin mailto:n.o.bouvin@daimi.au.dk and
* Henning Jae jehoej@daimi.au.dk * Henning Jae jehoej@daimi.au.dk
* <p> * <p>
@@ -22,28 +22,49 @@ import com.jacob.test.BaseTestCase;
public class IETest extends BaseTestCase { public class IETest extends BaseTestCase {
/**
* well known address we can navigate to
*/
private String testUrls[] = {
"http://sourceforge.net/projects/jacob-project",
"http://www.google.com" };
/** /**
* runs the IE test and feeds it commands * runs the IE test and feeds it commands
*/ */
public void testRunIE() { public void testRunIECleanly() {
runTheTest(true, testUrls);
}
/**
* runs the IE test and feeds it commands
*/
public void testRunIETerminateWithoutWait() {
runTheTest(false, testUrls);
}
/**
* The actual work of running the test.
*
* @param waitForQuit
* @param urls
*/
private void runTheTest(boolean waitForQuit, String[] urls) {
// this line starts the pump but it runs fine without it // this line starts the pump but it runs fine without it
ComThread.startMainSTA(); ComThread.startMainSTA();
// remove this line and it dies // Run the test in a thread. Lets us test running out of "main" thread
// /ComThread.InitMTA(true); IETestThread aThread = new IETestThread(waitForQuit, urls);
IETestThread aThread = new IETestThread();
aThread.start(); aThread.start();
while (aThread.isAlive()) { while (aThread.isAlive()) {
try { try {
Thread.sleep(1000); Thread.sleep(250);
} catch (InterruptedException e) { } catch (InterruptedException e) {
// doen with the sleep // done with the sleep
// e.printStackTrace();
} }
} }
System.out System.out.println("Main: Thread quit, about to quitMainSTA in thread "
.println("Main: Thread quit, about to quit main sta in thread " + Thread.currentThread().getName());
+ Thread.currentThread().getName()); // this line only does something if startMainSTA() was called
// this line only does someting if startMainSTA() was called
ComThread.quitMainSTA(); ComThread.quitMainSTA();
System.out.println("Main: did quit main sta in thread " System.out.println("Main: did quit main sta in thread "
+ Thread.currentThread().getName()); + Thread.currentThread().getName());
@@ -59,6 +80,17 @@ class IETestThread extends Thread {
/** flag that says we got a quit message from IE */ /** flag that says we got a quit message from IE */
public static boolean quitHandled = false; public static boolean quitHandled = false;
/**
* determines if we wait until last quit call back received before
* terminating
*/
private static boolean waitUntilReceivedQuitCallback = true;
/**
* the places we should navigate to
*/
private static String[] targets = null;
/** /**
* holds any caught exception so the main/test case can see them * holds any caught exception so the main/test case can see them
*/ */
@@ -66,15 +98,25 @@ class IETestThread extends Thread {
/** /**
* constructor for the test thread * constructor for the test thread
*
* @param beNeat
* should we wait until quit received
* @param urls
* the web pages we will navigate to
*/ */
public IETestThread() { public IETestThread(boolean beNeat, String urls[]) {
super(); super();
waitUntilReceivedQuitCallback = beNeat;
targets = urls;
} }
/**
* Run through the addresses passed in via the constructor
*/
public void run() { public void run() {
// this used to be 5 seconds but sourceforge is slow // pick a time that lets sourceforge respond (in msec)
int delay = 5000; // msec int delay = 3000;
// paired with statement below that blows up // pre-1.14 paired with statement below that blows up
ComThread.InitMTA(); ComThread.InitMTA();
ActiveXComponent ie = new ActiveXComponent( ActiveXComponent ie = new ActiveXComponent(
"InternetExplorer.Application"); "InternetExplorer.Application");
@@ -88,27 +130,16 @@ class IETestThread extends Thread {
IEEvents ieE = new IEEvents(); IEEvents ieE = new IEEvents();
new DispatchEvents(ie, ieE, "InternetExplorer.Application.1"); new DispatchEvents(ie, ieE, "InternetExplorer.Application.1");
System.out.println("IETestThread: Did hookup event listener"); System.out.println("IETestThread: Did hookup event listener");
// / why is this here? Was there some other code here in the past?
Variant optional = new Variant();
optional.putNoParam();
System.out for (String url : targets) {
.println("IETestThread: About to call navigate to sourceforge"); System.out.println("IETestThread: About to call navigate to "
Dispatch.call(ie, "Navigate", new Variant( + url);
"http://sourceforge.net/projects/jacob-project")); Dispatch.call(ie, "Navigate", new Variant(url));
System.out System.out.println("IETestThread: Did call navigate to " + url);
.println("IETestThread: Did call navigate to sourceforge"); try {
try { Thread.sleep(delay);
Thread.sleep(delay); } catch (Exception e) {
} catch (Exception e) { }
}
System.out.println("IETestThread: About to call navigate to yahoo");
Dispatch.call(ie, "Navigate", new Variant(
"http://groups.yahoo.com/group/jacob-project"));
System.out.println("IETestThread: Did call navigate to yahoo");
try {
Thread.sleep(delay);
} catch (Exception e) {
} }
} catch (Exception e) { } catch (Exception e) {
threadFailedWithException = e; threadFailedWithException = e;
@@ -121,35 +152,29 @@ class IETestThread extends Thread {
ie.invoke("Quit", new Variant[] {}); ie.invoke("Quit", new Variant[] {});
System.out.println("IETestThread: Did send Quit"); System.out.println("IETestThread: Did send Quit");
} }
// this blows up when it tries to release a DispatchEvents object // a value is set to false if we try to crash VM by leaving before
// I think this is because there is still one event we should get back // callbacks all received
// "OnQuit" that will came after we have released the thread pool if (waitUntilReceivedQuitCallback) {
// this is probably messed up because DispatchEvent object will have System.out
// been .println("IETestThread: Waiting until we've received quit callback");
// freed before the callback // wait a little while for it to end
// commenting out ie.invoke(quit...) causes this to work without error while (!quitHandled) {
// this code tries to wait until the quit has been handled but that try {
// doesn't work Thread.sleep(delay / 10);
System.out } catch (InterruptedException e) {
.println("IETestThread: Waiting until we've received the quit callback"); }
while (!quitHandled) {
try {
Thread.sleep(delay / 5);
} catch (InterruptedException e) {
} }
System.out.println("IETestThread: Received the OnQuit callback");
} else {
System.out.println("IETestThread: Not waiting for OnQuit callback");
} }
System.out.println("IETestThread: Received the quit callback"); System.out.println("IETestThread: Calling ComThread.Release in thread "
// wait a little while for it to end + Thread.currentThread().getName());
// try {Thread.sleep(delay); } catch (InterruptedException e) {}
System.out
.println("IETestThread: about to call ComThread.Release in thread "
+ Thread.currentThread().getName());
ComThread.Release(); ComThread.Release();
} }
/** /**
* The events class must be publicly accessable for reflection to work. The * The events class must be publicly accessible for reflection to work. The
* list of available events is located at * list of available events is located at
* http://msdn2.microsoft.com/en-us/library/aa768280.aspx * http://msdn2.microsoft.com/en-us/library/aa768280.aspx
*/ */
@@ -163,7 +188,7 @@ class IETestThread extends Thread {
public void BeforeNavigate2(Variant[] args) { public void BeforeNavigate2(Variant[] args) {
System.out.println("IEEvents Received (" System.out.println("IEEvents Received ("
+ Thread.currentThread().getName() + "): BeforeNavigate2 " + Thread.currentThread().getName() + "): BeforeNavigate2 "
+ args.length); + args.length + " parameters");
} }
/** /**
@@ -175,7 +200,7 @@ class IETestThread extends Thread {
public void CommandStateChange(Variant[] args) { public void CommandStateChange(Variant[] args) {
System.out.println("IEEvents Received (" System.out.println("IEEvents Received ("
+ Thread.currentThread().getName() + Thread.currentThread().getName()
+ "): CommandStateChange " + args.length); + "): CommandStateChange " + args.length + " parameters");
} }
/** /**
@@ -187,7 +212,7 @@ class IETestThread extends Thread {
public void DocumentComplete(Variant[] args) { public void DocumentComplete(Variant[] args) {
System.out.println("IEEvents Received (" System.out.println("IEEvents Received ("
+ Thread.currentThread().getName() + "): DocumentComplete " + Thread.currentThread().getName() + "): DocumentComplete "
+ args.length); + args.length + " parameters");
} }
/** /**
@@ -199,7 +224,7 @@ class IETestThread extends Thread {
public void DownloadBegin(Variant[] args) { public void DownloadBegin(Variant[] args) {
System.out.println("IEEvents Received (" System.out.println("IEEvents Received ("
+ Thread.currentThread().getName() + "): DownloadBegin " + Thread.currentThread().getName() + "): DownloadBegin "
+ args.length); + args.length + " parameters");
} }
/** /**
@@ -211,7 +236,7 @@ class IETestThread extends Thread {
public void DownloadComplete(Variant[] args) { public void DownloadComplete(Variant[] args) {
System.out.println("IEEvents Received (" System.out.println("IEEvents Received ("
+ Thread.currentThread().getName() + "): DownloadComplete " + Thread.currentThread().getName() + "): DownloadComplete "
+ args.length); + args.length + " parameters");
} }
/** /**
@@ -223,7 +248,7 @@ class IETestThread extends Thread {
public void NavigateError(Variant[] args) { public void NavigateError(Variant[] args) {
System.out.println("IEEvents Received (" System.out.println("IEEvents Received ("
+ Thread.currentThread().getName() + "): NavigateError " + Thread.currentThread().getName() + "): NavigateError "
+ args.length); + args.length + " parameters");
} }
/** /**
@@ -235,7 +260,7 @@ class IETestThread extends Thread {
public void NavigateComplete2(Variant[] args) { public void NavigateComplete2(Variant[] args) {
System.out.println("IEEvents Received (" System.out.println("IEEvents Received ("
+ Thread.currentThread().getName() + "): NavigateComplete " + Thread.currentThread().getName() + "): NavigateComplete "
+ args.length); + args.length + " parameters");
} }
/** /**
@@ -247,7 +272,7 @@ class IETestThread extends Thread {
public void NewWindow2(Variant[] args) { public void NewWindow2(Variant[] args) {
System.out.println("IEEvents Received (" System.out.println("IEEvents Received ("
+ Thread.currentThread().getName() + "): NewWindow2 " + Thread.currentThread().getName() + "): NewWindow2 "
+ args.length); + args.length + " parameters");
} }
/** /**
@@ -259,7 +284,7 @@ class IETestThread extends Thread {
public void OnFullScreen(Variant[] args) { public void OnFullScreen(Variant[] args) {
System.out.println("IEEvents Received (" System.out.println("IEEvents Received ("
+ Thread.currentThread().getName() + "): OnFullScreen " + Thread.currentThread().getName() + "): OnFullScreen "
+ args.length); + args.length + " parameters");
} }
/** /**
@@ -271,7 +296,7 @@ class IETestThread extends Thread {
public void OnMenuBar(Variant[] args) { public void OnMenuBar(Variant[] args) {
System.out.println("IEEvents Received (" System.out.println("IEEvents Received ("
+ Thread.currentThread().getName() + "): OnMenuBar " + Thread.currentThread().getName() + "): OnMenuBar "
+ args.length); + args.length + " parameters");
} }
/** /**
@@ -283,7 +308,7 @@ class IETestThread extends Thread {
public void OnQuit(Variant[] args) { public void OnQuit(Variant[] args) {
System.out.println("IEEvents Received (" System.out.println("IEEvents Received ("
+ Thread.currentThread().getName() + "): OnQuit " + Thread.currentThread().getName() + "): OnQuit "
+ args.length); + args.length + " parameters");
IETestThread.quitHandled = true; IETestThread.quitHandled = true;
} }
@@ -296,7 +321,7 @@ class IETestThread extends Thread {
public void OnStatusBar(Variant[] args) { public void OnStatusBar(Variant[] args) {
System.out.println("IEEvents Received (" System.out.println("IEEvents Received ("
+ Thread.currentThread().getName() + "): OnStatusBar " + Thread.currentThread().getName() + "): OnStatusBar "
+ args.length); + args.length + " parameters");
} }
/** /**
@@ -308,7 +333,7 @@ class IETestThread extends Thread {
public void OnTheaterMode(Variant[] args) { public void OnTheaterMode(Variant[] args) {
System.out.println("IEEvents Received (" System.out.println("IEEvents Received ("
+ Thread.currentThread().getName() + "): OnTheaterMode " + Thread.currentThread().getName() + "): OnTheaterMode "
+ args.length); + args.length + " parameters");
} }
/** /**
@@ -320,7 +345,7 @@ class IETestThread extends Thread {
public void OnToolBar(Variant[] args) { public void OnToolBar(Variant[] args) {
System.out.println("IEEvents Received (" System.out.println("IEEvents Received ("
+ Thread.currentThread().getName() + "): OnToolBar " + Thread.currentThread().getName() + "): OnToolBar "
+ args.length); + args.length + " parameters");
} }
/** /**
@@ -332,7 +357,7 @@ class IETestThread extends Thread {
public void OnVisible(Variant[] args) { public void OnVisible(Variant[] args) {
System.out.println("IEEvents Received (" System.out.println("IEEvents Received ("
+ Thread.currentThread().getName() + "): OnVisible " + Thread.currentThread().getName() + "): OnVisible "
+ args.length); + args.length + " parameters");
} }
/** /**
@@ -344,7 +369,7 @@ class IETestThread extends Thread {
public void ProgressChange(Variant[] args) { public void ProgressChange(Variant[] args) {
System.out.println("IEEvents Received (" System.out.println("IEEvents Received ("
+ Thread.currentThread().getName() + "): ProgressChange " + Thread.currentThread().getName() + "): ProgressChange "
+ args.length); + args.length + " parameters");
} }
/** /**
@@ -356,7 +381,7 @@ class IETestThread extends Thread {
public void PropertyChange(Variant[] args) { public void PropertyChange(Variant[] args) {
System.out.println("IEEvents Received (" System.out.println("IEEvents Received ("
+ Thread.currentThread().getName() + "): PropertyChange " + Thread.currentThread().getName() + "): PropertyChange "
+ args.length); + args.length + " parameters");
} }
/** /**
@@ -368,7 +393,7 @@ class IETestThread extends Thread {
public void SetSecureLockIcon(Variant[] args) { public void SetSecureLockIcon(Variant[] args) {
System.out.println("IEEvents Received (" System.out.println("IEEvents Received ("
+ Thread.currentThread().getName() + Thread.currentThread().getName()
+ "): setSecureLockIcon " + args.length); + "): setSecureLockIcon " + args.length + " parameters");
} }
/** /**
@@ -380,7 +405,7 @@ class IETestThread extends Thread {
public void StatusTextChange(Variant[] args) { public void StatusTextChange(Variant[] args) {
System.out.println("IEEvents Received (" System.out.println("IEEvents Received ("
+ Thread.currentThread().getName() + "): StatusTextChange " + Thread.currentThread().getName() + "): StatusTextChange "
+ args.length); + args.length + " parameters");
} }
/** /**
@@ -392,7 +417,7 @@ class IETestThread extends Thread {
public void TitleChange(Variant[] args) { public void TitleChange(Variant[] args) {
System.out.println("IEEvents Received (" System.out.println("IEEvents Received ("
+ Thread.currentThread().getName() + "): TitleChange " + Thread.currentThread().getName() + "): TitleChange "
+ args.length); + args.length + " parameters");
} }
/** /**
@@ -404,7 +429,7 @@ class IETestThread extends Thread {
public void WindowClosing(Variant[] args) { public void WindowClosing(Variant[] args) {
System.out.println("IEEvents Received (" System.out.println("IEEvents Received ("
+ Thread.currentThread().getName() + "): WindowClosing " + Thread.currentThread().getName() + "): WindowClosing "
+ args.length); + args.length + " parameters");
} }
} }