How-to trigger a desktop process from sideloaded Windows Store Apps with Brokered Components

Update again: (May 30th)

Check out this post before you continue reading!

https://blogs.msdn.com/b/dmx/archive/2014/04/30/how-to-trigger-a-desktop-process-from-windows-store-apps-the-easy-way-using-the-brand-new-visual-studio-templates.aspx

Update! (May 25th, 12:27)
In the meantime the templates have been released. This should make the process very comfortable. Be sure to check them out first!!! (Thanks, Erik!)

https://visualstudiogallery.msdn.microsoft.com/527286e4-b06a-4234-adde-d313c9c3c23e

This is a lengthy post in English. I decided to do it in Englisch because there are no step-by-step tutorials yet out there. Harry Pierson – who demonstrated the brokered components at //build provided some samples in the sample. I took them and re-engineered them to get my stuff done. Here’s my step-by-step tutorial to get a Windows Store App to trigger the command line.

Harry also promised to make available the Project templates for Visual Studio soon. This will make the work much more comfortable. Unfortunately, I couldn’t wait because I really think this is very cool.  So – have fun!

Preparation

1. Create a Visual Studio 2013 Solution starting with a Windows Store App in C#.
Use the template “Blank App C#. Call the App project “MyApp”.

2. Create another project within this solution.
Use the “Windows Runtime Component (Windows) C#“project template. Call this project “WindowsRuntimeComponentBroker”. This project will be able to do some calls to the full .NET Framework as soon as we did some additional work.

3. Create another project within this solution.
Use the “Win32 C++” project template. In the wizard select “empty project” and “DLL”. Call this project “WindowsRuntimeComponentBrokerProxy”. This project will provide a proxy for the inter process communication (IPC).

4. Create another project within this solution.
Use the “Class Library C#” project template. Call this project “ClassicClassLibrary”. This project will serve as sample for existing projects you already might have from your development in the past. This is a classic .NET 4.5 project. You will be able to call it from MyApp after we’re done.

5. Your Solution should look like this:

clip_image001

The brokered component

6. In the first run, we will just make a call to the broker. Later we will also call the ClassicLib. The logical sequence of calls at runtime will look like this:

MyApp—>Proxy—>Broker—>ClassicLib

7. So let’s start with adding some logic to the Broker. To see the full power of Windows what could be a better sample than calling the commandline? Let’s do this!

8. Rename Class1 to BrokerClass in the Broker project.

9. Add a public method in BrokerClass that calls the commandline.

 public int CallCmdFromBroker() 
          { 
             System.Diagnostics.Process proc = new System.Diagnostics.Process(); 
             var cmd = "xcopy"; 
             System.Diagnostics.Process.Start("CMD.exe", cmd); 
             proc.Close(); 
             return 42; 
          } 

10. System.Diagnostics.Proccess will probably not be found. We have to edit the project file a little to make this work.

11. Edit the Broker project file. You can do this by right-click on the Broker project in Solution explorer and by unloading it. Afterwards right-click it again and select edit. You will see pretty much xml.

12. Under the <ProjectTypeGuids> line create a new entry.

       <ImplicitlyExpandTargetFramework>false</ImplicitlyExpandTargetFramework> 
  

13. Create the following Item Group to add a bunch of references to DLLs. Why these? Well – I took them from the sample of Harry Pierson who showed brokered components at /Build 2014.

 

<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5.1\mscorlib.dll" /> <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5.1\System.ComponentModel.Composition.dll" /> <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5.1\System.Configuration.dll" /> <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5.1\System.Core.dll" /> <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5.1\System.dll" /> <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5.1\Facades\System.Threading.Tasks.dll" /> <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5.1\Facades\System.Runtime.dll" /> <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5.1\Facades\System.Runtime.InteropServices.WindowsRuntime.dll" /> <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5.1\System.Xml.dll" /> <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5.1\System.Data.dll" /> <ReferencePath Include="C:\Program Files (x86)\Windows Kits\8.1\References\CommonConfiguration\Neutral\Windows.winmd" /> <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETCore\v4.5.1\System.Runtime.WindowsRuntime.dll" />

14. Reload the project in Solution explorer.

15. Build the project. It should build now without errors.

16. We have to specify an Interface for our BrokerClass. Rightclick “BrokerClass” in code and press Ctrl+R,Ctrl+I. This will automatically generate IBrokerClass.cs for you. Make this Interface public. The content of IBrokerClass.cs should look pretty much like this:

 namespace WindowsRuntimeComponentBroker
  { 
     public interface IBrokerClass
      { 
         int CallCmdFromBroker(); 
      } 
  } 
  
 17. Derive BrokerClass from IBrokerClass if you created the interface manually.

18. Open the project properties of the Broker project and edit the post build events. (I also took these from Harry Piersons sample.) (Hint: You can resize the Post-Build-Event Command Line Window.) Add the following steps:

call "$(DevEnvDir)..\..\vc\vcvarsall.bat" x86

md "$(TargetDir)"\impl

md "$(TargetDir)"\reference

erase "$(TargetDir)\impl\*.winmd"

erase "$(TargetDir)\impl\*.pdb"

xcopy /y "$(TargetPath)" "$(TargetDir)impl"

xcopy /y "$(TargetDir)*.pdb" "$(TargetDir)impl"

winmdidl /nosystemdeclares /metadata_dir:C:\Windows\System32\Winmetadata "$(TargetPath)"

midl /metadata_dir "%WindowsSdkDir%References\CommonConfiguration\Neutral" /iid "$(SolutionDir)WindowsRuntimeComponentBrokerProxy\$(TargetName)_i.c" /env win32 /x86 /h "$(SolutionDir)WindowsRuntimeComponentBrokerProxy\$(TargetName).h" /winmd "$(TargetName).winmd" /W1 /char signed /nologo /winrt /dlldata "$(SolutionDir)WindowsRuntimeComponentBrokerProxy\dlldata.c" /proxy "$(SolutionDir)WindowsRuntimeComponentBrokerProxy\$(TargetName)_p.c" "$(TargetName).idl"

mdmerge -n 1 -i "$(ProjectDir)bin\$(PlatformName)\$(ConfigurationName)" -o "$(TargetDir)reference" -metadata_dir "%WindowsSdkDir%References\CommonConfiguration\Neutral" -partial

The Proxy

19. Now let’s take a look at the Proxy project. Delete Header, Resource and Source folder of the Proxy project.

20. Build the Broker project. This will generate a bunch of new files in the filesystem folder of the Proxy project.

21. Right-click the Proxy project and click “Add existing item”.

22. Choose “dlldata.c”, WindowsRuntimeComponentBroker.h, WindowsRuntimeComponentBroker_i.c and WindowsRuntimeComponentBroker_p.c. If they are not there, build the broker project.

23. Create a new file in the Proxy project called WindowsRuntimeComponentBrokerProxy.def. You can simply add a new text file and then rename it.

24. Add the following lines in the file:

 LIBRARY WindowsRuntimeComponentBrokerProxy.dll 
 EXPORTS
     DllCanUnloadNow PRIVATE
     DllGetClassObject PRIVATE
     DllRegisterServer PRIVATE
     DllUnregisterServer PRIVATE
  

25. Edit the Proxy project file. Add “REGISTER_PROXY_DLL;” in line <PreprocessorDefinitions>

26. Add the following block in the <link>…</link> section.

<ModuleDefinitionFile>WindowsRuntimeComponentBrokerProxy.def</ModuleDefinitionFile>

  <AdditionalDependencies>rpcrt4.lib;runtimeobject.lib;%(AdditionalDependencies)</AdditionalDependencies> 
  <GenerateWindowsMetadata>false</GenerateWindowsMetadata> 
  

27. Your proxy should be able to build now. You’re done with the proxy.



The app

28. Now let’s reference the Brokered Component from the app.

29. Click Add reference. Then do NOT reference the project itself, but the reference winmd file of the broker. Use the browse button in the references dialog to navigate there. It should be in the … WindowsRuntimeComponentBroker\bin\x86\Debug\reference folder, called WindowsRuntimeComponentBroker.winmd. Do NOT use the implementation winmd file!

30. Open MainPage.xaml.cs and add a method, that calls the broker after the InitializeComponents call. Hint: We don’t use the interface here! But we needed to specify the interface to make sure the IPC will work at runtime! Don’t get confused! J

clip_image003

31. So Intellisense already works – very nice. Now let’s make sure that during runtime everything will work, too. Therefore open the app manifest. Right click it and select “View Code”.

32. Add the following lines:

  <Extensions> 
      <Extension Category="windows.activatableClass.inProcessServer"> 
        <InProcessServer> 
          <Path>clrhost.dll</Path> 
          <ActivatableClass ActivatableClassId="WindowsRuntimeComponentBroker.BrokerClass" ThreadingModel="both"> 
            <ActivatableClassAttribute Name="DesktopApplicationPath" Type="string" Value="c:\brokerfolder" /> 
          </ActivatableClass> 
        </InProcessServer> 
      </Extension> 
    </Extensions> 

33. Notice two things. First: Specify the fully qualified class name of the class you want to call from the app. Second: specify the folder where you put your dlls! The other entries are standard. Don’t change them.

Run it

34. So far everything should build fine. Try it! If there are build errors, make sure you didn’t miss a thing.

35. Create c:\brokerfolder.

36. Copy the implementation winmd file of the broker component into that folder. You can find it here: [SolutionFolder]\WindowsRuntimeComponentBroker\bin\x86\Debug\imp\WindowsRuntimeComponentBroker.winmd

37. Copy the Proxy dll into that folder. You can find it in here [SolutionFolder]\Debug\WindowsRuntimeComponentBrokerProxy.dll

38. Register the Proxy.dll by running the following command:

regsvr32 "C:\brokerfolder\WindowsRuntimeComponentBrokerProxy.dll" /s

39. Run the following command from within the folder:

icacls $path /T /grant "ALL APPLICATION PACKAGES:RX"

40. Start the app and click the button. If everything went fine, the command line will open up. Awesome.

The classic library

41. So far, so good. But I want to use existing code and want to call an existing (.Net 4.5) library. Let’s do this.

42. Rename class1 in ClassicClassLibrary into ClassicClass.

43. Add a public method in it called RunCmdFromClassic and add the code to open the command line we already used before.

44. Add a reference to the ClassicClassLibrary to the Broker project. You can’t do this via UI. Open the project file and add the following lines.

  <ItemGroup> 
      <ProjectReference Include="..\ClassicClassLibrary\ClassicClassLibrary.csproj"> 
        <Project>{XXXXXXXXXXXXXXXXXXXX}</Project> 
        <Name>ClassicClassLibrary</Name> 
      </ProjectReference> 
    </ItemGroup> 

45. Make sure you specify the right project guid. You can find it in the project file of your ClassicClassLibrary project.

46. Modify the BorkerClass. Add another Method “CallFromClassic” and specify it in the interface.

This should look like this:

clip_image004clip_image005

47. Add another button in the App and wire it up to call the broker component with the CallFromClassic method.

48. Redeploy all files as described in steps 36 - 39!

49. If you can’t overwrite the files someone has still a hand on them. Kill them using Process Explorer.

50. Also deploy ClassicClassLibrary.dll into the same folder!

51. Run the app. You can click each button. Everytime CMD starts. How cool is that?

52. Doesn’t work? Make sure you ran regsvr32 again. Make sure you ran icacls again. (steps 38/39)

Thanks to the guys who wrote these articles:

https://msdn.microsoft.com/en-us/library/windows/apps/dn630195.aspx

https://code.msdn.microsoft.com/windowsapps/Brokered-Windows-Runtime-9d64cada

https://blogs.msdn.com/b/wsdevsol/archive/2014/04/14/cheat-sheet-for-using-brokered-windows-runtime-components-for-side-loaded-windows-store-apps.aspx