wangzhengbo Posted January 4, 2014 Posted January 4, 2014 package cn.com.test; import cn.com.jautoitx.AutoItX; import cn.com.jautoitx.Misc; import cn.com.jautoitx.Win; public class TooltipBug { public static void main(String[] args) { // display tooltip at position (200, 100) AutoItX.tooltip("Hello, AutoIt.", 200, 100); Misc.sleep(2000); // hide tooltip AutoItX.tooltip(); Thread t = new Thread(new Runnable() { @Override public void run() { System.out.println("#1"); Win.waitActive("[CLASS:Notepad]"); System.out.println("#2"); System.out.println("'" + Win.getActiveTitle() + "'"); Win.setTitle("[CLASS:Notepad]", "Untitled - Notepad"); Win.waitActive("Untitled - Notepad"); System.out.println("#3"); } }); t.start(); } } AU3_WinWaitActive has bug in AutoItX 3.3.8.1 and 3.3.10.2. See java example above. Steps: 1. display tooltip in main thread. 2. hide tooltip. 3. start another thread, in this thread call AU3_WinWaitActive("[CLASS:Notepad]") and AU3_WinWaitActive("Untitled - Notepad") 4. Run "notepad.exe" in the windows command line. Results: AU3_WinWaitActive("[CLASS:Notepad]") will return, but AU3_WinWaitActive("Untitled - Notepad") is blocked. I think this is AU3_WinWaitActive's bug. If you run AU3_Tooltip and AU3_WinWaitActive in the same thread, there will no problem. You can download the required jars for the above java code from http://code.google.com/p/jautoitx/downloads/list JAutoItX-3.3.10.2-1.0.0-alpha.jar, commons-lang3-3.1.jar, jna-4.0.0.jar, and jna-platform-4.0.0.jar are required.
Richard Robertson Posted January 4, 2014 Posted January 4, 2014 AutoItX is not threadsafe. This is your problem.
wangzhengbo Posted January 5, 2014 Author Posted January 5, 2014 AutoItX is not threadsafe. This is your problem. Win.waitActive("[CLASS:Notepad]"); can work, but why Win.waitActive("Untitled - Notepad"); can not?
Richard Robertson Posted January 5, 2014 Posted January 5, 2014 Does the title version work if you run it within a single thread?
wangzhengbo Posted January 6, 2014 Author Posted January 6, 2014 Does the title version work if you run it within a single thread? Yes, it's worked well in single thread.
Richard Robertson Posted January 6, 2014 Posted January 6, 2014 Yes, it's worked well in single thread. Then the problem is exactly as I said, and you are breaking its standard flow of execution.
mrider Posted January 8, 2014 Posted January 8, 2014 (edited) With all due respect, I'm not sure the thread is the problem. Consider that all the code runs in the same thread - I would only expect the problem to manifest if the AutoItX code spanned more than one thread. After all, the JVM has to be running in some thread. wangzhengbo: I was unable to figure out which library you are using for your Java to AutoItX code. So I can't duplicate your problem exactly. However, I whipped up a quick test using Jacob and AutoX4Java and it works regardless of threading (link http://code.google.com/p/autoitx4java/ ): expandcollapse popupimport java.io.File; import autoitx4java.AutoItX; import com.jacob.com.LibraryLoader; public class WaitActiveTest implements Runnable { public static void main(String[] args) { WaitActiveTest wat = new WaitActiveTest(); wat.notepad(); Thread t = new Thread(wat); t.start(); } public void run() { try { Thread.sleep(5000); } catch (InterruptedException ignored) {} notepad(); } private void notepad() { File file = new File("jacob-1.17-x86.dll"); System.setProperty(LibraryLoader.JACOB_DLL_PATH, file.getAbsolutePath()); AutoItX x = new AutoItX(); String notepad = "Untitled - Notepad"; String testString = "this is a test."; x.run("notepad.exe"); x.winActivate(notepad); x.winWaitActive(notepad); x.send(testString); x.winClose(notepad, testString); x.winWaitActive("Notepad"); x.send("{ALT}n"); } } Edited January 8, 2014 by mrider How's my riding? Dial 1-800-Wait-There Trying to use a computer with McAfee installed is like trying to read a book at a rock concert.
wangzhengbo Posted January 9, 2014 Author Posted January 9, 2014 With all due respect, I'm not sure the thread is the problem. Consider that all the code runs in the same thread - I would only expect the problem to manifest if the AutoItX code spanned more than one thread. After all, the JVM has to be running in some thread. wangzhengbo: I was unable to figure out which library you are using for your Java to AutoItX code. So I can't duplicate your problem exactly. However, I whipped up a quick test using Jacob and AutoX4Java and it works regardless of threading (link http://code.google.com/p/autoitx4java/ ): expandcollapse popupimport java.io.File; import autoitx4java.AutoItX; import com.jacob.com.LibraryLoader; public class WaitActiveTest implements Runnable { public static void main(String[] args) { WaitActiveTest wat = new WaitActiveTest(); wat.notepad(); Thread t = new Thread(wat); t.start(); } public void run() { try { Thread.sleep(5000); } catch (InterruptedException ignored) {} notepad(); } private void notepad() { File file = new File("jacob-1.17-x86.dll"); System.setProperty(LibraryLoader.JACOB_DLL_PATH, file.getAbsolutePath()); AutoItX x = new AutoItX(); String notepad = "Untitled - Notepad"; String testString = "this is a test."; x.run("notepad.exe"); x.winActivate(notepad); x.winWaitActive(notepad); x.send(testString); x.winClose(notepad, testString); x.winWaitActive("Notepad"); x.send("{ALT}n"); } } If you run Tooltip in one thread, and then run WinWaitActive in another thread, there will be a problem as i said above.
mrider Posted January 9, 2014 Posted January 9, 2014 As I say, I can't quite figure out what libraries you have, so I can't run code identical to what you are running. However, I converted my code to look like the following, and still have no problems. I've never actually used AutoItX from Java in any form, so I know very little about any of the libraries (either yours or mine). But I suspect that the problem in your code is the combination of the fact that the AutoItX stuff is static combined with your thread. Is there some sort of "de-initialize" function in that library? If not, you may wish to try a different library. Or if you are the author, you might wish to forego the static ness and initialize some actual objects. My code: expandcollapse popupimport java.io.File; import autoitx4java.AutoItX; import com.jacob.com.LibraryLoader; public class WaitActiveTest implements Runnable { public static void main(String[] args) { WaitActiveTest wat = new WaitActiveTest(); wat.notepad(); Thread t = new Thread(wat); t.start(); } private final AutoItX x; private WaitActiveTest() { File file = new File("jacob-1.17-x86.dll"); System.setProperty(LibraryLoader.JACOB_DLL_PATH, file.getAbsolutePath()); x = new AutoItX(); x.toolTip("AutoIt X", 200, 200); } public void run() { try { Thread.sleep(5000); } catch (InterruptedException ignored) {} notepad(); } private void notepad() { System.out.println("Waiting"); String notepad = "Untitled - Notepad"; String testString = "this is a test."; x.winActivate(notepad); x.winWaitActive(notepad); x.send(testString); x.winClose(notepad, testString); x.winWaitActive("Notepad"); x.send("{ALT}n"); } } How's my riding? Dial 1-800-Wait-There Trying to use a computer with McAfee installed is like trying to read a book at a rock concert.
Richard Robertson Posted January 10, 2014 Posted January 10, 2014 Once you call the tooltip in one thread, the object is initialized and owned by that thread.
mrider Posted January 10, 2014 Posted January 10, 2014 Once you call the tooltip in one thread, the object is initialized and owned by that thread. I agree. However, as I mentioned, I think the fact that the methods are static factors in as well. Because as you can see, I initialize one object and access it from more than one thread in my later example. How's my riding? Dial 1-800-Wait-There Trying to use a computer with McAfee installed is like trying to read a book at a rock concert.
wangzhengbo Posted January 11, 2014 Author Posted January 11, 2014 I agree. However, as I mentioned, I think the fact that the methods are static factors in as well. Because as you can see, I initialize one object and access it from more than one thread in my later example. I add a simple demo, see below: expandcollapse popupimport java.io.File; import com.sun.jna.Library; import com.sun.jna.Native; import com.sun.jna.WString; public class WinWaitActiveTest { public static void main(String[] args) { int SW_SHOWNORMAL = 1; System.load(new File("AutoItX3.dll").getAbsolutePath()); AutoItX autoItX = (AutoItX) Native.loadLibrary("AutoItX3", AutoItX.class); /* Display and hide tooltip in one thread */ autoItX.AU3_ToolTip(new WString("Hello 2014."), 400, 200); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } autoItX.AU3_ToolTip(null, 400, 200); /* Call WinWaitActive in another thread */ Thread t = new Thread(new Runnable() { @Override public void run() { AutoItX autoItX = (AutoItX) Native.loadLibrary("AutoItX3", AutoItX.class); System.out.println("#1"); autoItX.AU3_WinWaitActive(new WString("[CLASS:Notepad]"), new WString("")); System.out.println("#2"); autoItX.AU3_WinWaitActive(new WString("无标题 - 记事本"), new WString("")); System.out.println("#3"); } }); t.start(); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } autoItX.AU3_Run(new WString("notepad.exe"), null, SW_SHOWNORMAL); } protected static interface AutoItX extends Library { public int AU3_Run(final WString fileName, final WString workingDir, final Integer showFlag); public void AU3_ToolTip(final WString text, final Integer x, final Integer y); public int AU3_WinWaitActive(final WString title, final WString text); } } You can download WinWaitActiveBug.zip, and import it into eclipse. In the main thread, i called tooltip, and in another thread i called winWaitActive("[CLASS:Notepad]") and winWaitActive("无标题 - 记事本"). The first call of winWaitActive will return but the second is not. If I remove the tooltip call, winWaitActive("无标题 - 记事本") will return too. If you want to run the example, you must change the notepad title from "无标题 - 记事本" to "Untitled - Notepad" in the WinWaitActiveTest class.WinWaitActiveBug.zip
Richard Robertson Posted January 11, 2014 Posted January 11, 2014 Just because it works in one situation doesn't mean it always will. I'm telling you ActiveX is meant to be run in a single thread and there's no way to fix this. Methods being static doesn't mean they are thread safe.
mrider Posted January 14, 2014 Posted January 14, 2014 wangzhengbo: I don't know why the code I first tried (which uses Jacob) works. I've tried a number of variations on a theme using JNI directly as you have, and it fails as soon as I introduce a thread. Take a look at this latest bit where the code couldn't be much more thread safe on the Java side. As you can see, it still fails to see Notepad by name, it only sees it by class. You might want to dig through Jacob's source to see what they do (see my first post). I have little doubt that it's possible to correct this on the AutoItX side, but as Richard Robertson has mentioned several times, AutoItX does not support threads, so it's unlikely the AutoItX code will be altered. You'll just have to make do with keeping AutoItX all in the same thread. I haven't tested what happens if you spawn a thread and initialize the dll inside that. It may be that AutoItX will work as long as everything is in the same thread, or it may be that it has all be the main thread and no other. I don't know. Sorry. expandcollapse popupimport java.io.File; import com.sun.jna.Library; import com.sun.jna.Native; import com.sun.jna.WString; public class WinWaitActiveTest implements Runnable { private static final int SW_SHOWNORMAL = 1; private final AutoItX aux; private final WString notepad = new WString("Untitled - Notepad"); private final WString cnotepad = new WString("[CLASS:Notepad]"); private WinWaitActiveTest() { System.load(new File("AutoItX3.dll").getAbsolutePath()); aux = (AutoItX)Native.loadLibrary("AutoItX3", AutoItX.class); } public synchronized void run() { //this.waitFor(notepad, new WString("")); // <- FAILS this.waitFor(cnotepad, new WString("")); // <- WORKS } private void waitFor(final WString title, final WString text) { System.out.println("Waiting for " + title); aux.AU3_WinWaitActive(title, text); System.out.println("Found " + title); } public static void main(String[] args) { WinWaitActiveTest wat = new WinWaitActiveTest(); wat.aux.AU3_ToolTip(new WString("Hello 2014."), 400, 200); try { Thread.sleep(2000); } catch (InterruptedException ignored) {} wat.aux.AU3_ToolTip(null, 400, 200); Thread t = new Thread(wat); t.start(); try { Thread.sleep(2000); } catch (InterruptedException ignored) {} wat.aux.AU3_Run(new WString("notepad.exe"), null, SW_SHOWNORMAL); } protected static interface AutoItX extends Library { public int AU3_Run(final WString fileName, final WString workingDir, final Integer showFlag); public void AU3_ToolTip(final WString text, final Integer x, final Integer y); public int AU3_WinWaitActive(final WString title, final WString text); } } How's my riding? Dial 1-800-Wait-There Trying to use a computer with McAfee installed is like trying to read a book at a rock concert.
Richard Robertson Posted January 18, 2014 Posted January 18, 2014 It's not just AutoItX, it's every COM object. They are single threaded by design.
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now