/* * Copyright 2014, Synthuse.org * Released under the Apache Version 2.0 License. * * last modified by ejakubowski7@gmail.com */ package org.synthuse; import java.awt.Point; import java.awt.Rectangle; import java.io.*; import javax.swing.JOptionPane; public class UiaBridge { public static String CACHED_PROPERTY_LIST = "RuntimeIdProperty,ParentRuntimeIdProperty,ProcessIdProperty,FrameworkIdProperty,LocalizedControlTypeProperty,ClassNameProperty,NameProperty,ValueProperty,BoundingRectangleProperty"; public static final String FRAMEWORK_ID_WPF = "WPF"; public static final String FRAMEWORK_ID_SILVER = "Silverlight"; public static final String FRAMEWORK_ID_WINFORM = "WinForm"; public static final String FRAMEWORK_ID_WIN = "Win32"; static { String loadFailedMsg = "Failed to load uiabridge library, make sure you have .Net 4.0 already installed.\n"; if (!Api.isDotNet4Installed()) { //if .net 4.0 isn't installed don't use uiabridge SynthuseDlg.config.disableUiaBridge = "true"; JOptionPane.showMessageDialog(null, loadFailedMsg , "Native Library Load Error", JOptionPane.ERROR_MESSAGE); } if (!SynthuseDlg.config.isUiaBridgeDisabled()) { //System.out.println("SynthuseDlg.config.disableUiaBridge: " + SynthuseDlg.config.disableUiaBridge); String archDataModel = System.getProperty("sun.arch.data.model");//32 or 64 bit try { //System.loadLibrary("native/WpfBridge" + archDataModel); // WpfBridge32.dll (Windows) or WpfBridge32.so (Unixes) loadNativeLibraryFromJar("/uiabridge" + archDataModel + ".dll"); } catch (Exception ex) { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); ex.printStackTrace(pw); System.out.println(sw.toString()); JOptionPane.showMessageDialog(null, loadFailedMsg + sw.toString() , "Native Library Load Error", JOptionPane.ERROR_MESSAGE); SynthuseDlg.config.disableUiaBridge = "true"; } } } public static void loadNativeLibraryFromJar(String path) { // Obtain filename from path String[] parts = path.split("/"); String filename = (parts.length > 1) ? parts[parts.length - 1] : null; // Split filename to prexif and suffix (extension) String prefix = ""; String suffix = null; if (filename != null) { parts = filename.split("\\.", 2); prefix = parts[0]; suffix = (parts.length > 1) ? "."+parts[parts.length - 1] : null; } File temp = null; try { // Prepare temporary file temp = File.createTempFile(prefix, suffix); temp.deleteOnExit(); } catch(Exception e) { e.printStackTrace(); } if (!temp.exists()) { //some reason the temp file wasn't create so abort System.out.println("File " + temp.getAbsolutePath() + " does not exist."); return; } // Prepare buffer for data copying byte[] buffer = new byte[1024]; int readBytes; // Open and check input stream InputStream is = UiaBridge.class.getResourceAsStream(path); if (is == null) { //check if valid System.out.println("File " + path + " was not found inside JAR."); return; } // Open output stream and copy data between source file in JAR and the temporary file OutputStream os = null; try { os = new FileOutputStream(temp); while ((readBytes = is.read(buffer)) != -1) { os.write(buffer, 0, readBytes); } os.close(); is.close(); } catch(Exception e) { e.printStackTrace(); } // Finally, load the library System.load(temp.getAbsolutePath()); } public UiaBridge () { if (!SynthuseDlg.config.isUiaBridgeDisabled()) initialize(CACHED_PROPERTY_LIST); } public native void initialize(String properties); public native void shutdown(); public native void useCachedRequests(boolean cacheRequestsFlg); public native int addEnumFilter(String propertyName, String propertyValue); public native void clearEnumFilters(); public native String[] enumWindowInfo(String properties); public native String[] enumWindowInfo(int windowHandle, String properties); //native String[] enumWindowInfo(AutomationElement ^element, String properties); //native String[] enumWindowInfo(AutomationElement ^element, String properties, String[] filterModifierList); //native String getWindowInfo(AutomationElement ^element, String properties); public native String getWindowInfo(int x, int y, String properties); public native String getWindowInfo(int windowHandle, String properties); public native String getWindowInfo(String runtimeId, String properties); /* public native void setFrameworkId(String propertyValue); //default is WPF, but also accepts Silverlight, Win32 public native void setTouchableOnly(boolean val); //default is true //Descendants will walk the full tree of windows, NOT just one level of children public native int countDescendantWindows(); public native int countDescendantWindows(String runtimeIdValue); public native int countChildrenWindows(); public native int countChildrenWindows(String runtimeIdValue); public String[] enumChildrenWindowIds(String runtimeIdValue); //if runtimeIdValue is null will start at desktop public native String[] enumDescendantWindowIds(String runtimeIdValue); //if runtimeIdValue is null will start at desktop public native String[] enumDescendantWindowIds(long processId); //In all the above Enumerate methods will return a list of Runtime Ids for all related windows. public native String[] enumDescendantWindowInfo(String runtimeIdValue, String properties); //returns properties comma separated public native String getRuntimeIdFromHandle(long windowHandle); public native String getRuntimeIdFromPoint(int x, int y); public native String getParentRuntimeId(String runtimeIdValue); public native String getProperty(String propertyName, String runtimeIdValue); public native String[] getProperties(String runtimeIdValue); public native String[] getPropertiesAndValues(String runtimeIdValue); */ public static String replaceEscapedCodes(String input) { //, is a comma , String result = input; result = result.replaceAll(",", ","); result = result.replaceAll("<", "<"); result = result.replaceAll(">", ">"); result = result.replaceAll("'", "'"); result = result.replaceAll(""", "\""); result = result.replaceAll("&", "&"); return result; } public Point getCenterOfElement(String runtimeIdValue) { Point p = new Point(); String boundaryProperty = getWindowInfo(runtimeIdValue, "BoundingRectangleProperty"); Rectangle rect = getBoundaryRect(boundaryProperty); p.x = ((rect.width) /2) + rect.x; p.y = ((rect.height) /2) + rect.y; return p; } //BoundingRectangleProperty is the last property listed in comma separated properties string public static Rectangle getBoundaryRect(String properties) { Rectangle rect = new Rectangle(); String[] propSplt = properties.split(","); if (propSplt.length > 0) { String[] boundarySplt = replaceEscapedCodes(propSplt[propSplt.length - 1]).split(","); if (boundarySplt.length == 4 ) { rect.x = Integer.parseInt(boundarySplt[0]); rect.y = Integer.parseInt(boundarySplt[1]); rect.width = Integer.parseInt(boundarySplt[2]); rect.height = Integer.parseInt(boundarySplt[3]); } } return rect; } }