Added more exception handling in uiabridge, fixing Keyboard hook stability

uiabridge was having issues with getting ValueProperty from the cached
values. uiabridge was throwing exceptions if it couldn't find a missing
HWND handle.  Fixing keyboard hook to last longer.
This commit is contained in:
Edward Jakubowski
2014-05-14 08:17:58 -04:00
parent dcd8026204
commit 33522694e4
6 changed files with 76 additions and 19 deletions

Binary file not shown.

Binary file not shown.

View File

@@ -67,7 +67,9 @@ void AutomationBridge::initializeCache(System::String ^cachedProperties)
if (cachedPropStr->Contains(L"ValueProperty")) //special property not in the root property list if (cachedPropStr->Contains(L"ValueProperty")) //special property not in the root property list
{ {
cacheList->Add(ValuePattern::ValueProperty); cacheList->Add(ValuePattern::ValueProperty);
cacheRequest->Add(AutomationElement::IsValuePatternAvailableProperty);
cacheRequest->Add(ValuePattern::ValueProperty); cacheRequest->Add(ValuePattern::ValueProperty);
cacheRequest->Add(ValuePattern::Pattern);
} }
for each(AutomationProperty ^ap in rootProperties) //loop through all supported Properties for a child for each(AutomationProperty ^ap in rootProperties) //loop through all supported Properties for a child
{ {
@@ -109,8 +111,8 @@ Boolean AutomationBridge::isElementFiltered(System::Windows::Automation::Automat
int filterMatchCount = 0; int filterMatchCount = 0;
if (enumFilters->Count == 0) if (enumFilters->Count == 0)
return result; return result;
array<AutomationProperty^> ^aps = cachedRootProperties;//element->GetSupportedProperties(); //array<AutomationProperty^> ^aps = cachedRootProperties;//element->GetSupportedProperties();
for each(AutomationProperty ^ap in aps) //loop through all supported Properties for a child for each(AutomationProperty ^ap in cachedRootProperties) //loop through all supported Properties for a child
{ {
System::String ^currentPropertyStr = L""; //current property values System::String ^currentPropertyStr = L""; //current property values
System::String ^shortPropName = L" null "; System::String ^shortPropName = L" null ";
@@ -252,8 +254,16 @@ array<System::String ^> ^ AutomationBridge::enumWindowInfo(System::String ^prope
array<System::String ^> ^ AutomationBridge::enumWindowInfo(System::IntPtr windowHandle, System::String ^properties) array<System::String ^> ^ AutomationBridge::enumWindowInfo(System::IntPtr windowHandle, System::String ^properties)
{ {
AutomationElement ^element = AutomationElement::FromHandle(windowHandle);
List<System::String ^> ^winInfoList = gcnew List<System::String ^>(); List<System::String ^> ^winInfoList = gcnew List<System::String ^>();
AutomationElement ^element = nullptr;
try {
element = AutomationElement::FromHandle(windowHandle);
} catch (Exception ^ex) {
output(ex, "");
return winInfoList->ToArray();
}
if (element == nullptr)
return winInfoList->ToArray();
if (!isElementFiltered(element)) //test parent should be filtered if (!isElementFiltered(element)) //test parent should be filtered
winInfoList->Add(getWindowInfo(element, properties, nullptr)); winInfoList->Add(getWindowInfo(element, properties, nullptr));
winInfoList->AddRange(enumWindowInfo(element, properties)); winInfoList->AddRange(enumWindowInfo(element, properties));
@@ -307,7 +317,7 @@ array<System::String ^> ^ AutomationBridge::enumWindowInfo(AutomationElement ^pa
//currentElement-> //currentElement->
} catch (Exception ^ex) } catch (Exception ^ex)
{ {
System::Console::WriteLine("Exception: {0} {1}", ex->Message, ex->StackTrace); output(ex, "");
} }
currentElement = tw->GetNextSibling(currentElement, cacheRequest); currentElement = tw->GetNextSibling(currentElement, cacheRequest);
} }
@@ -342,7 +352,7 @@ System::String ^ AutomationBridge::getWindowInfo(AutomationElement ^element, Sys
System::String ^delim = L","; System::String ^delim = L",";
array<System::String ^> ^propSpltArray = properties->Split(delim->ToCharArray()); array<System::String ^> ^propSpltArray = properties->Split(delim->ToCharArray());
System::Int32 count = 0; System::Int32 count = 0;
array<AutomationProperty^> ^aps = cachedRootProperties;//element->GetSupportedProperties(); //array<AutomationProperty^> ^aps = cachedRootProperties;//element->GetSupportedProperties();
array<System::String ^> ^propValues = gcnew array<System::String ^>(propSpltArray->Length);//keep order array<System::String ^> ^propValues = gcnew array<System::String ^>(propSpltArray->Length);//keep order
System::String ^wildcardProperties = L""; System::String ^wildcardProperties = L"";
if (wildcardEnabled) { if (wildcardEnabled) {
@@ -357,7 +367,7 @@ System::String ^ AutomationBridge::getWindowInfo(AutomationElement ^element, Sys
propValues[i] = parentRuntimeId; propValues[i] = parentRuntimeId;
} }
} }
for each(AutomationProperty ^ap in aps) //loop through all supported Properties for a child for each(AutomationProperty ^ap in cachedRootProperties) //loop through all supported Properties for a child
{ {
propertyNameErrorCheck = ap->ProgrammaticName;//debug purposes propertyNameErrorCheck = ap->ProgrammaticName;//debug purposes
System::String ^currentPropertyStr = L""; //current property values System::String ^currentPropertyStr = L""; //current property values
@@ -369,7 +379,15 @@ System::String ^ AutomationBridge::getWindowInfo(AutomationElement ^element, Sys
{ {
//System::Console::WriteLine("shortPropName: {0}", shortPropName); //System::Console::WriteLine("shortPropName: {0}", shortPropName);
//System::Object ^currentVal = element->GetCurrentPropertyValue(ap); //System::Object ^currentVal = element->GetCurrentPropertyValue(ap);
System::Object ^currentVal = element->GetCachedPropertyValue(ap); System::Object ^currentVal = nullptr;
if (shortPropName->Equals("ValueProperty")) //check if Value Pattern is an Available Property
{
if (((Boolean)element->GetCurrentPropertyValue(element->IsValuePatternAvailableProperty)) == false)
continue;
else
currentVal = element->GetCurrentPropertyValue(ap); //cached pattern was having issues;
}
currentVal = element->GetCachedPropertyValue(ap);
if (currentVal == nullptr) if (currentVal == nullptr)
continue; continue;
if (ap->ProgrammaticName->Equals(L"AutomationElementIdentifiers.RuntimeIdProperty")) if (ap->ProgrammaticName->Equals(L"AutomationElementIdentifiers.RuntimeIdProperty"))
@@ -409,7 +427,7 @@ System::String ^ AutomationBridge::getWindowInfo(AutomationElement ^element, Sys
resultProperties += wildcardProperties; resultProperties += wildcardProperties;
} catch (Exception ^ex) //when some elements close during enumeration it might cause valid exceptions } catch (Exception ^ex) //when some elements close during enumeration it might cause valid exceptions
{ {
System::Console::WriteLine("Exception ({2}): {0} {1}", ex->Message, ex->StackTrace, propertyNameErrorCheck); output(ex, " getWindowInfo on " + propertyNameErrorCheck + ", results: " + resultProperties);
} }
return resultProperties; return resultProperties;
@@ -418,12 +436,22 @@ System::String ^ AutomationBridge::getWindowInfo(AutomationElement ^element, Sys
System::String ^ AutomationBridge::getWindowInfo(System::Int32 x, System::Int32 y, System::String ^properties) System::String ^ AutomationBridge::getWindowInfo(System::Int32 x, System::Int32 y, System::String ^properties)
{ {
AutomationElement ^element = AutomationElement::FromPoint(System::Windows::Point(x, y)); AutomationElement ^element = AutomationElement::FromPoint(System::Windows::Point(x, y));
if (element == nullptr)
return "";
return getWindowInfo(element, properties, nullptr); return getWindowInfo(element, properties, nullptr);
} }
System::String ^ AutomationBridge::getWindowInfo(System::IntPtr windowHandle, System::String ^properties) System::String ^ AutomationBridge::getWindowInfo(System::IntPtr windowHandle, System::String ^properties)
{ {
AutomationElement ^element = AutomationElement::FromHandle(windowHandle); AutomationElement ^element = nullptr;
try {
AutomationElement ^element = AutomationElement::FromHandle(windowHandle);
} catch (Exception ^ex) {
output(ex, "");
return "";
}
if (element == nullptr)
return "";
return getWindowInfo(element, properties, nullptr); return getWindowInfo(element, properties, nullptr);
} }
@@ -439,3 +467,8 @@ System::String ^ AutomationBridge::getWindowInfo(System::String ^runtimeIdStr, S
return ""; return "";
//return getWindowInfo(element, properties); //return getWindowInfo(element, properties);
} }
void AutomationBridge::output(Exception ^ex, System::String ^message)
{
System::Console::WriteLine("Exception ({0}): {1} \n{2}", message, ex->Message, ex->StackTrace);
}

View File

@@ -40,6 +40,7 @@ namespace uiabridge {
static System::String ^DEFAULT_CACHED_PROPS = L"RuntimeIdProperty,ParentRuntimeIdProperty,NativeWindowHandleProperty,ProcessIdProperty,FrameworkIdProperty,LocalizedControlTypeProperty,ControlTypeProperty,ClassNameProperty,NameProperty,BoundingRectangleProperty,ValueProperty"; static System::String ^DEFAULT_CACHED_PROPS = L"RuntimeIdProperty,ParentRuntimeIdProperty,NativeWindowHandleProperty,ProcessIdProperty,FrameworkIdProperty,LocalizedControlTypeProperty,ControlTypeProperty,ClassNameProperty,NameProperty,BoundingRectangleProperty,ValueProperty";
private: private:
void initializeCache(System::String ^cachedProperties); void initializeCache(System::String ^cachedProperties);
void output(Exception ^ex, System::String ^message);
Dictionary<System::String ^, System::String ^> ^enumFilters; Dictionary<System::String ^, System::String ^> ^enumFilters;
void AutomationBridge::processFilterModifier(Boolean filtered, Boolean modifierChanged, List<System::String ^> ^filterModifierList); void AutomationBridge::processFilterModifier(Boolean filtered, Boolean modifierChanged, List<System::String ^> ^filterModifierList);
CacheRequest ^cacheRequest; CacheRequest ^cacheRequest;

View File

@@ -14,6 +14,7 @@ import java.util.Collections;
import java.util.List; import java.util.List;
import com.sun.jna.*; import com.sun.jna.*;
import com.sun.jna.platform.win32.User32;
import com.sun.jna.platform.win32.WinUser.*; import com.sun.jna.platform.win32.WinUser.*;
import com.sun.jna.platform.win32.WinDef.*; import com.sun.jna.platform.win32.WinDef.*;
import com.sun.jna.win32.W32APIOptions; import com.sun.jna.win32.W32APIOptions;
@@ -62,8 +63,9 @@ public class KeyboardHook implements Runnable{
public static LowLevelKeyboardProc lpfn; public static LowLevelKeyboardProc lpfn;
public static volatile boolean quit = false; public static volatile boolean quit = false;
public interface User32 extends W32APIOptions {
User32 instance = (User32) Native.loadLibrary("user32", User32.class, DEFAULT_OPTIONS); public interface User32Ex extends W32APIOptions {
User32Ex instance = (User32Ex) Native.loadLibrary("user32", User32Ex.class, DEFAULT_OPTIONS);
LRESULT LowLevelKeyboardProc(int nCode,WPARAM wParam,LPARAM lParam); LRESULT LowLevelKeyboardProc(int nCode,WPARAM wParam,LPARAM lParam);
HHOOK SetWindowsHookEx(int idHook, HOOKPROC lpfn, HMODULE hMod, int dwThreadId); HHOOK SetWindowsHookEx(int idHook, HOOKPROC lpfn, HMODULE hMod, int dwThreadId);
@@ -72,11 +74,13 @@ public class KeyboardHook implements Runnable{
boolean PeekMessage(MSG lpMsg, HWND hWnd, int wMsgFilterMin, int wMsgFilterMax, int wRemoveMsg); boolean PeekMessage(MSG lpMsg, HWND hWnd, int wMsgFilterMin, int wMsgFilterMax, int wRemoveMsg);
boolean UnhookWindowsHookEx(HHOOK idHook); boolean UnhookWindowsHookEx(HHOOK idHook);
short GetKeyState(int nVirtKey); short GetKeyState(int nVirtKey);
short GetAsyncKeyState(int nVirtKey);
//public static interface HOOKPROC extends StdCallCallback { //public static interface HOOKPROC extends StdCallCallback {
// LRESULT callback(int nCode, WPARAM wParam, KBDLLHOOKSTRUCT lParam); // LRESULT callback(int nCode, WPARAM wParam, KBDLLHOOKSTRUCT lParam);
//} //}
} }
public interface Kernel32 extends W32APIOptions { public interface Kernel32 extends W32APIOptions {
Kernel32 instance = (Kernel32) Native.loadLibrary("kernel32", Kernel32.class, DEFAULT_OPTIONS); Kernel32 instance = (Kernel32) Native.loadLibrary("kernel32", Kernel32.class, DEFAULT_OPTIONS);
@@ -97,29 +101,48 @@ public class KeyboardHook implements Runnable{
events.keyPressed(target); events.keyPressed(target);
//if (lParam.vkCode == 87) //w //if (lParam.vkCode == 87) //w
// quit = true; // quit = true;
return User32.instance.CallNextHookEx(hHook, nCode, wParam, lParam.getPointer()); return User32.INSTANCE.CallNextHookEx(hHook, nCode, wParam, lParam.getPointer());
} }
}; };
hHook = User32.instance.SetWindowsHookEx(WH_KEYBOARD_LL, lpfn, hMod, 0); hHook = User32.INSTANCE.SetWindowsHookEx(WH_KEYBOARD_LL, lpfn, hMod, 0);
if (hHook == null) if (hHook == null)
return; return;
MSG msg = new MSG(); MSG msg = new MSG();
int cnt = 0;
try { try {
while (!quit) { while (!quit) {
User32.instance.PeekMessage(msg, null, 0, 0, 0); User32.INSTANCE.PeekMessage(msg, null, 0, 0, 1);
Thread.sleep(10); Thread.sleep(10);
++cnt;
if (cnt > 500)
{
cnt = 0;
//System.out.println("heartbeat test");
}
} }
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
/*
while (!quit) {
// hex arguments: WM_KEYFIRST, WM_KEYLAST
int result = User32.INSTANCE.GetMessage(msg, null, 0x100, 0x109);
if (result == -1) {
break;
} else {
User32.INSTANCE.TranslateMessage(msg);
User32.INSTANCE.DispatchMessage(msg);
}
}*/
//System.out.println("message loop stopped");
} }
//unhook the Global Windows Keyboard hook //unhook the Global Windows Keyboard hook
public void unhook() { public void unhook() {
if (hHook == null) if (hHook == null)
return; return;
if (!User32.instance.UnhookWindowsHookEx(hHook)) if (!User32.INSTANCE.UnhookWindowsHookEx(hHook))
System.out.println("Failed to unhook"); System.out.println("Failed to unhook");
//System.out.println("Unhooked"); //System.out.println("Unhooked");
hHook = null; hHook = null;
@@ -136,9 +159,9 @@ public class KeyboardHook implements Runnable{
for (TargetKeyPress tkp : KeyboardHook.targetList) { for (TargetKeyPress tkp : KeyboardHook.targetList) {
if (tkp.targetKeyCode != keyCode) if (tkp.targetKeyCode != keyCode)
continue; continue;
if (!tkp.withShift || ((User32.instance.GetKeyState(VK_SHIFT) & 0x8000) != 0)) { if (!tkp.withShift || ((User32Ex.instance.GetKeyState(VK_SHIFT) & 0x8000) != 0)) {
if (!tkp.withCtrl || ((User32.instance.GetKeyState(VK_CONTROL) & 0x8000) != 0)) { if (!tkp.withCtrl || ((User32Ex.instance.GetKeyState(VK_CONTROL) & 0x8000) != 0)) {
if (!tkp.withAlt || ((User32.instance.GetKeyState(VK_MENU) & 0x8000) != 0)) { if (!tkp.withAlt || ((User32Ex.instance.GetKeyState(VK_MENU) & 0x8000) != 0)) {
return tkp; return tkp;
} }
} }

View File

@@ -72,7 +72,7 @@ public class SynthuseDlg extends JFrame {
/** /**
* *
*/ */
public static String VERSION_STR = "1.1.7"; public static String VERSION_STR = "1.1.8";
public static String RES_STR_MAIN_ICON = "/org/synthuse/img/gnome-robots.png"; public static String RES_STR_MAIN_ICON = "/org/synthuse/img/gnome-robots.png";
public static String RES_STR_REFRESH_IMG = "/org/synthuse/img/rapidsvn.png"; public static String RES_STR_REFRESH_IMG = "/org/synthuse/img/rapidsvn.png";