/*
* Copyright 2014, Synthuse.org
* Released under the Apache Version 2.0 License.
*
* last modified by ejakubowski
*/
package org.synthuse;
import java.awt.Point;
import java.awt.Rectangle;
import java.util.LinkedHashMap;
import java.util.Map;
import org.synthuse.Api.*;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.WinDef.HMENU;
import com.sun.jna.platform.win32.WinDef.HWND;
import com.sun.jna.platform.win32.WinDef.LPARAM;
import com.sun.jna.platform.win32.WinDef.LRESULT;
import com.sun.jna.platform.win32.WinDef.RECT;
import com.sun.jna.platform.win32.WinDef.WPARAM;
import com.sun.jna.platform.win32.WinNT.HANDLE;
import com.sun.jna.ptr.PointerByReference;
public class WindowInfo {
public static String UIA_PROPERTY_LIST = "RuntimeIdProperty,ParentRuntimeIdProperty,ProcessIdProperty,FrameworkIdProperty,LocalizedControlTypeProperty,ClassNameProperty,NameProperty,ValueProperty";
public static String UIA_PROPERTY_LIST_ADV = "RuntimeIdProperty,ParentRuntimeIdProperty,ProcessIdProperty,FrameworkIdProperty,LocalizedControlTypeProperty,ClassNameProperty,NameProperty,ValueProperty,BoundingRectangleProperty";
public static String UIA_RUNTIME_ID = "RuntimeIdProperty";
public static String UIA_BOUNDING_RECT = "BoundingRectangleProperty";
public static int MAX_TEXT_SIZE = 200;
public HWND hwnd;
public String hwndStr = "";
public HWND parent = null;
public String parentStr = "";
public RECT rect;
public String text;
public String value;
public String controlType = "";
public String className = "";
public boolean isChild = false;
public String processName = "";
public long pid = 0;
public Object xmlObj = null;
public String framework = "win32";//default as win32
public String runtimeId = "";
public int menus = 0;
public HMENU menu = null;
public boolean useUiaBridge = false;
public boolean is64bit = false;
public Map<String, String> extra = null;
//Default Win32 support
public WindowInfo(HWND hWnd, boolean isChild) {
this.framework = "win32";
byte[] buffer = new byte[1024];
User32Ex.instance.GetWindowTextA(hWnd, buffer, buffer.length);
text = Native.toString(buffer);
if (text.isEmpty())
text = new Api().sendWmGetText(hWnd);
//if (text.isEmpty()) {
//System.out.println("getting toolbar text");
//}
if (text.length() > MAX_TEXT_SIZE) //if text is too large it will slow down xml display
text = text.substring(0, MAX_TEXT_SIZE);
//Get item count depending on what type of control it is
LRESULT tbCount = Api.User32Ex.instance.SendMessage(hWnd, Api.TB_BUTTONCOUNT, new WPARAM(0), new LPARAM(0));
if (tbCount.intValue() > 0) { // toolbar button count
//System.out.println("TB_BUTTONCOUNT: " + tbCount.intValue());
if (extra == null)
extra = new LinkedHashMap<String, String>();
extra.put("tbCount", tbCount.intValue() + "");
//Api.User32.instance.SendMessageA(hWnd, Api.TB_GETTOOLTIPS, 0, buffer);
//text = Native.toString(buffer);
}
LRESULT lvCount = Api.User32Ex.instance.SendMessage(hWnd, Api.LVM_GETITEMCOUNT, new WPARAM(0), new LPARAM(0));
if (lvCount.intValue() > 0) { // listview item count
if (extra == null)
extra = new LinkedHashMap<String, String>();
extra.put("lvCount", lvCount.intValue() + "");
}
LRESULT lbCount = Api.User32Ex.instance.SendMessage(hWnd, Api.LB_GETCOUNT, new WPARAM(0), new LPARAM(0));
if (lbCount.intValue() > 0) { // listbox item count
if (extra == null)
extra = new LinkedHashMap<String, String>();
extra.put("lbCount", lbCount.intValue() + "");
}
LRESULT cbCount = Api.User32Ex.instance.SendMessage(hWnd, Api.CB_GETCOUNT, new WPARAM(0), new LPARAM(0));
if (cbCount.intValue() > 0) { // listbox item count
if (extra == null)
extra = new LinkedHashMap<String, String>();
extra.put("cbCount", cbCount.intValue() + "");
}
LRESULT tvCount = Api.User32Ex.instance.SendMessage(hWnd, Api.TVM_GETCOUNT, new WPARAM(0), new LPARAM(0));
if (tvCount.intValue() > 0) { //treeview node count
if (extra == null)
extra = new LinkedHashMap<String, String>();
extra.put("tvCount", tvCount.intValue() + "");
}
char[] buffer2 = new char[1026];
User32Ex.instance.GetClassName(hWnd, buffer2, 1026);
className = Native.toString(buffer2);
//check if window has a menu
HMENU hmenu = null;
try {
hmenu = Api.User32Ex.instance.GetMenu(hWnd);
} catch(Exception ex) {
//ex.printStackTrace();
}
if (hmenu != null) { //menu item count
int menuCount = Api.User32Ex.instance.GetMenuItemCount(hmenu);
if (menuCount > 0) {
this.menus = menuCount;
this.menu = hmenu;
}
}
else // if (className.equals("#32768")) //check if its a popup menu window
{
//LRESULT result = Api.User32.instance.PostMessage(hWnd, Api.MN_GETHMENU, new WPARAM(0), new LPARAM(0));
LRESULT result = Api.User32Ex.instance.SendMessage(hWnd, Api.MN_GETHMENU, new WPARAM(0), new LPARAM(0));
if (result.longValue() != 1)
{
//System.out.println("MN_GETHMENU: " + result.longValue());
hmenu = new HMENU(new Pointer(result.longValue()));
int menuCount = Api.User32Ex.instance.GetMenuItemCount(hmenu);
if (menuCount > 0)
{
//System.out.println("Popup Win: " + menuCount);
this.menus = menuCount;
this.menu = hmenu;
}
}
}
rect = new RECT();
User32Ex.instance.GetWindowRect(hWnd, rect);
this.isChild = isChild;
if (isChild) {
parent = User32Ex.instance.GetParent(hWnd);
parentStr = Api.GetHandleAsString(parent);
// test to see if uiaBridge should be used on this child
if (this.className.startsWith("HwndWrapper") || this.className.startsWith("MicrosoftSilverlight") || this.className.startsWith("GeckoPluginWindow"))
useUiaBridge = true;
}
else {
PointerByReference pointer = new PointerByReference();
User32Ex.instance.GetWindowThreadProcessId(hWnd, pointer);
pid = pointer.getPointer().getInt(0);
getProcessInfo();
//test to see if uiaBridge should be used on this parent
if (this.className.startsWith("HwndWrapper") || this.className.startsWith("WindowsForms"))
useUiaBridge = true;
}
this.hwnd = hWnd;
hwndStr = Api.GetHandleAsString(hWnd);
if (this.hwndStr == null)
this.hwndStr = "";
}
//support for WPF, Silverlight, WinForms
public WindowInfo(String enumProperties, boolean isChild) {
//WPF_PROPERTY_LIST = "RuntimeIdProperty,ParentRuntimeIdProperty,ProcessIdProperty,FrameworkIdProperty,LocalizedControlTypeProperty,ClassNameProperty,NameProperty,ValueProperty";
String[] spltProperties = enumProperties.split(",");
this.isChild = isChild;
this.useUiaBridge = true;
if (SynthuseDlg.config.isFilterUiaDisabled()) { //use wildcard mode
extra = new LinkedHashMap<String, String>();
for(String prop: spltProperties) {
String[] propertyNameAndValue = prop.split(":", 2);
if (propertyNameAndValue.length < 2)
continue;
if (propertyNameAndValue[0].equals("RuntimeIdProperty"))
this.runtimeId = propertyNameAndValue[1];
else if (propertyNameAndValue[0].equals("ParentRuntimeIdProperty"))
this.parentStr = propertyNameAndValue[1];
else if (propertyNameAndValue[0].equals("ProcessIdProperty"))
this.pid = Long.parseLong(propertyNameAndValue[1]);
else if (propertyNameAndValue[0].equals("FrameworkIdProperty"))
this.framework = propertyNameAndValue[1];
else if (propertyNameAndValue[0].equals("LocalizedControlTypeProperty"))
this.controlType = propertyNameAndValue[1];
else if (propertyNameAndValue[0].equals("ClassNameProperty"))
this.className = propertyNameAndValue[1];
else if (propertyNameAndValue[0].equals("NameProperty"))
this.text = propertyNameAndValue[1];
else if (propertyNameAndValue[0].equals("ValueProperty"))
this.value = propertyNameAndValue[1];
else{
extra.put(propertyNameAndValue[0], propertyNameAndValue[1]);
}
}
this.hwndStr = this.runtimeId;
if (text != null)
if (text.length() > MAX_TEXT_SIZE)
text = text.substring(0, MAX_TEXT_SIZE);
if (this.hwndStr == null)
this.hwndStr = "";
//if (this.framework == null)
// this.framework = "na";
if(this.controlType.equals("window"))
this.isChild = false;
return;
}
// non-wildcard mode
if (spltProperties.length > 0)
this.runtimeId = spltProperties[0];
this.hwndStr = this.runtimeId;
if (spltProperties.length > 1 && isChild)
this.parentStr = spltProperties[1];
if (spltProperties.length > 2)
this.pid = Long.parseLong(spltProperties[2]);
if (spltProperties.length > 3)
this.framework = spltProperties[3];
if (spltProperties.length > 4)
this.controlType = UiaBridge.replaceEscapedCodes(spltProperties[4]);
if (spltProperties.length > 5)
this.className = UiaBridge.replaceEscapedCodes(spltProperties[5]);
if (spltProperties.length > 6)
this.text = UiaBridge.replaceEscapedCodes(spltProperties[6]);
if (spltProperties.length > 7)
this.value = UiaBridge.replaceEscapedCodes(spltProperties[7]);
if (this.className == "")
this.className = this.controlType;
if (text != null)
if (text.length() > MAX_TEXT_SIZE)
text = text.substring(0, MAX_TEXT_SIZE);
if (value != null)
if (value.length() > MAX_TEXT_SIZE)
value = value.substring(0, MAX_TEXT_SIZE);
if (this.hwndStr == null)
this.hwndStr = "";
getProcessInfo();
if(this.controlType.equals("window"))
this.isChild = false;
/*
this.rect = new RECT();
try {
String rectStr = wb.getProperty("BoundingRectangleProperty", runtimeId);
String[] rectSplt = rectStr.split(",");
this.rect.right = Integer.parseInt(rectSplt[0]);
this.rect.bottom = Integer.parseInt(rectSplt[1]);
this.rect.left = Integer.parseInt(rectSplt[2]);
this.rect.top = Integer.parseInt(rectSplt[3]);
} catch (Exception e) {
e.printStackTrace();
}
*/
}
private void getProcessInfo()
{
if (pid == 0)
return;
char[] buffer = new char[1026];
Pointer process = Kernel32Ex.instance.OpenProcess(Api.PROCESS_QUERY_INFORMATION | Api.PROCESS_VM_READ, false, new Pointer(pid));
PsapiEx.instance.GetModuleBaseNameW(process, null, buffer, 512);
processName = Native.toString(buffer);
Kernel32Ex.instance.CloseHandle(new HANDLE(process));
is64bit = Api.isProcess64bit((int)pid);
}
public static String getRuntimeIdFromProperties(String enumProperties)
{
String[] spltProperties = enumProperties.split(",");
if (spltProperties.length > 0)
return spltProperties[0];
return "";
}
public static String getFrameworkFromProperties(String enumProperties)
{
String[] spltProperties = enumProperties.split(",");
if (spltProperties.length > 3)
return spltProperties[3];
return "";
}
public static Point findOffset(Rectangle rect, int xPos, int yPos)
{
Point offset = new Point();
int x = ((rect.width) /2) + rect.x;
int y = ((rect.height) /2) + rect.y;
offset.x = xPos - x;
offset.y = yPos - y;
return offset;
}
public String toString() {
return String.format("%s \"%s\" [%s] (%s) {%s}", framework, text, className, controlType, hwndStr);
}
}