Step-By-Step: Building AllJoyn Universal Windows Apps for Windows 10 Public Preview

Sign in to queue

Description

*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:

AllJoyn: Building Universal Windows Apps that Discover, Connect, and Interact with Other Devices and Cloud Services Using AllJoyn

Understanding AllJoyn UWP App Development

Building apps for Windows 10 using UWP AllJoyn APIs involves three categories of code:

  1. The app code that you write in your UWP Windows app
  2. The AllJoyn core APIs: AllJoyn Standard Client API (C) and Windows.Devices.AllJoyn API (UWP)
  3. 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:

Generic Episode Image

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)

  1. Prepare your build environment  (Windows 10, Visual Studio 2015, and related tools)
  2. Determine which AllJoyn interfaces will be used, obtain or create necessary introspection XML (For more information on Introspection XML, see the D-Bus specification)
  3. Create your Visual Studio Solution and UWP app project
  4. Generate code from AllJoyn introspection XML
  5. Create UWP Windows Runtime Component projects for generated code files
  6. Adjust project settings and manage dependencies
  7. 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:

  1. Obtain the introspection XML from documentation, example: Lighting Service Framework (LSF) documentation from AllSeen
  2. Extract introspection XML from AllJoyn devices present on your network at runtime
  3. 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.

Generic Episode Image
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

Manufacturer: Microsoft

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:

Generic Episode Image

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:

  1. Build the UWP component project.
  2. Remove any files that are a part of the new project, but leave pch.cpp and pch.h as a part of the project.
  3. 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...".
  4. Open the file "pch.h" and find the root namespace defined there. For the toaster example, the root namespace declaration is:
    1. #define PROJECT_NAMESPACE com::microsoft::sample
  5. 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".
  6. 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:

  1. Select "All Platforms" and "All Configurations" in project properties
  2. Add the AllJoyn API library (MSAJAPI.lib) to the linker dependencies. (Right Click on Project -> Properties -> Linker -> Input -> Additional Dependencies)
  3. Make sure that calling convention is set to __stdcall (Properties -> C/C++ -> Advanced -> Calling Convention)
  4. QCC_OS_GROUP_WINDOWS needs to be added to the Preproccessor Definitions of each C++ Windows Runtime Component. (Properties -> C/C++ -> Preprocessor -> Preprocessor Definitions)
  5. 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.
    1. Example: -Zm160 (check build output for specific value recommended)

In the UWP app project, make the following updates/changes:

  1. Add a reference and build dependency from your UWP app project to your UWP Windows Runtime Component project
  2. Under your package manifest for your app (Package.appmanifest.xml), you will need to add the "allJoyn" capability under the <Capabilities> element:
    1. <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:

Git Repo: AllJoyn Toaster Producer and Consumer Sample for Windows 10 Public Preview

In addition, here are some resources  that will help you get up to speed with AllJoyn an AllJoyn support in Windows 10:

Thanks,
Gavin

Tag:

Windows 10

The Discussion

  • User profile image
    ken

    Great stuff, but where can I get the getajxml.exe application?

  • User profile image
    GavinGear

    Ken- the getajxml.exe tool is now included in the Git Repo that we linked to. Let us know if you have any issues with it.

  • User profile image
    ppatierno

    Hi Gavin,

    I'm creating a simple AllJoyn Led for excersing and I change a little the commands sequence you provided.

    I didn't delete pch.cpp and pch.h from created runtime component but override them with the auto generated version (I saw in your toaster example that you have autogenerated pch.h and pch.cpp in the runtime project). However, if you try to compile ... it fails of course, becase it doesn't have all dependencies needed from step "Editing Project Settings and Dependencies".

    My advice is to change in the following way :

    override pch.h and pch.cpp with autogenerated

    before trying to compile, the user can execute "Editing Project Settings and Dependencies" and then the build will work fine.

    Does it make sense for you ?

    Paolo

  • User profile image
    GavinGear

    Thanks Paolo- my directions could have been more clear. I meant "leave the project references to pch.h and pch.cpp", but didn't directly state to overwrite the actual files with the generated ones. I've simplified the instructions now. Yes, you do want the pch.h and pch.cpp that are generated by the AllJoyn code generator.

  • User profile image
    ppatierno

    It seems that a first compilation before copying all generated files is needed because I receive error regarding missing precompiled header pch.pch (in the Debug folder).

    If I compile the runtime component just created before replacing all generated files, it works.

    Another point ...

    In general, when you don't have a capability in the package manifest file but use it at runtime, an exception is raised. In my example application, I forgot to set the AllJoyn capability in the consumer app but no exception is raised. The only result is that the added watcher event isn't called.

    Paolo.

  • User profile image
    GavinGear

    Thanks Paolo! We are fixing the exception issue, and I updated the steps to start with a build of the UWP component project before modifying it.

  • User profile image
    ppatierno

    There is another main step that drove me crazy !

    To use toaster on the Raspberry Pi 2, it's needed to disable the firewall on the board with :

    netsh advfirewall set allprofiles state off

    It's documented in the ZWave DSB guide. I didn't read the guide because I didn't need to implement a DSB bridge so I lost this mandatory step.

    However, I think that it could be better to open only AllJoyn ports and not disable the firewall.

    Paolo

  • User profile image
    Joe

    I can't seem to get getajxml.exe to run on Windows 10 preview..I get the following message:

    This version of C:\temp\getajxml.exe is not compatible with the version of Windows you're running. Check your computer's system information and then contact the software publisher.

    Any Ideas?

    I'm attempting to use this instead of alljoyn explorer due to issues I am encountering. Alljoyn explorer is showing two different bus objects having identical interfaces (com.microsoft.zwaveadapter.xxxx.interface_1). They therefore generate identical introspection XML. When connecting via my UWP app it is connecting to the wrong bus. I can't seem to figure out how to differentiate between the two. I'm hoping to see different XML generated by the getajxml tool.

  • User profile image
    Chihfan Hsin

    I think that there may be an issue with current getajxml.exe and alljoyncodegen.exe, when there are interfaces with the same name under 2 different object paths.
    My scenario is to write a Win UWP AllJoyn Client app that controls Aeon Lab Smart Switch via Device System Bridge. The Aeon Lab Smart Switch is used as a demo/sample codes for Device System Bridge.
    The main control interface is "com.microsoft.ZWaveAdapter.HomeID25504235Node2.interface_1". However, both /Switch object path and /Enable_Wattage_Reports object path have the same interface.

    Issue 1: When I use "getajxml.exe" to generate the introspection xml, the "node" does not specify which object path to use. Therefore, I got the same xaml for 2 different object paths.
    Issue 2: Even when I manually add name="/Switch" to node and use "alljoyncodegen.exe", the resulting codes generated (I believe) do not consider the object path.
    In auto generated AllJoynHelpers::GetObjectPath(), it only returns the first object path for that interface name. Therefore, I alwasy got /Enable_Wattage_Reports object path, not the intended /Switch object path.

    Can some one shed some light about these issues?

    Thanks,
    Chih-fan Hsin.

  • User profile image
    Joe

    Chihfan,

    I am running into the exact same issue and have not been able to work around it. Please keep me updated if you find a solution.

    Thanks!
    Joe

  • User profile image
    Chihfan Hsin

    Joe,
    To workaround this issue, I modified the auto-generated codes at AllJoynHelpers::GetObjectPath(). You need to return multiple object paths that have the same interfaces. Then you need to loop through them, and get the object path you want, and return that object path.

    Currently, the auto-generated codes only return the 1st object path with a matching interface. I also reported this issue at https://github.com/MS-brock/AllJoynToasterDemo/issues/1 .
    Chih-fan

Add Your 2 Cents