diff --git a/.classpath b/.classpath index 3c497e1..a4a6148 100644 --- a/.classpath +++ b/.classpath @@ -1,7 +1,7 @@ - + diff --git a/build.xml b/build.xml index a4edace..2a69e30 100644 --- a/build.xml +++ b/build.xml @@ -58,7 +58,7 @@ - + @@ -69,7 +69,13 @@ - + + + + + + + + - \ No newline at end of file diff --git a/native/WpfBridge/WpfAutomation.cpp b/native/WpfBridge/WpfAutomation.cpp deleted file mode 100644 index f8e4a9f..0000000 --- a/native/WpfBridge/WpfAutomation.cpp +++ /dev/null @@ -1,351 +0,0 @@ -/* - * Copyright 2014, Synthuse.org - * Released under the Apache Version 2.0 License. - * - * last modified by ejakubowski7@gmail.com -*/ -#include "StdAfx.h" -#include "WpfAutomation.h" - -using namespace System; -using namespace System::Windows::Automation; - -WpfAutomation::WpfAutomation(void) -{ - this->frameworkId = WpfAutomation::DEFAULT_FRAMEWORK; - this->touchableOnly = true; -} - -void WpfAutomation::setFrameworkId(System::String ^propertyValue) -{ - this->frameworkId = propertyValue; -} - -void WpfAutomation::setTouchableOnly(System::Boolean val) -{ - this->touchableOnly = val; -} - -System::Windows::Automation::Condition ^ WpfAutomation::getSearchConditions() -{ - array ^cons = nullptr; - if (this->touchableOnly) - { - cons = gcnew array(3); - cons[0] = gcnew PropertyCondition(AutomationElement::FrameworkIdProperty, this->frameworkId);//is WPF framework - cons[1] = gcnew PropertyCondition(AutomationElement::IsEnabledProperty, true);//is enabled - cons[2] = gcnew PropertyCondition(AutomationElement::IsOffscreenProperty, false);// is off screen - } - else - { - cons = gcnew array(1); - cons[0] = gcnew PropertyCondition(AutomationElement::FrameworkIdProperty, this->frameworkId);//is WPF framework - } - System::Windows::Automation::Condition ^result = gcnew System::Windows::Automation::AndCondition(cons); - return result; -} - -array ^ WpfAutomation::convertRuntimeIdString(System::String ^runtimeIdValue) -{ - System::String ^delim = L"-"; - array ^idStrArray = runtimeIdValue->Split(delim->ToCharArray()); - array ^idArray = gcnew array(idStrArray->Length); - for(System::Int32 i = 0 ; i < idStrArray->Length ; i++) - { - idArray[i] = System::Int32::Parse(idStrArray[i]); - } - return idArray; -} - -AutomationElement ^ WpfAutomation::findAutomationElementById(System::String ^runtimeIdValue, System::Boolean unfiltered) -{ - if (runtimeIdValue == nullptr || runtimeIdValue->Equals(L"")) - return AutomationElement::RootElement; - array ^idArray = this->convertRuntimeIdString(runtimeIdValue); - if (unfiltered) - return AutomationElement::RootElement->FindFirst(TreeScope::Descendants, gcnew PropertyCondition(AutomationElement::RuntimeIdProperty, idArray)); - //Condition ^pcFramework = gcnew PropertyCondition(AutomationElement::FrameworkIdProperty, this->frameworkId); - Condition ^pcRunId = gcnew PropertyCondition(AutomationElement::RuntimeIdProperty, idArray); - Condition ^frameworkAndRuntimeId = gcnew AndCondition(getSearchConditions(), pcRunId); - return AutomationElement::RootElement->FindFirst(TreeScope::Descendants, frameworkAndRuntimeId); -} - -array ^ WpfAutomation::getRuntimeIdsFromCollection(System::Windows::Automation::AutomationElementCollection ^collection) -{ - array ^idStrArray = gcnew array(collection->Count); - System::Int32 count = 0; - for each(AutomationElement ^child in collection) - { - idStrArray[count] = getRuntimeIdFromElement(child); - ++count; - } - return idStrArray; -} - -System::String ^ WpfAutomation::getRuntimeIdFromElement(System::Windows::Automation::AutomationElement ^element) -{ - System::String ^result = L""; - System::Object ^currentVal = element->GetCurrentPropertyValue(AutomationElement::RuntimeIdProperty); - if (currentVal != nullptr) - { - array ^idArray = (array ^)currentVal; - for each(System::Int32 val in idArray) - { - result += System::Convert::ToString(val) + L"-"; - } - result = result->TrimEnd('-'); - //System::Console::WriteLine("id: {0}", result); - } - return result; -} - -//Descendants will walk the full tree of windows, NOT just one level of children -System::Int32 WpfAutomation::countDescendantWindows() -{ - //AutomationElementCollection ^aec = rootElem->FindAll(TreeScope::Children, Condition::TrueCondition); - AutomationElementCollection ^aec = AutomationElement::RootElement->FindAll(TreeScope::Descendants, getSearchConditions()); - if (aec == nullptr) - return 0; - System::Int32 result = aec->Count; - //delete aec; - return result; -} - -System::Int32 WpfAutomation::countDescendantWindows(System::String ^runtimeIdValue) -{ - AutomationElement ^parent = findAutomationElementById(runtimeIdValue, true); - AutomationElementCollection ^aec = parent->FindAll(TreeScope::Descendants, getSearchConditions()); - if (aec == nullptr) - return 0; - System::Int32 result = aec->Count; - //delete aec; - //delete frameworkAndRuntimeId; - return result; -} - -System::Int32 WpfAutomation::countChildrenWindows() -{ - //AutomationElementCollection ^aec = rootElem->FindAll(TreeScope::Children, Condition::TrueCondition); - AutomationElementCollection ^aec = AutomationElement::RootElement->FindAll(TreeScope::Children, getSearchConditions()); - if (aec == nullptr) - return 0; - System::Int32 result = aec->Count; - //delete aec; - return result; -} - -System::Int32 WpfAutomation::countChildrenWindows(System::String ^runtimeIdValue) -{ - AutomationElement ^parent = findAutomationElementById(runtimeIdValue, true); - AutomationElementCollection ^aec = parent->FindAll(TreeScope::Children, getSearchConditions()); - if (aec == nullptr) - return 0; - System::Int32 result = aec->Count; - //delete aec; - //delete frameworkAndRuntimeId; - return result; -} - -array ^ WpfAutomation::enumChildrenWindowIds(System::String ^runtimeIdValue) -{ - AutomationElement ^parent = findAutomationElementById(runtimeIdValue, true); - AutomationElementCollection ^aec = parent->FindAll(TreeScope::Children, getSearchConditions()); - if (aec == nullptr) - return nullptr; - return getRuntimeIdsFromCollection(aec); -} - -array ^ WpfAutomation::enumDescendantWindowIds(System::String ^runtimeIdValue) -{ - AutomationElement ^parent = findAutomationElementById(runtimeIdValue, true); - AutomationElementCollection ^aec = parent->FindAll(TreeScope::Descendants, getSearchConditions()); - if (aec == nullptr) - return nullptr; - return getRuntimeIdsFromCollection(aec); -} - -array ^ WpfAutomation::enumDescendantWindowIds(System::Int32 processId) -{ - Condition ^frameworkAndProcessId = gcnew AndCondition( - gcnew PropertyCondition(AutomationElement::FrameworkIdProperty, this->frameworkId), - gcnew PropertyCondition(AutomationElement::ProcessIdProperty, processId)); - AutomationElement ^parent = AutomationElement::RootElement->FindFirst(TreeScope::Descendants, frameworkAndProcessId); - AutomationElementCollection ^aec = parent->FindAll(TreeScope::Descendants, getSearchConditions()); - if (aec == nullptr) - return nullptr; - return getRuntimeIdsFromCollection(aec); -} - -System::String ^ WpfAutomation::getRuntimeIdFromHandle(System::IntPtr windowHandle) -{ - //AutomationElement test = AutomationElement.FromHandle(new System.IntPtr(123123)); - AutomationElement ^target = AutomationElement::FromHandle(windowHandle); - if (target == nullptr) - return nullptr; - return getRuntimeIdFromElement(target); -} - -array ^ WpfAutomation::enumDescendantWindowInfo(System::String ^runtimeIdValue, System::String ^properties) -{ - AutomationElement ^parent = findAutomationElementById(runtimeIdValue, true); - if (parent == nullptr) - return nullptr; - AutomationElementCollection ^aec = parent->FindAll(TreeScope::Descendants, getSearchConditions()); - - //when wildcard is enabled it will pull all property names & values - System::Boolean wildcardEnabled = false; - if (properties->Equals(L"*")) - wildcardEnabled = true; - - //create array for keeping order of properties - System::String ^delim = L","; - array ^propSpltArray = properties->Split(delim->ToCharArray()); - TreeWalker ^tw = TreeWalker::ControlViewWalker; - - array ^winInfoList = gcnew array(aec->Count); - System::Int32 count = 0; - for each(AutomationElement ^child in aec) //loop through all descendants - { - array ^aps = child->GetSupportedProperties(); - array ^propValues = gcnew array(propSpltArray->Length);//keep order - System::String ^wildcardProperties = L""; - if (wildcardEnabled) { - wildcardProperties += "ParentRuntimeIdProperty:" + getRuntimeIdFromElement(tw->GetParent(child)) + ","; - //propValues = gcnew array(aps->Length +1 );//add one for parent property since it doesn't exist - } - for(int i=0 ; i < propValues->Length ; i++) - { - propValues[i] = L""; - if (propSpltArray[i]->Equals("ParentRuntimeIdProperty"))//custom property for getting parent - { - propValues[i] = getRuntimeIdFromElement(tw->GetParent(child)); - } - } - for each(AutomationProperty ^ap in aps) //loop through all supported Properties for a child - { - System::String ^currentPropertyStr = L""; //current property values - //System::Console::WriteLine("property: {0}", ap->ProgrammaticName); - System::String ^shortPropName = L" null "; - if (ap->ProgrammaticName->Contains(L".")) - shortPropName = ap->ProgrammaticName->Substring(ap->ProgrammaticName->IndexOf(L".") + 1); - if (properties->Contains(shortPropName) || properties->Contains(ap->ProgrammaticName) || ap->ProgrammaticName->Equals(properties) || wildcardEnabled) - { - //System::Console::WriteLine("shortPropName: {0}", shortPropName); - System::Object ^currentVal = child->GetCurrentPropertyValue(ap); - if (currentVal == nullptr) - continue; - if (ap->ProgrammaticName->Equals(L"AutomationElementIdentifiers.RuntimeIdProperty")) - { - array ^idArray = (array ^)currentVal; - for each(System::Int32 val in idArray) - { - currentPropertyStr += System::Convert::ToString(val) + L"-"; - } - currentPropertyStr = currentPropertyStr->TrimEnd('-'); - //System::Console::WriteLine("id: {0}", result); - } - else//not runtimeId which is an Int32[] - { - currentPropertyStr = currentVal->ToString(); - currentPropertyStr = currentPropertyStr->Replace(",",","); - } - } - if (currentPropertyStr->Equals(L"")) //if there isn't a value skip - continue; - if (wildcardEnabled) { - wildcardProperties += shortPropName + ":" +currentPropertyStr + ","; - continue; - } - //System::Console::WriteLine("currentPropertyStr: {0}", currentPropertyStr); - //find the correct order to return this property - for(int i=0 ; i < propSpltArray->Length ; i++) - { - if (propSpltArray[i]->Equals(shortPropName) || propSpltArray[i]->Equals(ap->ProgrammaticName)) - propValues[i] = currentPropertyStr; - } - } - //output properties in the correct order - for(int i=0 ; i < propSpltArray->Length ; i++) - winInfoList[count] += propValues[i] + L","; - if (wildcardEnabled) - winInfoList[count] += wildcardProperties; - ++count; - } - return winInfoList; -} - -System::String ^ WpfAutomation::getRuntimeIdFromPoint(System::Int32 x, System::Int32 y) -{ - AutomationElement ^target = AutomationElement::FromPoint(System::Windows::Point(x,y)); - if (target == nullptr) - return nullptr; - return getRuntimeIdFromElement(target); -} - -System::String ^ WpfAutomation::getParentRuntimeId(System::String ^runtimeIdValue) -{ - AutomationElement ^target = findAutomationElementById(runtimeIdValue, true); - if (target == nullptr) - return nullptr; - TreeWalker ^tw = TreeWalker::ControlViewWalker; - AutomationElement ^parent = tw->GetParent(target); - return getRuntimeIdFromElement(parent); -} - -System::String ^ WpfAutomation::getProperty(System::String ^propertyName, System::String ^runtimeIdValue) -{ - AutomationElement ^parent = findAutomationElementById(runtimeIdValue, true); - if (parent == nullptr) - return nullptr; - //System::Object ^currentVal = parent->GetCurrentPropertyValue(AutomationElement::RuntimeIdProperty); - array ^aps = parent->GetSupportedProperties(); - for each(AutomationProperty ^ap in aps) - { - //System::Console::WriteLine("property: {0}", ap->ProgrammaticName); - if (ap->ProgrammaticName->Contains(L"." + propertyName) || ap->ProgrammaticName->Equals(propertyName)) - { - System::Object ^currentVal = parent->GetCurrentPropertyValue(ap); - return currentVal->ToString(); - } - } - return nullptr; -} - - -array ^ WpfAutomation::getProperties(System::String ^runtimeIdValue) -{ - AutomationElement ^parent = findAutomationElementById(runtimeIdValue, true); - if (parent == nullptr) - return nullptr; - array ^aps = parent->GetSupportedProperties(); - array ^propStrArray = gcnew array(aps->Length); - System::Int32 count = 0; - for each(AutomationProperty ^ap in aps) - { - System::Object ^currentVal = parent->GetCurrentPropertyValue(ap); - if (currentVal == nullptr) - continue; - propStrArray[count] = ap->ProgrammaticName; - ++count; - } - return propStrArray; -} - -array ^ WpfAutomation::getPropertiesAndValues(System::String ^runtimeIdValue) -{ - AutomationElement ^parent = findAutomationElementById(runtimeIdValue, true); - if (parent == nullptr) - return nullptr; - array ^aps = parent->GetSupportedProperties(); - array ^propStrArray = gcnew array(aps->Length); - System::Int32 count = 0; - for each(AutomationProperty ^ap in aps) - { - System::Object ^currentVal = parent->GetCurrentPropertyValue(ap); - if (currentVal == nullptr) - continue; - propStrArray[count] = ap->ProgrammaticName + ":" + currentVal->ToString(); - ++count; - } - return propStrArray; -} diff --git a/native/WpfBridge/WpfAutomation.h b/native/WpfBridge/WpfAutomation.h deleted file mode 100644 index fe8adb9..0000000 --- a/native/WpfBridge/WpfAutomation.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2014, Synthuse.org - * Released under the Apache Version 2.0 License. - * - * last modified by ejakubowski7@gmail.com -*/ -#pragma once - -public ref class WpfAutomation -{ -public: - WpfAutomation(void); - void setFrameworkId(System::String ^propertyValue); //default is WPF, but also accepts Silverlight, Win32 - void setTouchableOnly(System::Boolean val); //default is true - - //Descendants will walk the full tree of windows, NOT just one level of children - System::Int32 countDescendantWindows(); - System::Int32 countDescendantWindows(System::String ^runtimeIdValue); - - System::Int32 countChildrenWindows(); - System::Int32 countChildrenWindows(System::String ^runtimeIdValue); - - array ^ enumChildrenWindowIds(System::String ^runtimeIdValue); //if runtimeIdValue is null will start at desktop - array ^ enumDescendantWindowIds(System::String ^runtimeIdValue); //if runtimeIdValue is null will start at desktop - array ^ enumDescendantWindowIds(System::Int32 processId); - //In all the above Enumerate methods will return a list of Runtime Ids for all related windows. - array ^ enumDescendantWindowInfo(System::String ^runtimeIdValue, System::String ^properties); - - System::String ^ getRuntimeIdFromHandle(System::IntPtr windowHandle); - System::String ^ getRuntimeIdFromPoint(System::Int32 x, System::Int32 y); - System::String ^ getParentRuntimeId(System::String ^runtimeIdValue); - System::String ^ getProperty(System::String ^propertyName, System::String ^runtimeIdValue); - array ^ getProperties(System::String ^runtimeIdValue); - array ^ getPropertiesAndValues(System::String ^runtimeIdValue); -private: - array ^ convertRuntimeIdString(System::String ^runtimeIdValue); - System::Windows::Automation::AutomationElement ^ findAutomationElementById(System::String ^runtimeIdValue, System::Boolean unfiltered); - System::String ^ getRuntimeIdFromElement(System::Windows::Automation::AutomationElement ^element); - array ^ getRuntimeIdsFromCollection(System::Windows::Automation::AutomationElementCollection ^collection); - System::Windows::Automation::Condition ^ getSearchConditions(); - - static System::String ^DEFAULT_FRAMEWORK = L"WPF"; - static System::Boolean ^DEFAULT_TOUCHABLE = true; - System::String ^frameworkId; - System::Boolean ^touchableOnly; -}; - diff --git a/native/WpfBridge/bin/wpfbridge32.dll b/native/WpfBridge/bin/wpfbridge32.dll deleted file mode 100644 index b6dc92c..0000000 Binary files a/native/WpfBridge/bin/wpfbridge32.dll and /dev/null differ diff --git a/native/WpfBridge/bin/wpfbridge64.dll b/native/WpfBridge/bin/wpfbridge64.dll deleted file mode 100644 index 29affed..0000000 Binary files a/native/WpfBridge/bin/wpfbridge64.dll and /dev/null differ diff --git a/native/WpfBridge/org_synthuse_WpfBridge.cpp b/native/WpfBridge/org_synthuse_WpfBridge.cpp deleted file mode 100644 index 85e6d0e..0000000 --- a/native/WpfBridge/org_synthuse_WpfBridge.cpp +++ /dev/null @@ -1,300 +0,0 @@ -/* - * Copyright 2014, Synthuse.org - * Released under the Apache Version 2.0 License. - * - * last modified by ejakubowski7@gmail.com -*/ -#include "StdAfx.h" -#include "org_synthuse_WpfBridge.h" -#include "WpfAutomation.h" -#include "Global.h" -#include //using namespace msclr::interop; - -using namespace System; -using namespace System::Windows::Automation; -using namespace msclr::interop; -using namespace Globals; - -JNIEXPORT void JNICALL Java_org_synthuse_WpfBridge_setFrameworkId(JNIEnv *env, jobject obj, jstring jpropertyValue) -{ - const char *propertyValue = env->GetStringUTFChars(jpropertyValue, 0);//convert string - Global::WPF_AUTO->setFrameworkId(marshal_as(propertyValue)); - env->ReleaseStringUTFChars(jpropertyValue, propertyValue); //release string -} - -/* - * Class: org_synthuse_WpfBridge - * Method: setTouchableOnly - * Signature: (Z)V - */ -JNIEXPORT void JNICALL Java_org_synthuse_WpfBridge_setTouchableOnly(JNIEnv *env, jobject obj, jboolean jval) -{ - Global::WPF_AUTO->setTouchableOnly((bool)(jval == JNI_TRUE)); -} - -/* - * Class: org_synthuse_WpfBridge - * Method: CountDescendantWindows - * Signature: ()I - */ -JNIEXPORT jint JNICALL Java_org_synthuse_WpfBridge_countDescendantWindows__(JNIEnv *env, jobject obj) -{ - return Global::WPF_AUTO->countDescendantWindows(); -} - -/* - * Class: org_synthuse_WpfBridge - * Method: CountDescendantWindows - * Signature: (Ljava/lang/String;)I - */ -JNIEXPORT jint JNICALL Java_org_synthuse_WpfBridge_countDescendantWindows__Ljava_lang_String_2(JNIEnv *env, jobject obj, jstring jruntimeIdValue) -{ - const char *runtimeIdValue = env->GetStringUTFChars(jruntimeIdValue, 0);//convert string - jint result = Global::WPF_AUTO->countDescendantWindows(marshal_as(runtimeIdValue)); - env->ReleaseStringUTFChars(jruntimeIdValue, runtimeIdValue); //release string - return result; -} - - -/* - * Class: org_synthuse_WpfBridge - * Method: CountChildrenWindows - * Signature: ()I - */ -JNIEXPORT jint JNICALL Java_org_synthuse_WpfBridge_countChildrenWindows__(JNIEnv *env, jobject obj) -{ - return Global::WPF_AUTO->countChildrenWindows(); -} - - -/* - * Class: org_synthuse_WpfBridge - * Method: CountChildrenWindows - * Signature: (Ljava/lang/String;)I - */ -JNIEXPORT jint JNICALL Java_org_synthuse_WpfBridge_countChildrenWindows__Ljava_lang_String_2(JNIEnv *env, jobject obj, jstring jruntimeIdValue) -{ - const char *runtimeIdValue = env->GetStringUTFChars(jruntimeIdValue, 0);//convert string - jint result = Global::WPF_AUTO->countChildrenWindows(marshal_as(runtimeIdValue)); - env->ReleaseStringUTFChars(jruntimeIdValue, runtimeIdValue); //release string - return result; -} - - -/* - * Class: org_synthuse_WpfBridge - * Method: EnumChildrenWindowIds - * Signature: (Ljava/lang/String;)[Ljava/lang/String; - */ -JNIEXPORT jobjectArray JNICALL Java_org_synthuse_WpfBridge_enumChildrenWindowIds(JNIEnv *env, jobject obj, jstring jruntimeIdValue) -{ - const char *runtimeIdValue = env->GetStringUTFChars(jruntimeIdValue, 0);//convert string - array ^mchildrenIds = Global::WPF_AUTO->enumChildrenWindowIds(marshal_as(runtimeIdValue)); - if (mchildrenIds == nullptr) - return NULL; - //create result object array to the same size as the managed children Ids string array - jclass stringClass = env->FindClass("java/lang/String"); - jobjectArray results = env->NewObjectArray(mchildrenIds->Length, stringClass, 0); - marshal_context context; //lets you marshal managed classes to unmanaged types - //char **childrenIds = new char *[mchildrenIds->Length]; - for(int i = 0 ; i < mchildrenIds->Length ; i++) - { - //childrenIds[i] = (char *)context.marshal_as(mchildrenIds[i]); - //env->SetObjectArrayElement(results, i, env->GetStringUTFChars(childrenIds[i], 0) - env->SetObjectArrayElement(results, i, env->NewStringUTF(context.marshal_as(mchildrenIds[i]))); - } - //delete[] childrenIds; - env->ReleaseStringUTFChars(jruntimeIdValue, runtimeIdValue); //release string - return results; -} - - -/* - * Class: org_synthuse_WpfBridge - * Method: EnumDescendantWindowIds - * Signature: (Ljava/lang/String;)[Ljava/lang/String; - */ -JNIEXPORT jobjectArray JNICALL Java_org_synthuse_WpfBridge_enumDescendantWindowIds__Ljava_lang_String_2(JNIEnv *env, jobject obj, jstring jruntimeIdValue) -{ - const char *runtimeIdValue = env->GetStringUTFChars(jruntimeIdValue, 0);//convert string - array ^mchildrenIds = Global::WPF_AUTO->enumDescendantWindowIds(marshal_as(runtimeIdValue)); - if (mchildrenIds == nullptr) - return NULL; - //create result object array to the same size as the managed children Ids string array - jclass stringClass = env->FindClass("java/lang/String"); - jobjectArray results = env->NewObjectArray(mchildrenIds->Length, stringClass, 0); - marshal_context context; //lets you marshal managed classes to unmanaged types - //char **childrenIds = new char *[mchildrenIds->Length]; - for(int i = 0 ; i < mchildrenIds->Length ; i++) - { - //childrenIds[i] = (char *)context.marshal_as(mchildrenIds[i]); - //env->SetObjectArrayElement(results, i, env->GetStringUTFChars(childrenIds[i], 0) - env->SetObjectArrayElement(results, i, env->NewStringUTF(context.marshal_as(mchildrenIds[i]))); - } - //delete[] childrenIds; - env->ReleaseStringUTFChars(jruntimeIdValue, runtimeIdValue); //release string - return results; -} - - -/* - * Class: org_synthuse_WpfBridge - * Method: EnumDescendantWindowIds - * Signature: (J)[Ljava/lang/String; - */ -JNIEXPORT jobjectArray JNICALL Java_org_synthuse_WpfBridge_enumDescendantWindowIds__J(JNIEnv *env, jobject obj, jlong jprocessId) -{ - array ^mchildrenIds = Global::WPF_AUTO->enumDescendantWindowIds((System::Int32)jprocessId); - if (mchildrenIds == nullptr) - return NULL; - //create result object array to the same size as the managed children Ids string array - jclass stringClass = env->FindClass("java/lang/String"); - jobjectArray results = env->NewObjectArray(mchildrenIds->Length, stringClass, 0); - marshal_context context; //lets you marshal managed classes to unmanaged types - for(int i = 0 ; i < mchildrenIds->Length ; i++) - { - env->SetObjectArrayElement(results, i, env->NewStringUTF(context.marshal_as(mchildrenIds[i]))); - } - return results; -} - - -/* - * Class: org_synthuse_WpfBridge - * Method: getRuntimeIdFromHandle - * Signature: (J)Ljava/lang/String; - */ -JNIEXPORT jstring JNICALL Java_org_synthuse_WpfBridge_getRuntimeIdFromHandle(JNIEnv *env, jobject obj, jlong jwindowHandle) -{ - System::String ^mrunId = Global::WPF_AUTO->getRuntimeIdFromHandle(System::IntPtr(jwindowHandle)); - if (mrunId == nullptr) - return NULL; - marshal_context context; //lets you marshal managed classes to unmanaged types - jstring result = env->NewStringUTF(context.marshal_as(mrunId)); - return result; -} - -/* - * Class: org_synthuse_WpfBridge - * Method: enumDescendantWindowInfo - * Signature: (Ljava/lang/String;Ljava/lang/String;)[Ljava/lang/String; - */ -JNIEXPORT jobjectArray JNICALL Java_org_synthuse_WpfBridge_enumDescendantWindowInfo(JNIEnv *env, jobject obj, jstring jruntimeIdValue, jstring jproperties) -{ - const char *runtimeIdValue = env->GetStringUTFChars(jruntimeIdValue, 0);//convert string - const char *properties = env->GetStringUTFChars(jproperties, 0);//convert string - array ^mwinInfo = Global::WPF_AUTO->enumDescendantWindowInfo(marshal_as(runtimeIdValue), marshal_as(properties)); - if (mwinInfo == nullptr) - return NULL; - //create result object array to the same size as the managed window info string array - jclass stringClass = env->FindClass("java/lang/String"); - jobjectArray results = env->NewObjectArray(mwinInfo->Length, stringClass, 0); - marshal_context context; //lets you marshal managed classes to unmanaged types - for(int i = 0 ; i < mwinInfo->Length ; i++) - { - env->SetObjectArrayElement(results, i, env->NewStringUTF(context.marshal_as(mwinInfo[i]))); - } - env->ReleaseStringUTFChars(jproperties, properties); //release string - env->ReleaseStringUTFChars(jruntimeIdValue, runtimeIdValue); //release string - return results; -} - - -/* - * Class: org_synthuse_WpfBridge - * Method: getRuntimeIdFromPoint - * Signature: (II)Ljava/lang/String; - */ -JNIEXPORT jstring JNICALL Java_org_synthuse_WpfBridge_getRuntimeIdFromPoint(JNIEnv *env, jobject obj, jint x, jint y) -{ - System::String ^mresult = Global::WPF_AUTO->getRuntimeIdFromPoint(x, y); - if (mresult == nullptr) - return NULL; - marshal_context context; //lets you marshal managed classes to unmanaged types - jstring result = env->NewStringUTF(context.marshal_as(mresult)); - return result; -} - -/* - * Class: org_synthuse_WpfBridge - * Method: getParentRuntimeId - * Signature: (Ljava/lang/String;)Ljava/lang/String; - */ -JNIEXPORT jstring JNICALL Java_org_synthuse_WpfBridge_getParentRuntimeId(JNIEnv *env, jobject obj, jstring jruntimeIdValue) -{ - const char *runtimeIdValue = env->GetStringUTFChars(jruntimeIdValue, 0);//convert string - System::String ^mresult = Global::WPF_AUTO->getParentRuntimeId(marshal_as(runtimeIdValue)); - if (mresult == nullptr) - return NULL; - marshal_context context; //lets you marshal managed classes to unmanaged types - jstring result = env->NewStringUTF(context.marshal_as(mresult)); - env->ReleaseStringUTFChars(jruntimeIdValue, runtimeIdValue); //release string - return result; -} - -/* - * Class: org_synthuse_WpfBridge - * Method: GetProperty - * Signature: (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; - */ -JNIEXPORT jstring JNICALL Java_org_synthuse_WpfBridge_getProperty(JNIEnv *env, jobject obj, jstring jpropertyName, jstring jruntimeIdValue) -{ - const char *runtimeIdValue = env->GetStringUTFChars(jruntimeIdValue, 0);//convert string - const char *propertyName = env->GetStringUTFChars(jpropertyName, 0);//convert string - System::String ^mresult = Global::WPF_AUTO->getProperty(marshal_as(propertyName), marshal_as(runtimeIdValue)); - if (mresult == nullptr) - return NULL; - marshal_context context; //lets you marshal managed classes to unmanaged types - jstring result = env->NewStringUTF(context.marshal_as(mresult)); - env->ReleaseStringUTFChars(jpropertyName, propertyName); //release string - env->ReleaseStringUTFChars(jruntimeIdValue, runtimeIdValue); //release string - return result; -} - - -/* - * Class: org_synthuse_WpfBridge - * Method: GetProperties - * Signature: (Ljava/lang/String;)[Ljava/lang/String; - */ -JNIEXPORT jobjectArray JNICALL Java_org_synthuse_WpfBridge_getProperties(JNIEnv *env, jobject obj, jstring jruntimeIdValue) -{ - const char *runtimeIdValue = env->GetStringUTFChars(jruntimeIdValue, 0);//convert string - array ^mprops = Global::WPF_AUTO->getProperties(marshal_as(runtimeIdValue)); - if (mprops == nullptr) - return NULL; - //create result object array to the same size as the managed children Ids string array - jclass stringClass = env->FindClass("java/lang/String"); - jobjectArray results = env->NewObjectArray(mprops->Length, stringClass, 0); - marshal_context context; //lets you marshal managed classes to unmanaged types - for(int i = 0 ; i < mprops->Length ; i++) - { - env->SetObjectArrayElement(results, i, env->NewStringUTF(context.marshal_as(mprops[i]))); - } - env->ReleaseStringUTFChars(jruntimeIdValue, runtimeIdValue); //release string - return results; -} - - -/* - * Class: org_synthuse_WpfBridge - * Method: GetPropertiesAndValues - * Signature: (Ljava/lang/String;)[Ljava/lang/String; - */ -JNIEXPORT jobjectArray JNICALL Java_org_synthuse_WpfBridge_getPropertiesAndValues(JNIEnv *env, jobject obj, jstring jruntimeIdValue) -{ - const char *runtimeIdValue = env->GetStringUTFChars(jruntimeIdValue, 0);//convert string - array ^mprops = Global::WPF_AUTO->getPropertiesAndValues(marshal_as(runtimeIdValue)); - if (mprops == nullptr) - return NULL; - //create result object array to the same size as the managed children Ids string array - jclass stringClass = env->FindClass("java/lang/String"); - jobjectArray results = env->NewObjectArray(mprops->Length, stringClass, 0); - marshal_context context; //lets you marshal managed classes to unmanaged types - for(int i = 0 ; i < mprops->Length ; i++) - { - env->SetObjectArrayElement(results, i, env->NewStringUTF(context.marshal_as(mprops[i]))); - } - env->ReleaseStringUTFChars(jruntimeIdValue, runtimeIdValue); //release string - return results; -} diff --git a/native/WpfBridge/org_synthuse_WpfBridge.h b/native/WpfBridge/org_synthuse_WpfBridge.h deleted file mode 100644 index 6a546b9..0000000 --- a/native/WpfBridge/org_synthuse_WpfBridge.h +++ /dev/null @@ -1,141 +0,0 @@ -/* DO NOT EDIT THIS FILE - it is machine generated */ -#include -/* Header for class org_synthuse_WpfBridge */ - -#ifndef _Included_org_synthuse_WpfBridge -#define _Included_org_synthuse_WpfBridge -#ifdef __cplusplus -extern "C" { -#endif -/* - * Class: org_synthuse_WpfBridge - * Method: setFrameworkId - * Signature: (Ljava/lang/String;)V - */ -JNIEXPORT void JNICALL Java_org_synthuse_WpfBridge_setFrameworkId - (JNIEnv *, jobject, jstring); - -/* - * Class: org_synthuse_WpfBridge - * Method: setTouchableOnly - * Signature: (Z)V - */ -JNIEXPORT void JNICALL Java_org_synthuse_WpfBridge_setTouchableOnly - (JNIEnv *, jobject, jboolean); - -/* - * Class: org_synthuse_WpfBridge - * Method: countDescendantWindows - * Signature: ()I - */ -JNIEXPORT jint JNICALL Java_org_synthuse_WpfBridge_countDescendantWindows__ - (JNIEnv *, jobject); - -/* - * Class: org_synthuse_WpfBridge - * Method: countDescendantWindows - * Signature: (Ljava/lang/String;)I - */ -JNIEXPORT jint JNICALL Java_org_synthuse_WpfBridge_countDescendantWindows__Ljava_lang_String_2 - (JNIEnv *, jobject, jstring); - -/* - * Class: org_synthuse_WpfBridge - * Method: countChildrenWindows - * Signature: ()I - */ -JNIEXPORT jint JNICALL Java_org_synthuse_WpfBridge_countChildrenWindows__ - (JNIEnv *, jobject); - -/* - * Class: org_synthuse_WpfBridge - * Method: countChildrenWindows - * Signature: (Ljava/lang/String;)I - */ -JNIEXPORT jint JNICALL Java_org_synthuse_WpfBridge_countChildrenWindows__Ljava_lang_String_2 - (JNIEnv *, jobject, jstring); - -/* - * Class: org_synthuse_WpfBridge - * Method: enumChildrenWindowIds - * Signature: (Ljava/lang/String;)[Ljava/lang/String; - */ -JNIEXPORT jobjectArray JNICALL Java_org_synthuse_WpfBridge_enumChildrenWindowIds - (JNIEnv *, jobject, jstring); - -/* - * Class: org_synthuse_WpfBridge - * Method: enumDescendantWindowIds - * Signature: (Ljava/lang/String;)[Ljava/lang/String; - */ -JNIEXPORT jobjectArray JNICALL Java_org_synthuse_WpfBridge_enumDescendantWindowIds__Ljava_lang_String_2 - (JNIEnv *, jobject, jstring); - -/* - * Class: org_synthuse_WpfBridge - * Method: enumDescendantWindowIds - * Signature: (J)[Ljava/lang/String; - */ -JNIEXPORT jobjectArray JNICALL Java_org_synthuse_WpfBridge_enumDescendantWindowIds__J - (JNIEnv *, jobject, jlong); - -/* - * Class: org_synthuse_WpfBridge - * Method: enumDescendantWindowInfo - * Signature: (Ljava/lang/String;Ljava/lang/String;)[Ljava/lang/String; - */ -JNIEXPORT jobjectArray JNICALL Java_org_synthuse_WpfBridge_enumDescendantWindowInfo - (JNIEnv *, jobject, jstring, jstring); - -/* - * Class: org_synthuse_WpfBridge - * Method: getRuntimeIdFromHandle - * Signature: (J)Ljava/lang/String; - */ -JNIEXPORT jstring JNICALL Java_org_synthuse_WpfBridge_getRuntimeIdFromHandle - (JNIEnv *, jobject, jlong); - -/* - * Class: org_synthuse_WpfBridge - * Method: getRuntimeIdFromPoint - * Signature: (II)Ljava/lang/String; - */ -JNIEXPORT jstring JNICALL Java_org_synthuse_WpfBridge_getRuntimeIdFromPoint - (JNIEnv *, jobject, jint, jint); - -/* - * Class: org_synthuse_WpfBridge - * Method: getParentRuntimeId - * Signature: (Ljava/lang/String;)Ljava/lang/String; - */ -JNIEXPORT jstring JNICALL Java_org_synthuse_WpfBridge_getParentRuntimeId - (JNIEnv *, jobject, jstring); - -/* - * Class: org_synthuse_WpfBridge - * Method: getProperty - * Signature: (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; - */ -JNIEXPORT jstring JNICALL Java_org_synthuse_WpfBridge_getProperty - (JNIEnv *, jobject, jstring, jstring); - -/* - * Class: org_synthuse_WpfBridge - * Method: getProperties - * Signature: (Ljava/lang/String;)[Ljava/lang/String; - */ -JNIEXPORT jobjectArray JNICALL Java_org_synthuse_WpfBridge_getProperties - (JNIEnv *, jobject, jstring); - -/* - * Class: org_synthuse_WpfBridge - * Method: getPropertiesAndValues - * Signature: (Ljava/lang/String;)[Ljava/lang/String; - */ -JNIEXPORT jobjectArray JNICALL Java_org_synthuse_WpfBridge_getPropertiesAndValues - (JNIEnv *, jobject, jstring); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/native/uiabridge.sln b/native/uiabridge.sln new file mode 100644 index 0000000..88b543c --- /dev/null +++ b/native/uiabridge.sln @@ -0,0 +1,36 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "uiabridge", "uiabridge\uiabridge.vcxproj", "{BAC1B079-7B87-4396-B17F-91A86DF1AE29}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "uiabtest", "uiabtest\uiabtest.vcxproj", "{7958D1B7-F169-40FA-A7A0-10E8E0F90CDA}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {BAC1B079-7B87-4396-B17F-91A86DF1AE29}.Debug|Win32.ActiveCfg = Debug|Win32 + {BAC1B079-7B87-4396-B17F-91A86DF1AE29}.Debug|Win32.Build.0 = Debug|Win32 + {BAC1B079-7B87-4396-B17F-91A86DF1AE29}.Debug|x64.ActiveCfg = Debug|x64 + {BAC1B079-7B87-4396-B17F-91A86DF1AE29}.Debug|x64.Build.0 = Debug|x64 + {BAC1B079-7B87-4396-B17F-91A86DF1AE29}.Release|Win32.ActiveCfg = Release|Win32 + {BAC1B079-7B87-4396-B17F-91A86DF1AE29}.Release|Win32.Build.0 = Release|Win32 + {BAC1B079-7B87-4396-B17F-91A86DF1AE29}.Release|x64.ActiveCfg = Release|x64 + {BAC1B079-7B87-4396-B17F-91A86DF1AE29}.Release|x64.Build.0 = Release|x64 + {7958D1B7-F169-40FA-A7A0-10E8E0F90CDA}.Debug|Win32.ActiveCfg = Debug|Win32 + {7958D1B7-F169-40FA-A7A0-10E8E0F90CDA}.Debug|Win32.Build.0 = Debug|Win32 + {7958D1B7-F169-40FA-A7A0-10E8E0F90CDA}.Debug|x64.ActiveCfg = Debug|x64 + {7958D1B7-F169-40FA-A7A0-10E8E0F90CDA}.Debug|x64.Build.0 = Debug|x64 + {7958D1B7-F169-40FA-A7A0-10E8E0F90CDA}.Release|Win32.ActiveCfg = Release|Win32 + {7958D1B7-F169-40FA-A7A0-10E8E0F90CDA}.Release|Win32.Build.0 = Release|Win32 + {7958D1B7-F169-40FA-A7A0-10E8E0F90CDA}.Release|x64.ActiveCfg = Release|x64 + {7958D1B7-F169-40FA-A7A0-10E8E0F90CDA}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/native/uiabridge.suo b/native/uiabridge.suo new file mode 100644 index 0000000..0c2f744 Binary files /dev/null and b/native/uiabridge.suo differ diff --git a/native/WpfBridge/AssemblyInfo.cpp b/native/uiabridge/AssemblyInfo.cpp similarity index 72% rename from native/WpfBridge/AssemblyInfo.cpp rename to native/uiabridge/AssemblyInfo.cpp index 8d9e333..5ef1b63 100644 --- a/native/WpfBridge/AssemblyInfo.cpp +++ b/native/uiabridge/AssemblyInfo.cpp @@ -1,9 +1,3 @@ -/* - * Copyright 2014, Synthuse.org - * Released under the Apache Version 2.0 License. - * - * last modified by ejakubowski7@gmail.com -*/ #include "stdafx.h" using namespace System; @@ -17,12 +11,12 @@ using namespace System::Security::Permissions; // set of attributes. Change these attribute values to modify the information // associated with an assembly. // -[assembly:AssemblyTitleAttribute("WpfBridge")]; +[assembly:AssemblyTitleAttribute("uiabridge")]; [assembly:AssemblyDescriptionAttribute("")]; [assembly:AssemblyConfigurationAttribute("")]; -[assembly:AssemblyCompanyAttribute("Synthuse")]; -[assembly:AssemblyProductAttribute("WpfBridge")]; -[assembly:AssemblyCopyrightAttribute("Copyright (c) Synthuse 2014")]; +[assembly:AssemblyCompanyAttribute("na")]; +[assembly:AssemblyProductAttribute("uiabridge")]; +[assembly:AssemblyCopyrightAttribute("Copyright (c) na 2014")]; [assembly:AssemblyTrademarkAttribute("")]; [assembly:AssemblyCultureAttribute("")]; @@ -37,7 +31,7 @@ using namespace System::Security::Permissions; // You can specify all the value or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly:AssemblyVersionAttribute("1.1.*")]; +[assembly:AssemblyVersionAttribute("1.0.*")]; [assembly:ComVisible(false)]; diff --git a/native/WpfBridge/Global.cpp b/native/uiabridge/Global.cpp similarity index 68% rename from native/WpfBridge/Global.cpp rename to native/uiabridge/Global.cpp index 6832972..2523535 100644 --- a/native/WpfBridge/Global.cpp +++ b/native/uiabridge/Global.cpp @@ -4,7 +4,7 @@ * * last modified by ejakubowski7@gmail.com */ -#include "StdAfx.h" +#include "stdafx.h" #include "Global.h" -#include "WpfAutomation.h" - +#include "uiabridge.h" +using namespace uiabridge; diff --git a/native/WpfBridge/Global.h b/native/uiabridge/Global.h similarity index 70% rename from native/WpfBridge/Global.h rename to native/uiabridge/Global.h index d7b5a56..c486cd8 100644 --- a/native/WpfBridge/Global.h +++ b/native/uiabridge/Global.h @@ -5,7 +5,8 @@ * last modified by ejakubowski7@gmail.com */ #pragma once -#include "WpfAutomation.h" +#include "uiabridge.h" +using namespace uiabridge; namespace Globals { using namespace System; @@ -13,7 +14,7 @@ namespace Globals public ref class Global { public: - static WpfAutomation ^WPF_AUTO = gcnew WpfAutomation(); + static AutomationBridge ^AUTO_BRIDGE = nullptr; }; } diff --git a/native/WpfBridge/ReadMe.txt b/native/uiabridge/ReadMe.txt similarity index 67% rename from native/WpfBridge/ReadMe.txt rename to native/uiabridge/ReadMe.txt index 4d5f4e6..bba57e9 100644 --- a/native/WpfBridge/ReadMe.txt +++ b/native/uiabridge/ReadMe.txt @@ -1,9 +1,8 @@ ======================================================================== - DYNAMIC LINK LIBRARY : WpfBridge Project Overview + DYNAMIC LINK LIBRARY : uiabridge Project Overview ======================================================================== - Created By Edward Jakubowski ejakubowski7@gmail.com Description: This is a bridge for java to access .net 4 UI Automation libraries. This -library enables Synthuse to access and automation WPF and Silverlight apps. +library enables Synthuse to access and automate WinForms, WPF and Silverlight apps. \ No newline at end of file diff --git a/native/uiabridge/Stdafx.cpp b/native/uiabridge/Stdafx.cpp new file mode 100644 index 0000000..c445b97 --- /dev/null +++ b/native/uiabridge/Stdafx.cpp @@ -0,0 +1,6 @@ +// stdafx.cpp : source file that includes just the standard includes +// uiabridge.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" +#include \ No newline at end of file diff --git a/native/WpfBridge/Stdafx.h b/native/uiabridge/Stdafx.h similarity index 100% rename from native/WpfBridge/Stdafx.h rename to native/uiabridge/Stdafx.h diff --git a/native/WpfBridge/app.ico b/native/uiabridge/app.ico similarity index 100% rename from native/WpfBridge/app.ico rename to native/uiabridge/app.ico diff --git a/native/WpfBridge/app.rc b/native/uiabridge/app.rc similarity index 100% rename from native/WpfBridge/app.rc rename to native/uiabridge/app.rc diff --git a/native/WpfBridge/build.bat b/native/uiabridge/build.bat similarity index 100% rename from native/WpfBridge/build.bat rename to native/uiabridge/build.bat diff --git a/native/uiabridge/org_synthuse_UiaBridge.cpp b/native/uiabridge/org_synthuse_UiaBridge.cpp new file mode 100644 index 0000000..6bd5bc9 --- /dev/null +++ b/native/uiabridge/org_synthuse_UiaBridge.cpp @@ -0,0 +1,157 @@ +/* + * Copyright 2014, Synthuse.org + * Released under the Apache Version 2.0 License. + * + * last modified by ejakubowski7@gmail.com +*/ +#include "stdafx.h" +#include //using namespace msclr::interop; +#include "org_synthuse_UiaBridge.h" +#include "uiabridge.h" +#include "Global.h" + +using namespace System; +using namespace System::Windows::Automation; +using namespace msclr::interop; +using namespace Globals; +using namespace uiabridge; + + +/* + * Class: org_synthuse_UiaBridge + * Method: initialize + * Signature: (Ljava/lang/String;)V + */ +JNIEXPORT void JNICALL Java_org_synthuse_UiaBridge_initialize(JNIEnv *env, jobject obj, jstring jproperties) +{ + Global::AUTO_BRIDGE = gcnew AutomationBridge(); +} + +/* + * Class: org_synthuse_UiaBridge + * Method: shutdown + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_org_synthuse_UiaBridge_shutdown(JNIEnv *env, jobject obj) +{ +} + +/* + * Class: org_synthuse_UiaBridge + * Method: addEnumFilter + * Signature: (Ljava/lang/String;Ljava/lang/String;)I + */ +JNIEXPORT jint JNICALL Java_org_synthuse_UiaBridge_addEnumFilter(JNIEnv *env, jobject obj, jstring jpropertyName, jstring jpropertyValue) +{ + const char *propertyName = env->GetStringUTFChars(jpropertyValue, 0);//convert string + const char *propertyValue = env->GetStringUTFChars(jpropertyValue, 0);//convert string + return (jint)Global::AUTO_BRIDGE->addEnumFilter(marshal_as(propertyName), marshal_as(propertyValue)); +} + +/* + * Class: org_synthuse_UiaBridge + * Method: clearEnumFilters + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_org_synthuse_UiaBridge_clearEnumFilters(JNIEnv *env, jobject obj) +{ + Global::AUTO_BRIDGE->clearEnumFilters(); +} + +/* + * Class: org_synthuse_UiaBridge + * Method: enumWindowInfo + * Signature: (Ljava/lang/String;)[Ljava/lang/String; + */ +JNIEXPORT jobjectArray JNICALL Java_org_synthuse_UiaBridge_enumWindowInfo__Ljava_lang_String_2(JNIEnv *env, jobject obj, jstring jproperties) +{ + const char *properties = env->GetStringUTFChars(jproperties, 0);//convert string + array ^mwinInfo = Global::AUTO_BRIDGE->enumWindowInfo(marshal_as(properties)); + if (mwinInfo == nullptr) + return NULL; + //create result object array to the same size as the managed children Ids string array + jclass stringClass = env->FindClass("java/lang/String"); + jobjectArray results = env->NewObjectArray(mwinInfo->Length, stringClass, 0); + marshal_context context; //lets you marshal managed classes to unmanaged types + //char **childrenIds = new char *[mchildrenIds->Length]; + for(int i = 0 ; i < mwinInfo->Length ; i++) + { + //childrenIds[i] = (char *)context.marshal_as(mchildrenIds[i]); + //env->SetObjectArrayElement(results, i, env->GetStringUTFChars(childrenIds[i], 0) + env->SetObjectArrayElement(results, i, env->NewStringUTF(context.marshal_as(mwinInfo[i]))); + } + //delete[] childrenIds; + env->ReleaseStringUTFChars(jproperties, properties); //release string + return results; +} + +/* + * Class: org_synthuse_UiaBridge + * Method: enumWindowInfo + * Signature: (ILjava/lang/String;)[Ljava/lang/String; + */ +JNIEXPORT jobjectArray JNICALL Java_org_synthuse_UiaBridge_enumWindowInfo__ILjava_lang_String_2(JNIEnv *env, jobject obj, jint jwindowHandle, jstring jproperties) +{ + const char *properties = env->GetStringUTFChars(jproperties, 0);//convert string + array ^mwinInfo = Global::AUTO_BRIDGE->enumWindowInfo(System::IntPtr(jwindowHandle), marshal_as(properties)); + if (mwinInfo == nullptr) + return NULL; + //create result object array to the same size as the managed children Ids string array + jclass stringClass = env->FindClass("java/lang/String"); + jobjectArray results = env->NewObjectArray(mwinInfo->Length, stringClass, 0); + marshal_context context; //lets you marshal managed classes to unmanaged types + //char **childrenIds = new char *[mchildrenIds->Length]; + for(int i = 0 ; i < mwinInfo->Length ; i++) + { + //childrenIds[i] = (char *)context.marshal_as(mchildrenIds[i]); + //env->SetObjectArrayElement(results, i, env->GetStringUTFChars(childrenIds[i], 0) + env->SetObjectArrayElement(results, i, env->NewStringUTF(context.marshal_as(mwinInfo[i]))); + } + //delete[] childrenIds; + env->ReleaseStringUTFChars(jproperties, properties); //release string + return results; +} + +/* + * Class: org_synthuse_UiaBridge + * Method: getWindowInfo + * Signature: (IILjava/lang/String;)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_org_synthuse_UiaBridge_getWindowInfo__IILjava_lang_String_2(JNIEnv *env, jobject obj, jint jx, jint jy, jstring jproperties) +{ + const char *properties = env->GetStringUTFChars(jproperties, 0);//convert string + System::String ^mwinInfo = Global::AUTO_BRIDGE->getWindowInfo(jx, jy, marshal_as(properties)); + env->ReleaseStringUTFChars(jproperties, properties); //release string + marshal_context context; + return env->NewStringUTF(context.marshal_as(mwinInfo)); +} + +/* + * Class: org_synthuse_UiaBridge + * Method: getWindowInfo + * Signature: (ILjava/lang/String;)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_org_synthuse_UiaBridge_getWindowInfo__ILjava_lang_String_2(JNIEnv *env, jobject obj, jint jwindowHandle, jstring jproperties) +{ + const char *properties = env->GetStringUTFChars(jproperties, 0);//convert string + System::String ^mwinInfo = Global::AUTO_BRIDGE->getWindowInfo(System::IntPtr(jwindowHandle), marshal_as(properties)); + env->ReleaseStringUTFChars(jproperties, properties); //release string + marshal_context context; + return env->NewStringUTF(context.marshal_as(mwinInfo)); +} + +/* + * Class: org_synthuse_UiaBridge + * Method: getWindowInfo + * Signature: (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_org_synthuse_UiaBridge_getWindowInfo__Ljava_lang_String_2Ljava_lang_String_2(JNIEnv *env, jobject obj, jstring jruntimeIdStr, jstring jproperties) +{ + const char *properties = env->GetStringUTFChars(jproperties, 0);//convert string + const char *runtimeIdStr = env->GetStringUTFChars(jruntimeIdStr, 0);//convert string + System::String ^mwinInfo = Global::AUTO_BRIDGE->getWindowInfo(marshal_as(runtimeIdStr), marshal_as(properties)); + env->ReleaseStringUTFChars(jruntimeIdStr, runtimeIdStr); //release string + env->ReleaseStringUTFChars(jproperties, properties); //release string + marshal_context context; + return env->NewStringUTF(context.marshal_as(mwinInfo)); +} diff --git a/native/uiabridge/org_synthuse_UiaBridge.h b/native/uiabridge/org_synthuse_UiaBridge.h new file mode 100644 index 0000000..a41405e --- /dev/null +++ b/native/uiabridge/org_synthuse_UiaBridge.h @@ -0,0 +1,85 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class org_synthuse_UiaBridge */ + +#ifndef _Included_org_synthuse_UiaBridge +#define _Included_org_synthuse_UiaBridge +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: org_synthuse_UiaBridge + * Method: initialize + * Signature: (Ljava/lang/String;)V + */ +JNIEXPORT void JNICALL Java_org_synthuse_UiaBridge_initialize + (JNIEnv *, jobject, jstring); + +/* + * Class: org_synthuse_UiaBridge + * Method: shutdown + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_org_synthuse_UiaBridge_shutdown + (JNIEnv *, jobject); + +/* + * Class: org_synthuse_UiaBridge + * Method: addEnumFilter + * Signature: (Ljava/lang/String;Ljava/lang/String;)I + */ +JNIEXPORT jint JNICALL Java_org_synthuse_UiaBridge_addEnumFilter + (JNIEnv *, jobject, jstring, jstring); + +/* + * Class: org_synthuse_UiaBridge + * Method: clearEnumFilters + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_org_synthuse_UiaBridge_clearEnumFilters + (JNIEnv *, jobject); + +/* + * Class: org_synthuse_UiaBridge + * Method: enumWindowInfo + * Signature: (Ljava/lang/String;)[Ljava/lang/String; + */ +JNIEXPORT jobjectArray JNICALL Java_org_synthuse_UiaBridge_enumWindowInfo__Ljava_lang_String_2 + (JNIEnv *, jobject, jstring); + +/* + * Class: org_synthuse_UiaBridge + * Method: enumWindowInfo + * Signature: (ILjava/lang/String;)[Ljava/lang/String; + */ +JNIEXPORT jobjectArray JNICALL Java_org_synthuse_UiaBridge_enumWindowInfo__ILjava_lang_String_2 + (JNIEnv *, jobject, jint, jstring); + +/* + * Class: org_synthuse_UiaBridge + * Method: getWindowInfo + * Signature: (IILjava/lang/String;)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_org_synthuse_UiaBridge_getWindowInfo__IILjava_lang_String_2 + (JNIEnv *, jobject, jint, jint, jstring); + +/* + * Class: org_synthuse_UiaBridge + * Method: getWindowInfo + * Signature: (ILjava/lang/String;)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_org_synthuse_UiaBridge_getWindowInfo__ILjava_lang_String_2 + (JNIEnv *, jobject, jint, jstring); + +/* + * Class: org_synthuse_UiaBridge + * Method: getWindowInfo + * Signature: (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_org_synthuse_UiaBridge_getWindowInfo__Ljava_lang_String_2Ljava_lang_String_2 + (JNIEnv *, jobject, jstring, jstring); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/native/WpfBridge/resource.h b/native/uiabridge/resource.h similarity index 100% rename from native/WpfBridge/resource.h rename to native/uiabridge/resource.h diff --git a/native/uiabridge/uiabridge.cpp b/native/uiabridge/uiabridge.cpp new file mode 100644 index 0000000..7b495c1 --- /dev/null +++ b/native/uiabridge/uiabridge.cpp @@ -0,0 +1,422 @@ +/* + * Copyright 2014, Synthuse.org + * Released under the Apache Version 2.0 License. + * + * last modified by ejakubowski7@gmail.com +*/ +// This is the main DLL file. + +#include "stdafx.h" +#include "uiabridge.h" + +using namespace System; +using namespace System::Collections::Generic; +using namespace System::Windows::Automation; +using namespace uiabridge; + +AutomationBridge::AutomationBridge() +{ + enumFilters = gcnew Dictionary(); + cacheRequest = nullptr; + initializeCache(); +} + +AutomationBridge::~AutomationBridge() +{ + enumFilters->Clear(); + if (cacheRequest != nullptr) + cacheRequest->Pop(); //disable UI Automation Cache + //Console::WriteLine("disposing of AutomationBridge"); +} + +void AutomationBridge::initializeCache() +{ + cacheRequest = gcnew CacheRequest(); + //cacheRequest->AutomationElementMode = AutomationElementMode::Full; + cacheRequest->TreeFilter = Automation::RawViewCondition; + cacheRequest->TreeScope = TreeScope::Element;// | TreeScope::Children; + /* + cacheRequest->Add(AutomationElement::RuntimeIdProperty); + cacheRequest->Add(AutomationElement::ProcessIdProperty); + cacheRequest->Add(AutomationElement::FrameworkIdProperty); + cacheRequest->Add(AutomationElement::LocalizedControlTypeProperty); + cacheRequest->Add(AutomationElement::ControlTypeProperty); + cacheRequest->Add(AutomationElement::ClassNameProperty); + cacheRequest->Add(AutomationElement::NameProperty); + cacheRequest->Add(AutomationElement::BoundingRectangleProperty); + */ + System::String ^cachedPropStr = L"RuntimeIdProperty,ParentRuntimeIdProperty,NativeWindowHandleProperty,ProcessIdProperty,FrameworkIdProperty,LocalizedControlTypeProperty,ControlTypeProperty,ClassNameProperty,NameProperty,BoundingRectangleProperty"; + array ^rootProperties = AutomationElement::RootElement->GetSupportedProperties(); + List ^cacheList = gcnew List(); + if (cachedPropStr->Contains(L"NativeWindowHandleProperty")) //special property not in the root property list + { + cacheList->Add(AutomationElement::NativeWindowHandleProperty); + cacheRequest->Add(AutomationElement::NativeWindowHandleProperty); + } + for each(AutomationProperty ^ap in rootProperties) //loop through all supported Properties for a child + { + System::String ^currentPropertyStr = L""; //current property values + System::String ^shortPropName = L" null "; + if (ap->ProgrammaticName->Contains(L".")) //get short Property name + shortPropName = ap->ProgrammaticName->Substring(ap->ProgrammaticName->IndexOf(L".") + 1); + if (cachedPropStr->Contains(shortPropName) || cachedPropStr->Contains(ap->ProgrammaticName)) + { + cacheList->Add(ap);// add property to cachedRootProperties + cacheRequest->Add(ap); // add property to cacheRequest + //Console::WriteLine("caching property {0}", ap->ProgrammaticName); + } + } + cachedRootProperties = cacheList->ToArray(); + cacheRequest->Push(); //enable UI Automation Cache + //cachedRootProperties = AutomationElement::RootElement->GetSupportedProperties(); +} + +int AutomationBridge::addEnumFilter(System::String ^propertyName, System::String ^propertyValue) +{ + enumFilters->Add(propertyName, propertyValue); + return enumFilters->Count; +} + +void AutomationBridge::clearEnumFilters() +{ + enumFilters->Clear(); +} + +Boolean AutomationBridge::isElementFiltered(System::Windows::Automation::AutomationElement ^element) +{ + return isElementFiltered(element, nullptr); +} + +Boolean AutomationBridge::isElementFiltered(System::Windows::Automation::AutomationElement ^element, List ^filterModifierList) +{ + Boolean result = false; + int filterMatchCount = 0; + if (enumFilters->Count == 0) + return result; + array ^aps = cachedRootProperties;//element->GetSupportedProperties(); + for each(AutomationProperty ^ap in aps) //loop through all supported Properties for a child + { + System::String ^currentPropertyStr = L""; //current property values + System::String ^shortPropName = L" null "; + if (ap->ProgrammaticName->Contains(L".")) //get short Property name + shortPropName = ap->ProgrammaticName->Substring(ap->ProgrammaticName->IndexOf(L".") + 1); + //System::Console::WriteLine("property: {0}", shortPropName); + for each(System::String ^key in enumFilters->Keys) + { + if (filterModifierList != nullptr) + if (filterModifierList->Contains(key) && key->StartsWith(PARENT_MODIFIER+ "/") ) // modifier has been applied and filters should be ignored + { + ++filterMatchCount; + //System::Console::WriteLine("PARENT_MODIFIER {0}", key); + continue; + } + else if(filterModifierList->Contains(key) && key->StartsWith(FIRST_MODIFIER+ "/")) //first already found stop! + { + //System::Console::WriteLine("FIRST_MODIFIER {0}", key); + return true; + } + System::String ^filterProp = key; + System::String ^modifier = L""; + int pos = key->IndexOf(L"/"); + if (pos != -1)//tree modifier + { + modifier = filterProp->Substring(0, pos); + filterProp = filterProp->Substring(pos+1); + //System::Console::WriteLine("modifier: {0}, {1}, {2}", modifier, filterProp, key); + } + if (shortPropName->Equals(filterProp) || ap->ProgrammaticName->Equals(filterProp)) + {//this element has a matching filter property + //System::Console::WriteLine("matched property: {0}", filterProp); + System::String ^valStr = L""; + if (ap->ProgrammaticName->Equals(L"AutomationElementIdentifiers.RuntimeIdProperty")) + {//runtimeId are int array so need to test it differently + array ^idArray = (array ^)element->GetCurrentPropertyValue(ap); + for each(System::Int32 val in idArray) + { + valStr += System::Convert::ToString(val) + L"-"; + } + valStr = valStr->TrimEnd('-'); + //System::Console::WriteLine("runtimeId: {0}", valStr); + } + else //all other property types that are strings + { + valStr = element->GetCachedPropertyValue(ap)->ToString(); + //valStr = element->GetCurrentPropertyValue(ap)->ToString(); + } + //System::Console::WriteLine("test property vals: {0} , {1}", valStr, enumFilters[key]); + + if (valStr->Equals(enumFilters[key])) // value matches filter value + { + //System::Console::WriteLine("matched property vals: {0} , {1}", valStr, enumFilters[key]); + //result = false; + ++filterMatchCount; + if (filterModifierList != nullptr) + if (modifier->Equals(PARENT_MODIFIER)) //if modifier is parent then add to modifier list + { + //System::Console::WriteLine("modifier added1 {0}", key); + filterModifierList->Add(key); + } + else if(modifier->Equals(FIRST_MODIFIER)) { + //System::Console::WriteLine("first modifier added1 {0} {1}", key, filterModifierList->Count); + //for each (System::String ^mod in filterModifierList) + // System::Console::WriteLine("mod {0}", mod); + filterModifierList->Add(key); + return false; + } + } + else// not matched + if (filterModifierList != nullptr) + if (modifier->Equals(ALL_MODIFIER)) //doesn't matter if ALL modifier doesn't match, need to keep searching + { + //System::Console::WriteLine("modifier added2 {0}", key); + filterModifierList->Add(key); + } + else if(modifier->Equals(FIRST_MODIFIER)) + filterModifierList->Add(ALL_MODIFIER + "/" + filterProp); + } + } + + } + //System::Console::WriteLine("filterMatchCount: {0}", filterMatchCount); + if (filterMatchCount > 0) + return false; + else + return true; + //return result; +} + +void AutomationBridge::processFilterModifier(Boolean filtered, Boolean modifierChanged, List ^filterModifierList) +{ + if (!filtered) //not filtered so return element + { + //winInfoList->Add(getWindowInfo(currentElement, properties)); + //winInfoList->AddRange(enumWindowInfo(currentElement, properties, filterModifierList)); + if (modifierChanged && filterModifierList[filterModifierList->Count - 1]->StartsWith(FIRST_MODIFIER) == false) //modifier was added and needs to be removed + {// don't remove First modifier + //System::Console::WriteLine("modifier removed1 {0}", filterModifierList[filterModifierList->Count - 1]); + filterModifierList->RemoveAt(filterModifierList->Count - 1); + } + } + else //filtered, but if modifier used keep searching children + { + if (modifierChanged) //modifier was added and needs to be removed (ALL) + { + //winInfoList->AddRange(enumWindowInfo(currentElement, properties, filterModifierList)); + if (filterModifierList[filterModifierList->Count - 1]->StartsWith(FIRST_MODIFIER) == false)// don't remove First modifier + { + //System::Console::WriteLine("modifier removed2 {0}", filterModifierList[filterModifierList->Count - 1]); + filterModifierList->RemoveAt(filterModifierList->Count - 1); + } + } + } + +} + +System::String ^ AutomationBridge::getRuntimeIdFromElement(System::Windows::Automation::AutomationElement ^element) +{ + System::String ^result = L""; + System::Object ^currentVal = element->GetCurrentPropertyValue(AutomationElement::RuntimeIdProperty); + if (currentVal != nullptr) + { + array ^idArray = (array ^)currentVal; + for each(System::Int32 val in idArray) + { + result += System::Convert::ToString(val) + L"-"; + } + result = result->TrimEnd('-'); + //System::Console::WriteLine("id: {0}", result); + } + return result; +} + +array ^ AutomationBridge::enumWindowInfo(System::String ^properties) +{ + return enumWindowInfo(AutomationElement::RootElement, properties); +} + +array ^ AutomationBridge::enumWindowInfo(System::IntPtr windowHandle, System::String ^properties) +{ + AutomationElement ^element = AutomationElement::FromHandle(windowHandle); + List ^winInfoList = gcnew List(); + if (!isElementFiltered(element)) //test parent should be filtered + winInfoList->Add(getWindowInfo(element, properties)); + winInfoList->AddRange(enumWindowInfo(element, properties)); + return winInfoList->ToArray(); +} + +array ^ AutomationBridge::enumWindowInfo(AutomationElement ^element, System::String ^properties) +{ + List ^filterModifierList = gcnew List(); //can change descendants filters based on parent's filters + return enumWindowInfo(element, properties, filterModifierList); +} + +array ^ AutomationBridge::enumWindowInfo(AutomationElement ^element, System::String ^properties, List ^filterModifierList) +{ + List ^winInfoList = gcnew List(); + if (element == nullptr) + return winInfoList->ToArray(); + TreeWalker ^tw = TreeWalker::RawViewWalker; + //System::Console::WriteLine("get info: {0}", getWindowInfo(element, properties)); + //AutomationElement ^currentElement = tw->GetFirstChild(element, cacheRequest); + AutomationElement ^currentElement = nullptr; + /*if (element->CachedChildren != nullptr) + { + System::Console::WriteLine("using cached child"); + currentElement = element->CachedChildren[0]; + } + else*/ + { + //System::Console::WriteLine("not cached child"); + currentElement = tw->GetFirstChild(element, cacheRequest); + } + if (currentElement == nullptr) + { + //System::Console::WriteLine("no children {0}", element->CachedChildren->Count); + //System::Console::WriteLine("no children"); + return winInfoList->ToArray(); + } + //else + // System::Console::WriteLine("yes children"); + + while (currentElement != nullptr) + { + try + { + int fmlOriginalSize = filterModifierList->Count; + Boolean filtered = isElementFiltered(currentElement, filterModifierList); + Boolean modifierChanged = fmlOriginalSize != filterModifierList->Count; + if (!filtered) //not filtered so return element + { + winInfoList->Add(getWindowInfo(currentElement, properties)); + winInfoList->AddRange(enumWindowInfo(currentElement, properties, filterModifierList)); + } + else //filtered, but if modifier used keep searching children + { + if (modifierChanged) //modifier was added search children + winInfoList->AddRange(enumWindowInfo(currentElement, properties, filterModifierList)); + } + processFilterModifier(filtered, modifierChanged, filterModifierList); //cleans filterModifierList + //System::Console::WriteLine("element: {0}", currentElement); + //currentElement-> + currentElement = tw->GetNextSibling(currentElement, cacheRequest); + } catch (Exception ^ex) + { + System::Console::WriteLine("Exception: {0} {1}", ex->Message, ex->StackTrace); + } + } + return winInfoList->ToArray(); +} + +System::String ^ AutomationBridge::getWindowInfo(AutomationElement ^element, System::String ^properties) +{ + System::String ^resultProperties = L""; + System::String ^propertyNameErrorCheck = L""; + try + { + //when wildcard is enabled it will pull all property names & values + System::Boolean wildcardEnabled = false; + if (properties->Equals(L"*")) + wildcardEnabled = true; + + //create array for keeping order of properties + System::String ^delim = L","; + array ^propSpltArray = properties->Split(delim->ToCharArray()); + TreeWalker ^tw = TreeWalker::ControlViewWalker; + System::Int32 count = 0; + array ^aps = cachedRootProperties;//element->GetSupportedProperties(); + array ^propValues = gcnew array(propSpltArray->Length);//keep order + System::String ^wildcardProperties = L""; + if (wildcardEnabled) { + wildcardProperties += "ParentRuntimeIdProperty:" + getRuntimeIdFromElement(tw->GetParent(element, cacheRequest)) + ","; + //propValues = gcnew array(aps->Length +1 );//add one for parent property since it doesn't exist + } + for(int i=0 ; i < propValues->Length ; i++) + { + propValues[i] = L""; + if (propSpltArray[i]->Equals("ParentRuntimeIdProperty"))//custom property for getting parent + { + propValues[i] = getRuntimeIdFromElement(tw->GetParent(element, cacheRequest)); + } + } + for each(AutomationProperty ^ap in aps) //loop through all supported Properties for a child + { + propertyNameErrorCheck = ap->ProgrammaticName;//debug purposes + System::String ^currentPropertyStr = L""; //current property values + //System::Console::WriteLine("property: {0}", ap->ProgrammaticName); + System::String ^shortPropName = L" null "; + if (ap->ProgrammaticName->Contains(L".")) + shortPropName = ap->ProgrammaticName->Substring(ap->ProgrammaticName->IndexOf(L".") + 1); + if (properties->Contains(shortPropName) || properties->Contains(ap->ProgrammaticName) || ap->ProgrammaticName->Equals(properties) || wildcardEnabled) + { + //System::Console::WriteLine("shortPropName: {0}", shortPropName); + //System::Object ^currentVal = element->GetCurrentPropertyValue(ap); + System::Object ^currentVal = element->GetCachedPropertyValue(ap); + if (currentVal == nullptr) + continue; + if (ap->ProgrammaticName->Equals(L"AutomationElementIdentifiers.RuntimeIdProperty")) + { + array ^idArray = (array ^)currentVal; + for each(System::Int32 val in idArray) + { + currentPropertyStr += System::Convert::ToString(val) + L"-"; + } + currentPropertyStr = currentPropertyStr->TrimEnd('-'); + //System::Console::WriteLine("id: {0}", result); + } + else//not runtimeId which is an Int32[] + { + currentPropertyStr = currentVal->ToString(); + currentPropertyStr = currentPropertyStr->Replace(",",","); + } + } + if (currentPropertyStr->Equals(L"")) //if there isn't a value skip + continue; + if (wildcardEnabled) { + wildcardProperties += shortPropName + ":" +currentPropertyStr + ","; + continue; + } + //System::Console::WriteLine("currentPropertyStr: {0}", currentPropertyStr); + //find the correct order to return this property + for(int i=0 ; i < propSpltArray->Length ; i++) + { + if (propSpltArray[i]->Equals(shortPropName) || propSpltArray[i]->Equals(ap->ProgrammaticName)) + propValues[i] = currentPropertyStr; + } + } + //output properties in the correct order + for(int i=0 ; i < propSpltArray->Length ; i++) + resultProperties += propValues[i] + L","; + if (wildcardEnabled) + resultProperties += wildcardProperties; + } 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); + } + return resultProperties; + +} + +System::String ^ AutomationBridge::getWindowInfo(System::Int32 x, System::Int32 y, System::String ^properties) +{ + AutomationElement ^element = AutomationElement::FromPoint(System::Windows::Point(x, y)); + return getWindowInfo(element, properties); +} + +System::String ^ AutomationBridge::getWindowInfo(System::IntPtr windowHandle, System::String ^properties) +{ + AutomationElement ^element = AutomationElement::FromHandle(windowHandle); + return getWindowInfo(element, properties); +} + +System::String ^ AutomationBridge::getWindowInfo(System::String ^runtimeIdStr, System::String ^properties) +{ + System::String ^filter = L"First/RuntimeIdProperty"; //get first matching runtimeIdProperty + enumFilters->Add(filter, runtimeIdStr); + array ^props = enumWindowInfo(properties); + enumFilters->Remove(filter); + if (props->Length > 0) //if result array has a match return first result + return props[0]; + else + return ""; + //return getWindowInfo(element, properties); +} diff --git a/native/uiabridge/uiabridge.h b/native/uiabridge/uiabridge.h new file mode 100644 index 0000000..16cd3aa --- /dev/null +++ b/native/uiabridge/uiabridge.h @@ -0,0 +1,46 @@ +/* + * Copyright 2014, Synthuse.org + * Released under the Apache Version 2.0 License. + * + * last modified by ejakubowski7@gmail.com +*/ +// uiabridge.h + +#pragma once + +using namespace System; +using namespace System::Collections::Generic; +using namespace System::Windows::Automation; + +namespace uiabridge { + + public ref class AutomationBridge + { + public: + AutomationBridge(void); + ~AutomationBridge(); + int addEnumFilter(System::String ^propertyName, System::String ^propertyValue); + void clearEnumFilters(); + Boolean isElementFiltered(System::Windows::Automation::AutomationElement ^element); + Boolean isElementFiltered(System::Windows::Automation::AutomationElement ^element, List ^filterModifierList); + System::String ^ getRuntimeIdFromElement(System::Windows::Automation::AutomationElement ^element); + array ^ enumWindowInfo(System::String ^properties); + array ^ enumWindowInfo(System::IntPtr windowHandle, System::String ^properties); + array ^ enumWindowInfo(AutomationElement ^element, System::String ^properties); + array ^ enumWindowInfo(AutomationElement ^element, System::String ^properties, List ^filterModifierList); + System::String ^ getWindowInfo(AutomationElement ^element, System::String ^properties); + System::String ^ getWindowInfo(System::Int32 x, System::Int32 y, System::String ^properties); + System::String ^ getWindowInfo(System::IntPtr windowHandle, System::String ^properties); + System::String ^ getWindowInfo(System::String ^runtimeIdStr, System::String ^properties); + + static System::String ^ALL_MODIFIER = L"All";// find all matching elements of this filter + static System::String ^PARENT_MODIFIER = L"Parent";//find all children of this matching parent filter + static System::String ^FIRST_MODIFIER = L"First"; //find first element matching this filter then stop + private: + void initializeCache(); + Dictionary ^enumFilters; + void AutomationBridge::processFilterModifier(Boolean filtered, Boolean modifierChanged, List ^filterModifierList); + CacheRequest ^cacheRequest; + array ^cachedRootProperties; + }; +} diff --git a/native/WpfBridge/WpfBridge.vcxproj b/native/uiabridge/uiabridge.vcxproj similarity index 93% rename from native/WpfBridge/WpfBridge.vcxproj rename to native/uiabridge/uiabridge.vcxproj index 3e86389..c39c426 100644 --- a/native/WpfBridge/WpfBridge.vcxproj +++ b/native/uiabridge/uiabridge.vcxproj @@ -19,10 +19,10 @@ - {3141812E-36D5-4E7C-A388-EFED9AE250A5} + {BAC1B079-7B87-4396-B17F-91A86DF1AE29} v4.0 ManagedCProj - WpfBridge + uiabridge @@ -120,8 +120,7 @@ mkdir "$(ProjectDir)bin" -copy /Y "$(TargetPath)" "$(ProjectDir)bin\wpfbridge$(PlatformArchitecture)$(TargetExt)" - +copy /Y "$(TargetPath)" "$(ProjectDir)bin\uiabridge$(PlatformArchitecture)$(TargetExt)" @@ -137,8 +136,7 @@ copy /Y "$(TargetPath)" "$(ProjectDir)bin\wpfbridge$(PlatformArchitecture)$(Targ mkdir "$(ProjectDir)bin" -copy /Y "$(TargetPath)" "$(ProjectDir)bin\wpfbridge$(PlatformArchitecture)$(TargetExt)" - +copy /Y "$(TargetPath)" "$(ProjectDir)bin\uiabridge$(PlatformArchitecture)$(TargetExt)" @@ -146,28 +144,29 @@ copy /Y "$(TargetPath)" "$(ProjectDir)bin\wpfbridge$(PlatformArchitecture)$(Targ + - + - + - + Create Create Create Create - + diff --git a/native/WpfBridge/WpfBridge.vcxproj.filters b/native/uiabridge/uiabridge.vcxproj.filters similarity index 90% rename from native/WpfBridge/WpfBridge.vcxproj.filters rename to native/uiabridge/uiabridge.vcxproj.filters index 9689af0..f0a71a3 100644 --- a/native/WpfBridge/WpfBridge.vcxproj.filters +++ b/native/uiabridge/uiabridge.vcxproj.filters @@ -15,16 +15,16 @@ + + Header Files + Header Files Header Files - - Header Files - - + Header Files @@ -32,16 +32,16 @@ + + Source Files + Source Files Source Files - - Source Files - - + Source Files diff --git a/native/WpfBridge/WpfBridge.vcxproj.user b/native/uiabridge/uiabridge.vcxproj.user similarity index 100% rename from native/WpfBridge/WpfBridge.vcxproj.user rename to native/uiabridge/uiabridge.vcxproj.user diff --git a/native/uiabtest/AssemblyInfo.cpp b/native/uiabtest/AssemblyInfo.cpp new file mode 100644 index 0000000..8c84297 --- /dev/null +++ b/native/uiabtest/AssemblyInfo.cpp @@ -0,0 +1,40 @@ +#include "stdafx.h" + +using namespace System; +using namespace System::Reflection; +using namespace System::Runtime::CompilerServices; +using namespace System::Runtime::InteropServices; +using namespace System::Security::Permissions; + +// +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +// +[assembly:AssemblyTitleAttribute("uiabtest")]; +[assembly:AssemblyDescriptionAttribute("")]; +[assembly:AssemblyConfigurationAttribute("")]; +[assembly:AssemblyCompanyAttribute("na")]; +[assembly:AssemblyProductAttribute("uiabtest")]; +[assembly:AssemblyCopyrightAttribute("Copyright (c) na 2014")]; +[assembly:AssemblyTrademarkAttribute("")]; +[assembly:AssemblyCultureAttribute("")]; + +// +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the value or you can default the Revision and Build Numbers +// by using the '*' as shown below: + +[assembly:AssemblyVersionAttribute("1.0.*")]; + +[assembly:ComVisible(false)]; + +[assembly:CLSCompliantAttribute(true)]; + +[assembly:SecurityPermission(SecurityAction::RequestMinimum, UnmanagedCode = true)]; diff --git a/native/uiabtest/ReadMe.txt b/native/uiabtest/ReadMe.txt new file mode 100644 index 0000000..0002f31 --- /dev/null +++ b/native/uiabtest/ReadMe.txt @@ -0,0 +1,35 @@ +======================================================================== + APPLICATION : uiabtest Project Overview +======================================================================== + +AppWizard has created this uiabtest Application for you. + +This file contains a summary of what you will find in each of the files that +make up your uiabtest application. + +uiabtest.vcxproj + This is the main project file for VC++ projects generated using an Application Wizard. + It contains information about the version of Visual C++ that generated the file, and + information about the platforms, configurations, and project features selected with the + Application Wizard. + +uiabtest.vcxproj.filters + This is the filters file for VC++ projects generated using an Application Wizard. + It contains information about the association between the files in your project + and the filters. This association is used in the IDE to show grouping of files with + similar extensions under a specific node (for e.g. ".cpp" files are associated with the + "Source Files" filter). + +uiabtest.cpp + This is the main application source file. + +AssemblyInfo.cpp + Contains custom attributes for modifying assembly metadata. + +///////////////////////////////////////////////////////////////////////////// +Other notes: + +AppWizard uses "TODO:" to indicate parts of the source code you +should add to or customize. + +///////////////////////////////////////////////////////////////////////////// diff --git a/native/uiabtest/app.ico b/native/uiabtest/app.ico new file mode 100644 index 0000000..3a5525f Binary files /dev/null and b/native/uiabtest/app.ico differ diff --git a/native/uiabtest/app.rc b/native/uiabtest/app.rc new file mode 100644 index 0000000..eab4306 Binary files /dev/null and b/native/uiabtest/app.rc differ diff --git a/native/uiabtest/resource.h b/native/uiabtest/resource.h new file mode 100644 index 0000000..d5ac7c4 --- /dev/null +++ b/native/uiabtest/resource.h @@ -0,0 +1,3 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by app.rc diff --git a/native/WpfBridge/Stdafx.cpp b/native/uiabtest/stdafx.cpp similarity index 75% rename from native/WpfBridge/Stdafx.cpp rename to native/uiabtest/stdafx.cpp index a9a851a..b0e7c23 100644 --- a/native/WpfBridge/Stdafx.cpp +++ b/native/uiabtest/stdafx.cpp @@ -1,5 +1,7 @@ // stdafx.cpp : source file that includes just the standard includes -// WpfBridge.pch will be the pre-compiled header +// uiabtest.pch will be the pre-compiled header // stdafx.obj will contain the pre-compiled type information #include "stdafx.h" + + diff --git a/native/uiabtest/stdafx.h b/native/uiabtest/stdafx.h new file mode 100644 index 0000000..347bb4c --- /dev/null +++ b/native/uiabtest/stdafx.h @@ -0,0 +1,11 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once + +// TODO: reference additional headers your program requires here +#include +#include +#include \ No newline at end of file diff --git a/native/uiabtest/uiabtest.cpp b/native/uiabtest/uiabtest.cpp new file mode 100644 index 0000000..c14b813 --- /dev/null +++ b/native/uiabtest/uiabtest.cpp @@ -0,0 +1,71 @@ +/* + * Copyright 2014, Synthuse.org + * Released under the Apache Version 2.0 License. + * + * last modified by ejakubowski7@gmail.com +*/ +// uiabtest.cpp : main project file. + +#include "stdafx.h" + +using namespace System; +using namespace System::Windows::Automation; +using namespace uiabridge; + +void outputResults(array ^winInfo) +{ + System::IO::StreamWriter ^file = gcnew System::IO::StreamWriter("c:\\temp.txt"); + for each(System::String ^prop in winInfo) + { + Console::WriteLine(prop); + file->WriteLine(prop); + } + file->Flush(); + file->Close(); + +} + +int main(array ^args) +{ + Console::WriteLine(L"UI Automation Bridge Test"); + AutomationBridge ^ab = gcnew AutomationBridge(); + System::String ^propList = L"RuntimeIdProperty,ParentRuntimeIdProperty,NativeWindowHandleProperty,ProcessIdProperty,FrameworkIdProperty,LocalizedControlTypeProperty,ClassNameProperty,NameProperty"; + //System::String ^propList = L"RuntimeIdProperty,BoundingRectangleProperty"; + Console::WriteLine(propList); + //System::String ^winInfo1 = ab->getWindowInfo(System::IntPtr(3409618), propList); + + System::DateTime start = System::DateTime::Now; + //ab->addEnumFilter("Parent/ClassNameProperty", "Notepad"); + //ab->addEnumFilter("First/RuntimeIdProperty", "42-4784952"); + //ab->addEnumFilter("ClassNameProperty", "Notepad"); + //ab->addEnumFilter("All/ClassNameProperty", "Edit"); + //ab->addEnumFilter("All/LocalizedControlTypeProperty", "menu item"); + ab->addEnumFilter("Parent/FrameworkIdProperty", "WinForm"); + //ab->addEnumFilter("Parent/FrameworkIdProperty", "WPF"); + //ab->addEnumFilter("Parent/ClassNameProperty", "WindowsForms10.Window.8.app.0.2bf8098_r13_ad1"); + array ^winInfo = ab->enumWindowInfo(propList); //L"*" + //ab->clearEnumFilters(); + //ab->addEnumFilter("Parent/FrameworkIdProperty", "WinForm"); + //array ^winInfo = ab->enumWindowInfo(System::IntPtr(3409618), propList); //L"*" + //array ^winInfo = ab->enumWindowInfo(System::IntPtr(12977932), propList); //L"*" + //Console::WriteLine("enumWindowInfo x,y: {0}", ab->getWindowInfo(100,100, propList); //L"*" + + outputResults(winInfo); + //Globals::Global::AUTO_BRIDGE->clearEnumFilters(); + //winInfo = nullptr; + //winInfo = Globals::Global::AUTO_BRIDGE->enumWindowInfo(System::IntPtr(7603636), propList); + //Console::WriteLine("winInfo length: {0}", winInfo->Length); + //winInfo = Globals::Global::AUTO_BRIDGE->enumWindowInfo(System::IntPtr(7603636), propList); + //Console::WriteLine("winInfo length: {0}", winInfo->Length); + + //Console::WriteLine("getWindowInfo RuntimeIdProperty: {0}", ab->getWindowInfo("42-4784952", propList)); + + //System::Threading::Thread::Sleep(10000); //10 seconds sleep + //array ^winInfo2 = ab->enumWindowInfo(propList); //L"*" + //outputResults(winInfo2); + + System::Double seconds = System::Math::Round(System::DateTime::Now.Subtract(start).TotalSeconds, 4); + Console::WriteLine(L"Total Elements: {0} in {1} seconds", winInfo->Length, seconds); + getch();//wait for user input + return 0; +} diff --git a/native/uiabtest/uiabtest.vcxproj b/native/uiabtest/uiabtest.vcxproj new file mode 100644 index 0000000..1f42b2a --- /dev/null +++ b/native/uiabtest/uiabtest.vcxproj @@ -0,0 +1,169 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {7958D1B7-F169-40FA-A7A0-10E8E0F90CDA} + v4.0 + ManagedCProj + uiabtest + + + + Application + true + true + Unicode + + + Application + true + true + Unicode + + + Application + false + true + Unicode + + + Application + false + true + Unicode + + + + + + + + + + + + + + + + + + + true + + + true + + + false + + + false + + + + Level3 + Disabled + WIN32;_DEBUG;%(PreprocessorDefinitions) + Use + + + true + + + + + + + Level3 + Disabled + WIN32;_DEBUG;%(PreprocessorDefinitions) + Use + + + true + + + + + + + Level3 + WIN32;NDEBUG;%(PreprocessorDefinitions) + Use + + + true + + + + + + + Level3 + WIN32;NDEBUG;%(PreprocessorDefinitions) + Use + + + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Create + Create + Create + Create + + + + + + {bac1b079-7b87-4396-b17f-91a86df1ae29} + + + + + + \ No newline at end of file diff --git a/native/uiabtest/uiabtest.vcxproj.filters b/native/uiabtest/uiabtest.vcxproj.filters new file mode 100644 index 0000000..7f6715d --- /dev/null +++ b/native/uiabtest/uiabtest.vcxproj.filters @@ -0,0 +1,47 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + + Resource Files + + + + + Header Files + + + Header Files + + + + + Resource Files + + + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/native/uiabtest/uiabtest.vcxproj.user b/native/uiabtest/uiabtest.vcxproj.user new file mode 100644 index 0000000..ace9a86 --- /dev/null +++ b/native/uiabtest/uiabtest.vcxproj.user @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/org/synthuse/RobotMacro.java b/src/org/synthuse/RobotMacro.java index e35f5fc..999365b 100644 --- a/src/org/synthuse/RobotMacro.java +++ b/src/org/synthuse/RobotMacro.java @@ -195,14 +195,142 @@ public class RobotMacro { lastException = e; } } +/* SendKeys Special Keys List +{BACKSPACE}, {BS}, or {BKSP} +{BREAK} +{CAPSLOCK} +{DELETE} or {DEL} +{DOWN} +{END} +{ENTER} or ~ +{ESC} +{HELP} +{HOME} +{INSERT} or {INS} +{LEFT} +{NUMLOCK} +{PGDN} +{PGUP} +{PRTSC} (reserved for future use) +{RIGHT} +{SCROLLLOCK} +{TAB} +{UP} +{F1} +{F2} +{F3} +{F4} +{F5} +{F6} +{F7} +{F8} +{F9} +{F10} +{F11} +{F12} +{F13} +{F14} +{F15} +{F16} +{ADD} +{SUBTRACT} +{MULTIPLY} +{DIVIDE} +{{} +{}} +SHIFT + +CTRL ^ +ALT % + + */ public static boolean sendKeys(String keyCommands) { try { Robot robot = new Robot(); + boolean specialKeyFlag = false; + String specialKey = ""; + boolean modifierKeyFlag = false; + String modifierKeys = ""; for (int i = 0; i < keyCommands.length(); i++) { char key = keyCommands.charAt(i); - int[] keyCode = getKeyCode(key); - pressKeyCodes(robot, keyCode); + if (specialKeyFlag) + specialKey += key; + if (key == '{' && specialKeyFlag == false) { + specialKeyFlag = true; + specialKey = "{"; + } + + if (!specialKeyFlag) { //not special key(tab,enter,...) just press normal keys and modifiers + // Modifier key logic + if (key == '+' || key == '^' || key == '%') { //shift alt or ctrl + if (!modifierKeyFlag) { + modifierKeys = key + ""; + modifierKeyFlag = true; + } + else + modifierKeys += key + ""; //append multiple modifiers + if (key == '+') + robot.keyPress(KeyEvent.VK_SHIFT); + if (key == '^') + robot.keyPress(KeyEvent.VK_CONTROL); + if (key == '%') + robot.keyPress(KeyEvent.VK_ALT); + continue; //skip to next key + } + pressKeyCodes(robot, getKeyCode(key)); + } + if (specialKeyFlag) { + if (specialKey.equals("{ENTER}")) { + specialKeyFlag = false; + pressKeyCodes(robot, new int[]{KeyEvent.VK_ENTER} ); + } + else if (specialKey.equals("{ESC}")) { + specialKeyFlag = false; + pressKeyCodes(robot, new int[]{KeyEvent.VK_ESCAPE} ); + } + else if (specialKey.equals("{HOME}")) { + specialKeyFlag = false; + pressKeyCodes(robot, new int[]{KeyEvent.VK_HOME} ); + } + else if (specialKey.equals("{END}")) { + specialKeyFlag = false; + pressKeyCodes(robot, new int[]{KeyEvent.VK_END} ); + } + else if (specialKey.equals("{PGDN}")) { + specialKeyFlag = false; + pressKeyCodes(robot, new int[]{KeyEvent.VK_PAGE_DOWN} ); + } + else if (specialKey.equals("{PGUP}")) { + specialKeyFlag = false; + pressKeyCodes(robot, new int[]{KeyEvent.VK_PAGE_UP} ); + } + else if (specialKey.equals("{TAB}")) { + specialKeyFlag = false; + pressKeyCodes(robot, new int[]{KeyEvent.VK_TAB} ); + } + else if (specialKey.equals("{UP}")) { + specialKeyFlag = false; + pressKeyCodes(robot, new int[]{KeyEvent.VK_UP} ); + } + else if (specialKey.equals("{DOWN}")) { + specialKeyFlag = false; + pressKeyCodes(robot, new int[]{KeyEvent.VK_DOWN} ); + } + } + + if (modifierKeyFlag) { //time to release all the modifier keys + modifierKeyFlag = false; + for (int m = 0; m < modifierKeys.length(); m++) { + char mkey = modifierKeys.charAt(m); + if (mkey == '+') + robot.keyRelease(KeyEvent.VK_SHIFT); + if (mkey == '^') + robot.keyRelease(KeyEvent.VK_CONTROL); + if (mkey == '%') + robot.keyRelease(KeyEvent.VK_ALT); + } + modifierKeys = ""; + } } } catch (Exception e) { lastException = e; diff --git a/src/org/synthuse/SynthuseDlg.java b/src/org/synthuse/SynthuseDlg.java index 180f4e7..086dfa3 100644 --- a/src/org/synthuse/SynthuseDlg.java +++ b/src/org/synthuse/SynthuseDlg.java @@ -71,7 +71,7 @@ public class SynthuseDlg extends JFrame { /** * */ - public static String VERSION_STR = "1.1.0"; + public static String VERSION_STR = "1.1.2"; 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"; @@ -102,7 +102,7 @@ public class SynthuseDlg extends JFrame { private TestIdeFrame testIde = null; private int targetX; private int targetY; - private WpfBridge wpf = new WpfBridge(); + private UiaBridge uiabridge = new UiaBridge(); /** * Launch the application. @@ -449,7 +449,8 @@ public class SynthuseDlg extends JFrame { String handleStr = Api.GetHandleAsString(hwnd); String classStr = WindowsEnumeratedXml.escapeXmlAttributeValue(Api.GetWindowClassName(hwnd)); String parentStr = Api.GetHandleAsString(User32.instance.GetParent(hwnd)); - String runtimeId = wpf.getRuntimeIdFromPoint(targetX, targetY); + String enumProperties = uiabridge.getWindowInfo(targetX, targetY, WindowInfo.UIA_PROPERTY_LIST); + String runtimeId = WindowInfo.getRuntimeIdFromProperties(enumProperties); lblStatus.setText("rid:" + runtimeId + " class: " + classStr + " hWnd: " + handleStr + " parent: " + parentStr + " X,Y: " + targetX + ", " + targetY); if (!lastDragHwnd.equals(handleStr) || !lastRuntimeId.equals(runtimeId)) { if (!lastDragHwnd.isEmpty()) { @@ -459,7 +460,7 @@ public class SynthuseDlg extends JFrame { lastRuntimeId = runtimeId; //lastDragHwnd = (hwnd + ""); Api.highlightWindow(hwnd); - XpathManager.buildXpathStatementThreaded(hwnd, runtimeId, textPane, xpathEvents); + XpathManager.buildXpathStatementThreaded(hwnd, enumProperties, textPane, xpathEvents); } } diff --git a/src/org/synthuse/WpfBridge.java b/src/org/synthuse/UiaBridge.java similarity index 72% rename from src/org/synthuse/WpfBridge.java rename to src/org/synthuse/UiaBridge.java index 3e26bfd..fabaac9 100644 --- a/src/org/synthuse/WpfBridge.java +++ b/src/org/synthuse/UiaBridge.java @@ -1,23 +1,14 @@ -/* - * 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.io.*; -public class WpfBridge { - +public class UiaBridge { static { String archDataModel = System.getProperty("sun.arch.data.model");//32 or 64 bit - //System.loadLibrary("native/WpfBridge" + archDataModel); // WpfBridge32.dll (Windows) or WpfBridge32.so (Unixes) - loadNativeLibraryFromJar("/wpfbridge" + archDataModel + ".dll"); + loadNativeLibraryFromJar("/uiabridge" + archDataModel + ".dll"); } public static void loadNativeLibraryFromJar(String path) { @@ -49,7 +40,7 @@ public class WpfBridge { byte[] buffer = new byte[1024]; int readBytes; // Open and check input stream - InputStream is = WpfBridge.class.getResourceAsStream(path); + InputStream is = UiaBridge.class.getResourceAsStream(path); if (is == null) { //check if valid System.out.println("File " + path + " was not found inside JAR."); return; @@ -69,7 +60,27 @@ public class WpfBridge { // Finally, load the library System.load(temp.getAbsolutePath()); } + + public UiaBridge () + { + initialize(""); + } + + public native void initialize(String properties); + public native void shutdown(); + 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 @@ -80,7 +91,7 @@ public class WpfBridge { public native int countChildrenWindows(); public native int countChildrenWindows(String runtimeIdValue); - public native String[] enumChildrenWindowIds(String runtimeIdValue); //if runtimeIdValue is null will start at desktop + 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. @@ -92,11 +103,12 @@ public class WpfBridge { public native String getProperty(String propertyName, String runtimeIdValue); public native String[] getProperties(String runtimeIdValue); public native String[] getPropertiesAndValues(String runtimeIdValue); - + */ public Point getCenterOfElement(String runtimeIdValue) { Point p = new Point(); - String boundary = getProperty("BoundingRectangleProperty", runtimeIdValue); - //System.out.println("boundary: " + boundary); //boundary: 841,264,125,29 + String boundary = getWindowInfo(runtimeIdValue, "BoundingRectangleProperty"); + boundary = WindowInfo.replaceEscapedCodes(boundary); + //System.out.println("runtimeId: " + runtimeIdValue + ", boundary: " + boundary); //boundary: 841,264,125,29 String[] boundarySplt = boundary.split(","); int x = Integer.parseInt(boundarySplt[0]); int y = Integer.parseInt(boundarySplt[1]); @@ -106,25 +118,4 @@ public class WpfBridge { p.y = ((height) /2) + y; return p; } - - public String getWindowClass(String runtimeIdValue) { - return getProperty("ClassNameProperty", runtimeIdValue); - } - - public String getWindowText(String runtimeIdValue) { - return getProperty("NameProperty", runtimeIdValue); - } - - public String getWindowValue(String runtimeIdValue) { - return getProperty("ValueProperty", runtimeIdValue); - } - - public String getWindowAutomationId(String runtimeIdValue) { - return getProperty("AutomationIdProperty", runtimeIdValue); - } - - public String getWindowFramework(String runtimeIdValue) { - return getProperty("FrameworkIdProperty", runtimeIdValue); - } - } diff --git a/src/org/synthuse/WindowInfo.java b/src/org/synthuse/WindowInfo.java index 3c47989..aae79af 100644 --- a/src/org/synthuse/WindowInfo.java +++ b/src/org/synthuse/WindowInfo.java @@ -24,7 +24,9 @@ import com.sun.jna.ptr.PointerByReference; public class WindowInfo { - public static String WPF_PROPERTY_LIST = "RuntimeIdProperty,ParentRuntimeIdProperty,ProcessIdProperty,FrameworkIdProperty,ClassNameProperty,NameProperty,ValueProperty"; + public static String UIA_PROPERTY_LIST = "RuntimeIdProperty,ParentRuntimeIdProperty,ProcessIdProperty,FrameworkIdProperty,LocalizedControlTypeProperty,ClassNameProperty,NameProperty,ValueProperty"; + public static String UIA_RUNTIME_ID = "RuntimeIdProperty"; + public static int MAX_TEXT_SIZE = 200; public HWND hwnd; public String hwndStr = ""; @@ -33,6 +35,7 @@ public class WindowInfo { public RECT rect; public String text; public String value; + public String controlType = ""; public String className = ""; public boolean isChild = false; public String processName = ""; @@ -53,9 +56,11 @@ public class WindowInfo { text = Native.toString(buffer); if (text.isEmpty()) text = new Api().sendWmGetText(hWnd); - if (text.isEmpty()) { + //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.User32.instance.SendMessage(hWnd, Api.TB_BUTTONCOUNT, new WPARAM(0), new LPARAM(0)); @@ -146,9 +151,11 @@ public class WindowInfo { } this.hwnd = hWnd; hwndStr = Api.GetHandleAsString(hWnd); + if (this.hwndStr == null) + this.hwndStr = ""; } - public String replaceEscapedCodes(String input) { + public static String replaceEscapedCodes(String input) { //, is a comma , String result = input; result = result.replaceAll(",", ","); @@ -160,9 +167,9 @@ public class WindowInfo { return result; } - //support for WPF and Silverlight + //support for WPF, Silverlight, WinForms public WindowInfo(String enumProperties, boolean isChild) { - //WPF_PROPERTY_LIST = "RuntimeIdProperty,ParentRuntimeIdProperty,ProcessIdProperty,FrameworkIdProperty,ClassNameProperty,NameProperty"; + //WPF_PROPERTY_LIST = "RuntimeIdProperty,ParentRuntimeIdProperty,ProcessIdProperty,FrameworkIdProperty,LocalizedControlTypeProperty,ClassNameProperty,NameProperty,ValueProperty"; String[] spltProperties = enumProperties.split(","); this.isChild = isChild; if (SynthuseDlg.config.isFilterWpfDisabled()) { //use wildcard mode @@ -180,6 +187,8 @@ public class WindowInfo { 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")) @@ -191,6 +200,13 @@ public class WindowInfo { } } 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"; return; } // non-wildcard mode @@ -204,11 +220,21 @@ public class WindowInfo { if (spltProperties.length > 3) this.framework = spltProperties[3]; if (spltProperties.length > 4) - this.className = replaceEscapedCodes(spltProperties[4]); + this.controlType = replaceEscapedCodes(spltProperties[4]); if (spltProperties.length > 5) - this.text = replaceEscapedCodes(spltProperties[5]); + this.className = replaceEscapedCodes(spltProperties[5]); if (spltProperties.length > 6) - this.value = replaceEscapedCodes(spltProperties[6]); + this.text = replaceEscapedCodes(spltProperties[6]); + if (spltProperties.length > 7) + this.value = 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 (this.hwndStr == null) + this.hwndStr = ""; + /* this.rect = new RECT(); try { @@ -224,8 +250,16 @@ public class WindowInfo { */ } + public static String getRuntimeIdFromProperties(String enumProperties) + { + String[] spltProperties = enumProperties.split(","); + if (spltProperties.length > 0) + return spltProperties[0]; + return ""; + } + public String toString() { - return String.format("(%d,%d)-(%d,%d) : \"%s\" [%s] {%s}", rect.left,rect.top,rect.right,rect.bottom,text,className,hwnd.toString()); + return String.format("%s \"%s\" [%s] (%s) {%s}", framework, text, className, controlType, hwndStr); } } diff --git a/src/org/synthuse/WindowsEnumeratedXml.java b/src/org/synthuse/WindowsEnumeratedXml.java index 8d9d85e..a3ee89e 100644 --- a/src/org/synthuse/WindowsEnumeratedXml.java +++ b/src/org/synthuse/WindowsEnumeratedXml.java @@ -45,6 +45,7 @@ import com.sun.jna.platform.win32.WinUser; import com.sun.jna.platform.win32.WinDef.HWND; public class WindowsEnumeratedXml implements Runnable{ + public static Exception lastException = null; public static AtomicBoolean enumeratingXmlFlag = new AtomicBoolean(false); public JTextPane outputPane = null; @@ -81,10 +82,16 @@ public class WindowsEnumeratedXml implements Runnable{ final Map processList = new LinkedHashMap(); final List wpfParentList = new ArrayList();//HwndWrapper final List silverlightParentList = new ArrayList();//MicrosoftSilverlight + final List winFormParentList = new ArrayList();//class="WindowsForms*" int wpfCount = 0; + int winFormCount = 0; int silverlightCount = 0; int menuCount = 0; + //wpf.setTouchableOnly(false); + //wpf.countChildrenWindows();//fix for missing cached elements + + class ChildWindowCallback implements WinUser.WNDENUMPROC { @Override public boolean callback(HWND hWnd, Pointer lParam) { @@ -105,22 +112,31 @@ public class WindowsEnumeratedXml implements Runnable{ infoList.put(wi.hwndStr, wi); if (wi.className.startsWith("HwndWrapper")) wpfParentList.add(wi.hwndStr); + if (wi.className.startsWith("WindowsForms")) + winFormParentList.add(wi.hwndStr); Api.User32.instance.EnumChildWindows(hWnd, new ChildWindowCallback(), new Pointer(0)); return true; } } Api.User32.instance.EnumWindows(new ParentWindowCallback(), 0); - //Enumerate WPF windows and add to list + //Enumerate WPF, WinForm, Silverlight windows and add to list if (!SynthuseDlg.config.isWpfBridgeDisabled()) { + UiaBridge uiabridge = new UiaBridge(); for (String handle : wpfParentList) { - Map wpfInfoList = EnumerateWindowsWithWpfBridge(handle, "WPF"); + Map wpfInfoList = EnumerateWindowsWithUiaBridge(uiabridge, handle, "*"); wpfCount += wpfInfoList.size(); infoList.putAll(wpfInfoList); } + for (String handle : winFormParentList) { + //System.out.println("winform parent " + handle); + Map winFormInfoList = EnumerateWindowsWithUiaBridge(uiabridge, handle, "*"); + winFormCount += winFormInfoList.size(); + infoList.putAll(winFormInfoList); + } for (String handle : silverlightParentList) { - Map slInfoList = EnumerateWindowsWithWpfBridge(handle, "Silverlight"); + Map slInfoList = EnumerateWindowsWithUiaBridge(uiabridge, handle, "Silverlight"); silverlightCount += slInfoList.size(); infoList.putAll(slInfoList); } @@ -147,8 +163,13 @@ public class WindowsEnumeratedXml implements Runnable{ win = doc.createElement("win"); else if (w.framework.equals("WPF")) win = doc.createElement("wpf"); + else if (w.framework.equals("WinForm")) + win = doc.createElement("winfrm"); else if (w.framework.equals("Silverlight")) win = doc.createElement("silver"); + else + win = doc.createElement("win"); + //System.out.println(w.toString()); win.setAttribute("hwnd", w.hwndStr); win.setAttribute("text", w.text); @@ -159,6 +180,9 @@ public class WindowsEnumeratedXml implements Runnable{ win.setAttribute("class", w.className); if (w.className != null) win.setAttribute("CLASS", w.className.toUpperCase()); + if (w.controlType != null) + if (!w.controlType.isEmpty()) + win.setAttribute("type", w.controlType); if (!w.isChild) { parentCount++; if (w.processName != null && !w.processName.isEmpty()) { @@ -207,6 +231,7 @@ public class WindowsEnumeratedXml implements Runnable{ totals.setAttribute("windowCount", infoList.size()+""); totals.setAttribute("wpfWrapperCount", wpfParentList.size()+""); totals.setAttribute("wpfCount", wpfCount+""); + totals.setAttribute("winFormCount", winFormCount+""); totals.setAttribute("silverlightCount", silverlightCount+""); totals.setAttribute("menuCount", menuCount+""); totals.setAttribute("processCount", processList.size()+""); @@ -242,22 +267,19 @@ public class WindowsEnumeratedXml implements Runnable{ return xmlElement; } - public static Map EnumerateWindowsWithWpfBridge(String parentHwndStr, String frameworkType) { + public static Map EnumerateWindowsWithUiaBridge(UiaBridge uiabridge, String parentHwndStr, String frameworkType) { final Map infoList = new LinkedHashMap(); - WpfBridge wb = new WpfBridge(); - wb.setFrameworkId(frameworkType); - if (SynthuseDlg.config.isFilterWpfDisabled()) - wb.setTouchableOnly(false); + //WpfBridge wb = new WpfBridge(); + //wpf.setFrameworkId(frameworkType); long hwnd = Long.parseLong(parentHwndStr); - //List parentIds = new ArrayList(Arrays.asList(wb.enumChildrenWindowIds(""))); - //System.out.println("getRuntimeIdFromHandle"); - String parentRuntimeId = wb.getRuntimeIdFromHandle(hwnd); + //System.out.println("getRuntimeIdFromHandle of " + hwnd); + String parentRuntimeId = uiabridge.getWindowInfo((int) hwnd, WindowInfo.UIA_RUNTIME_ID); //System.out.println("runtimeId=" + runtimeId); String[] allIds = null; if (SynthuseDlg.config.isFilterWpfDisabled()) - allIds = wb.enumDescendantWindowInfo(parentRuntimeId, "*"); + allIds = uiabridge.enumWindowInfo((int) hwnd, "*"); else - allIds = wb.enumDescendantWindowInfo(parentRuntimeId, WindowInfo.WPF_PROPERTY_LIST); + allIds = uiabridge.enumWindowInfo((int) hwnd, WindowInfo.UIA_PROPERTY_LIST); if (allIds == null) return infoList; //empty list //System.out.println("enumDescendantWindowIds " + allIds.length); diff --git a/src/org/synthuse/XpathManager.java b/src/org/synthuse/XpathManager.java index 17f632f..08c26d7 100644 --- a/src/org/synthuse/XpathManager.java +++ b/src/org/synthuse/XpathManager.java @@ -21,9 +21,8 @@ import com.sun.jna.platform.win32.WinDef.HWND; public class XpathManager implements Runnable{ private HWND hwnd = null; - private String runtimeId = null; + private String enumProperties = null; private JTextPane windowsXmlTextPane = null; - private WpfBridge wpf = null; public static interface Events { void statusChanged(String status); @@ -44,12 +43,11 @@ public class XpathManager implements Runnable{ this.windowsXmlTextPane = windowsXmlTextPane; } - public XpathManager(HWND hwnd, String runtimeId, JTextPane windowsXmlTextPane, Events events) { + public XpathManager(HWND hwnd, String enumProperties, JTextPane windowsXmlTextPane, Events events) { this.events = events; this.hwnd = hwnd; - this.runtimeId = runtimeId; + this.enumProperties = enumProperties; this.windowsXmlTextPane = windowsXmlTextPane; - this.wpf = new WpfBridge(); } @Override @@ -78,44 +76,46 @@ public class XpathManager implements Runnable{ return escapedTxtStr; } - public String buildWpfXpathStatement() { + public String buildUiaXpathStatement() { + if (enumProperties == null) + return ""; + if (enumProperties.isEmpty()) + return ""; String builtXpath = ""; String xml = this.windowsXmlTextPane.getText(); - String classStr = wpf.getWindowClass(runtimeId); - //System.out.println("class: " + classStr); - String txtOrig = wpf.getWindowText(runtimeId); - String winValueOrig = wpf.getWindowValue(runtimeId); - if (classStr == null || txtOrig == null) + + WindowInfo wi = new WindowInfo(enumProperties, true); + String onlyRuntimeIdXpath = "//*[@hwnd='" + wi.runtimeId + "']"; + List wpfResultList = WindowsEnumeratedXml.evaluateXpathGetValues(xml, onlyRuntimeIdXpath); + //System.out.println("evaluateXpathGetValues1: " + onlyRuntimeIdXpath + " = " + wpfResultList.size()); + if (wpfResultList.size() == 0) + return""; + //System.out.println("enumProperties: " + enumProperties); + String typeStr = wi.controlType; + String txtOrig = wi.text; + //String winValueOrig = wpf.getWindowValue(runtimeId); + if (typeStr == null || txtOrig == null) return ""; //System.out.println("text: " + txtOrig); String txtStr = compareLongTextString(txtOrig); - String valueStr = ""; - if (winValueOrig != null) - if (!winValueOrig.isEmpty()) //if value attribute exists then use it too - valueStr = " and starts-with(@value,'" + compareLongTextString(winValueOrig) + "')"; - - builtXpath = "//*[@class='" + classStr + "' and starts-with(@text,'" + txtStr + "')" + valueStr + "]"; + builtXpath = "//*[@type='" + typeStr + "' and starts-with(@text,'" + txtStr + "')" + "]"; //builtXpath = "//*[@hwnd='" + runtimeId + "']"; - //System.out.println("evaluateXpathGetValues: " + builtXpath); - List wpfResultList = WindowsEnumeratedXml.evaluateXpathGetValues(xml, builtXpath); + wpfResultList = WindowsEnumeratedXml.evaluateXpathGetValues(xml, builtXpath); + //System.out.println("evaluateXpathGetValues2: " + builtXpath + " = " + wpfResultList.size()); if (wpfResultList.size() == 1) return builtXpath; - builtXpath = "//*[@hwnd='" + runtimeId + "']"; - wpfResultList = WindowsEnumeratedXml.evaluateXpathGetValues(xml, builtXpath); - if (wpfResultList.size() > 0) - return builtXpath; - return ""; + return onlyRuntimeIdXpath; } public String buildXpathStatement() { String builtXpath = ""; try { String xml = this.windowsXmlTextPane.getText(); - if (runtimeId != null && !SynthuseDlg.config.isWpfBridgeDisabled()) { - if (!runtimeId.isEmpty()) { - builtXpath = buildWpfXpathStatement(); + if (enumProperties != null && !SynthuseDlg.config.isWpfBridgeDisabled()) { + if (!enumProperties.isEmpty()) { + builtXpath = buildUiaXpathStatement(); } } if (builtXpath != "") @@ -164,6 +164,9 @@ public class XpathManager implements Runnable{ } builtXpath = "//win[@class='" + classStr + "'" + txtStr + "]"; } + resultList = WindowsEnumeratedXml.evaluateXpathGetValues(xml, builtXpath); + if (resultList.size() > 1) //still too many matched, only use hwnd + builtXpath = "//win[@hwnd='" + handleStr + "']"; } } catch (Exception e) { e.printStackTrace(); diff --git a/src/org/synthuse/commands/BaseCommand.java b/src/org/synthuse/commands/BaseCommand.java index 958b119..03abcf1 100644 --- a/src/org/synthuse/commands/BaseCommand.java +++ b/src/org/synthuse/commands/BaseCommand.java @@ -16,7 +16,7 @@ public class BaseCommand { static long LAST_UPDATED_XML = 0; protected Api api = new Api(); - protected WpfBridge wpf = new WpfBridge(); + protected UiaBridge wpf = new UiaBridge(); protected CommandProcessor parentProcessor = null; protected int getExecuteErrorCount() { @@ -116,6 +116,7 @@ public class BaseCommand { resultStr = item; break; } + resultStr = resultStr.replaceAll("[^\\d-.]", ""); //remove all non-numeric values (except dash -) if (WinPtr.isWpfRuntimeIdFormat(resultStr)) { result.runtimeId = resultStr; if (!ignoreFailedFind && result.isEmpty()) @@ -143,7 +144,7 @@ public class BaseCommand { if (item.contains("hmenu=")) { List list = WindowsEnumeratedXml.evaluateXpathGetValues(item, "//@id"); if (list.size() > 0) - resultStr = list.get(0); //get first id; + resultStr = list.get(0); //get first id } else resultStr = item; diff --git a/src/org/synthuse/test/UnitTestHelper.java b/src/org/synthuse/test/UnitTestHelper.java index ce82523..fc75158 100644 --- a/src/org/synthuse/test/UnitTestHelper.java +++ b/src/org/synthuse/test/UnitTestHelper.java @@ -54,7 +54,7 @@ public class UnitTestHelper { byte[] buffer = new byte[1024]; int readBytes; // Open and check input stream - InputStream is = WpfBridgeTest.class.getResourceAsStream(path); + InputStream is = UnitTestHelper.class.getResourceAsStream(path); if (is == null) { //check if valid System.out.println("File " + path + " was not found inside JAR."); return null; diff --git a/src/org/synthuse/test/WpfBridgeTest.java b/src/org/synthuse/test/WpfBridgeTest.java deleted file mode 100644 index 9749950..0000000 --- a/src/org/synthuse/test/WpfBridgeTest.java +++ /dev/null @@ -1,125 +0,0 @@ -package org.synthuse.test; -import static org.junit.Assert.*; - -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; -import org.synthuse.*; - -public class WpfBridgeTest { - - - @BeforeClass - public static void setUpBeforeClass() { - //this runs only once for this class - UnitTestHelper.RunApp("/org/synthuse/test/WpfMockTestApp.exe"); - } - - @AfterClass - public static void tearDownAfterClass() { - //this runs only once for this class - UnitTestHelper.DestroyApp(); - } - - @Before - public void setUp() throws Exception { - - } - - @After - public void tearDown() throws Exception { - - } - - @Test - public void countChildrenWin32() { - WpfBridge wb = new WpfBridge(); - wb.setFrameworkId("Win32");//We should find some Win32 windows, maybe not WPF - int win32Cnt = wb.countChildrenWindows(); - System.out.println("win32 countChildrenWindows: " + win32Cnt); - assertTrue(win32Cnt > 0); - wb.setTouchableOnly(false);//disable filter - int ufwin32Cnt = wb.countChildrenWindows(); - System.out.println("win32 unfiltered countChildrenWindows: " + ufwin32Cnt); - assertTrue(ufwin32Cnt >= win32Cnt); - } - - @Test - public void countChildrenWpf() { - WpfBridge wb = new WpfBridge(); - wb.setFrameworkId("WPF");// maybe not WPF - wb.setTouchableOnly(true);//enable filter - System.out.println("wpf countChildrenWindows: " + wb.countChildrenWindows()); - wb.setTouchableOnly(false);//disable filter - System.out.println("wpf unfiltered countChildrenWindows: " + wb.countChildrenWindows()); - } - - //@Test - public void countDescendantsWin32() { - WpfBridge wb = new WpfBridge(); - wb.setFrameworkId("Win32");//We should find some Win32 windows, maybe not WPF - int win32Cnt = wb.countDescendantWindows(); - System.out.println("win32 countDescendantWindows: " + win32Cnt); - assertTrue(win32Cnt > 0); - wb.setTouchableOnly(false);//disable filter - int ufwin32Cnt = wb.countDescendantWindows(); - System.out.println("win32 unfiltered countDescendantWindows: " + ufwin32Cnt); - assertTrue(ufwin32Cnt >= win32Cnt); - } - - //@Test - public void countDescendantsWpf() { - WpfBridge wb = new WpfBridge(); - wb.setFrameworkId("WPF");// maybe not WPF - wb.setTouchableOnly(true);//enable filter - System.out.println("wpf countDescendantWindows: " + wb.countDescendantWindows()); - wb.setTouchableOnly(false);//disable filter - System.out.println("wpf unfiltered countDescendantWindows: " + wb.countDescendantWindows()); - } - - - @Test - public void getRuntimeFromHandle() { - WpfBridge wb = new WpfBridge(); - Api api = new Api(); - wb.setFrameworkId("WPF"); - WinPtr wp = new WinPtr(api.user32.FindWindow(null, "MainWindow"));//find WpfMockTestApp.exe - long handle = Long.parseLong(wp.hWndStr); - if (handle == 0) - return; - System.out.println("calling getRuntimeIdFromHandle: " + handle); - String rid = wb.getRuntimeIdFromHandle(handle); - System.out.println(wp.hWndStr + " getRuntimeIdFromHandle: " + rid); - assertTrue(rid != null); - - String[] props = wb.getPropertiesAndValues(rid); - assertTrue(props != null); - - //for(String p : props) - // System.out.println(p); - } - - @Test - public void enumerateWindowInfo() { - WpfBridge wb = new WpfBridge(); - Api api = new Api(); - wb.setFrameworkId("WPF"); - wb.setTouchableOnly(false); - WinPtr wp = new WinPtr(api.user32.FindWindow(null, "MainWindow"));//find WpfMockTestApp.exe - long handle = Long.parseLong(wp.hWndStr); - if (handle == 0) - return; - String rid = wb.getRuntimeIdFromHandle(handle); - System.out.println(wp.hWndStr + " getRuntimeIdFromHandle: " + rid); - if (rid == null) - return; - String[] wInfo = wb.enumDescendantWindowInfo(rid, WindowInfo.WPF_PROPERTY_LIST); - System.out.println("enumDescendantWindowInfo length: " + wInfo.length); - System.out.println(WindowInfo.WPF_PROPERTY_LIST); - for(String w : wInfo) - System.out.println(w); - } - -} diff --git a/synthuse.properties b/synthuse.properties index 734eda2..4eb8c02 100644 --- a/synthuse.properties +++ b/synthuse.properties @@ -1,8 +1,8 @@ # -#Tue Apr 08 22:36:47 EDT 2014 +#Tue Apr 29 23:17:11 EDT 2014 DEFAULT_PROP_FILENAME= urlList= disableFiltersWpf=false -xpathList= -xpathHightlight=.*process\="([^"]*)".* +xpathList=//*[@class\='TextBlock' and starts-with(@text,'CheckBox is here')]\u00BA//win[@class\='HwndWrapper[WpfMockTestApp.exe;;e0e45a66-6643-4c32-a6b8-6313b79ee700]']\u00BA//win[starts-with(@class,'HwndWrapper[WpfMockTestApp.exe;;')]\u00BA//win[starts-with(@class,'HwndWrapper[WpfMockTestApp.exe;;' and @TEXT\="MAINWINDOW")]\u00BA//win[starts-with(@class,'HwndWrapper[WpfMockTestApp.exe;;' and @TEXT\='MAINWINDOW')]\u00BA//win[starts-with(@class,'HwndWrapper[WpfMockTestApp.exe;;') and @TEXT\='MAINWINDOW']\u00BA//win[@class\='HwndWrapper[WpfMockTestApp.exe;;7c11a88a-1622-4ec8-8a29-0d7f20d3f36d]']\u00BA//win[@class\='HwndWrapper']\u00BA//win[starts-with(@class,'HwndWrapper')]\u00BA//wpf\u00BA//*[@class\='WindowsForms10.Window.8.app.0.2bf8098_r13_ad1' and starts-with(@text,'')]\u00BA//*[@ListViewCount]\u00BA//*[@menuCount]\u00BA//*[@dgText]\u00BA//menus\u00BA//menu\u00BA//win[@class\='SunAwtFrame']\u00BA//win[@class\='Edit']\u00BA//win[@class\='Notepad']\u00BA//*[@class\='\#32768']\u00BA//menu[@text\='Help']\u00BA//win[@class\='WindowsForms10.Window.8.app.0.2bf8098_r13_ad1']/win[@class\='WindowsForms10.Window.8.app.0.2bf8098_r13_ad1'][2]\u00BA//*[@tbCount]\u00BA//win[@class\='WindowsForms10.Window.8.app.0.2bf8098_r13_ad1']/win[@class\='WindowsForms10.EDIT.app.0.2bf8098_r13_ad1']\u00BA//*[@class\='WindowsForms10.Window.8.app.0.2bf8098_r13_ad1' and starts-with(@text,'Form1')]\u00BA//*[@class\='WindowsForms10.Window.8.app.0.2bf8098_r13_ad1' and starts-with(@text,'Win Forms Mock Test ')]\u00BA//*[@class\='' and starts-with(@text,'toolStripButton1')]\u00BA//win[@class\='3147770']\u00BA//*[@hwnd\='52298946']\u00BA//*[@hwnd\='14222438']\u00BA//*[@hwnd\='9175840']\u00BA//*[@hwnd\='6751400']\u00BA//*[starts-with(@class,'WindowsForms')]\u00BA//win[starts-with(@class,'WindowsForms')]\u00BA/*/win[starts-with(@class,'WindowsForms')]\u00BA//winfrm\u00BA//win[@class\='WindowsForms10.Window.8.app.0.2bf8098_r13_ad1']/win[@class\='WindowsForms10.EDIT.app.0.2bf8098_r13_ad1'][2]\u00BA//*[@class\='WindowsForms10.Window.8.app.0.2bf8098_r13_ad1']/win[@class\='WindowsForms10.EDIT.app.0.2bf8098_r13_ad1']\u00BA//*[@type\='button' and starts-with(@text,'button1')]\u00BA disableWpf=false +xpathHightlight=.*process\="([^"]*)".*