From 7d4c5ee814024d4e8cf3d6099599d5ad41bbce0d Mon Sep 17 00:00:00 2001 From: Ibrahim Esmat Date: Tue, 6 Jun 2017 19:22:04 -0700 Subject: [PATCH] Windows: UWP Sample App with WACK tests An elevator client UWP sample app using the dynamic ipca and octbstack dlls. The Supported APIs WACK test is run if building for Release. Change-Id: I54b03d366a21b51cb723c355a252572b71050cd8 Signed-off-by: Ibrahim Esmat Reviewed-on: https://gerrit.iotivity.org/gerrit/21315 Tested-by: jenkins-iotivity Reviewed-by: Dan Mihai --- build_common/windows/SConscript | 114 ++++- resource/IPCA/samples/ElevatorClientUWP/App.xaml | 8 + .../IPCA/samples/ElevatorClientUWP/App.xaml.cpp | 143 ++++++ resource/IPCA/samples/ElevatorClientUWP/App.xaml.h | 46 ++ .../Assets/LockScreenLogo.scale-200.png | Bin 0 -> 1430 bytes .../Assets/SplashScreen.scale-200.png | Bin 0 -> 7700 bytes .../Assets/Square150x150Logo.scale-200.png | Bin 0 -> 2937 bytes .../Assets/Square44x44Logo.scale-200.png | Bin 0 -> 1647 bytes ...are44x44Logo.targetsize-24_altform-unplated.png | Bin 0 -> 1255 bytes .../samples/ElevatorClientUWP/Assets/StoreLogo.png | Bin 0 -> 1451 bytes .../Assets/Wide310x150Logo.scale-200.png | Bin 0 -> 3204 bytes .../IPCA/samples/ElevatorClientUWP/Elevator.cpp | 487 +++++++++++++++++++++ resource/IPCA/samples/ElevatorClientUWP/Elevator.h | 107 +++++ .../ElevatorClientUWP/ElevatorClientUWP.sln | 39 ++ .../ElevatorClientUWP/ElevatorClientUWP.vcxproj | 261 +++++++++++ .../ElevatorClientUWP.vcxproj.filters | 75 ++++ .../ElevatorClientUWP_TemporaryKey.pfx | Bin 0 -> 2528 bytes .../ElevatorClientUWP/ElevatorDiscovery.cpp | 395 +++++++++++++++++ .../samples/ElevatorClientUWP/ElevatorDiscovery.h | 98 +++++ .../ElevatorClientUWP/ElevatorViewModel.cpp | 172 ++++++++ .../samples/ElevatorClientUWP/ElevatorViewModel.h | 64 +++ .../samples/ElevatorClientUWP/IPCALibs.targets | 21 + .../IPCA/samples/ElevatorClientUWP/MainPage.xaml | 38 ++ .../samples/ElevatorClientUWP/MainPage.xaml.cpp | 72 +++ .../IPCA/samples/ElevatorClientUWP/MainPage.xaml.h | 48 ++ .../samples/ElevatorClientUWP/Package.appxmanifest | 29 ++ resource/IPCA/samples/ElevatorClientUWP/SConscript | 70 +++ resource/IPCA/samples/ElevatorClientUWP/Util.cpp | 143 ++++++ resource/IPCA/samples/ElevatorClientUWP/Util.h | 34 ++ resource/IPCA/samples/ElevatorClientUWP/pch.cpp | 6 + resource/IPCA/samples/ElevatorClientUWP/pch.h | 12 + resource/IPCA/samples/SConscript | 2 + tools/scons/RunTest.py | 41 ++ 33 files changed, 2524 insertions(+), 1 deletion(-) create mode 100644 resource/IPCA/samples/ElevatorClientUWP/App.xaml create mode 100644 resource/IPCA/samples/ElevatorClientUWP/App.xaml.cpp create mode 100644 resource/IPCA/samples/ElevatorClientUWP/App.xaml.h create mode 100644 resource/IPCA/samples/ElevatorClientUWP/Assets/LockScreenLogo.scale-200.png create mode 100644 resource/IPCA/samples/ElevatorClientUWP/Assets/SplashScreen.scale-200.png create mode 100644 resource/IPCA/samples/ElevatorClientUWP/Assets/Square150x150Logo.scale-200.png create mode 100644 resource/IPCA/samples/ElevatorClientUWP/Assets/Square44x44Logo.scale-200.png create mode 100644 resource/IPCA/samples/ElevatorClientUWP/Assets/Square44x44Logo.targetsize-24_altform-unplated.png create mode 100644 resource/IPCA/samples/ElevatorClientUWP/Assets/StoreLogo.png create mode 100644 resource/IPCA/samples/ElevatorClientUWP/Assets/Wide310x150Logo.scale-200.png create mode 100644 resource/IPCA/samples/ElevatorClientUWP/Elevator.cpp create mode 100644 resource/IPCA/samples/ElevatorClientUWP/Elevator.h create mode 100644 resource/IPCA/samples/ElevatorClientUWP/ElevatorClientUWP.sln create mode 100644 resource/IPCA/samples/ElevatorClientUWP/ElevatorClientUWP.vcxproj create mode 100644 resource/IPCA/samples/ElevatorClientUWP/ElevatorClientUWP.vcxproj.filters create mode 100644 resource/IPCA/samples/ElevatorClientUWP/ElevatorClientUWP_TemporaryKey.pfx create mode 100644 resource/IPCA/samples/ElevatorClientUWP/ElevatorDiscovery.cpp create mode 100644 resource/IPCA/samples/ElevatorClientUWP/ElevatorDiscovery.h create mode 100644 resource/IPCA/samples/ElevatorClientUWP/ElevatorViewModel.cpp create mode 100644 resource/IPCA/samples/ElevatorClientUWP/ElevatorViewModel.h create mode 100644 resource/IPCA/samples/ElevatorClientUWP/IPCALibs.targets create mode 100644 resource/IPCA/samples/ElevatorClientUWP/MainPage.xaml create mode 100644 resource/IPCA/samples/ElevatorClientUWP/MainPage.xaml.cpp create mode 100644 resource/IPCA/samples/ElevatorClientUWP/MainPage.xaml.h create mode 100644 resource/IPCA/samples/ElevatorClientUWP/Package.appxmanifest create mode 100644 resource/IPCA/samples/ElevatorClientUWP/SConscript create mode 100644 resource/IPCA/samples/ElevatorClientUWP/Util.cpp create mode 100644 resource/IPCA/samples/ElevatorClientUWP/Util.h create mode 100644 resource/IPCA/samples/ElevatorClientUWP/pch.cpp create mode 100644 resource/IPCA/samples/ElevatorClientUWP/pch.h diff --git a/build_common/windows/SConscript b/build_common/windows/SConscript index cd0fc4c..fd167e9 100644 --- a/build_common/windows/SConscript +++ b/build_common/windows/SConscript @@ -2,7 +2,103 @@ # This script includes windows specific config (MSVS/MSVC) ## Import('env') -import os.path +import os +import winreg +import platform + +def OpenRegKey(env, key, sub_key, reg_view_64bit=False): + # Default access + reg_access_mask = winreg.KEY_READ + if reg_view_64bit: + # Access the 64bit Registry View + reg_access_mask |= winreg.KEY_WOW64_64KEY + + try: + hkey = winreg.OpenKey(key, + sub_key, + 0, # Reserved + reg_access_mask) + except WindowsError, err: + if err.errno != os.errno.ENOENT: + # Couldn't open Registry Key + Exit('Error: Could not Open %s Registry Key. Err=%s' % (sub_key, err.errno)) + else: + # Registry Key not found + hkey = None + + return hkey + +def ReadRegistryStringValue(env, key, sub_key, value_name, reg_view_64bit=False): + hkey = env.OpenRegKey(key, sub_key, reg_view_64bit) + if hkey: + try: + (value, type) = winreg.QueryValueEx(hkey, value_name) + if type != winreg.REG_SZ: + Exit('Error: Registry Value \'%s\' is not a String' % value_name) + except WindowsError, err: + if err.errno != os.errno.ENOENT: + Exit('Error: Could not QueryValueEx for Registry Value \'%s\'. Err=%s' \ + % (value_name, err.errno)) + else: + # Registry Value not found + value = None + + hkey.Close() + else: + value = None + + return value + +def SetupMSBuildEnv(env): + # Add MSBuild path to path + msbuild_reg_path = 'SOFTWARE\\Microsoft\\MSBuild\\ToolsVersions\\' + env.get('MSVC_VERSION') + # MSBuild executable arch needs to be the same as the python/SCons environment Arch. + # Open the Registry key with the same registry view as the environment (handled by the + # winreg.OpenKey function) + msbuild_path = env.ReadRegistryStringValue(winreg.HKEY_LOCAL_MACHINE, + msbuild_reg_path, + 'MSBuildToolsPath') + if not msbuild_path: + Exit('Error: Could not Find the MSBuild Registry Key/Value') + + env.AppendUnique(PATH = [msbuild_path]) + # Need to update the 'ENV' dictionary PATH as that's what is used when executing + # commands + env['ENV']['PATH'] = env.get('PATH') + +def GetMSBuildArgs(env): + target_arch = env.get('TARGET_ARCH') + platform = target_arch + if target_arch in ['amd64']: + platform = 'x64' + + # Set configuration value used by Visual Studio. + if env.get('RELEASE'): + configuration = 'Release' + else: + configuration = 'Debug /p:AppxPackageAllowDebugFrameworkReferencesInManifest=true' + + # Get the MSBuildOutDir env variable for the output directory + # Note: This should only be set on a cloned Environment and not the global one + outdir = env.get('MSBuildOutDir') + + return (configuration, platform, outdir) + +def MSBuildGenerator(source, target, env, for_signature): + env.SetupMSBuildEnv() + (configuration, platform, outdir) = env.GetMSBuildArgs() + + msbuild_cmd = 'msbuild.exe %s /p:Configuration=%s /p:Platform=%s /p:OutDir="%s"' \ + % (source[0], configuration, platform, outdir) + return msbuild_cmd + +def MSBuildClean(env, target, solutionfile): + env.SetupMSBuildEnv() + (configuration, platform, outdir) = env.GetMSBuildArgs() + + msbuild_cmd = 'msbuild.exe %s /p:Configuration=%s /p:Platform=%s /p:OutDir="%s" /t:Clean' \ + % (solutionfile, configuration, platform, outdir) + env.Execute(msbuild_cmd) help_vars = Variables() if env.get('BUILD_JAVA') == True: @@ -26,6 +122,22 @@ if env.get('BUILD_JAVA') == True: help_vars.Update(env) Help(help_vars.GenerateHelpText(env)) +if env.get('UWP_APP') == '1': + # Create an MSBuilder that uses a generator to generate the MSBuild actions + MSBuilder = Builder(generator = MSBuildGenerator) + # Add the builder to the env + env.Append(BUILDERS = {'MSBuild' : MSBuilder}) + # Add MSBuildClean function to env + env.AddMethod(MSBuildClean) + # Add SetupMSBuildEnv function to env + env.AddMethod(SetupMSBuildEnv) + # Add GetMSBuildArgs function to env + env.AddMethod(GetMSBuildArgs) + # Add OpenRegKey function to env + env.AddMethod(OpenRegKey) + # Add ReadRegistryStringValue function to env + env.AddMethod(ReadRegistryStringValue) + # Set common flags if env['CC'] == 'cl': if env.get('UWP_APP') == '1': diff --git a/resource/IPCA/samples/ElevatorClientUWP/App.xaml b/resource/IPCA/samples/ElevatorClientUWP/App.xaml new file mode 100644 index 0000000..293ddf2 --- /dev/null +++ b/resource/IPCA/samples/ElevatorClientUWP/App.xaml @@ -0,0 +1,8 @@ + + + diff --git a/resource/IPCA/samples/ElevatorClientUWP/App.xaml.cpp b/resource/IPCA/samples/ElevatorClientUWP/App.xaml.cpp new file mode 100644 index 0000000..6c5f7e0 --- /dev/null +++ b/resource/IPCA/samples/ElevatorClientUWP/App.xaml.cpp @@ -0,0 +1,143 @@ +/* ***************************************************************** +* +* Copyright 2017 Microsoft +* +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +******************************************************************/ + +// +// App.xaml.cpp +// Implementation of the App class. +// + +#include "pch.h" +#include "MainPage.xaml.h" + +using namespace ElevatorClientUWP; + +using namespace Platform; +using namespace Windows::ApplicationModel; +using namespace Windows::ApplicationModel::Activation; +using namespace Windows::Foundation; +using namespace Windows::Foundation::Collections; +using namespace Windows::UI::Xaml; +using namespace Windows::UI::Xaml::Controls; +using namespace Windows::UI::Xaml::Controls::Primitives; +using namespace Windows::UI::Xaml::Data; +using namespace Windows::UI::Xaml::Input; +using namespace Windows::UI::Xaml::Interop; +using namespace Windows::UI::Xaml::Media; +using namespace Windows::UI::Xaml::Navigation; + +/// +/// Initializes the singleton application object. This is the first line of authored code +/// executed, and as such is the logical equivalent of main() or WinMain(). +/// +App::App() +{ + InitializeComponent(); + Suspending += ref new SuspendingEventHandler(this, &App::OnSuspending); +} + +/// +/// Invoked when the application is launched normally by the end user. Other entry points +/// will be used such as when the application is launched to open a specific file. +/// +/// Details about the launch request and process. +void App::OnLaunched(Windows::ApplicationModel::Activation::LaunchActivatedEventArgs^ e) +{ +#if _DEBUG + // Show graphics profiling information while debugging. + if (IsDebuggerPresent()) + { + // Display the current frame rate counters + DebugSettings->EnableFrameRateCounter = true; + } +#endif + auto rootFrame = dynamic_cast(Window::Current->Content); + + // Do not repeat app initialization when the Window already has content, + // just ensure that the window is active + if (rootFrame == nullptr) + { + // Create a Frame to act as the navigation context and associate it with + // a SuspensionManager key + rootFrame = ref new Frame(); + + rootFrame->NavigationFailed += ref new Windows::UI::Xaml::Navigation::NavigationFailedEventHandler(this, &App::OnNavigationFailed); + + if (e->PreviousExecutionState == ApplicationExecutionState::Terminated) + { + // TODO: Restore the saved session state only when appropriate, scheduling the + // final launch steps after the restore is complete + + } + + if (e->PrelaunchActivated == false) + { + if (rootFrame->Content == nullptr) + { + // When the navigation stack isn't restored navigate to the first page, + // configuring the new page by passing required information as a navigation + // parameter + rootFrame->Navigate(TypeName(MainPage::typeid), e->Arguments); + } + // Place the frame in the current Window + Window::Current->Content = rootFrame; + // Ensure the current window is active + Window::Current->Activate(); + } + } + else + { + if (e->PrelaunchActivated == false) + { + if (rootFrame->Content == nullptr) + { + // When the navigation stack isn't restored navigate to the first page, + // configuring the new page by passing required information as a navigation + // parameter + rootFrame->Navigate(TypeName(MainPage::typeid), e->Arguments); + } + // Ensure the current window is active + Window::Current->Activate(); + } + } +} + +/// +/// Invoked when application execution is being suspended. Application state is saved +/// without knowing whether the application will be terminated or resumed with the contents +/// of memory still intact. +/// +/// The source of the suspend request. +/// Details about the suspend request. +void App::OnSuspending(Object^ sender, SuspendingEventArgs^ e) +{ + (void) sender; // Unused parameter + (void) e; // Unused parameter + + //TODO: Save application state and stop any background activity +} + +/// +/// Invoked when Navigation to a certain page fails +/// +/// The Frame which failed navigation +/// Details about the navigation failure +void App::OnNavigationFailed(Platform::Object ^sender, Windows::UI::Xaml::Navigation::NavigationFailedEventArgs ^e) +{ + throw ref new FailureException("Failed to load Page " + e->SourcePageType.Name); +} \ No newline at end of file diff --git a/resource/IPCA/samples/ElevatorClientUWP/App.xaml.h b/resource/IPCA/samples/ElevatorClientUWP/App.xaml.h new file mode 100644 index 0000000..9e0011b --- /dev/null +++ b/resource/IPCA/samples/ElevatorClientUWP/App.xaml.h @@ -0,0 +1,46 @@ +/* ***************************************************************** +* +* Copyright 2017 Microsoft +* +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +******************************************************************/ + +// +// App.xaml.h +// Declaration of the App class. +// + +#pragma once + +#include "App.g.h" + +namespace ElevatorClientUWP +{ + /// + /// Provides application-specific behavior to supplement the default Application class. + /// + ref class App sealed + { + protected: + virtual void OnLaunched(Windows::ApplicationModel::Activation::LaunchActivatedEventArgs^ e) override; + + internal: + App(); + + private: + void OnSuspending(Platform::Object^ sender, Windows::ApplicationModel::SuspendingEventArgs^ e); + void OnNavigationFailed(Platform::Object ^sender, Windows::UI::Xaml::Navigation::NavigationFailedEventArgs ^e); + }; +} diff --git a/resource/IPCA/samples/ElevatorClientUWP/Assets/LockScreenLogo.scale-200.png b/resource/IPCA/samples/ElevatorClientUWP/Assets/LockScreenLogo.scale-200.png new file mode 100644 index 0000000000000000000000000000000000000000..735f57adb5dfc01886d137b4e493d7e97cf13af3 GIT binary patch literal 1430 zcmaJ>TTC2P7~aKltDttVHYH6u8Io4i*}3fO&d$gd*bA_<3j~&e7%8(eXJLfhS!M@! zKrliY>>6yT4+Kr95$!DoD(Qn-5TP|{V_KS`k~E6(LGS@#`v$hQo&^^BKsw3HIsZBT z_y6C2n`lK@apunKojRQ^(_P}Mgewt$(^BBKCTZ;*xa?J3wQ7~@S0lUvbcLeq1Bg4o zH-bvQi|wt~L7q$~a-gDFP!{&TQfc3fX*6=uHv* zT&1&U(-)L%Xp^djI2?~eBF2cxC@YOP$+9d?P&h?lPy-9M2UT9fg5jKm1t$m#iWE{M zIf%q9@;fyT?0UP>tcw-bLkz;s2LlKl2qeP0w zECS7Ate+Awk|KQ+DOk;fl}Xsy4o^CY=pwq%QAAKKl628_yNPsK>?A>%D8fQG6IgdJ ztnxttBz#NI_a@fk7SU`WtrpsfZsNs9^0(2a z@C3#YO3>k~w7?2hipBf{#b6`}Xw1hlG$yi?;1dDs7k~xDAw@jiI*+tc;t2Lflg&bM)0!Y;0_@=w%`LW^8DsYpS#-bLOklX9r?Ei}TScw|4DbpW%+7 zFgAI)f51s}{y-eWb|vrU-Ya!GuYKP)J7z#*V_k^Xo>4!1Yqj*m)x&0L^tg3GJbVAJ zJ-Pl$R=NAabouV=^z_t;^K*0AvFs!vYU>_<|I^#c?>>CR<(T?=%{;U=aI*SbZADLH z&(f2wz_Y0??Tf|g;?|1Znw6}6U43Q#qNRwv1vp9uFn1)V#*4p&%$mP9x&15^OaBiDS(XppT|z^>;B{PLVEbS3IFYV yGvCsSX*m literal 0 HcmV?d00001 diff --git a/resource/IPCA/samples/ElevatorClientUWP/Assets/SplashScreen.scale-200.png b/resource/IPCA/samples/ElevatorClientUWP/Assets/SplashScreen.scale-200.png new file mode 100644 index 0000000000000000000000000000000000000000..023e7f1feda78d5100569825acedfd213a0d84e9 GIT binary patch literal 7700 zcmeHLYj~4Yw%(;oxoEH#Kxq-eR|+VkP17b#Vk;?4QwkI+A{L04G+#<<(x#Un1#+h5>eArRq zTw$)ZvTWW_Y?bDho0nPVTh08+s`sp!j74rJTTtXIDww0SILedFv?sZ?yb@@}GN;#8 znk_b~Q(A0YR#uV4ef!osoV1M3;vQ8N$O|fStfgf$S5;ddUNv`tWtGjM;koG#N;7M< zP*84lnx(bn_KF&9Z5Ai$)#Cs3a|$OFw>WKCT$of*L7_CqQEinflT|W{JT+aKp-E0v zsxmYg)1(T>DROm+LN1eQw8}KCTp=C!$H7`PU!t9_Hw@TsTI2`udRZv*!a5`#A9hK6Y95L(CDUX&_@QxKV z_feX{UhA#ZWlvgpL$#w^D#lq`_A4AzDqd|Zv6y9PX&DNcN|l}_D^{q@GG&H^Pg583 z8FI6N8^H7b5WjGp;urW)d7F+_lcp%KsLX0viCmE(OHH+=%ZfD_=`voUuoUxFO^L;- z;!;2{g-YiiO6m4bs89OuF9!p{FGtH-f%8<2gY!h9s)4ciN%{Kh1+`}{^}M~+TDH9N z^Z5PlgVXMC&2&k*Hw^Lb9gny#ro$MOIxIt{+r)EA10$VR3 zanN8D{TUkl+v0CQ_>ZoHP<M-x#8@8ZiT#$Kh`(uRaX1g$Bg|qy$<#7 zSSAi{Nb8Y=lvNVeio+UGLCAtoLBfL`iOv`)yoJMDJBN>4IH@(l7YRF;61@>qq1iM9 zr@b#OC~SAxSle?5Pp8Z78{VO0YFr1x7kZU64Z23eLf2T2#6J_t;-E}DkB?NufZ0Ug zi?J&byXeaB-uTNVhuiM!UVQw}bZrJ3GtAETYp->!{q#zfN7D3AS9@Q7*V^85jGx#R z(QxYV(wW#F0XF9^^s>>H8pPlVJ>)3Oz z&_X8Sf@~?cH_O*cgi$U#`v`RRfv#y3m(ZpKk^5uLup+lVs$~}FZU$r_+}#hl%?g5m z-u-}-666ssp-xWQak~>PPy$mRc|~?pVSs1_@mBEXpPVfLF6(Ktf1S* zPPh@QZ=tFMs?LM2(5P3L2;l_6XX6s&cYsP1ip#eg0`ZEP0HGYh{UmS@o`MihLLvkU zgyAG0G`b1|qjxxh1(ODKFE%AP}Dq=3vK$P7TXP4GrM1kQ72!GUVMDl`rDC&2;TA}*nF z8$nQD&6ys_nc1*E7$*1S@R8$ymy(sQV}imGSedB@{!QR5P&N_H=-^o!?LsWs+2|mH z-e=)T^SvI)=_JIm7}j4;@*Z17=(#}m=~YF~z~CLI+vdAGlJDcdF$TM?CVI1%LhUrN zaa6DJ=Yh$)$k&Oz{-~8yw^GM^8prYxSxo zvI4k#ibryMa%%*8oI-5m61Koa_A_xg=(fwp0aBX{;X4Q;NXUhtaoJDo1>TqhWtn=_ zd5~chq#&6~c%8JZK#t_&J(9EVUU&upYeIovLt1>vaHe}UUq>#RGQj!EN#5+0@T`(@ z^g~>*c`VGRiSt;!$_4+0hk^I!@O3``5=sZ8IwlxWW7km1B&_t&E*u0_9UBa#VqwY* zz>nxv?FAsVnRaD(Bui=6i==BFUw0k4n$>`umU`F2l?7CYTD^)c2X+d9X&ddS9|gj? zM?knGkGCX&W8offw8aLC2$D{PjC3nVZwd4k?eZH8*mZ)U@3Qk8RDFOz_#WUA#vnzy zyP>KrCfKwSXea7}jgJjBc}PGY+4#6%lbZyjhy`5sZd_Vy6Wz;ixa?czkN}J9It1K6 zY!eu>|AwF^fwZlLAYyQI*lM@^>O>Iu6Vf6i>Q$?v!SeUS<{>UYMwz$*%Aq?w^`j{h z!$GZbhu=^D{&ET8;))LL%ZBDZkQqRd2;u~!d9bHGmLRhLDctNgYyjsuvoSZ#iVdoB z2!f--UUA#U;<{je#?cYt^{PIyKa%hW>}uepWMyAI{{Zo7?2>?$c9;whJae%oN|I-kpTQSx_C$Z&;f zi2i)qmEn=y4U0uvk)$m;zKfjPK@oc?I`}1Jzl$Q~aoKBd3kt7L#7gyt|A_qgz6ai< z=X%D1i!d2h?rHR^R8SUj&G||dkC?DT>{o#Yau<@uqVT{Xef&XG}5*E4aPk{}~ zplx&XhaV)&1EfI3Em;Bw#O5SV^c;{twb-1Rw)+=0!e_BLbd7tYmXCH0wrlOSS+~`7He8Iqx0{CN+DVit9;*6L~JAN zD&cyT)2?h}xnYmL?^)<7YyzZ3$FHU^Eg;DLqAV{#wv#Wj7S`Jdl1pX&{3(uZ?!uh} zDc$ZTNV*7le_W6}Hju~GMTxZQ1aWCeUc%!jv3MHAzt>Y-nQK%zfT*3ebDQA5b?iGn; zBjv3B+GhLTexd_(CzZDP4|#n5^~scvB6#Pk%Ho!kQ>yYw((Dv{6=$g3jT1!u6gORW zx5#`7Wy-ZHRa~IxGHdrp(bm%lf>2%J660nj$fCqN(epv@y!l9s7@k6EvxS{AMP>WY zX4$@F8^kayphIx-RGO$+LYl9YdoI5d|4#q9##`_F5Xnx`&GPzp2fB{-{P@ATw=X@~ z_|&^UMWAKD;jjBKTK(~o?cUFRK8EX=6>cXpfzg4ZpMB>*w_^8GSiT-Jp|xBOnzM+j z*09-@-~qJ(eqWq5@R4i^u4^{McCP(!3}C|v_WsTR*bIUxN(Nx`u##3B4{sE`Z`v8w zAwIG`?1~PkID~W{uDzmqH98Pew_1(;x2%8r^vY{)_&J2K)cN{W+h5+g)ZcjP&Ci#O zgy|8K@4kyMfwilHd&6TDlhb%++Pk!>9HRld6HT7gwyZGrxS$}CsD6`>6!!2K1@Mjf z(P0WYB7V_OFZyeWrbOFb>O54BNXf~K&?}3=^v;v_wT{DKr?jN^DtN&DXwX%u?s*c6`%8>WFz z7}YW^tp0bp^NriE)AB6M2l<7rn7fzePtR*omOevpfm9n?}2V*+0iW;S)C zhg`NAjL?D=W#k*$aR{>pGf~lD-rVtD;5jW1_*Jn1j1=es@Kcx4ySM_bwcQCT=d+DV z>Sz~L=Hj@(X%31nK$mWI@7d>}ORB`K(p=+`UD)+99YUGQc7y^bHZ1F(8|tL0 zdK*DT0kSXG_{BKTpP2*2PecdKV9;dq$^ZZDP;Nyq1kp-&GI5eAyZsK!e3V zK@rPy*{(`KIfo+lc878mDKk^V#`VT05}64kBtk%DgwLrOvLMj5-;*GNKv6c6pzMuL z6EP%ob|_0IW}lLRXCP2!9wWhEw3LA7iF#1O1mIZ@Z=6&bz41F;@S_GvYAG-#CW3z{ zP3+6vHhvP&A3$##Vo9$dT^#MoGg^|MDm=Bt1d2RRwSZ<;ZHICpLBv5Xs!D?BH^(9_ z7`H=N&^v|Z-%mP}wNzG{aiFCsRgwzwq!N6obW9+7(R; z(SZ=23`|`>qil!LMGG{_Heq!BD>(Y-zV9wD)}hz25JA37YR%39;kI4y9pgtcUass6 zP24}ZY$vvYeI`zy&)A_X#nY3017ap*0&jx|mVwyGhg3;!keU53a}Uhm3BZI$N$6Se zLWlAmy1S0xKJm4G_U@sN_Tm=`$xWJSEwKU98rZ&)1R^*$$1vA3oG#&*%SMxY_~oGP zP&PFJatFLM-Ps%84IV-+Ow)T{C7cqUAvauy4C z(FRz&?6$Rypj{xO!`y=*J5o4@U8Q-(y5(*=YoKeZ+-1YdljXxkA#B)zo=FeQH#?Le zycNUmEEHWO9a=X^pb#&cOq7-`7UA87#|S22)<7RUtZo|(zibX=w;K3qur9vy#`MNV z6UUcf9ZwEnKCCp+OoBnF@OdbvH)ANXO0o~Pi9l8=x3))}L<#vO0-~O4!~--Ket?d} zJaqsj<@CD1%S2cTW%rOP{Vto%0sGW~1RMa_j^)5nil0Yw- z0EE#bP+l4#P^%PQ+N*oxu1Zq05xZ!bXfYTg>9c{(Iw*lnjR^>kz%lAN^zFce7rppy zY8zA~3GD=A6d*hze&l4D_wA~+O!56)BZTe_rEu}Ezi<4!kG|W#amBZ5{&XS2@6R~H z{9o^y*BkH4$~yX9U&@CgbOzX1bn9xqF|zh$Dh0Y5y*E0e90*$!ObrHY3Ok0`2=O~r zCuke6KrP9KOf?V(YDsM<6pX2nVoN%M$LT^q#FmtaF?1^27F*IcNX~XRB(|hCFvdcc zc)$=S-)acdk$g4?_>jRqxpI6M3vHZk?0c^3=byamYDNf;uB{3NlKW5IhnOS3DNkMV z?tK8?kJ}pmvp%&&eTVOVjHP`q34hN1@!aK}H(K!vI`~gf|Gv+FNEQD5Yd<~yX7k_l h&G-K)@HZb3BABY{)U1?^%I#E6`MGoTtustd{~yM6srvu` literal 0 HcmV?d00001 diff --git a/resource/IPCA/samples/ElevatorClientUWP/Assets/Square150x150Logo.scale-200.png b/resource/IPCA/samples/ElevatorClientUWP/Assets/Square150x150Logo.scale-200.png new file mode 100644 index 0000000000000000000000000000000000000000..af49fec1a5484db1d52a7f9b5ec90a27c7030186 GIT binary patch literal 2937 zcma)84OCO-8BSud5)jwMLRVKgX(S?$n?Ld|vrsm<$CF7)&zTbyy1FE5bU`Q17MRv`9ue$;R(@8kR;#vJ*IM0>cJIAOte!d7oRgdH zd%ySjdB6L9=gX^A6)VzH7p2l@v~3zJAMw|DFy#^)F@@F*`mqUn=Il>l)8_+ab;nOW{%+iPx z+s{Eu|&pIs)Z7{La9~?xKfyl z#43?gjEL15d4WbOZo#SiP%>DB^+BcnJ=7dHEe;r#G=tuw|ka z%q@}##Uh7;tc%L_64m(kHtw74ty%BJMb)_1)#S0j`)F8_1jF7vScpsnH=0V19bO8y zR`0SjIdCUo&=>JwMQF8KHA<{ODHTiQh}0^@5QRmCA?gOH6_H3K^-_sNB^RrdNuK-R zOO*vOrKCVvDwgUck`kF(E7j{I#iiN;b*ZdCt4m@HPA`EuEqGGf4%!K<;(=I=&Vyrw z%TwcWtxa}8mCZ%Cyf&ActJ6_$ox5z6-D!0-dvnRx6t7y3d+h6QYpKWO;8OdnvERo7 zuEf>ih5`wqY)~o@OeVt-wM?Q!>QzdGRj!bz6fzYrfw$hZfAKzr2-M+D+R>}~oT574c;_3zquHcElqKIsryILt3g8n3jcMb+j?i?-L3FpZJ z2WRVBRdDPc+G5aaYg#5hpE+6nQ|(VSoxT3|biF;BUq#==-27Xi=gihDPYP$7?=9cP zYKE$jeQ|3~_L0VG-(F~2ZPyD0=k{J4Q~h(t__{-mz_w8{JDY9{`1ouzz!Vr5!ECdE z6U~O1k8c}24V7~zzXWTV-Pe4)y}wQJS&q%H5`Fo_f_JvIU489aCX$;P`u#!I-=^4ijC2{&9!O&h>mi?9oYD=GC#%)6{GzN6nQYw+Fal50!#x^asjBBR50i`+mho*ttoqV)ubM2KD9S~k7+FR4>{29?6 z{!l6kDdyTN0YJ9LgkPWeXm|gyi@zM3?0@{&pXT12w|78&W-q!RRF)&iLCEZVH<|fR zN0fr2^t8H(>L?>K#>^+jWROLral(Qy-xoBq1U7A&DV||wClb)Otd9?(gZ|8znMF}D zf<1haWz^s0qgecz;RFGt0C-B4g`jNGHsFU+;{<%t65v^sjk^h$lmWn#B0#_)9ij&d z-~lc`A)YYExi^7sBuPM^Y|wA2g*5?`K?#7tzELQYNxGo$UB$4J8RJp1k(8Jj+~hMT zlN~>M@KTTh^--8y3PK_NZ@AC!{PT=CziBzGd+wTJ^@icH!Bd}%)g8V)%K?|c&WTUk zy}qv1C%(fjRoZ4ozC3{O%@5?)XzH35zHns$pgU*Q?fj4v?fp1Qbm+j;3l;9jam9Da zXVcKjPlQ73x78QPu|Ffm6x?`~e3oD=gl=4kYK?={kD5j~QCXU)`HSdduNNENzA*2$ zOm3PzF!lN5e*06-f1Uot67wY#{o-S1!KZ7E=!~7ynnk9_iJR#kFoNbAOT#^2Gd17F zMmvU6>lndZQGd|ax9kUoXXO+$N?|j@6qpsF&_j7YXvwo_C{JpmLw5&#e6k>atv%es z5)7r*Wvv_JkUpT}M!_o!nVlEk1Zbl=a*2hQ*<|%*K1Glj^FcF`6kTzGQ3lz~2tCc@ z&x|tj;aH&1&9HwcJBcT`;{?a+pnej;M1HO(6Z{#J!cZA04hnFl;NXA+&`=7bjW_^o zfC40u3LMG?NdPtwGl>Tq6u}*QG)}-y;)lu-_>ee3kibW(69n0$0Zy!}9rQz%*v1iO zT9_H>99yIrSPYVy6^);rR}7Yo=J_T@hi+qhTZXnVWyf;JDYm5#eYLTxr*?kiNn!+Y zQ+LUkBafNJ#rH#C(?d5^;gw9o#%daEI{mA*LHPIHPU`#|H$hD zwm>0&+kahQ)E#%~k>&5@&#Vg82H?s%71=)(soi@174pi9--2{w{1$}Sz4zGn3Du&x bht0Iza^2ykEt4(epJ78uh5nDlX8(TxzDYwP literal 0 HcmV?d00001 diff --git a/resource/IPCA/samples/ElevatorClientUWP/Assets/Square44x44Logo.scale-200.png b/resource/IPCA/samples/ElevatorClientUWP/Assets/Square44x44Logo.scale-200.png new file mode 100644 index 0000000000000000000000000000000000000000..ce342a2ec8a61291ba76c54604aea7e9d20af11b GIT binary patch literal 1647 zcmaJ?eM}Q)7(e+G1Q(|`V9JhTI2>MkceK4;p;PR&$Pi?ejk3YQ_3o`S&|W_dsOZ8# zWPTt69g`t$ab`0cj-Y0yiBSOqmd)tG7G(}M5aP0_%&9TijB#&)I{zSE^4@#z^FF`l z`8{8`o%wlL(UI|y2!cdsuVamHH~H86F!*-15em4)NqUpCQM5?aoC_eCf@lV4wvF2a zjDQn1JBL69f&@2M3rvzJcfE!eZ8FZUBlFlC5RD)it33{mF9#B82AiyQE%w)`vlwa> zv{<1sm&kSKK$&%2jSFn7$t&P%%6Ue>R=EAnG8N7fqynWG8L3p!4801a;8{+nliO(qd(jNJ_?+9W3#hLIDLoT6~3fx9=`CC-D}-AMrpEO7HK zt3$GicGPc?GmDjy7K2P@La;eu4!$zWCZ`ym{Z$b zu-O6RM&K4JT|BIZB`E-gxqG%FzanI#+2FFmqHqXG7yxWB=w55RGOM)$xMb(>kSNR z2w=1AZi%z=AmG~yea~XaXJR!v7vLn(RUnELfiB1|6D84ICOS}^Zo2AdN}<&*h}G_u z{xZ!(%>tLT3J3<5XhWy-tg+6)0nmUUENLW8TWA{R6bgVd3X;anYFZ^IRis*_P-C-r z;i>%1^eL3UI2-{w8nuFFcs0e~7J{O2k^~Ce%+Ly4U?|=!0LH=t6()xi<^I-rs+9sF z*q{E-CxZbGPeu#a;XJwE;9S1?#R&uns>^0G3p`hEUF*v`M?@h%T%J%RChmD|EVydq zmHWh*_=S%emRC*mhxaVLzT@>Z2SX0u9v*DIJ@WC^kLVdlGV6LpK$KIrlJqc zpJ921)+3JJdTx|<`G&kXpKkjGJv=76R`yYIQ{#c-`%+`#V(7}Q;&@6U8!Td1`d;?N z_9mnI#?AA}4J!r)LN4!E-@H5eXauuB7TOawS>Y|{-P?NNx-lq+z1W-+y(;39P&&LP zL{N80?&=C*qKmdA^moMZRuPcD!B<*mq$ch=0Cnlitw#txRWhb3%TQvPqjkC`F69G4b! ze7z9MZ#+;_#l?H37UqUhDFb^l&s2{oM$3I0o^Q!yx;;V)QmCMo)Tb_ui|mit8MS?U zm##6$sZZ1$@|s%?l@>4Z<*Q}sRBSKMhb4I{e5LdEhsHIHTe8Bod5c>6QtT>$XgUBz z6MK`kO$=jmt@FqggOhJ5j~e@ygRbG;<{Vu)*+nn9aQeo0;$#j;|MS=S$&L?BeV25z xs3B`@=#`5TF{^6(A1rvdY@|-RtQ|iS5{tyX+wH?;n8E)G$kykv-D^wh{{!TZT%7;_ literal 0 HcmV?d00001 diff --git a/resource/IPCA/samples/ElevatorClientUWP/Assets/Square44x44Logo.targetsize-24_altform-unplated.png b/resource/IPCA/samples/ElevatorClientUWP/Assets/Square44x44Logo.targetsize-24_altform-unplated.png new file mode 100644 index 0000000000000000000000000000000000000000..f6c02ce97e0a802b85f6021e822c89f8bf57d5cd GIT binary patch literal 1255 zcmaJ>TWs4@7*5+{G#S+&C!qC#> zf>5N3P6jO*Cz>ug*(_DmW=)kea&m$gZ^+nyiF`;j%w@}y8)>p*SH}C`m?DXeieF2U zyQHecc_L%Gh!7GMt+hG06y;+|p4>m~}PjA}rKViGiEnn7G0ZO<>G|7q;2?NwGCM3s?eued6%hd$B+ z*kQJ{#~$S=DFE(%=E+UkmlEI*%3llUf~8Ja9YU1Vui0IbGBkW_gHB%Rd&!!ioX zs40O?i9I{};kle7GMvE7(rk`la=gTI)47=>%?q@^iL-nUo3}h4S}N-KHn8t5mVP8w z&bSErwp+37 zNJJ8?a|{r5Q3R0Z5s-LB1WHOwYC@7pCHWND#cL1cZ?{kJ368_*(UDWUDyb<}0y@o# zfMF016iMWPCb6obAxT$JlB6(2DrlXDTB&!0`!m??4F(qWMhjVZo?JXQmz`1*58Z=& zcDmB|S-E@j?BoFGix0flckqdS4jsPNzhfWyWIM98GxcLs89C(~dw%$_t;JjX-SD}E zfiGV;{8Q%8r}w9x>EEigW81>`kvnU@pK)4+xk9@+bNj9L!AAZ@SZ@q|)&BmY3+HZx zul~BeG4|}-;L%cHViQGQX?^zFfO0&#cHwel=d`lH9sJ-@Sl@n*(8J2>%Ac`IxyY?Q z{=GhWvC#gu-~Ia7*n{=+;qM?Ul_wy1+u7ho;=`>EwP^g~R@{unBds`!#@}tluZQpS zm)M~nYEifJWJGx?_6DcTy>#uh%>!H9=hb^(v`=m3F1{L>db=<5_tm+_&knAQ2EU$s Mu9UqpbNZeC0BbUo^Z)<= literal 0 HcmV?d00001 diff --git a/resource/IPCA/samples/ElevatorClientUWP/Assets/StoreLogo.png b/resource/IPCA/samples/ElevatorClientUWP/Assets/StoreLogo.png new file mode 100644 index 0000000000000000000000000000000000000000..7385b56c0e4d3c6b0efe3324aa1194157d837826 GIT binary patch literal 1451 zcmaJ>eN5D57_Z|bH;{0+1#mbl)eTU3{h)Wf7EZV?;HD@XL@{B`Ui%(2aMxQ~xdXSv z5nzWi(LW)U2=Vc-cY@s7nPt{i0hc6!7xN4NNHI#EQl>YNBy8l4%x9gr_W-j zEZMQmmTIy(>;lblRfh`dIyTgc9W5d!VP$L4(kKrN1c5G~(O_#xG zAJCNTstD^5SeXFB+&$h=ToJP2H>xr$iqPs-#O*;4(!Fjw25-!gEb*)mU}=)J;Iu>w zxK(5XoD0wrPSKQ~rbL^Cw6O_03*l*}i=ydbu7adJ6y;%@tjFeXIXT+ms30pmbOP%Q zX}S;+LBh8Tea~TSkHzvX6$rYb)+n&{kSbIqh|c7hmlxmwSiq5iVhU#iEQ<>a18|O^Sln-8t&+t`*{qBWo5M?wFM(JuimAOb5!K#D}XbslM@#1ZVz_;!9U zpfEpLAOz=0g@bd6Xj_ILi-x^!M}73h^o@}hM$1jflTs|Yuj9AL@A3<-?MV4!^4q`e z)fO@A;{9K^?W?DbnesnPr6kK>$zaKo&;FhFd(GYFCIU^T+OIMb%Tqo+P%oq(IdX7S zf6+HLO?7o0m+p>~Tp5UrXWh!UH!wZ5kv!E`_w)PTpI(#Iw{AS`gH4^b(bm^ZCq^FZ zY9DD7bH}rq9mg88+KgA$Zp!iWncuU2n1AuIa@=sWvUR-s`Qb{R*kk(SPU^`$6BXz8 zn#7yaFOIK%qGxyi`dYtm#&qqox0$h=pNi#u=M8zUG@bpiZ=3sT=1}Trr}39cC)H|v zbL?W)=&s4zrh)7>L(|cc%$1#!zfL?HjpeP%T+x_a+jZ16b^iKOHxFEX$7d|8${H-* zIrOJ5w&i$>*D>AKaIoYg`;{L@jM((Kt?$N$5OnuPqVvq**Nm}(f0wwOF%iX_Pba;V z;m@wxX&NcV3?<1+u?A{y_DIj7#m3Af1rCE)o`D&Y3}0%7E;iX1yMDiS)sh0wKi!36 zL!Wmq?P^Ku&rK~HJd97KkLTRl>ScGFYZNlYytWnhmuu|)L&ND8_PmkayQb{HOY640 bno1(wj@u8DCVuFR|31B*4ek@pZJqxCDDe1x literal 0 HcmV?d00001 diff --git a/resource/IPCA/samples/ElevatorClientUWP/Assets/Wide310x150Logo.scale-200.png b/resource/IPCA/samples/ElevatorClientUWP/Assets/Wide310x150Logo.scale-200.png new file mode 100644 index 0000000000000000000000000000000000000000..288995b397fdbef1fb7e85afd71445d5de1952c5 GIT binary patch literal 3204 zcmbVPeQXow8NYmBd90>}0NP?GhXW~VaeThm=a0tV#EwJMI!)6M3}|c4_Bl3=Kd>G0 z(GHx1wl<7(tP?FsOQkTilSo*iIvF%uArExJ73~P zSv1xEy!U(Wd4A9D`FQV@W3@F^qJ@PEF$@z`Z!*BbFsS(^?B zyiAzJ+q})bkgiQHWqEb*jJD-coHYr1^iocg)l!Qa{Xqs-l~6J}p-|##ZHYofskQ3$ zI0;xzXyhazBeXhIsg5A=%ufo@f)1yy&ScKS0;HF^!r_2UE^lpZEom(+@duma3awTv zCrCL-%D_SvYWIcdHkmI}#50(fkUi)Qgx!80ju>g1za^}ff>JI8Z@^-iCiaCgg@TgF z+vtE?Q9{VQUX&MW9SYYmGcxA14%N2@7FwBTD4N<(2{nWgV8$e3?-F=L^&FrtWn~(U_Q~~^uYiyeY6-KoTnfh9AWz@ zIKje0)u!_Lw)E}G!#kEfwKVdNt(UAf9*f>tEL_(=xco-T%jTi@7YlC3hs2ik%Le0H ztj}RTeCF(5mwvi3_56>-yB?l;J>-1%!9~=fs|QcNG3J~a@JCu`4SB460s0ZO+##4fFUSGLcj_ja^fL4&BKALfb#$6$O?>P@qx2Agl^x0i&ugt zsy5Pyu=()`7HRMG3IB7F1@`_ z+-!J%#i6e^U$e#+C%Q>_qVRzWRsG^W_n+@OcX@vzI&z;mzHNb!GQ?LWA(wtpqHqTM z1OFw_{Zn?fD)p)`c`kOgv{de=v@suGRqY{N^U7gI1VF3*F=obwaXI6ob5__Yn zVTguS!%(NI09J8x#AO_aW!9W7k*UvB;IWDFC3srwftr{kHj%g)fvnAm;&h_dnl~

MY- zf+K}sCe8qU6Ujs`3ua{U0Of$R_gVQBuUA za0v=mu#vIOqiiAZOr&h*$WyOw&k-xr$;G4Ixa!#TJNr>95(h>l%)PUy4p+^SgR(uR zta%k*?ny-+nAr8spEk1fo{J4i!b^Fia`N{_F6@zidA2ZTTrjl#^5Z-2KfB@Cu}l9s z(*|Z2jc?p~vn2f)3y9i*7zJV1L{$?|&q)4oaT;uXi6>1GkRXVTOzAz(RHEmr=eFIi z`}<>-Q?K0GN8!IYxeP1XKXO+jsJbp~o^);Bc;%b7Flpe7;1`Ny@3r7ZR;?R)aJt8C ziNlEC<@3f_lIV4TwV}&e;D!Ee5_|e#g0LUh=5vmYWYm7&2h*M>QPKvGh9-)wfMMW3 z8J9b%1k7dzPzO0_NGQy92BZ^FR6R~6;^6?lqO;-QUP4BY%cG%3vEhbm#>4vIhPBh3 z-+pZGjh$x%Hp{?=FHsMp0&wNPlj00us{&`1ZOZTqs8%4X&xH=UDr*xyBW(Zp&Em94 zf)ZSfn#yg0N)>!1kWdkqJ^S*z0FF5|fj&qcE#Na|%OY0$uO>!&hP+1ywfD_WXk@4J(?MBftK7>$Nvqh@tDuarN%PrTLQ2Uzysx>UV=V zk^RrDSvdQ?0;=hY67EgII-f4`t=+i*yS=Y~!XlqIy_4x&%+OdfbKOFPXS2X5%4R{N z$SQMX^AK6(fA +#include +#include "ipca.h" +#include "Elevator.h" +#include "ElevatorViewModel.h" + +using namespace ElevatorClientUWP; + +using namespace std; +using namespace Platform; +using namespace Windows::ApplicationModel::Core; +using namespace Windows::Foundation; +using namespace Windows::Foundation::Collections; +using namespace Windows::UI::Core; +using namespace Windows::UI::Xaml; +using namespace Windows::UI::Xaml::Controls; +using namespace Windows::UI::Xaml::Controls::Primitives; +using namespace Windows::UI::Xaml::Data; +using namespace Windows::UI::Xaml::Input; +using namespace Windows::UI::Xaml::Media; +using namespace Windows::UI::Xaml::Navigation; + +// Callback from IPCAObserveResource(). +void IPCA_CALL ResourceChangeNotificationCallback( + IPCAStatus result, + void* context, + IPCAPropertyBagHandle propertyBagHandle) +{ + if (context) + { + Elevator^ dev = (reinterpret_cast(context))->Resolve(); + if (dev) + { + dev->ResourceChangeNotificationCallback(result, propertyBagHandle); + } + } +} + +void IPCA_CALL SetPropertiesCallback( + IPCAStatus result, + void* context, + IPCAPropertyBagHandle propertyBagHandle) +{ + if (context) + { + Elevator^ dev = (reinterpret_cast(context))->Resolve(); + if (dev) + { + dev->SetPropertiesCallback(result, propertyBagHandle); + } + } +} + +void IPCA_CALL AuthCompletionCallback(IPCAStatus completionStatus, void* context) +{ + if (context) + { + Elevator^ dev = (reinterpret_cast(context))->Resolve(); + if (dev) + { + dev->AuthCompletionCallback(completionStatus); + } + } +} + +Elevator::Elevator() : + m_initialized(false), + m_dispatcher(nullptr), + m_ipcaAppHandle(nullptr), + m_observeHandle(nullptr), + m_deviceName(nullptr), + m_deviceHandle(nullptr), + m_deviceInfo(nullptr), + m_platformInfo(nullptr), + m_requestedAccess(false), + m_requestAccessHandle(nullptr) +{ + m_thisWeakRef = new WeakReference(this); + m_dispatcher = CoreApplication::MainView->Dispatcher; +} + +Elevator::~Elevator() +{ + StopObservation(); + + if (m_requestAccessHandle != nullptr) + { + IPCACloseHandle(m_requestAccessHandle, nullptr, nullptr); + m_requestAccessHandle = nullptr; + } + + if (m_deviceHandle != nullptr) + { + IPCACloseDevice(m_deviceHandle); + m_deviceHandle = nullptr; + } + + if (m_deviceInfo != nullptr) + { + IPCAFreeDeviceInfo(m_deviceInfo); + m_deviceInfo = nullptr; + } + + if (m_platformInfo != nullptr) + { + IPCAFreePlatformInfo(m_platformInfo); + m_platformInfo = nullptr; + } +} + +String^ Elevator::Name::get() +{ + String^ ret = m_deviceName; + + if ((ret == nullptr) || ret->IsEmpty()) + { + ret = Util::ConvertStrtoPlatformStr(m_deviceId.c_str()); + } + + return ret; +} + +void Elevator::Name::set(String^ value) +{ + if (m_deviceName != value) + { + m_deviceName = value; + OnPropertyChanged("Name"); + } +} + +String^ Elevator::CurrentFloor::get() +{ + return m_curFloor; +} + +void Elevator::CurrentFloor::set(String^ value) +{ + if (m_curFloor != value) + { + m_curFloor = value; + OnPropertyChanged("CurrentFloor"); + } +} + +void Elevator::OnPropertyChanged(String^ propertyName) +{ + m_dispatcher->RunAsync(CoreDispatcherPriority::Normal, ref new DispatchedHandler( + [this, propertyName] + { + PropertyChanged(this, ref new PropertyChangedEventArgs(propertyName)); + })); +} + +IPCAStatus Elevator::OpenDevice() +{ + if (m_deviceHandle != nullptr) + { + return IPCA_OK; + } + else + { + return IPCAOpenDevice(m_ipcaAppHandle, m_deviceId.c_str(), &m_deviceHandle); + } +} + +void Elevator::UpdateDeviceInfo() +{ + IPCAStatus status; + + if (!m_initialized) + { + return; + } + + if (OpenDevice() != IPCA_OK) + { + return; + } + + if (m_deviceInfo != nullptr) + { + IPCAFreeDeviceInfo(m_deviceInfo); + m_deviceInfo = nullptr; + } + + status = IPCAGetDeviceInfo(m_deviceHandle, &m_deviceInfo); + if (IPCA_OK != status) + { + return; + } + + Name = Util::ConvertStrtoPlatformStr(m_deviceInfo->deviceName); +} + +void Elevator::UpdatePlatformInfo() +{ + IPCAStatus status; + + if (!m_initialized) + { + return; + } + + if (OpenDevice() != IPCA_OK) + { + return; + } + + if (m_platformInfo != nullptr) + { + IPCAFreePlatformInfo(m_platformInfo); + m_platformInfo = nullptr; + } + + status = IPCAGetPlatformInfo(m_deviceHandle, &m_platformInfo); + if (IPCA_OK != status) + { + return; + } +} + +void Elevator::UpdateResourceInfo() +{ + IPCAStatus status; + + ResourceList emptyResourceList; + + if (!m_initialized) + { + return; + } + + if (OpenDevice() != IPCA_OK) + { + return; + } + + char** resourcePathList; + size_t resourceListCount; + status = IPCAGetResources(m_deviceHandle, + nullptr, nullptr, &resourcePathList, &resourceListCount); + if (IPCA_OK != status) + { + return; + } + + m_resourceList.clear(); + for (size_t i = 0; i < resourceListCount; i++) + { + char** resourceTypes; + size_t resourceTypeCount; + status = IPCAGetResourceTypes(m_deviceHandle, + resourcePathList[i], &resourceTypes, &resourceTypeCount); + if (IPCA_OK == status) + { + for (size_t j = 0; j < resourceTypeCount; j++) + { + m_resourceList[resourcePathList[i]].push_back(resourceTypes[j]); + } + IPCAFreeStringArray(resourceTypes, resourceTypeCount); + } + else + { + // Log failure + } + } + + IPCAFreeStringArray(resourcePathList, resourceListCount); +} + +bool Elevator::Init(IPCAAppHandle appHandle, Platform::String^ name, std::string id) +{ + if (!m_initialized) + { + m_ipcaAppHandle = appHandle; + m_deviceName = name; + m_deviceId = id; + m_initialized = true; + } + + return m_initialized; +} + +void Elevator::StartObservation() +{ + if (OpenDevice() != IPCA_OK) + { + throw ref new FailureException("Failed to open device"); + } + + StopObservation(); + + if (IPCAObserveResource( + m_deviceHandle, + &::ResourceChangeNotificationCallback, + m_thisWeakRef, + "/ipca/sample/elevator", + nullptr, + &m_observeHandle) != IPCA_OK) + { + throw ref new FailureException("IPCAObserveResource failed."); + } +} + +void Elevator::StopObservation() +{ + if (m_observeHandle != nullptr) + { + IPCACloseHandle(m_observeHandle, nullptr, nullptr); + m_observeHandle = nullptr; + } +} + +void Elevator::ResourceChangeNotificationCallback(IPCAStatus result, + IPCAPropertyBagHandle propertyBagHandle) +{ + int observedCurrentFloor = -1; + + if (result == IPCA_ACCESS_DENIED) + { + std::lock_guard lock(m_requestAccessMutex); + if (!m_requestedAccess) + { + if (m_requestAccessHandle != nullptr) + { + IPCACloseHandle(m_requestAccessHandle, nullptr, nullptr); + m_requestAccessHandle = nullptr; + } + + IPCAStatus reqResult = IPCARequestAccess( + m_deviceHandle, + nullptr, + &::AuthCompletionCallback, + m_thisWeakRef, + &m_requestAccessHandle); + if (reqResult == IPCA_OK) + { + m_requestedAccess = true; + } + } + return; + } + else if ((result != IPCA_OK) && (result != IPCA_DEVICE_APPEAR_OFFLINE)) + { + String^ err = "Failure in Resource Change Notification. result=" + + static_cast(result).ToString(); + Util::ShowErrorMsg(m_dispatcher, err); + return; + } + + if (IPCAPropertyBagGetValueInt(propertyBagHandle, "x.org.iotivity.CurrentFloor", + &observedCurrentFloor) == IPCA_OK) + { + CurrentFloor = observedCurrentFloor.ToString(); + } +} + +void Elevator::AuthCompletionCallback(IPCAStatus completionStatus) +{ + if ((completionStatus != IPCA_SECURITY_UPDATE_REQUEST_FINISHED) && + (completionStatus != IPCA_DEVICE_APPEAR_OFFLINE)) + { + std::lock_guard lock(m_requestAccessMutex); + // Reset requested access to enable request access again. + m_requestedAccess = false; + + String^ err = "Failure in Auth Callback. result=" + + static_cast(completionStatus).ToString(); + Util::ShowErrorMsg(m_dispatcher, err); + OnAuthFailure(); + return; + } + + // Restart observation + StartObservation(); +} + +void Elevator::SetPropertiesCallback(IPCAStatus result, IPCAPropertyBagHandle propertyBagHandle) +{ + if ((result != IPCA_OK) && (result != IPCA_DEVICE_APPEAR_OFFLINE)) + { + String^ err = "Failure trying to Set Properties. result=" + + static_cast(result).ToString(); + Util::ShowErrorMsg(m_dispatcher, err); + } +} + +void Elevator::OnUpdatedInfo() +{ + std::lock_guard lock(m_deviceMutex); + UpdateDeviceInfo(); + UpdatePlatformInfo(); + UpdateResourceInfo(); +} + +IPCADeviceInfo* Elevator::GetDeviceInfo() +{ + std::lock_guard lock(m_deviceMutex); + if (!m_initialized) + { + return nullptr; + } + + return m_deviceInfo; +} + +IPCAPlatformInfo* Elevator::GetPlatformInfo() +{ + std::lock_guard lock(m_deviceMutex); + if (!m_initialized) + { + return nullptr; + } + + return m_platformInfo; +} + +ResourceList Elevator::GetResourceInfo() +{ + std::lock_guard lock(m_deviceMutex); + ResourceList emptyResourceList; + + if (!m_initialized) + { + return emptyResourceList; + } + + return m_resourceList; +} + +bool Elevator::SetTargetFloor(int floor) +{ + if (OpenDevice() != IPCA_OK) + { + return false; + } + + bool ret = false; + IPCAPropertyBagHandle propertyBagHandle; + IPCAStatus status = IPCAPropertyBagCreate(&propertyBagHandle); + if (IPCA_OK == status) + { + status = IPCAPropertyBagSetValueInt(propertyBagHandle, + "x.org.iotivity.TargetFloor", floor); + + if (IPCA_OK == status) + { + status = IPCASetProperties(m_deviceHandle, + &::SetPropertiesCallback, + m_thisWeakRef, + "/ipca/sample/elevator", + "x.org.iotivity.sample.elevator", + nullptr, + propertyBagHandle, + nullptr); + + if (IPCA_OK == status) + { + ret = true; + } + } + IPCAPropertyBagDestroy(propertyBagHandle); + } + + return ret; +} diff --git a/resource/IPCA/samples/ElevatorClientUWP/Elevator.h b/resource/IPCA/samples/ElevatorClientUWP/Elevator.h new file mode 100644 index 0000000..df02603 --- /dev/null +++ b/resource/IPCA/samples/ElevatorClientUWP/Elevator.h @@ -0,0 +1,107 @@ +/* ***************************************************************** + * + * Copyright 2017 Microsoft + * + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************/ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ipca.h" + +namespace ElevatorClientUWP +{ + public delegate void AuthFailure(); + // Key of map is resource path. Value is array of resource types. + typedef std::map> ResourceList; + + /** + * Each Elevator object represents a device discovered by IPCA. + */ + [Windows::UI::Xaml::Data::Bindable] + public ref class Elevator sealed : Windows::UI::Xaml::Data::INotifyPropertyChanged + { + public: + Elevator(); + virtual ~Elevator(); + internal: + bool Init(IPCAAppHandle appHandle, Platform::String^ name, std::string id); + void StartObservation(); + void StopObservation(); + void ResourceChangeNotificationCallback(IPCAStatus result, IPCAPropertyBagHandle propertyBagHandle); + void SetPropertiesCallback(IPCAStatus result, IPCAPropertyBagHandle propertyBagHandle); + void AuthCompletionCallback(IPCAStatus completionStatus); + void OnUpdatedInfo(); + + IPCADeviceInfo* GetDeviceInfo(); + IPCAPlatformInfo* GetPlatformInfo(); + ResourceList GetResourceInfo(); + + bool SetTargetFloor(int floor); + + public: + virtual event Windows::UI::Xaml::Data::PropertyChangedEventHandler^ PropertyChanged; + event AuthFailure^ OnAuthFailure; + + property Platform::String^ Name + { + Platform::String^ get(); + void set(Platform::String^ value); + } + + property Platform::String^ CurrentFloor + { + Platform::String^ get(); + void set(Platform::String^ value); + } + + private: + void OnPropertyChanged(Platform::String^ propertyName); + IPCAStatus OpenDevice(); + void UpdateDeviceInfo(); + void UpdatePlatformInfo(); + void UpdateResourceInfo(); + + private: + Platform::WeakReference* m_thisWeakRef; + Windows::UI::Core::CoreDispatcher^ m_dispatcher; + bool m_initialized; + Platform::String^ m_deviceName; + Platform::String^ m_curFloor; + IPCAAppHandle m_ipcaAppHandle; + IPCAHandle m_observeHandle; + IPCAHandle m_requestAccessHandle; + std::string m_deviceId; + std::string m_hostAddress; + IPCADeviceHandle m_deviceHandle; // from IPCAOpenDevice(); + IPCADeviceInfo* m_deviceInfo; // valid between IPCAOpenDevice() and IPCACloseDevice(). + IPCAPlatformInfo* m_platformInfo; // valid between IPCAOpenDevice() and IPCACloseDevice(). + ResourceList m_resourceList; + std::mutex m_deviceMutex; + bool m_requestedAccess; + std::mutex m_requestAccessMutex; + }; +} diff --git a/resource/IPCA/samples/ElevatorClientUWP/ElevatorClientUWP.sln b/resource/IPCA/samples/ElevatorClientUWP/ElevatorClientUWP.sln new file mode 100644 index 0000000..86629fc --- /dev/null +++ b/resource/IPCA/samples/ElevatorClientUWP/ElevatorClientUWP.sln @@ -0,0 +1,39 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25420.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ElevatorClientUWP", "ElevatorClientUWP.vcxproj", "{D30AE502-76EE-4061-87A3-C7142283D03E}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|ARM = Debug|ARM + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|ARM = Release|ARM + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {D30AE502-76EE-4061-87A3-C7142283D03E}.Debug|ARM.ActiveCfg = Debug|ARM + {D30AE502-76EE-4061-87A3-C7142283D03E}.Debug|ARM.Build.0 = Debug|ARM + {D30AE502-76EE-4061-87A3-C7142283D03E}.Debug|ARM.Deploy.0 = Debug|ARM + {D30AE502-76EE-4061-87A3-C7142283D03E}.Debug|x64.ActiveCfg = Debug|x64 + {D30AE502-76EE-4061-87A3-C7142283D03E}.Debug|x64.Build.0 = Debug|x64 + {D30AE502-76EE-4061-87A3-C7142283D03E}.Debug|x64.Deploy.0 = Debug|x64 + {D30AE502-76EE-4061-87A3-C7142283D03E}.Debug|x86.ActiveCfg = Debug|Win32 + {D30AE502-76EE-4061-87A3-C7142283D03E}.Debug|x86.Build.0 = Debug|Win32 + {D30AE502-76EE-4061-87A3-C7142283D03E}.Debug|x86.Deploy.0 = Debug|Win32 + {D30AE502-76EE-4061-87A3-C7142283D03E}.Release|ARM.ActiveCfg = Release|ARM + {D30AE502-76EE-4061-87A3-C7142283D03E}.Release|ARM.Build.0 = Release|ARM + {D30AE502-76EE-4061-87A3-C7142283D03E}.Release|ARM.Deploy.0 = Release|ARM + {D30AE502-76EE-4061-87A3-C7142283D03E}.Release|x64.ActiveCfg = Release|x64 + {D30AE502-76EE-4061-87A3-C7142283D03E}.Release|x64.Build.0 = Release|x64 + {D30AE502-76EE-4061-87A3-C7142283D03E}.Release|x64.Deploy.0 = Release|x64 + {D30AE502-76EE-4061-87A3-C7142283D03E}.Release|x86.ActiveCfg = Release|Win32 + {D30AE502-76EE-4061-87A3-C7142283D03E}.Release|x86.Build.0 = Release|Win32 + {D30AE502-76EE-4061-87A3-C7142283D03E}.Release|x86.Deploy.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/resource/IPCA/samples/ElevatorClientUWP/ElevatorClientUWP.vcxproj b/resource/IPCA/samples/ElevatorClientUWP/ElevatorClientUWP.vcxproj new file mode 100644 index 0000000..a4a3b43 --- /dev/null +++ b/resource/IPCA/samples/ElevatorClientUWP/ElevatorClientUWP.vcxproj @@ -0,0 +1,261 @@ + + + + {d30ae502-76ee-4061-87a3-c7142283d03e} + ElevatorClientUWP + en-US + 14.0 + true + Windows Store + 10.0.14393.0 + 10.0.10586.0 + 10.0 + 1D05309EEC0622608A78ABCCA0E20C7528C4C79E + + + + + Debug + ARM + + + Debug + Win32 + + + Debug + x64 + + + Release + ARM + + + Release + Win32 + + + Release + x64 + + + + Application + true + v140 + + + Application + true + v140 + + + Application + true + v140 + + + Application + false + true + v140 + true + + + Application + false + true + v140 + true + + + Application + false + true + v140 + true + + + + + + + + + + + + + + + + + + + + + + + + ElevatorClientUWP_TemporaryKey.pfx + False + Always + x64 + + + ElevatorClientUWP_TemporaryKey.pfx + False + Always + x86 + + + ElevatorClientUWP_TemporaryKey.pfx + False + Always + arm + + + $(ProjectDir)\..\..\inc;$(ProjectDir)\..\..\..\c_common;$(IncludePath) + $(SolutionDir)Out\$(Configuration)\$(PlatformTarget)\$(MSBuildProjectName)\ + $(PlatformTarget)\$(Configuration)\ + + + $(ProjectDir)\..\..\inc;$(ProjectDir)\..\..\..\c_common;$(IncludePath) + $(SolutionDir)Out\$(Configuration)\$(PlatformTarget)\$(MSBuildProjectName)\ + $(PlatformTarget)\$(Configuration)\ + + + $(ProjectDir)\..\..\inc;$(ProjectDir)\..\..\..\c_common;$(IncludePath) + $(SolutionDir)Out\$(Configuration)\$(PlatformTarget)\$(MSBuildProjectName)\ + $(PlatformTarget)\$(Configuration)\ + + + $(ProjectDir)\..\..\inc;$(ProjectDir)\..\..\..\c_common;$(IncludePath) + $(SolutionDir)Out\$(Configuration)\$(PlatformTarget)\$(MSBuildProjectName)\ + $(PlatformTarget)\$(Configuration)\ + + + $(ProjectDir)\..\..\inc;$(ProjectDir)\..\..\..\c_common;$(IncludePath) + $(SolutionDir)Out\$(Configuration)\$(PlatformTarget)\$(MSBuildProjectName)\ + $(PlatformTarget)\$(Configuration)\ + + + $(ProjectDir)\..\..\inc;$(ProjectDir)\..\..\..\c_common;$(IncludePath) + $(SolutionDir)Out\$(Configuration)\$(PlatformTarget)\$(MSBuildProjectName)\ + $(PlatformTarget)\$(Configuration)\ + + + + /bigobj %(AdditionalOptions) + 4453;28204 + + + WindowsApp.lib;ipca.lib;%(AdditionalDependencies) + + + + + /bigobj %(AdditionalOptions) + 4453;28204 + + + WindowsApp.lib;ipca.lib;%(AdditionalDependencies) + + + + + /bigobj %(AdditionalOptions) + 4453;28204 + + + WindowsApp.lib;ipca.lib;%(AdditionalDependencies) + + + + + /bigobj %(AdditionalOptions) + 4453;28204 + + + WindowsApp.lib;ipca.lib;%(AdditionalDependencies) + + + + + /bigobj %(AdditionalOptions) + 4453;28204 + + + WindowsApp.lib;ipca.lib;%(AdditionalDependencies) + + + + + /bigobj %(AdditionalOptions) + 4453;28204 + + + WindowsApp.lib;ipca.lib;%(AdditionalDependencies) + + + + + + + + + App.xaml + + + MainPage.xaml + + + + + + Designer + + + Designer + + + + + Designer + + + + + + + + + + + + + + + App.xaml + + + + + MainPage.xaml + + + + Create + Create + Create + Create + Create + Create + + + + + + + + \ No newline at end of file diff --git a/resource/IPCA/samples/ElevatorClientUWP/ElevatorClientUWP.vcxproj.filters b/resource/IPCA/samples/ElevatorClientUWP/ElevatorClientUWP.vcxproj.filters new file mode 100644 index 0000000..fb55832 --- /dev/null +++ b/resource/IPCA/samples/ElevatorClientUWP/ElevatorClientUWP.vcxproj.filters @@ -0,0 +1,75 @@ + + + + + d30ae502-76ee-4061-87a3-c7142283d03e + + + 12bbc0a4-0b14-4fc7-bc95-3eef4bdbe84e + bmp;fbx;gif;jpg;jpeg;tga;tiff;tif;png + + + + + + + + + + + + + + + + + + + + + + + + + + Assets + + + Assets + + + Assets + + + Assets + + + Assets + + + Assets + + + Assets + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resource/IPCA/samples/ElevatorClientUWP/ElevatorClientUWP_TemporaryKey.pfx b/resource/IPCA/samples/ElevatorClientUWP/ElevatorClientUWP_TemporaryKey.pfx new file mode 100644 index 0000000000000000000000000000000000000000..2a6baaa627e0d9c1250404d61d85b22c293024f4 GIT binary patch literal 2528 zcmZXUc|6oxAIE>Q7}*9zS%z#AE^3M_l@T#_?2H&==qCHV4AEv8J7ddL*~$`=h7_Yr z#?nKmWR1qY-E8TKDU2-7++NRf@9TLzuk$+R`~AGX%Q^p?FN(}J4hBI`WWIYazF!it ziJL+oUQjWaF9k~GOW@*I6q#rHe?mN;p=6!~E}rA=DVV^2ss#B#;9@d#4@HJMfr00qOq`Lz?;hZ@>TzV|Jvv~Tebe{OQ=Wg9RcA_I9VNd2q)D3gO zog=SO=CNukLxRU;^T=@Oo9>06I;oOx*_7`=QZL9_l(Jgi3XJR3_AjoWnFzwdX{+dK z^K{Q4#(Cj0<&D;P^IpM^ylxwQ2Oy(qqf%XId%Mt$dwY^$Y-OvAg69$)7mL>}TYF)w z>VLcdAKnOmtQkm|;qh*!<9HosCoSaWRuBC-rVRKJ-*9=Qgf}!ZOrx>-8?2c;Q}utwmX+bvcW@dB9hJTLoqAIPL47Gd3bs+APg|z@*hI?F`))l( zJXUeN(d|ARIX40auaB*!r24m(DmX9F3YMnr(m+`))xRkkn?&ErNoO>$w|1$;#qz^~ zr=R2x=+tby3m>wzo7F-8rby`3qQ7TC@((VkrfrwK)ZX>_V0i8zBVAsC&?+6|n_%;8 z<&jZ>7DoKbb=e+xsHH=sa&%hO6>E)6kOElF&JCmpXJu(juh;X~Y)pJrFfgDfB7t|u zz(ym3k+0IU3keT-^*KwJ;r6bNfDkq=wb@+YWzeZu%*~+uQ^JbMVoX18m+&Nei%Vi} z8jqV0$!1Gub5Hu3XmqI-1$qnTuc)d_$C$>O=MN$O1@_FC%2pC*ez5#qz33tf+XF|H zA|*pORbLcq`qS##7jxLQ^wWK8G!q8w58vIS1gHS&l_TlH0bja6e`@Llr+E@eR3l1BnY&h!EKblz?e_XM(#oqt@c6WtC;hMjG;+|g* zBfD_p{EWw4)>1cKe!)wBk-8x$!^E%Z;hth$r&`7=_-fLx=c4ZBysE(I@4u7YO}sdp zN0R#xJ(+x&5Iyf-Q^JZKSk5vt0IeD;~s(E z#Yr?Ie}SPkvZ6U*OX^u#mW9Z{l}a|N@V7FXLrn0M^7h6SdB-{{^DC0q>hfFyBW*Xm ziJ6?~W%YwzU}-;brIJr<`K7bgiJq3IwX>MElsoRtRWbI8mkwC4-*)Wo`$=TLet1P% z0n#NbD)t_1Eg&x8!LWeMrj=omR_xxcfv+fIxU&$fXM84cDMuxj`jM%aTOA2;y12Z)*xWg|uHDl1 zK$|Kmk@PUD8o@ak`yO@Z?{Uc|ei8Hg z42k~x<-D+BG9;Lb{J|iAYdrpmfc}5v|It24)4B+p{%hpNkRiIvmF~@D&Kq>4oW5=I zYS&$iVqF@@Wm82%%dzkI{>p2nNKx?@u`P+IHUFj)u8HjPW3`9xTNl-RQgbnltxCRc zhmN4RXiT{~`3{X}A8_1VRm~yuqYkJqulmaPIi(3m-kJ~pp_)XPSCKy1z{9jGAYPhq z?18G`>kCm)_N|3I*3$>&%vO8EJ#{WQAgLU ztJB?5aUW$8=+RQazlP!J5e1@W%&E;)iMvA^ZsW#VQYwmzCM@r*h!;u`euvUP=jwx1 zdsmHfMxNc>pW_^`qbpYTD;-nTYb=>@*gDb{Y#<)5+Vg~>plcHI6m3RMc&^89lzC{s zh3ZMUwxF64;>Q23C{XC=}KNdmnO|a@yFkFye31|sx-8dFu}t7y?&g zx_*~g%tMZG)~jBd3|6XrSly6CszkO*llJU&m=n4}tGBP@MlBR@gc4N{bF)I-HgkNx z+v^|Mp-*-SiH(}Wkjk(Jh}$NtyeJtRBMob|E&3_EyVuI;(MHsbNQ+~L{o6Jc+Hg!< ziM+>QPEmkyW4=AP;Yhq4%DUqDV)XF-of^`=d|mt)&&(9o3L}JBsT$_meF;m}9jOl; zmAlFw2U@w%(h~Up=7=z2)uNO>ZZyvlINo zyN2m61q#3Fl+P+cRIq8KaT6k&Zu&Tyck741KGa#%Q4}wXM-2`EOF_k4oM|A@S^adM owGnh$pq+n=Mf(e=SdgSo{9C|~>4e}HKw{q^zw4bb +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ipca.h" +#include "Elevator.h" +#include "ElevatorViewModel.h" + +using namespace ElevatorClientUWP; + +using namespace concurrency; + +using namespace std; +using namespace Platform; +using namespace Platform::Collections; +using namespace Windows::ApplicationModel::Core; +using namespace Windows::Foundation; +using namespace Windows::Foundation::Collections; +using namespace Windows::UI::Core; +using namespace Windows::UI::Xaml; +using namespace Windows::UI::Xaml::Controls; +using namespace Windows::UI::Xaml::Controls::Primitives; +using namespace Windows::UI::Xaml::Data; +using namespace Windows::UI::Xaml::Input; +using namespace Windows::UI::Xaml::Media; +using namespace Windows::UI::Xaml::Navigation; + +#define TIMEOUT_MS 3000 + +String^ ElevatorDiscovery::guidStr = "{ab2593e4-2994-401e-a526-c92fd9b71414}"; + +static void IPCA_CALL DiscoverDevicesCallback( + void* context, + IPCADeviceStatus deviceStatus, + const IPCADiscoveredDeviceInfo* deviceInfo) +{ + if (context) + { + ElevatorDiscovery^ elvDisc = + (reinterpret_cast(context))->Resolve(); + if (elvDisc) + { + elvDisc->DiscoverDevicesCallback(deviceStatus, deviceInfo); + } + } +} + +static IPCAStatus IPCA_CALL PwdInputCallback( + void* context, + const IPCADeviceInfo* deviceInformation, + const IPCAPlatformInfo* platformInformation, + IPCAOwnershipTransferType type, + char* passwordBuffer, + size_t passwordBufferSize) +{ + if (context) + { + ElevatorDiscovery^ elvDisc = + (reinterpret_cast(context))->Resolve(); + if (elvDisc) + { + return elvDisc->PwdInputCallback(deviceInformation, platformInformation, type, + passwordBuffer, passwordBufferSize); + } + } + + // If reached here means context is either null or wrong type + return IPCA_INVALID_ARGUMENT; +} + +static IPCAStatus IPCA_CALL PwdDisplayCallback( + void* context, + const IPCADeviceInfo* deviceInformation, + const IPCAPlatformInfo* platformInformation, + IPCAOwnershipTransferType type, + const char* password) +{ + if (context) + { + ElevatorDiscovery^ elvDisc = + (reinterpret_cast(context))->Resolve(); + if (elvDisc) + { + return elvDisc->PwdDisplayCallback(deviceInformation, platformInformation, type, password); + } + } + + // If reached here means context is either null or wrong type + return IPCA_INVALID_ARGUMENT; +} + +ElevatorDiscovery::ElevatorDiscovery() : + m_ipcaAppHandle(nullptr), + m_deviceHandle(nullptr), + m_discoverDeviceHandle(nullptr), + m_deviceDiscoveryHandle(nullptr), + m_targetElevatorDiscovered(false), + m_currentFloor(0) +{ + m_thisWeakRef = new WeakReference(this); + m_dispatcher = CoreApplication::MainView->Dispatcher; + + GUID guid; + HRESULT hr = IIDFromString(guidStr->Data(), &guid); + if (FAILED(hr)) + { + if (hr == E_INVALIDARG) + { + throw ref new InvalidArgumentException("IIDFromString invalid arg"); + } + else if (hr == E_OUTOFMEMORY) + { + throw ref new OutOfMemoryException("IIDFromString out of memory"); + } + else + { + throw ref new FailureException("IIDFromString failed"); + } + } + + IPCAUuid appId; + byte* guidBytes = reinterpret_cast(&guid); + for (int i = 0; i < 16; i++) + { + appId.uuid[i] = guidBytes[i]; + } + + IPCAAppInfo ipcaAppInfo = { appId, "ElevatorClientUWP", "1.0.0", "Microsoft" }; + + IPCAStatus status = IPCAOpen(&ipcaAppInfo, IPCA_VERSION_1, &m_ipcaAppHandle); + if (status != IPCA_OK) + { + String^ err = "IPCAOpen() Failed. Status: " + static_cast(status).ToString(); + throw ref new FailureException(err); + } + + status = IPCASetPasswordCallbacks(m_ipcaAppHandle, &::PwdInputCallback, + &::PwdDisplayCallback, m_thisWeakRef); + if (status != IPCA_OK) + { + String^ err = "IPCASetPasswordCallbacks() Failed. Status: " + static_cast(status).ToString(); + throw ref new FailureException(err); + } + + m_ElevatorList = ref new Map(); + + // Generate Password Input Content Dialog + TextBlock^ tbPwdInput = ref new TextBlock(); + tbPwdInput->Text = "Please enter Elevator Password:"; + tbPwdInput->Margin = Thickness(0, 5, 0, 0); + + m_pbPwdInput = ref new PasswordBox(); + m_pbPwdInput->PasswordRevealMode = PasswordRevealMode::Peek; + m_pbPwdInput->Margin = Thickness(10); + m_pbPwdInput->MinWidth = 250; + + StackPanel^ spPwdInput = ref new StackPanel(); + spPwdInput->Orientation = Orientation::Vertical; + spPwdInput->Children->Append(tbPwdInput); + spPwdInput->Children->Append(m_pbPwdInput); + + m_passInputDiag = ref new ContentDialog(); + m_passInputDiag->Title = "Authentication Needed"; + m_passInputDiag->Content = spPwdInput; + m_passInputDiag->PrimaryButtonText = "Authenticate"; + m_passInputDiag->SecondaryButtonText = "Cancel"; + + // Generate Password Display Content Dialog + TextBlock^ tbPwdDisplay = ref new TextBlock(); + tbPwdDisplay->Text = "Elevator Password is:"; + tbPwdDisplay->Margin = Thickness(0, 5, 0, 0); + + m_txtPwdDisplay = ref new TextBox(); + m_txtPwdDisplay->IsReadOnly = true; + m_txtPwdDisplay->Margin = 10; + m_txtPwdDisplay->BorderThickness = 0; + + StackPanel^ spPwdDisplay = ref new StackPanel(); + spPwdDisplay->Orientation = Orientation::Vertical; + spPwdDisplay->Children->Append(tbPwdDisplay); + spPwdDisplay->Children->Append(m_txtPwdDisplay); + + m_passDisplayDiag = ref new ContentDialog(); + m_passDisplayDiag->Title = "Authentication Info"; + m_passDisplayDiag->Content = spPwdDisplay; + m_passDisplayDiag->PrimaryButtonText = "OK"; +} + +ElevatorDiscovery::~ElevatorDiscovery() +{ + StopElevatorDiscovery(); + + std::lock_guard lock(m_ElevatorListMutex); + m_ElevatorList->Clear(); + + if (m_ipcaAppHandle != nullptr) + { + IPCAClose(m_ipcaAppHandle); + } + + delete m_thisWeakRef; +} + +bool ElevatorDiscovery::StartElevatorDiscovery() +{ + std::unique_lock lock(m_deviceDiscoveryMutex); + + if (!m_deviceDiscoveryHandle) + { + // Start the discovery if not already started + + const char* resourceTypes[] = { + "x.org.iotivity.sample.elevator", + "x.org.iotivity.sample.elevator2", + "x.org.iotivity.sample.elevator3", + "x.org.iotivity.sample.elevator4", + }; + + const int NUMBER_OF_RESOURCE_TYPES = sizeof(resourceTypes) / sizeof(char*); + + IPCAStatus status = IPCADiscoverDevices( + m_ipcaAppHandle, + &::DiscoverDevicesCallback, + m_thisWeakRef, + resourceTypes, + NUMBER_OF_RESOURCE_TYPES, + &m_deviceDiscoveryHandle); + + if (status != IPCA_OK) + { + return false; + } + } + + return true; +} + +void ElevatorDiscovery::StopElevatorDiscovery() +{ + std::unique_lock lock(m_deviceDiscoveryMutex); + // Stop discovery. + if (m_deviceDiscoveryHandle) + { + IPCACloseHandle(m_deviceDiscoveryHandle, nullptr, nullptr); + m_deviceDiscoveryHandle = nullptr; + } +} + +void ElevatorDiscovery::DiscoverDevicesCallback(IPCADeviceStatus deviceStatus, + const IPCADiscoveredDeviceInfo* deviceInfo) +{ + std::lock_guard lock(m_ElevatorListMutex); + + std::string deviceIdStr = deviceInfo->deviceId; + String^ deviceId = Util::ConvertStrtoPlatformStr(deviceInfo->deviceId); + String^ deviceName = Util::ConvertStrtoPlatformStr(deviceInfo->deviceName); + std::vector deviceUris; + for (size_t i = 0; i < deviceInfo->deviceUriCount; i++) + { + deviceUris.push_back(deviceInfo->deviceUris[i]); + } + + Elevator^ elevator = nullptr; + + try + { + elevator = m_ElevatorList->Lookup(deviceId); + } + catch (OutOfBoundsException^ e) + { + if (deviceStatus != IPCA_DEVICE_DISCOVERED) + { + // Log Unexpected discovery status + } + // Device not in the Map + elevator = ref new Elevator(); + elevator->Init(m_ipcaAppHandle, deviceName, deviceIdStr); + m_ElevatorList->Insert(deviceId, elevator); + } + + switch (deviceStatus) + { + case IPCA_DEVICE_DISCOVERED: + OnElevatorDiscovered(elevator); + break; + case IPCA_DEVICE_UPDATED_INFO: + elevator->OnUpdatedInfo(); + break; + case IPCA_DEVICE_STOPPED_RESPONDING: + OnElevatorDisconnected(elevator); + m_ElevatorList->Remove(deviceId); + break; + default: + break; + } +} + +IPCAStatus ElevatorDiscovery::PwdInputCallback( + const IPCADeviceInfo* deviceInformation, + const IPCAPlatformInfo* platformInformation, + IPCAOwnershipTransferType type, + char* passwordBuffer, + size_t passwordBufferSize) +{ + IAsyncOperation^ showPwdDiagAsync; + create_task(m_dispatcher->RunAsync(CoreDispatcherPriority::Normal, ref new DispatchedHandler( + [this, &showPwdDiagAsync] + { + m_pbPwdInput->Password = nullptr; + showPwdDiagAsync = m_passInputDiag->ShowAsync(); + })) + ).get(); + + ContentDialogResult result = create_task(showPwdDiagAsync).get(); + // Get the password + if (result == ContentDialogResult::Primary) + { + String^ pwd = nullptr; + create_task(m_dispatcher->RunAsync(CoreDispatcherPriority::Normal, ref new DispatchedHandler( + [this, &pwd] + { + pwd = m_pbPwdInput->Password; + })) + ).get(); + + std::string pwdStr = Util::ConvertWStrtoStr(pwd->Data()); + if (pwdStr.empty() || ((pwdStr.length() + 1) > passwordBufferSize)) // +1 for null char + { + return IPCA_INVALID_ARGUMENT; + } + + strcpy_s(passwordBuffer, passwordBufferSize, pwdStr.c_str()); + } + else + { + return IPCA_INVALID_ARGUMENT; + } + + return IPCA_OK; +} + +IPCAStatus ElevatorDiscovery::PwdDisplayCallback( + const IPCADeviceInfo* deviceInformation, + const IPCAPlatformInfo* platformInformation, + IPCAOwnershipTransferType type, + const char* password) +{ + String^ pwd = Util::ConvertStrtoPlatformStr(password); + if (pwd == nullptr) + { + return IPCA_INVALID_ARGUMENT; + } + + m_dispatcher->RunAsync(CoreDispatcherPriority::Normal, ref new DispatchedHandler( + [this, pwd] + { + m_txtPwdDisplay->Text = pwd; + m_passDisplayDiag->ShowAsync(); + } + )); + + return IPCA_OK; +} diff --git a/resource/IPCA/samples/ElevatorClientUWP/ElevatorDiscovery.h b/resource/IPCA/samples/ElevatorClientUWP/ElevatorDiscovery.h new file mode 100644 index 0000000..9fd631a --- /dev/null +++ b/resource/IPCA/samples/ElevatorClientUWP/ElevatorDiscovery.h @@ -0,0 +1,98 @@ +/* ***************************************************************** +* +* Copyright 2017 Microsoft +* +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +******************************************************************/ + +#pragma once + +#include "ipca.h" +#include "Elevator.h" + +namespace ElevatorClientUWP +{ + public delegate void ElevatorEvent(Elevator^ elevator); + + public ref class ElevatorDiscovery sealed + { + public: + ElevatorDiscovery(); + virtual ~ElevatorDiscovery(); + + bool StartElevatorDiscovery(); + void StopElevatorDiscovery(); + + public: + event ElevatorEvent^ OnElevatorDiscovered; + event ElevatorEvent^ OnElevatorDisconnected; + + internal: + void DiscoverDevicesCallback( + IPCADeviceStatus deviceStatus, + const IPCADiscoveredDeviceInfo* deviceInfo); + + IPCAStatus PwdInputCallback( + const IPCADeviceInfo* deviceInformation, + const IPCAPlatformInfo* platformInformation, + IPCAOwnershipTransferType type, + char* passwordBuffer, + size_t passwordBufferSize); + + IPCAStatus PwdDisplayCallback( + const IPCADeviceInfo* deviceInformation, + const IPCAPlatformInfo* platformInformation, + IPCAOwnershipTransferType type, + const char* password); + + private: + static Platform::String^ guidStr; + + Platform::WeakReference* m_thisWeakRef; + Windows::UI::Core::CoreDispatcher^ m_dispatcher; + + std::string m_targetDeviceId; + + IPCAAppHandle m_ipcaAppHandle; + IPCADeviceHandle m_deviceHandle; + IPCAHandle m_discoverDeviceHandle; + IPCAHandle m_deviceDiscoveryHandle; + + bool m_targetElevatorDiscovered; + + Windows::UI::Xaml::Controls::PasswordBox^ m_pbPwdInput; + Windows::UI::Xaml::Controls::TextBox^ m_txtPwdDisplay; + Windows::UI::Xaml::Controls::ContentDialog^ m_passInputDiag; + Windows::UI::Xaml::Controls::ContentDialog^ m_passDisplayDiag; + + // Key is device id. Value is pointer to Elevator. + Windows::Foundation::Collections::IMap^ m_ElevatorList; + + // Sync access to m_ElevatorList. + std::recursive_mutex m_ElevatorListMutex; + // Discovery mutex and cond var + std::mutex m_deviceDiscoveredCbMutex; + std::condition_variable m_deviceDiscoveredCV; + std::mutex m_deviceDiscoveryMutex; + std::condition_variable m_deviceDiscoveryCV; + // Device mutex + std::mutex m_deviceMutex; + // Get properties mutex and cond var + std::mutex m_getPropsMutex; + std::condition_variable m_getPropsCV; + + int m_currentFloor; + }; +} \ No newline at end of file diff --git a/resource/IPCA/samples/ElevatorClientUWP/ElevatorViewModel.cpp b/resource/IPCA/samples/ElevatorClientUWP/ElevatorViewModel.cpp new file mode 100644 index 0000000..a81a1b3 --- /dev/null +++ b/resource/IPCA/samples/ElevatorClientUWP/ElevatorViewModel.cpp @@ -0,0 +1,172 @@ +/* ***************************************************************** +* +* Copyright 2017 Microsoft +* +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +******************************************************************/ + +#include "pch.h" +#include "ElevatorViewModel.h" +#include "ElevatorDiscovery.h" + +using namespace ElevatorClientUWP; + +using namespace concurrency; + +using namespace Platform; +using namespace Platform::Collections; +using namespace Windows::ApplicationModel::Core; +using namespace Windows::Foundation; +using namespace Windows::Foundation::Collections; +using namespace Windows::UI::Core; +using namespace Windows::UI::Xaml; +using namespace Windows::UI::Xaml::Controls; +using namespace Windows::UI::Xaml::Controls::Primitives; +using namespace Windows::UI::Xaml::Data; +using namespace Windows::UI::Xaml::Input; +using namespace Windows::UI::Xaml::Media; +using namespace Windows::UI::Xaml::Navigation; + +ElevatorViewModel::ElevatorViewModel() : m_dispatcher(nullptr), m_elevatorDisc(nullptr) +{ + m_dispatcher = CoreApplication::MainView->Dispatcher; + + m_deviceList = ref new Vector(); + + try + { + ElevatorDiscovery^ elvDisc = ref new ElevatorDiscovery(); + elvDisc->OnElevatorDiscovered += ref new ElevatorEvent(this, &ElevatorViewModel::ElevatorDiscovered); + elvDisc->OnElevatorDisconnected += ref new ElevatorEvent(this, &ElevatorViewModel::ElevatorDisconnected); + m_elevatorDisc = elvDisc; + } + catch (Exception^ e) + { + Util::ShowErrorMsg(nullptr, e->Message); + } +} + +ElevatorViewModel::~ElevatorViewModel() +{ + if (m_elevatorDisc) + { + m_elevatorDisc->StopElevatorDiscovery(); + } +} + +void ElevatorViewModel::DiscoverElevators() +{ + if (!m_elevatorDisc->StartElevatorDiscovery()) + { + Util::ShowErrorMsg(nullptr, "Couldn't Start Elevator Discovery"); + } +} + +void ElevatorViewModel::ElevatorDiscovered(Elevator^ elevator) +{ + elevator->OnAuthFailure += ref new ElevatorClientUWP::AuthFailure(this, + &ElevatorViewModel::AuthFailure); + + m_dispatcher->RunAsync(CoreDispatcherPriority::Normal, ref new DispatchedHandler( + [this, elevator] + { + unsigned int index; + if (!m_deviceList->IndexOf(elevator, &index)) + { + m_deviceList->Append(elevator); + } + } + )); +} + +void ElevatorViewModel::ElevatorDisconnected(Elevator^ elevator) +{ + m_dispatcher->RunAsync(CoreDispatcherPriority::Normal, ref new DispatchedHandler( + [this, elevator] + { + unsigned int index; + if (m_deviceList->IndexOf(elevator, &index)) + { + m_deviceList->RemoveAt(index); + } + } + )); +} + +void ElevatorViewModel::AuthFailure() +{ + m_dispatcher->RunAsync(CoreDispatcherPriority::Normal, ref new DispatchedHandler([this] + { + SelectedDevice = nullptr; + })); +} + +void ElevatorViewModel::SetFloor(int floor) +{ + if (m_selectedDevice != nullptr) + { + if (!m_selectedDevice->SetTargetFloor(floor)) + { + Util::ShowErrorMsg(nullptr, "Failed to set the target floor"); + } + } +} + +IVector^ ElevatorViewModel::DeviceList::get() +{ + return m_deviceList; +} + +Elevator^ ElevatorViewModel::SelectedDevice::get() +{ + return m_selectedDevice; +} + +void ElevatorViewModel::SelectedDevice::set(Elevator^ value) +{ + if (m_selectedDevice != value) + { + // Stop Observation for the previously selected device + if (m_selectedDevice) + { + m_selectedDevice->StopObservation(); + } + + // Set the new device + m_selectedDevice = value; + OnPropertyChanged("SelectedDevice"); + + // Start Observation for the newly selected device + if (m_selectedDevice) + { + try + { + m_selectedDevice->StartObservation(); + } + catch (Exception^ e) + { + Util::ShowErrorMsg(nullptr, e->Message); + } + } + } +} + +void ElevatorViewModel::OnPropertyChanged(String^ propertyName) +{ + m_dispatcher->RunAsync(CoreDispatcherPriority::Normal, ref new DispatchedHandler([this, propertyName] + { + PropertyChanged(this, ref new PropertyChangedEventArgs(propertyName)); + })); +} diff --git a/resource/IPCA/samples/ElevatorClientUWP/ElevatorViewModel.h b/resource/IPCA/samples/ElevatorClientUWP/ElevatorViewModel.h new file mode 100644 index 0000000..b7b0e63 --- /dev/null +++ b/resource/IPCA/samples/ElevatorClientUWP/ElevatorViewModel.h @@ -0,0 +1,64 @@ +/* ***************************************************************** +* +* Copyright 2017 Microsoft +* +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +******************************************************************/ + +#pragma once + +#include "Elevator.h" + +namespace ElevatorClientUWP +{ + ref class ElevatorDiscovery; + + [Windows::UI::Xaml::Data::Bindable] + public ref class ElevatorViewModel sealed : Windows::UI::Xaml::Data::INotifyPropertyChanged + { + public: + ElevatorViewModel(); + virtual ~ElevatorViewModel(); + void DiscoverElevators(); + void SetFloor(int floor); + + public: + virtual event Windows::UI::Xaml::Data::PropertyChangedEventHandler^ PropertyChanged; + + property Windows::Foundation::Collections::IVector^ DeviceList + { + Windows::Foundation::Collections::IVector^ get(); + } + + property Elevator^ SelectedDevice + { + Elevator^ get(); + void set(Elevator^ value); + } + + private: + void OnPropertyChanged(Platform::String^ propertyName); + void ElevatorDiscovered(Elevator^ elevator); + void ElevatorDisconnected(Elevator ^elevator); + void AuthFailure(); + + private: + Windows::UI::Core::CoreDispatcher^ m_dispatcher; + ElevatorDiscovery^ m_elevatorDisc; + Platform::String^ m_targetDeviceId; + Platform::Collections::Vector^ m_deviceList; + Elevator^ m_selectedDevice; + }; +} diff --git a/resource/IPCA/samples/ElevatorClientUWP/IPCALibs.targets b/resource/IPCA/samples/ElevatorClientUWP/IPCALibs.targets new file mode 100644 index 0000000..1b439ba --- /dev/null +++ b/resource/IPCA/samples/ElevatorClientUWP/IPCALibs.targets @@ -0,0 +1,21 @@ + + + $(ProjectDir)..\..\..\..\out\windows\uwp\amd64\$(Configuration) + + + $(ProjectDir)..\..\..\..\out\windows\uwp\$(PlatformTarget)\$(Configuration) + + + + + %(RecursiveDir)%(FileName)%(Extension) + PreserveNewest + + + + + + $(IoTivityOutDir);%(AdditionalLibraryDirectories) + + + diff --git a/resource/IPCA/samples/ElevatorClientUWP/MainPage.xaml b/resource/IPCA/samples/ElevatorClientUWP/MainPage.xaml new file mode 100644 index 0000000..2bd594e --- /dev/null +++ b/resource/IPCA/samples/ElevatorClientUWP/MainPage.xaml @@ -0,0 +1,38 @@ + + + + 10 + + + + + + + + + + + + + + + +