Wrote my first code project article in quite sometime about something I’ve been curious about related to COVID. Glad to see code project is still around.
No windows?!?!
Having just installed Pi-Hole, I made an interesting observation as I analysed what is running on my home network… Ever since late 2016 I’ve been moving to linux or apple OS’s. Now I don’t have a single windows machine. With the exception of the XBox One, everything is linux, or android, MacOS or iOS. For someone who’s entire career has been spent writing software on and for the windows operating system it feels quite weird.
And perhaps the stranger thing is that I don’t think this bodes at all ill for Microsoft. Microsoft, by my estimation, has moved away from the success of Windows being the same as the success of the company.
I still miss my Windows phone though…
If you’re looking for an inexpensive 2:1 to run Linux I would highly recommend the Yoga 710, 11.6″. I found an open box deal from BestBuy at $350 and eBay has plenty of them running form $300-400. For that price you get a solidly built fanless 2:1 laptop, with 4 cores, 4GB Ram and 128GB SSD.
If you go the Ubuntu route like me, don’t waste your time trying to install 16.10. According to the interwebs it’s possible but I didn’t have any luck. 17.04 however, installed without a hitch. I replaced the pre-installed Windows 10 image and now have nicely portable (2.3 lbs) laptop to cart around the house and yard for basic computing and light development.
One hint though: learn about the Novo Button before starting any OS modification. As far as I can tell easy access to the BIOS assumes restarting from that Windows 10 option. No combination of ALT, DEL or function keys will trigger the BIOS at boot. On the 710 the NOVO button is paper clip actuated and sits between the power and HDMI slot on the right side of the chassis. This seems to be a Lenovo thing, that’s not easily discoverable, but pretty handy once you realize it’s there.
DynamicRestProxy Documentation
Just published some documentation for DynamicRestProxy:
https://dkackman.github.io/DynamicRestProxy/
As of right now still a work in process but hopefully helps those using this library.
I’ve got a handful of Ubuntu VPS’s on DigitalOcean. This is all part of my effort to teach myself how to admin and eventually develop for that OS. So far I’ve got a WordPress site (this one), a node box and an ELK box to monitor them.
When I’m working at home in my office I’m running Windows 10. When I’m camped in front of the TV with my wife, I’m on a Chromebook with Crouton and Ubuntu. The first thing I notice is that the workflow between the two is quite different. Putty and FileZilla on the one, straight Bash on the other.
I’m not ready (nor will I likely ever be) ready to switch to Linux for everything so I’m going to try to get the to environments to feel the same.
If you’re a Windows guy like me, but interacting with Linux machines, you probably started with PUTTY to generate ssh keys and are using it for secure shell. Another option is now Bash on Ubuntu for Windows (aka the Windows Subsystem for Linux), which I’ve just started to play with.
The nice thing about it is that it’s, well…, Linux. Everything (I’m sure not everything but you get the point) just works the same. No need to SSH to a remote machine just to start running some Bash scripts. No PAgent. No PUTTY. Just pop open Bash right on your Windows box and away you go.
Converting and Sharing PuttyGen SSH Keys with the Linux Environment
Since I’ve already got a private key for my Windows box, and don’t really want a new one for the Linux environment, it’s also possible to share the same key between environments.
A couple of stackexchange posts help immensely there. I want to keep my keys all in one spot, so directions on how to convert a PuttyGen key and share them with the Ubuntu environment made that a snap.
- Open your private key with PuttyGen
- Export it to a file named
id_rsa
in the same location as theppk
file. (Conversions->Export OpenSSH
) - From Bash on Ubuntu for Windows execute the following (assuming that your private key is in
.ssh
in the root user location on Windows):
ssh-keygen -e -f /mnt/c/Users/UserName/.ssh/id_rsa > /mnt/c/Users/UserName/.ssh/id_rsa_com.pub ssh-keygen -i -f /mnt/c/Users/UserName/.ssh/id_rsa_com.pub > /mnt/c/Users/UserName/.ssh/id_rsa.pub ln -s /mnt/c/Users/UserName/.ssh/id_rsa ~/.ssh/id_rsa ln -s /mnt/c/Users/UserName/.ssh/id_rsa.pub ~/.ssh/id_rsa.pub chmod 600 ~/.ssh/id_rsa |
This will convert the PuttyGen key to OpenSSH format and link it from the Windows file system to the Linux home location.
Now that you’ve defined how your package will be structured, you need to build the AppX Package. Before getting to that though there are some things you’ll need…
Prerequisites
- Windows 10 Anniversary update or later. I assume because the anniversary update include the infrastructure to run a Win32 app in a UWP container.
- Windows 10 SDK. You’ll need this for the tools that will be covered below.
- A code signing certificate. If you or your organization already have one you’re good to go. If not, create a self signing certificate for yourself.
- Visual Studio 2015 Update 3. Visual Studio 2017 works too. We’ll use that in a later article for debugging the AppX (Right now it is still a Release Candidate so we’ll stick with 2015)
- The complete example project is on GitHub.
Setup Visual Studio
We’re going to use build events in VS.NET to build the AppX. This is nice and easy. If you use MSBuild or some other build toolchain the same concepts apply.
Since we are going to use a couple of tools form the Windows SDK, we need to specify its location for the build event scripts. Open your csproj file in a text editor and add this declaration:
<PropertyGroup> <Win10SDKDir Condition=" '$(Win10SDKDir)' == '' ">C:\Program Files (x86)\Windows Kits\10\bin\x64\</Win10SDKDir> </PropertyGroup> |
Build Event Scripts
The simple package build approach we’ll take looks like this:
- After the build, copy all of the files that go into the package to a working folder named (appropriately enough) “AppX”.
- Use MakeAppX.exe to package the contents of that folder into a package file.
- Sign the package using signtool.exe.
- Use Powershell to install our package
Pre-build
Since we’ll rebuild the AppX package each time make sure we cleanup previous outputs at the start of a new build. All paths are relative to the $(TargetDir)
location.
:: clean any previous package outputs rmdir AppX /s /q del $(TargetName).appx /q /f
Post-build
Let’s walk through the four phases of the build script and then put it all together in a single script at the end.
Collect the Package Contents
:: create the working folder for packaging mkdir AppX :: copy output, dependencies, and content into working a folder xcopy "$(TargetPath)" AppX\ /R /Y xcopy "$(TargetPath).config" AppX\ /R /Y xcopy "$(TargetDir)Microsoft.HockeyApp.*.dll" AppX\ /R /Y xcopy "$(SolutionDir)appxmanifest.xml" AppX\ /R /Y xcopy "$(SolutionDir)*.png" AppX\ /R /Y
Since our example is pretty simple we’re just dumping everything in the folder root. Be sure to get everything your app needs into the working folder:
- Build outputs:
xcopy "$(TargetPath)"
- Runtime configuration or data files:
xcopy "$(TargetPath).config"
- Binary dependencies:
xcopy "$(TargetDir)Microsoft.HockeyApp.*.dll"
- The AppXManifest (this needs to be in the root):
xcopy "$(SolutionDir)appxmanifest.xml"
- Content and other assets:
xcopy "$(SolutionDir)*.png"
I’ve got the AppXManifest
and images in the solution directory so modify those locations as appropriate.
Build and Sign the Package
Next we’re going to use the Windows 10 SDK to make the package and get it ready for installation.
MakeAppX.exe is the sdk tool the generates the package file.
"$(Win10SDKDir)MakeAppX.exe" pack /d AppX /p "$(TargetName).appx"
- The
pack
command tells it to create the package /d
specifies the working folder to pack/p
is the package file name
This will create the package file in the build out directory $(TargetDir)
. Next we’ll sign the package using SignTool.exe. In this example case I’ve got a signing certificate named tempcastore.pfx
, in the solution folder.
"$(Win10SDKDir)SignTool.exe" sign -f "$(SolutionDir)tempcastore.pfx" -fd SHA256 -p YOUR_PFX_PASSWORD -v .\$(TargetName).appx
- The
sign
command tell it to the sign the input file - -f is the path to the signing certificate
- -fd SHA256 tells it to use SHA256 for the digest algorithm
- -p is the password for your pfx file
- -v is the path to the file to sign
The result is a signed AppX package that we can install and run!
Install the Package
Because the Add-AppXPackage
cmdlet won’t install a package with the same version on top of itself doing this in script takes a little finagling. The version Add-AppXPackage
is concerned with is in the AppXManifest
as an attribute on the Identity
element. If you always update that version there’s no need to remove any previous packages. This isn’t convenient when working in the IDE so we’ll remove any previously installed packages in our build script.
powershell if ((Get-AppxPackage -Name '3652dkackman.FishyFishyFish').count -gt 0) { Remove-AppxPackage (Get-AppxPackage -Name '3652dkackman.FishyFishyFish').PackageFullName } powershell Add-AppxPackage $(TargetName).appx
The first line invokes a powershell command that first checks if the package is installed and removes it if it is. The argument to both Get-AppxPackage and Remove-AppxPackage is the Identity.Name
from your AppXManifest.
The second line uses Add-AppxPackage to install the package we just built. If everything worked out right, the package should now be available on your start menu.
Putting it All Together
The complete Post-build script should look like this:
:: create the working folder for packaging mkdir AppX :: copy build output, dependencies, and content into the working folder xcopy "$(TargetPath)" AppX\ /R /Y xcopy "$(TargetPath).config" AppX\ /R /Y xcopy "$(TargetDir)Microsoft.HockeyApp.*.dll" AppX\ /R /Y xcopy "$(SolutionDir)appxmanifest.xml" AppX\ /R /Y xcopy "$(SolutionDir)*.png" AppX\ /R /Y :: build and sign the AppX package "$(Win10SDKDir)MakeAppX.exe" pack /d AppX /p "$(TargetName).appx" "$(Win10SDKDir)SignTool.exe" sign -f "$(SolutionDir)tempcastore.pfx" -fd SHA256 -p YOUR_PFX_PASSWORD -v .\$(TargetName).appx :: install it powershell if ((Get-AppxPackage -Name '3652dkackman.FishyFishyFish').count -gt 0) { Remove-AppxPackage (Get-AppxPackage -Name '3652dkackman.FishyFishyFish').PackageFullName } powershell Add-AppxPackage $(TargetName).appx
Now every time you change and build your code in the IDE it will be installed as a UWP app. F5 debugging will still start the normal build output not the AppX.
Debugging the AppX from the IDE will be our next step.
Start with the Documentation
The Desktop Bridge documentation has gotten better and better since the released the first preview. They have lot’s good articles, GitHub samples, snippets and guidance. I’ll try to cover some specifics and tie things together based on my experience. After you’ve brushed up on the documentation the next step is to generate an AppXManifest.xml. The AppXManifest describes the contents and meta data of a UWP AppX package.
Instead of using the Desktop App Converter (DAC), we will convert our app by hand. This way we’ll understand better what’s going on under the hood. Plus, unless your installation is exceedingly complex, doing this manually simplifies your build toolchain. Assuming that this isn’t a one time conversion, and you’ll be adding modern features to you Win32 app, you need to consider how you are going to iteratively build the project.
The DAC runs your installer in a Windows 10 VM, detects the system changes and spits out an AppX package. It looks like it does a really nice job of that but is a 3+ GB package (for the OS based image) and a bit of a black box. Depending on the needs of your deployment, the manual conversion may very well be fine.
Copy the Sample AppXManifest and Edit for Your App
Copy the sample Xml from the manual conversion documentation page in a blank AppXManifest.xml file and add it as a solution item in Visual Studio. Next, fill out all of the placeholders with the specifics of your app. You’ll end up with something that looks like:
<?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="3652dkackman.FishyFishyFish" ProcessorArchitecture="x86" Publisher="CN=D84FAA85-E110-4951-93B4-A797B4808678" Version="1.1.19.0" /> <Properties> <DisplayName>Fishy Fishy Fish</DisplayName> <PublisherDisplayName>dkackman</PublisherDisplayName> <Description>Some fish. Swimming around on your screen.</Description> <Logo>StoreLogo.png</Logo> </Properties> <Resources> <Resource Language="en-us" /> </Resources> <Dependencies> <TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.14316.0" MaxVersionTested="10.0.14352.0" /> </Dependencies> <Capabilities> <Capability Name="internetClient" /> <rescap:Capability Name="runFullTrust"/> </Capabilities> <Applications> <Application Id="FishyFishyFish" Executable="FishyFish.exe" EntryPoint="Windows.FullTrustApplication"> <uap:VisualElements BackgroundColor="transparent" DisplayName="Fishy Fishy Fish" Square150x150Logo="Square150x150Logo.png" Square44x44Logo="Square44x44Logo.png" Description="Some fish. Swimming around on your screen." /> </Application> </Applications> </Package> |
You’ll get real values for the Name
and Publisher
attributes of the Identity
when you reserve the app name online. In the meantime, placeholder values of your choosing are fine. You will need to provide the 150 and 44 pixel logo images. as these are required assets. If you create a blank Universal app in visual studio you can hijack those png’s and make something better later on.
And finally, any place you see REALTIVE PATH
referenced in the sample xml, it is a path relative to the root of your AppX package. An AppX file is just a Zip file and since Zip’s can have folder structure, make all those paths relative to the Zip/AppX file root. My app deploy is simple enough that I just have everything in the root but you might have an assets folder or the like to better organize your packages files.
So that’s the AppXManifest. Next we’ll turn it into an AppX package.
Orthodox C++
It’s been quite some time since anyone has paid me to write C++, but once upon a time they actually did. Since that time, at least watching questions on StackOverflow, “modern” C++ has seemed increasingly foreign and arcane. Excessive meta-programming, compile time evaluation, references, traits, autos, lamdas, move constructors… Seems like one has to spend more time managing the language than the problem domain.
I get C++ is a powerful language with immense utility but does it really need every possible language feature? I have always maintained that the audience for source code is other humans, not the compiler. Source code is the mechanism to describe to our colleagues (and future selves) what the software is attempting to accomplish. The fact that it is easier and safer to author than assembler or machine code is an important but secondary benefit.
I like the simplifying tenants of Orthodox C++. But then again, no one pays me to write C++ any more.
DigitalOcean tutorials are one of their best features (which is saying a lot as managing a VPS there is cheap and easy). There look to be hundreds of them, they are concise and explicit.
From setting up and hardening Ubuntu, to installing the LEMP stack and WordPress, they made getting this site going a snap.
Kudos to them.
From GUI to CLI
So thus far I’m running an Ubuntu desktop on a Chromebook (mostly to play around with VSCode and dotnetcore) and this here Linux VPS running wordpress. Now I’m not a 100% *nix noob but pretty close. The last time I really interacted with a Unix system in a meaningful way was college (SCO and Irix).
My first observation is that 25 years of living in a Microsoft world has made forget how to run a computer from the command line. It is amazing when you think about it how much Windows tooling allows you to do without needing the command line.
Since Visual C++ 4 or so, projects were less and less about config/make files and more about settings dialogs (which generated config/make files). Now in VS.NET 2017, if there isn’t a checkbox for it, you probably don’t need it. A nice thing about that is it allows you to focus on the problem domain. The downside is I seem to have forgotten a lot about the actual toolchain.
There was a time when I could troubleshoot a build problem by quickly examining a make file or preprocessor output. Or run a complex system build from a batch script. Now I wouldn’t know how to invoke the c# compiler without at least a few minutes on google.
VSCode is a radical shift from the approach of Visual Studio. The IDE looks to be going back to being a code editor and debugger. You can’t make good use of it without the CLI. Configuration is all file, not GUI, based. In short you need to be much closer to the toolchain.
I’m not quite sure how I feel about it yet. Nostalgically it feels somewhat more pure and powerful. The first thing I notice I miss is the discoverability that GUI based configuration brings.
Setting up even a fairly simple set of projects in VSCode for the first time entails a lot of documentation reading. Not a bad thing. But also I’m not quite sure if it’s 100% good.
Are software engineers better off being fully immersed in the tooling or insulated from it?