diff --git a/.classpath b/.classpath index 2762e90..3c497e1 100644 --- a/.classpath +++ b/.classpath @@ -1,6 +1,7 @@ + diff --git a/.gitignore b/.gitignore index 0f84274..dc6b6da 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,6 @@ build/ lib/ dist/ synthuse.properties +native/WpfBridge/x64 +native/WpfBridge/release +!native/WpfBridge/bin \ No newline at end of file diff --git a/build.xml b/build.xml index 732ae6c..a4edace 100644 --- a/build.xml +++ b/build.xml @@ -39,7 +39,7 @@ - + @@ -58,6 +58,9 @@ + + + diff --git a/native/WpfBridge/AssemblyInfo.cpp b/native/WpfBridge/AssemblyInfo.cpp new file mode 100644 index 0000000..118f215 --- /dev/null +++ b/native/WpfBridge/AssemblyInfo.cpp @@ -0,0 +1,46 @@ +/* + * Copyright 2014, Synthuse.org + * Released under the Apache Version 2.0 License. + * + * last modified by ejakubowski7@gmail.com +*/ +#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("WpfBridge")]; +[assembly:AssemblyDescriptionAttribute("")]; +[assembly:AssemblyConfigurationAttribute("")]; +[assembly:AssemblyCompanyAttribute("Synthuse")]; +[assembly:AssemblyProductAttribute("WpfBridge")]; +[assembly:AssemblyCopyrightAttribute("Copyright (c) Synthuse 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/WpfBridge/Global.cpp b/native/WpfBridge/Global.cpp new file mode 100644 index 0000000..6832972 --- /dev/null +++ b/native/WpfBridge/Global.cpp @@ -0,0 +1,10 @@ +/* + * Copyright 2014, Synthuse.org + * Released under the Apache Version 2.0 License. + * + * last modified by ejakubowski7@gmail.com +*/ +#include "StdAfx.h" +#include "Global.h" +#include "WpfAutomation.h" + diff --git a/native/WpfBridge/Global.h b/native/WpfBridge/Global.h new file mode 100644 index 0000000..d7b5a56 --- /dev/null +++ b/native/WpfBridge/Global.h @@ -0,0 +1,20 @@ +/* + * Copyright 2014, Synthuse.org + * Released under the Apache Version 2.0 License. + * + * last modified by ejakubowski7@gmail.com +*/ +#pragma once +#include "WpfAutomation.h" +namespace Globals +{ + using namespace System; + + public ref class Global + { + public: + static WpfAutomation ^WPF_AUTO = gcnew WpfAutomation(); + }; + +} + diff --git a/native/WpfBridge/ReadMe.txt b/native/WpfBridge/ReadMe.txt new file mode 100644 index 0000000..4d5f4e6 --- /dev/null +++ b/native/WpfBridge/ReadMe.txt @@ -0,0 +1,9 @@ +======================================================================== + DYNAMIC LINK LIBRARY : WpfBridge 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. diff --git a/native/WpfBridge/Stdafx.cpp b/native/WpfBridge/Stdafx.cpp new file mode 100644 index 0000000..a9a851a --- /dev/null +++ b/native/WpfBridge/Stdafx.cpp @@ -0,0 +1,5 @@ +// stdafx.cpp : source file that includes just the standard includes +// WpfBridge.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" diff --git a/native/WpfBridge/Stdafx.h b/native/WpfBridge/Stdafx.h new file mode 100644 index 0000000..3cc4c24 --- /dev/null +++ b/native/WpfBridge/Stdafx.h @@ -0,0 +1,7 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, +// but are changed infrequently + +#pragma once + + diff --git a/native/WpfBridge/WpfAutomation.cpp b/native/WpfBridge/WpfAutomation.cpp new file mode 100644 index 0000000..fa4cd59 --- /dev/null +++ b/native/WpfBridge/WpfAutomation.cpp @@ -0,0 +1,187 @@ +/* + * 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; +} + +void WpfAutomation::setFrameworkId(System::String ^propertyValue) +{ + this->frameworkId = propertyValue; +} + +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) +{ + array ^idArray = this->convertRuntimeIdString(runtimeIdValue); + Condition ^pcFramework = gcnew PropertyCondition(AutomationElement::FrameworkIdProperty, this->frameworkId); + Condition ^pcRunId = gcnew PropertyCondition(AutomationElement::RuntimeIdProperty, idArray); + Condition ^frameworkAndRuntimeId = gcnew AndCondition(pcFramework, 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) + { + System::Object ^currentVal = child->GetCurrentPropertyValue(AutomationElement::RuntimeIdProperty); + if (currentVal != nullptr) + { + array ^idArray = (array ^)currentVal; + for each(System::Int32 val in idArray) + { + idStrArray[count] += System::Convert::ToString(val) + L"-"; + //System::String->Concat(idStrArray[count], System::String->Concat(val->ToString(), L"-")); + } + idStrArray[count] = idStrArray[count]->TrimEnd('-'); + //System::Console::WriteLine("id: {0}", idStrArray[count]); + } + ++count; + } + return idStrArray; +} + +//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, gcnew PropertyCondition(AutomationElement::FrameworkIdProperty, this->frameworkId)); + System::Int32 result = aec->Count; + //delete aec; + return result; +} + +System::Int32 WpfAutomation::countDescendantWindows(System::String ^runtimeIdValue) +{ + AutomationElement ^parent = findAutomationElementById(runtimeIdValue); + AutomationElementCollection ^aec = parent->FindAll(TreeScope::Descendants, gcnew PropertyCondition(AutomationElement::FrameworkIdProperty, this->frameworkId)); + 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, gcnew PropertyCondition(AutomationElement::FrameworkIdProperty, this->frameworkId)); + System::Int32 result = aec->Count; + //delete aec; + return result; +} + +System::Int32 WpfAutomation::countChildrenWindows(System::String ^runtimeIdValue) +{ + AutomationElement ^parent = findAutomationElementById(runtimeIdValue); + AutomationElementCollection ^aec = parent->FindAll(TreeScope::Children, gcnew PropertyCondition(AutomationElement::FrameworkIdProperty, this->frameworkId)); + System::Int32 result = aec->Count; + //delete aec; + //delete frameworkAndRuntimeId; + return result; +} + +array ^ WpfAutomation::enumChildrenWindowIds(System::String ^runtimeIdValue) +{ + AutomationElement ^parent = findAutomationElementById(runtimeIdValue); + AutomationElementCollection ^aec = parent->FindAll(TreeScope::Children, gcnew PropertyCondition(AutomationElement::FrameworkIdProperty, this->frameworkId)); + return getRuntimeIdsFromCollection(aec); +} + +array ^ WpfAutomation::enumDescendantWindowIds(System::String ^runtimeIdValue) +{ + AutomationElement ^parent = findAutomationElementById(runtimeIdValue); + AutomationElementCollection ^aec = parent->FindAll(TreeScope::Descendants, gcnew PropertyCondition(AutomationElement::FrameworkIdProperty, this->frameworkId)); + 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, gcnew PropertyCondition(AutomationElement::FrameworkIdProperty, this->frameworkId)); + return getRuntimeIdsFromCollection(aec); +} + +array ^ WpfAutomation::EnumDescendantWindowIdsFromHandle(System::IntPtr windowHandle) +{ + //AutomationElement test = AutomationElement.FromHandle(new System.IntPtr(123123)); + AutomationElement ^parent = AutomationElement::FromHandle(windowHandle); + AutomationElementCollection ^aec = parent->FindAll(TreeScope::Descendants, gcnew PropertyCondition(AutomationElement::FrameworkIdProperty, this->frameworkId)); + return getRuntimeIdsFromCollection(aec); +} + +System::String ^ WpfAutomation::getProperty(System::String ^propertyName, System::String ^runtimeIdValue) +{ + AutomationElement ^parent = findAutomationElementById(runtimeIdValue); + //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); + 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); + 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 new file mode 100644 index 0000000..e1ce513 --- /dev/null +++ b/native/WpfBridge/WpfAutomation.h @@ -0,0 +1,39 @@ +/* + * 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 + + //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); + array ^ EnumDescendantWindowIdsFromHandle(System::IntPtr windowHandle); + //In all the above Enumerate methods will return a list of Runtime Ids for all related windows. + + 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); + array ^ getRuntimeIdsFromCollection(System::Windows::Automation::AutomationElementCollection ^collection); + + static System::String ^DEFAULT_FRAMEWORK = L"WPF"; + System::String ^frameworkId; +}; + diff --git a/native/WpfBridge/WpfBridge.vcxproj b/native/WpfBridge/WpfBridge.vcxproj new file mode 100644 index 0000000..93b88ec --- /dev/null +++ b/native/WpfBridge/WpfBridge.vcxproj @@ -0,0 +1,181 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {3141812E-36D5-4E7C-A388-EFED9AE250A5} + v4.0 + ManagedCProj + WpfBridge + + + + DynamicLibrary + true + true + Unicode + + + DynamicLibrary + true + true + Unicode + + + DynamicLibrary + false + true + Unicode + + + DynamicLibrary + false + true + Unicode + + + + + + + + + + + + + + + + + + + true + $(JAVA_HOME)\include;$(JAVA_HOME)\include\win32;$(IncludePath) + + + true + $(JAVA_HOME)\include;$(JAVA_HOME)\include\win32;$(IncludePath) + + + false + $(JAVA_HOME)\include;$(JAVA_HOME)\include\win32;$(IncludePath) + + + false + $(JAVA_HOME)\include;$(JAVA_HOME)\include\win32;$(IncludePath) + + + + Level3 + Disabled + WIN32;_DEBUG;%(PreprocessorDefinitions) + Use + + + true + + + + + + + Level3 + Disabled + WIN32;_DEBUG;%(PreprocessorDefinitions) + Use + + + true + + + + + + + Level3 + WIN32;NDEBUG;%(PreprocessorDefinitions) + Use + + + true + + + + + mkdir "$(ProjectDir)bin" +copy /Y "$(TargetPath)" "$(ProjectDir)bin\wpfbridge$(PlatformArchitecture)$(TargetExt)" + + + + + + Level3 + WIN32;NDEBUG;%(PreprocessorDefinitions) + Use + + + true + + + + + mkdir "$(ProjectDir)bin" +copy /Y "$(TargetPath)" "$(ProjectDir)bin\wpfbridge$(PlatformArchitecture)$(TargetExt)" + + + + + + + + + + + + + + + + + + + + + + + + Create + Create + Create + Create + + + + + + + + + + + + + + \ No newline at end of file diff --git a/native/WpfBridge/WpfBridge.vcxproj.filters b/native/WpfBridge/WpfBridge.vcxproj.filters new file mode 100644 index 0000000..9689af0 --- /dev/null +++ b/native/WpfBridge/WpfBridge.vcxproj.filters @@ -0,0 +1,62 @@ + + + + + {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 + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + + Resource Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/native/WpfBridge/WpfBridge.vcxproj.user b/native/WpfBridge/WpfBridge.vcxproj.user new file mode 100644 index 0000000..ace9a86 --- /dev/null +++ b/native/WpfBridge/WpfBridge.vcxproj.user @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/native/WpfBridge/app.ico b/native/WpfBridge/app.ico new file mode 100644 index 0000000..3a5525f Binary files /dev/null and b/native/WpfBridge/app.ico differ diff --git a/native/WpfBridge/app.rc b/native/WpfBridge/app.rc new file mode 100644 index 0000000..eab4306 Binary files /dev/null and b/native/WpfBridge/app.rc differ diff --git a/native/WpfBridge/bin/wpfbridge32.dll b/native/WpfBridge/bin/wpfbridge32.dll new file mode 100644 index 0000000..7fd0949 Binary files /dev/null and b/native/WpfBridge/bin/wpfbridge32.dll differ diff --git a/native/WpfBridge/bin/wpfbridge64.dll b/native/WpfBridge/bin/wpfbridge64.dll new file mode 100644 index 0000000..ab73fbd Binary files /dev/null and b/native/WpfBridge/bin/wpfbridge64.dll differ diff --git a/native/WpfBridge/build.bat b/native/WpfBridge/build.bat new file mode 100644 index 0000000..6c0af5f --- /dev/null +++ b/native/WpfBridge/build.bat @@ -0,0 +1,5 @@ + +%WinDir%\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe /p:configuration=release /p:platform=x64 %* +%WinDir%\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe /p:configuration=release /p:platform=win32 %* + +pause \ No newline at end of file diff --git a/native/WpfBridge/org_synthuse_WpfBridge.cpp b/native/WpfBridge/org_synthuse_WpfBridge.cpp new file mode 100644 index 0000000..449666a --- /dev/null +++ b/native/WpfBridge/org_synthuse_WpfBridge.cpp @@ -0,0 +1,230 @@ +/* + * 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: 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)); + + //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)); + + //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); + + //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: EnumDescendantWindowIdsFromHandle + * Signature: (J)[Ljava/lang/String; + */ +JNIEXPORT jobjectArray JNICALL Java_org_synthuse_WpfBridge_EnumDescendantWindowIdsFromHandle(JNIEnv *env, jobject obj, jlong jwindowHandle) +{ + array ^mchildrenIds = Global::WPF_AUTO->EnumDescendantWindowIdsFromHandle(System::IntPtr(jwindowHandle)); + + //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: 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)); + 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)); + + //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)); + + //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 new file mode 100644 index 0000000..e6d8f07 --- /dev/null +++ b/native/WpfBridge/org_synthuse_WpfBridge.h @@ -0,0 +1,115 @@ +/* + * Copyright 2014, Synthuse.org + * Released under the Apache Version 2.0 License. + * + * last modified by ejakubowski7@gmail.com +*/ +/* 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: 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: EnumDescendantWindowIdsFromHandle + * Signature: (J)[Ljava/lang/String; + */ +JNIEXPORT jobjectArray JNICALL Java_org_synthuse_WpfBridge_EnumDescendantWindowIdsFromHandle + (JNIEnv *, jobject, jlong); + +/* + * 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/WpfBridge/resource.h b/native/WpfBridge/resource.h new file mode 100644 index 0000000..d5ac7c4 --- /dev/null +++ b/native/WpfBridge/resource.h @@ -0,0 +1,3 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by app.rc diff --git a/src/org/synthuse/Api.java b/src/org/synthuse/Api.java index 6896e2d..0cb236d 100644 --- a/src/org/synthuse/Api.java +++ b/src/org/synthuse/Api.java @@ -2,7 +2,7 @@ * Copyright 2014, Synthuse.org * Released under the Apache Version 2.0 License. * - * last modified by ejakubowski + * last modified by ejakubowski7@gmail.com */ package org.synthuse; diff --git a/src/org/synthuse/CommandPopupMenu.java b/src/org/synthuse/CommandPopupMenu.java index aca4309..ca5d3bb 100644 --- a/src/org/synthuse/CommandPopupMenu.java +++ b/src/org/synthuse/CommandPopupMenu.java @@ -2,7 +2,7 @@ * Copyright 2014, Synthuse.org * Released under the Apache Version 2.0 License. * - * last modified by ejakubowski + * last modified by ejakubowski7@gmail.com */ package org.synthuse; diff --git a/src/org/synthuse/WpfBridge.java b/src/org/synthuse/WpfBridge.java new file mode 100644 index 0000000..75c65ee --- /dev/null +++ b/src/org/synthuse/WpfBridge.java @@ -0,0 +1,90 @@ +/* + * Copyright 2014, Synthuse.org + * Released under the Apache Version 2.0 License. + * + * last modified by ejakubowski7@gmail.com +*/ + +package org.synthuse; + +import java.io.*; + +public class WpfBridge { + + 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"); + } + + public static void loadNativeLibraryFromJar(String path) { + // Obtain filename from path + String[] parts = path.split("/"); + String filename = (parts.length > 1) ? parts[parts.length - 1] : null; + // Split filename to prexif and suffix (extension) + String prefix = ""; + String suffix = null; + if (filename != null) { + parts = filename.split("\\.", 2); + prefix = parts[0]; + suffix = (parts.length > 1) ? "."+parts[parts.length - 1] : null; + } + File temp = null; + try { + // Prepare temporary file + temp = File.createTempFile(prefix, suffix); + temp.deleteOnExit(); + } catch(Exception e) { + e.printStackTrace(); + } + if (!temp.exists()) { //some reason the temp file wasn't create so abort + System.out.println("File " + temp.getAbsolutePath() + " does not exist."); + return; + } + + // Prepare buffer for data copying + byte[] buffer = new byte[1024]; + int readBytes; + // Open and check input stream + InputStream is = WpfBridge.class.getResourceAsStream(path); + if (is == null) { //check if valid + System.out.println("File " + path + " was not found inside JAR."); + return; + } + // Open output stream and copy data between source file in JAR and the temporary file + OutputStream os = null; + try { + os = new FileOutputStream(temp); + while ((readBytes = is.read(buffer)) != -1) { + os.write(buffer, 0, readBytes); + } + os.close(); + is.close(); + } catch(Exception e) { + e.printStackTrace(); + } + // Finally, load the library + System.load(temp.getAbsolutePath()); + } + + native void SetFrameworkId(String propertyValue); //default is WPF, but also accepts Silverlight, Win32 + + //Descendants will walk the full tree of windows, NOT just one level of children + native int CountDescendantWindows(); + native int CountDescendantWindows(String runtimeIdValue); + + native int CountChildrenWindows(); + native int CountChildrenWindows(String runtimeIdValue); + + native String[] EnumChildrenWindowIds(String runtimeIdValue); //if runtimeIdValue is null will start at desktop + native String[] EnumDescendantWindowIds(String runtimeIdValue); //if runtimeIdValue is null will start at desktop + native String[] EnumDescendantWindowIds(long processId); + native String[] EnumDescendantWindowIdsFromHandle(long windowHandle); + //In all the above Enumerate methods will return a list of Runtime Ids for all related windows. + + native String GetProperty(String propertyName, String runtimeIdValue); + native String[] GetProperties(String runtimeIdValue); + native String[] GetPropertiesAndValues(String runtimeIdValue); +} diff --git a/synthuse.properties b/synthuse.properties index 06a1f84..9fea982 100644 --- a/synthuse.properties +++ b/synthuse.properties @@ -1,5 +1,5 @@ # -#Tue Mar 25 12:56:37 EDT 2014 +#Thu Apr 03 22:00:23 EDT 2014 DEFAULT_PROP_FILENAME= urlList= xpathList=