Following on from my previous post;
What I’d done in that previous post was to make a desktop application that really didn’t “do anything” and so it was fairly easy for me to create a .APPX package from the .EXE that it consisted of and deploy and run it.
That desktop application doesn’t depend on any specific file locations or any particular registry key and so it’s going to run ok both in a ‘regular desktop’ context and in a ‘UWP’ context.
As another, more realistic experiment, I wanted to take more of a real desktop application and see what it’s like to try and package that up into the .APPX format.
I used to build desktop applications for a living but I don’t any more and so I don’t have the source for a reasonably sized desktop application kicking around and so I had to be a little imaginative and have a think about where I might borrow a desktop application from.
Given that I use Live Writer to write my blog posts, my imagination didn’t have to wander too far to come up with the idea of using;
and so off I went to Github and cloned that repository and opened it up inside of Visual Studio “15” preview before making sure that I could actually build it and run/debug it as a regular-desktop-app which was fairly easy.
There’s a few projects in here;
and having built and run it, I then wanted to try and understand how Open Live Writer built up an installer for itself which it seems to drop out into this folder as part of the build process;
and I could see that there was the PostBuild.CreateInstaller project which has a post-build step to run a createinstaller.cmd file and the contents of that .cmd file are on the web here.
That .cmd file seems to use nuget.exe to pack a bunch of files listed in OpenLiveWriter.nuspec from the build output folder into a NuGet package.
It then uses squirrel to take that NuGet package and build the OpenLiveWriterSetup.exe from it that’s in the screenshot above.
It then wraps that up into a chocolatey package (I think ).
With those pieces, there are two (or more) ways that I could go to package this into a .APPX install.
- Run the Setup.exe into the desktop app converter and collect the output as per my first blog post.
- Add something to the build process to make a .APPX in the first place as per my second blog post.
Either way, I figured that I’d be needing a certificate so I started there.
Step 1 – Making Certificates
From my prior experiments, I know that I’m going to need a signing certificate and so I made one with;
MakeCert.exe -r -h 0 -n “CN=Open Live Writer” -eku 126.96.36.199.188.8.131.52.3 -pe -sv my.pvk my.cer
pvk2pfx.exe -pvk my.pvk -spc my.cer -pfx my.pfx
and I then installed the certificate into my local machine’s trusted roots certificate store.
I also dropped the various pieces I’d used in a top-level Certificates folder within the Open Live Writer folder structure so that I knew where to find them again.
Experiment 1 – Using the Desktop Converter
I took the OpenLiveWriterSetup.exe file that the build process emits and I ran it through the DesktopAppConverter.ps1 script with the command line below;
.\DesktopAppConverter\DesktopAppConverter.ps1 -Installer .\apps\OpenLiveWriterSetup.exe -Version 184.108.40.206 -MakeAppx -Destination .\OpenLiveWriterOut -Publisher “CN=Open Live Writer” -PackageName “OpenLiveWriter” -Log out.txt
but I found that it seemed to run for a very long time and checking of the log file revealed that it was always waiting for the installation to complete and that never seemed to happen.
I wasn’t sure what the installer might be doing but one guess was that it might be related to the installer running the app at the end of the installation and so appearing to never end.
To see if I could mitigate that, I tried to use the “–silent” flag and in an interactive context that seemed to work (i.e. installation without app launch) but when I tagged it on to the desktop conversion process;
.\DesktopAppConverter\DesktopAppConverter.ps1 -Installer .\Apps\OpenLiveWriterSetup.exe -Version 220.127.116.11 -MakeAppx -Destination .\OpenLiveWriterOut\ -Publisher “CN=Open Live Writer” -PackageName “OpenLiveWriter” -InstallerArguments “–silent”
I found that the tool would still sit there for a long time and a check of the log file revealed the last entry was always;
“Waiting for the installer process to complete inside Isolated Environment”
and it was tricky to know what was happening inside of that environment – was the installer trying to do something like install an earlier version of .NET? Did it relate to the installation targeting the user’s local folder rather than a central location? Was the installer showing a dialog or similar?
It’s possible that I’m just missing something around this particular type of installation but, so far, I haven’t managed to get this to work.
I moved on to the other approach.
Experiment 2 – Altering the Build Script
I wondered if I could alter the build script that the Open Live Writer guys have built in order to package the app ‘automatically’ into a .APPX format as part of the build rather than taking the Setup.exe from the build and trying to record its output with the desktop converter tool.
I made a manifest in line with my previous post, changing a few names to ‘Open Live Writer’ where appropriate.
I’ve copied it below for completeness;
<?xml version="1.0" encoding="utf-8" ?> <Package xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10" xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"> <Identity Name="c2030cf7-74d5-479f-aa19-f907e4145698" ProcessorArchitecture="x64" Publisher="CN=Open Live Writer" Version="18.104.22.168" /> <Properties> <DisplayName>Open Live Writer</DisplayName> <PublisherDisplayName>Open Live Writer</PublisherDisplayName> <Description>Open source version of the classic Live Writer blogging application</Description> <Logo>assets\StoreLogo.png</Logo> </Properties> <Resources> <Resource Language="en-us" /> </Resources> <Dependencies> <TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.14316.0" MaxVersionTested="10.0.14316.0" /> </Dependencies> <Capabilities> <rescap:Capability Name="runFullTrust"/> </Capabilities> <Applications> <Application Id="OpenLiveWriter" Executable="OpenLiveWriter.exe" EntryPoint="Windows.FullTrustApplication"> <uap:VisualElements BackgroundColor="#464646" DisplayName="Open Live Writer" Square150x150Logo="assets\Square150x150Logo.png" Square44x44Logo="assets\Square44x44Logo.png" Description="Open Live Writer Blogging App" /> </Application> </Applications> </Package>
and I made logos at size 50×50, 150×50 and 44×44 based on the image that I found in OpenLiveWriter.CoreServices\Images\SplashScreenLogo.jpg although I suspect there are better logos I could have chosen here.
I added a top level folder named AppxArtefacts to hold my assets and appxmanifest.xml;
and I added the certificate pieces into a top level folder named Certificates although I really only need the .pfx file to sign the .appx as part of the build script.
I then set about seeing if I could alter the script which creates the installer.
Hacking the Build Script
I’m no expert on anything and especially not on NuGet and I’m even more clueless when it comes to Squirrel so I tried to add something into the build script that wouldn’t destroy what was already there and just move a few things around rather than dramatically change anything.
With that in mind, I added these lines to the script in between the piece which makes the NuGet package and the piece which runs Squirrel.exe on it.
:: mtaulty1 - unpack that nuget package into a folder named UnpackedNuget "%LocalAppData%\Nuget\Nuget.exe" install -ExcludeVersion OpenLiveWriter -Source %cd% -OutputDirectory UnpackedNuget ECHO Unpacked that package. :: mtaulty2 - copy the AppxArtefacts and that unpacked content into a folder named AppxContents :: hard-coding the lib\net451 pieces here isn't great. mkdir AppxContents xcopy /s "AppxArtefacts\*.*" .\AppxContents xcopy /s "UnpackedNuget\OpenLiveWriter\lib\net451\*.*" .\AppxContents :: mtaulty3 - make an appx package out of that. Hard-coding the location of the tool here isn't great. "c:\program files (x86)\Windows Kits\10\bin\x86\makeappx.exe" pack /d AppxContents /p OpenLiveWriter.appx :: mtaulty4 - sign that appx package "c:\program files (x86)\Windows Kits\10\bin\x86\signtool.exe" sign -f Certificates\my.pfx -fd SHA256 -v OpenLiveWriter.appx :: mtaulty5 - tidy up rmdir /s /q AppxContents rmdir /s /q UnpackedNuget
The attempt here is to make a .APPX file out of the pieces that are in the AppxArtefacts folder that I’ve already pre-populated mixed with the contents of the build outputs that have just been added into the NuGet package by the existing script.
Sure enough, out of this drops a .APPX file and that file install the app just fine.
Trying it Out
The app that’s installed by this process runs ‘just fine’ but it’s not entirely surprising that it then hits upon a bit of a snag…
When installed through its regular installer, this app would end up in the equivalent of c:\users\mtaulty\appdata\local\OpenLiveWriter\app-0.6.0 and when it runs up for the first time within that folder it has the permission to create a folder named plugins if it wants to.
When packaged as a .APPX, the application doesn’t have the permission to create that Plugins folder and hence it fails at startup when it tries to do it.
I wondered why the code would think it was ok to create a ‘Plugins’ folder within its own installation folder and so I dug in and saw that the code in PostEditorPluginManager.cs seems to only attempt to create this folder in the DEBUG build of the app and so maybe this is more of a developer convenience than anything else.
Repackaging the Release Code, not the Debug Code
With that in mind, I went and built the released version and tried running that up instead and that seemed to work out pretty well in the sense that it looks like I can get Open Live Writer installed and running from that .APPX package. Whether all of the functionality then works, I’m not so sure but I tried a few dialogs and it all seemed to be hanging together and so I have 2 Open Live Writers on my Start Menu;
and the ‘Windows App’ launches and does the right thing.
It’s important to say that this is (clearly) just an experiment and I didn’t worry about making the app target .NET 4.6.x and I didn’t overly worry about 32-bit/64-bit or anything like that.
I also didn’t spend too much time concerning myself over whether the app ere does/doesn’t use squirrel to do some level of automatic updating because that could clearly perhaps clash with the app having been installed via .APPX and you perhaps don’t need both the Windows Store and Squirrel both trying to keep the app automatically up to date at the same time
So, to do this properly would require more thought but I wanted to experiment with it and hence the write up here and, of course, if you know why the converter tool can’t get beyond the “waiting for the installer to finish” stage then do leave me a comment and let me know.