*Windows 10 RTM update: you can now use the Visual Studio extension for AllJoyn and Windows 10 to generate AllJoyn code from Windows 10 interfaces. Many of the steps listed in this article are no longer necessary. Please see the following blog post for more information.
AllJoyn was created to empower the Internet of Things. Because AllJoyn support is built into Windows 10, you can easily take advantage of AllJoyn to "IoT-enable" your Windows 10 apps. This article will outline the steps required to build apps for Windows 10 Public Preview using the Universal Windows Platform (UWP) AllJoyn APIs and Visual Studio 2015. Note that most of the steps outlined in this post will not be required when Windows 10 RTM is available, because Visual Studio 2015 will offer full AllJoyn integration when Windows 10 is released.
This blog post is a companion to the AllJoyn session presented at //build/ 2015 where you can learn AllJoyn fundamentals, understand how Windows 10 incorporates AllJoyn, and watch an end-to-end coding demo which will guide you through the same coding scenario outlined in this post:
Understanding AllJoyn UWP App Development
Building apps for Windows 10 using UWP AllJoyn APIs involves three categories of code:
- The app code that you write in your UWP Windows app
- The AllJoyn core APIs: AllJoyn Standard Client API (C) and Windows.Devices.AllJoyn API (UWP)
- One or more UWP Windows Runtime Components (code is generated from AllJoyn interfaces)
The following diagram shows the layout for an example AllJoyn UWP project:
AllJoyn-enabled UWP apps can be either Producers (implement and expose interfaces, typically a device), Consumers (call interfaces, typically apps), or both. While this article will focus on the AllJoyn Consumer scenario, the steps required to implement an AllJoyn Producer are the same for the most part. If you want to implement an AllJoyn producer UWP app, at the bottom of this post, you'll find a link to a sample project which includes code for a UWP producer app and a UWP consumer app.
Developing your AllJoyn-enabled UWP app
Developing AllJoyn-enabled UWP apps for Windows 10 Public Preview involves the following steps: (explained in detail later in this document)
- Prepare your build environment (Windows 10, Visual Studio 2015, and related tools)
- Determine which AllJoyn interfaces will be used, obtain or create necessary introspection XML (For more information on Introspection XML, see the D-Bus specification)
- Create your Visual Studio Solution and UWP app project
- Generate code from AllJoyn introspection XML
- Create UWP Windows Runtime Component projects for generated code files
- Adjust project settings and manage dependencies
- Add AllJoyn consumer code in your UWP app project
Preparing your Build Environment
The Windows 10 Public Preview build and related tools include all of the resources that you'll need to write AllJoyn-enabled UWP apps.
Here's what you'll need to do before you get started writing code:
- Install Windows 10 Public Preview on a PC
- Install Visual Studio 2015
- Download the code and tools included with this article (see link at end of this post)
Obtaining Introspection XML for AllJoyn Interfaces
There are three ways that you can obtain the AllJoyn interface definitions that you will need to start your project:
- Obtain the introspection XML from documentation, example: Lighting Service Framework (LSF) documentation from AllSeen
- Extract introspection XML from AllJoyn devices present on your network at runtime
- Create your own introspection XML that is compliant with the AllJoyn/D-Bus introspection format
You can use the getajxml command line application (included in the download attached to this post) to get introspection XML from AllJoyn devices running on your network. Running the tool without command line parameters will list all AllJoyn apps on the network.
When you run getajxml without parameters, you will see a list of all the AllJoyn devices on the network, each of the interfaces exposed by each device, and other AllJoyn metadata like the unique name, the session port, and the object path.
At //build 2015, an AllJoyn-enabled toaster device was shown which will serve as the example for this post, and the corresponding code that you can download. This toaster exposes controls for starting and stopping the toasting sequence, setting the "darkness", and notifications when toast is done.
The AllJoyn toaster hardware sample in action
The following output is obtained from the AllJoyn toaster device running on a network when you run the getajxml tool:
Discovery : About Announcement
Model # : 070773
Device Name : Raspberry Pi Toaster
Device ID : 41d9a124-6913-40c5-a20a-9d1b20f8121b
App Name : Toaster Producer
Bus Name Port Object Path
============================== ===== ===============================
:3yZG_wu1.2 25 /emergency
:3yZG_wu1.2 25 /info
:3yZG_wu1.2 25 /notificationDismisser
:3yZG_wu1.2 25 /notificationProducer
:3yZG_wu1.2 25 /toaster
:3yZG_wu1.2 25 /warning
In this case, we're interested in obtaining the introspection XML for the toaster interface which has a unique name of ":3yZG_wu1.2", a session port value of "25", and an object path with value "/toaster".
In order to obtain the introspection XML, we pass these values to the getajxml tool as shown here:
getajxml.exe :3yZG_wu1.2 25 /toaster > toaster.xml
When the above command was run, the following was included in the XML which was output to the file:
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://standards.freedesktop.org/dbus/introspect-1.0.dtd"> <node> <interface name="com.microsoft.sample.toaster"> <method name="startToasting"> </method> <method name="stopToasting"> </method> <signal name="toastDone"> <arg name="status" type="i" direction="out"/> </signal> <property name="Darkness" type="u" access="readwrite"/> </interface> </node>
Note: In the XML file which is output you will potentially find many different interfaces. In this example, you can remove all interfaces except the "toaster" interface for the purposes of this coding demo.
Generating Code from AllJoyn Interfaces
The AllJoyn code generator takes in an XML file containing one or more AllJoyn introspection interfaces and generates C++ code that implements APIs for the AllJoyn interface(s) described in the XML.
The AllJoyn code generator tool is included in the Windows 10 Public Preview build, and is located in the following directory: [Windows Kits Directory]\10\bin\x64\
Example directory: C:\Program Files (x86)\Windows Kits\10\bin\x64\
Using the AllJoyn code generator tool involves supplying two command line arguments: an input introspection XML file, and an output directory:
alljoyncodegen.exe -i <input xml file> -o <output folder>
The following example shows the AllJoyn code generator in use:
alljoyncodegen.exe -i c:\alljoyn\toaster\toaster.xml -o c:\alljoyn\toaster\toaster-uwp-component
This example assumes that the "c:\alljoyn\toaster\toaster-uwp-component" directory already exists.
After running the code generator you'll see a number of files in the output directory. For the toaster example, the following files are generated:
Once the C++ files are generated, it's then time to create a UWP Windows Runtime Component project that will contain these files.
Creating UWP Windows Runtime Component Projects
In Visual Studio 2015, add a new "Windows Runtime Component (Windows Universal)" project to the solution containing your UWP app (You can do this easily by right clicking on the solution, then selecting Add New->Project). Once this project has been created, you will need to perform the following steps:
- Build the UWP component project.
- Remove any files that are a part of the new project, but leave pch.cpp and pch.h as a part of the project.
- Copy files generated by the code generator to the new project directory (overwriting pch.cpp and pch.h with the versions created by the code generator), add these files to the new project by right-clicking on the Windows Runtime Component project, then selecting "Add->Existing Item...".
- Open the file "pch.h" and find the root namespace defined there. For the toaster example, the root namespace declaration is:
- #define PROJECT_NAMESPACE com::microsoft::sample
- If the UWP component project root namespace is different from the root namespace found in step 3 above, in the UWP project settings page, change the root namespace accordingly. For the toaster example, the root namespace should be changed to: "com.microsoft.sample".
- Rebuild the UWP component project. If the rebuild succeeds, move forward to the next section.
If you are using AllJoyn interfaces that don't share the same root namespace, you'll need to generate code for each root namespace used. The steps in this section need to be performed for each collection of code that is generated. In the end, you should have one UWP component project for each AllJoyn root namespace used by your UWP app.
Editing Project Settings and Dependencies
At this point, you should have a Visual Studio solution that includes a UWP app project, and one or more UWP Windows Runtime Component projects. Before you embark on writing your AllJoyn consumer code, there's a few last things to take care of.
In each UWP component project, make the following updates/changes:
- Select "All Platforms" and "All Configurations" in project properties
- Add the AllJoyn API library (MSAJAPI.lib) to the linker dependencies. (Right Click on Project -> Properties -> Linker -> Input -> Additional Dependencies)
- Make sure that calling convention is set to __stdcall (Properties -> C/C++ -> Advanced -> Calling Convention)
- QCC_OS_GROUP_WINDOWS needs to be added to the Preproccessor Definitions of each C++ Windows Runtime Component. (Properties -> C/C++ -> Preprocessor -> Preprocessor Definitions)
- In some cases, you may need to add the C++ Command Line options "-Zm###", where ### is additional resource allocation required for compilation to succeed. If you encounter related compiler errors when compiling the component project, this step will be required.
- Example: -Zm160 (check build output for specific value recommended)
In the UWP app project, make the following updates/changes:
- Add a reference and build dependency from your UWP app project to your UWP Windows Runtime Component project
- Under your package manifest for your app (Package.appmanifest.xml), you will need to add the "allJoyn" capability under the <Capabilities> element:
- <Capability Name:"allJoyn" />
After completing these steps, build and run the UWP app project. Your builds should succeed, and the app should run. If you have build or deployment errors, investigate and fix before continuing on.
Writing AllJoyn Consumer Code
If you've navigated all of the instructions in this document and followed all of the steps correctly, you are ready to start writing AllJoyn consumer code in your app. The good news is, most of the steps outlined in this document will be replaced by AllJoyn integration in Visual Studio 2015 which will be available at the time Windows 10 is released. This means you'll be able to start writing AllJoyn consumer and/or producer code in just a few minutes.
The attached toaster sample project contains sample code for both a toaster producer (simulates a toaster device) and a toaster consumer (a toaster control app).
For a detailed walkthrough of how to create an AllJoyn consumer UWP application, please watch the AllJoyn session 623 from //build 2015:
"AllJoyn: Building Windows apps that discover, connect and interact with other devices and cloud services using AllJoyn".
We have also provided all of the code and tools that you will need to walkthrough the toaster UWP app development exercise demonstrated at //build and in this post:
In addition, here are some resources that will help you get up to speed with AllJoyn an AllJoyn support in Windows 10:
- Using the AllJoyn Visual Studio Extension for Windows 10
- AllSeen Alliance: http://allseenalliance.org
- Windows 10 IoT: http://windowsondevices.com
- MSDN documentation for Windows 10 AllJoyn