Big Note: this post is a bunch of experimentation with the Desktop App Converter. I reference the official documents which should be your guide to what can/can’t be done and what’s supported and so on. These notes are really just the results of me experimenting with a few things as I find that’s the best/only way to learn anything and I find writing it down as I’m going along quite useful both at the time and afterwards.

Even in this modern world of mobile-first, cloud-first computing and a heterogenous client computing environment it’s fair to say that desktop applications on Windows (and on Mac) are still hugely important and billions of people are using them every day.

And, very importantly, continuing to develop them.

One of the first set of questions that I got back in 2012 when the Windows Store launched were along the lines of;

How do I put my existing desktop application into that Store? ( you could, but only to ‘advertise it’ )

How do I make use of those new WinRT APIs from my existing desktop application? ( no great answer there )

If I rewrite my desktop application to be ‘WinRT’ (now expanded to UWP) then what do I do about the APIs that I use which are missing? ( brokered components added something here )

These were all fair questions and, at the time, I mostly found myself having to say “not sure”.

Here in 2016, the picture is a bit clearer in that;

The “Desktop App Converter” means that, with the Anniversary Update, desktop applications can truly go into the Windows Store for discovery, purchase, installation, updating, etc. Desktop applications can make use of a lot of the UWP APIs available. It’s still very fair to say that the set of APIs available to a desktop app is huge in comparison to those available to a UWP app but the UWP API set has grown a lot in the past 4 years and so includes some of those areas that developers were asking for back in 2012.

I wanted to dig into (1) and (2) above and the arrival of the Anniversary Update seemed like the perfect time to do that and that’s what this post (and maybe some follow-on-posts) is about.

If you’ve not looked at the “Desktop App Converter” then I’d suggest the //build 2016 session as a starting point.

and then you can go and read the docs over here;

which includes a link to go and get the preview converter tool itself.

I downloaded both the converter and the base image (3.3GB in total) and then ran through the setup instructions which all worked out fine although my machine did seem to reboot at the;

PS C:\> .\DesktopAppConverter.ps1 -Setup -BaseImage .\BaseImage-1XXXX.wim -Verbose

stage but, apart from this, it all seemed to work out.

As a note, the first time I downloaded I got presented with only a file for 14352.wim whereas I think I need a 14393.wim to work on the Anniversary Update. A revisit to the page seemed to sort that out for me so take care if you see something similar because the .wim file has to match the version of the OS you’re running on.

From here, it seems to me that there’s at least two routes that I could go with this;

I have a desktop application which I build and would like to package as a .appx in order to be able to deploy that way and put in the Store etc. I have a desktop application which I have some kind of installer for and I would like to “play its installer actions” into a .appx or manually create a .appx in order to be able to deploy that way and put in the Store etc.

In the former case, a .appx file is just a fancy .zip file with some structure to it but it’s probably easier to have a tool make one if possible and Visual Studio “15” (Preview 3) does have one of those things and you can grab it from here;

but, in the first instance I thought I’d try out the latter case and see if I could take existing installers and “play them” into a .appx using the converter.

Which desktop app should I try this out with? I tried a few.

Trial 1 – Spotify

I went to Spotify.com, downloaded their Windows installer and then wondered whether it would work or not because it’s one of those installers that goes on to download more bits from the web.

Regardless, I thought that I’d give it a whirl as everything’s a learning experience so I executed the command;

.\DesktopAppConverter\DesktopAppConverter.ps1 -Installer .\Apps\SpotifySetup.exe –PackageName Spotify -Publisher “CN=mtaultyTest” -Version 1.0.0.0 -Destination .\SpotifyOut -MakeAppx

You can perhaps see that I have a folder for the converter, another for Apps and another for output and I’m asking the converter to make a .appx file.

Out of this popped a .appx file and the tool also emitted a registry.dat, a AppxManifest.xml, some basic imagery and a VFS folder which looked like it contained the contents of all the files that the installer had tried to put down onto my system.

So far, so good! I then went through the process of signing the .appx file as described in the documentation as I can never, ever remember how to use makecert and signtool.

One thing I’d flag here – you need to make sure that the common name of your certificate here is exactly the same as the –Publisher argument that you specified to DesktopAppConverter.ps1 otherwise you’ll find that you get the “SignerSign()” error.

The other thing I’d flag is to not forget that you need to trust the certificate that you just made via makecert or the package deployment will fail.

At that point, I had a .appx file and so I went about trying to use add-appxpackage to install it and it worked.

I was actually expecting it to fail because the tool had given me a warning about not being able to figure out my app’s installation folder but, no, it worked.

followed by silence…

and then it’s installed…

and it works…

and, no, I mean it really works

so that was fairly impressive.

Trial 2 – InkScape

I use InkScape quite a lot for playing with vector graphics and so I thought I’d give that a try and downloaded their 64-bit MSI and wondered whether I’d have success with it.

I was initially encouraged as the .msi has a /quiet option so I figured that might help me out and so I tried that out and hit an error;

Something relating to the installer returning 1639 rather than 0, 1641, 3010.

I wondered what that might mean and so I made sure that I could install the app on my system manually using the “/quiet /n” switches and that seemed to work ok.

I tried making use of the –LogFile option to see if that would help me figure out what the problem was. The log file was pretty decent but I couldn’t figure out where the 1639 was coming from based on its contents.

I wondered if the 1639 might be a red herring and so I tried the –InstallerValidExitCodes option to see what that would do for me. I was glad to see that it was an option although I doubted that the installer was setting this return value for no reason.

This got me here;

Now, I actually got the W_INSTALL_PATH_NOT_DISCOVERED warning when I did Spotify so I figured that I may be able to ignore that but it seems that the W_EXE_NOT_DISCOVERED was going to cause me a problem.

I rooted around the VFS folders that the tool had made for InkScape and I couldn’t see any .exe in there myself and this was in contrast to the VFS folder that I’d seen when I’d processed Spotify.

So, for some reason the InkScape installation wasn’t working out for me here.

I wondered whether I could use a different option for the InkScape installer and so I tried the /passive flag rather than the /quiet flag. That makes the command line that I used;

.\DesktopAppConverter\DesktopAppConverter.ps1 -Installer .\Apps\inkscape-0.91-x64.msi -PackageName InkSpace -Publisher “CN=mtaultyTest” -Version 1.0.0.0 -Destination .\InkSpaceOut -MakeAppx -InstallerArguments “/passive”

and out popped an .appx file with no warnings. I signed it. Around this time I realised that I’d called it InkSPACE rather than InkSCAPE – my mistake.

I installed it;

and I ran it…

and it seemed to work just fine

I suspect that my trials/errors here were more related to me not passing the right flags to the installer rather than anything that the Desktop App Converter was doing.

Trial 3 – Paint.NET

I use Paint.NET at all the time and (as the name suggests) it’s clearly a .NET application and so I thought I’d try that out as I suspected that I might hit a snag if it isn’t currently built on .NET 4.6.1 plus I also suspected that I might have to do something to deal with the x86/x64/AnyCPU nature of the code.

I downloaded the installer for Paint.NET – unlike InkScape, it’s a .exe rather than a .msi and when you run it, it seems to extract a bunch of files somewhere.

I first off ran with this command prompt;

PS C:\temp\dac> .\DesktopAppConverter\DesktopAppConverter.ps1 -Installer .\Apps\paint.net.4.0.10.install.exe -PackageName PaintNet -Version 1.0.0.0 -Publisher “CN=mtaultyTest” -MakeAppx -InstallerArguments “/skipConfig” -Destination ./PaintNetOut

and I hit the same snag that I’d hit when trying out InkScape – the two warnings around W_EXE_NOT_DISCOVERED and W_INSTALL_PATH_NOT_DISCOVERED leading to the error E_CANNOT_MAKEAPPX_WITHOUT_EXE which seems entirely reasonable.

I wondered whether there was a tweak that I could make to the parameters again and I tried the “/auto” option to the installer but got the same result.

It felt like the Paint.NET installer wasn’t installing itself into the containerised environment.

However, the installer does have an option /createMsi which makes a .MSI for Paint.NET so I wondered whether that might give different results and I asked it to make that .MSI (it makes both an x86 and x64 variant) and then took the 64-bit version and tried to see if I could use the Desktop App Converter to make a .appx from that.

If I ran the .MSI that I’d created interactively then it worked fine and Paint.NET got installed whereas, typically, different combinations of parameters to both the Desktop App Converter and the Paint.NET .MSI seemed to cause the Desktop App Converter to error in different ways but the error generally related to either;

The .MSI has exited with a code other than 0. Now, I could try and hack around this by telling the converter that the error code was “ok to ignore” but that didn’t help because I’d then get…

The converter can’t find the EXE inside of the bits that the .MSI has installed.

And I’d find that if I dug around in the VFS folder that the converter had created then I couldn’t find the .EXE file either so I could understand why the converter was having trouble but why was the installer not installing the .EXE file in the first place?

This had me poking around in the log file that the Desktop App Converter produces and it’s pretty decent with the revelant bit for me here seeming to be;

Running Installer in Isolated Environment

[2016-08-05T11:10:42] No installer valid exit codes specified. Using defaults: 0 1641 3010

[2016-08-05T11:10:42] Replace any occurence of <log_folder> in -InstallerArguments with C:\shared\logs

[2016-08-05T11:10:42] Creating Isolated Environment

[2016-08-05T11:10:43] Starting the Isolated Environment

[2016-08-05T11:10:45] Logging known folder locations in Isolated Environment

[2016-08-05T11:10:45] Command line: “C:\shared\dac\bin\KnownFolderDump.exe” “C:\shared\dac\out\KnownFolders.xml”

[2016-08-05T11:10:45] Waiting for known folder mapping process to finish in Isolated Environment

[2016-08-05T11:10:56] Running installer command in Isolated Environment

[2016-08-05T11:10:56] Command line: “C:\WINDOWS\system32\msiexec.exe” /quiet DISABLEADVTSHORTCUTS=1 INSTALLSTARTMENUSHORTCUTS=1 /norestart /i “C:\shared\installer\PaintDotNet_x64.msi” /l*v “C:\shared\logs\install_PaintDotNet_x64.log”

[2016-08-05T11:10:56] Waiting for installer process to complete inside Isolated Environment

[2016-08-05T11:11:41] Stopping the Isolated Environment

[2016-08-05T11:11:42] Exporting changes made by your installer inside the Isolated Environment

[2016-08-05T11:11:48] Disposing of the Isolated Environment

[2016-08-05T11:11:48] Moving any logs in C:\DesktopAppConverter\021d9821-ef35-4641-95dd-0f3f4c1411ed\shared\logs to .

[2016-08-05T11:11:48] Moving any dac output in C:\DesktopAppConverter\021d9821-ef35-4641-95dd-0f3f4c1411ed\shared\dac\out to C:\DesktopAppConverter\021d9821-ef35-4641-95dd-0f3f4c1411ed\output\dac

[2016-08-05T11:11:48] Cleaning up by removing isolated environment shared folder C:\DesktopAppConverter\021d9821-ef35-4641-95dd-0f3f4c1411ed\shared

[2016-08-05T11:11:48] Isolated Install Complete. Moving output from C:\DesktopAppConverter\021d9821-ef35-4641-95dd-0f3f4c1411ed\output\export to C:\DesktopAppConverter\021d9821-ef35-4641-95dd-0f3f4c1411ed\output\packageRoot

[2016-08-05T11:11:48] Checking installer exit code 0 to ensure it is indicative of success

[2016-08-05T11:11:48] Isolated Installer Run Complete!

[2016-08-05T11:11:48] ————————————————–

and that all looked pretty good and I can see that it copies the log that the installer makes out of the isolated environment for me so I had a look in there and there was something that caught my eye amongst all of the spew which was as far as I could tell (and I’m not good at reading .MSI logs) the installer did seem to be laying down the .EXE file;

MSI (s) (28:20) [11:10:59:161]: Executing op: FileCopy(SourceName=PAINTD~1.EXE|PaintDotNet.exe,SourceCabKey=_BC1135F9DC4A8788EA40968E8DE47726,DestName=PaintDotNet.exe,Attributes=512,FileSize=1764048,PerTick=65536,,VerifyMedia=1,,,,,CheckCRC=0,Version=4.10.6033.29846,Language=0,InstallMode=58982400,,,,,,,)

MSI (s) (28:20) [11:10:59:161]: File: C:\Program Files\paint.net\PaintDotNet.exe; To be installed; Won’t patch; No existing file

and it seemed to be putting it into C:\Program Files\paint.net which didn’t seem to be unreasonable but I wondered about this installation into c:\program files\ as there’s a comment in the Desktop App Converter help page which sounds ‘similar’ if not the same to this;

“A .NET app compiled with “AnyCPU” build option will fail to install if the main executable or any of the dependencies were placed under “Program Files” or “Windows\System32”. As a workaround, please use your architecture specific desktop installer (32 bit or 64 bit) to successfully generate an AppX package.”

Whether this was my issue or not, I wasn’t sure but I thought I’d see if I could alter that behaviour and see if it made any difference and so I first asked the Paint.NET installer to make me an .MSI;

.\paint.net.4.0.10.install.exe /createMsi /auto /skipConfig TARGETDIR=”c:\paintnet”

and I was hoping that this .MSI would install into c:\paintnet\ rather than Program Files. I then took the 64-bit .MSI package that made and ran it through the converter;

.\DesktopAppConverter\DesktopAppConverter.ps1 -Installer .\Apps\PaintDotNet_x64.msi -Publisher “CN=mtaultyTest” -Version 1.0.0.0 -Destination .\PaintNetOut -MakeAppx -PackageName PaintNet -InstallerArguments “/passive” -LogFile .\log.txt

and that produced me a .appx file albeit once again with a warning around finding binaries. I then signed that .appx as before and installed it.

and, ran it;

and, sure enough, there’s Paint.NET;

Now, I must admit that I’m pretty sure that Paint.NET does some NGEN’ing as part of its initial installation and I’m very unsure whether this code that I’m running here as been NGEN’d or not – I suspect not but I haven’t dug in and tried to figure that out.

But, after quite a bit of fumbling (and some learning around where log files go and what they look like) I got it working

Trial 4 – Skype

On the Windows 10 Anniversary Update, there’s a preview of a UWP version of Skype already installed which I really like the look of but I wondered if I could get the Skype desktop offline installer to package itself up as a .appx and install that desktop application that way because I still use that desktop Skype app on my main Surface Pro 3 system today (running 1511).

I went off to Skype and got their installer;

From a bit of web searching I found that this installer supports arguments /VERYSILENT and /NOLAUNCH and so I wanted to see if I could pass them to the app converter. My initial attempt produced this;

PS C:\temp\DAC> .\DesktopAppConverter\DesktopAppConverter.ps1 -Installer .\Apps\skypesetupfull.exe -Publisher “CN=mtaultyTest” -Version 1.0.0.0 -Destination .\SkypeOut -MakeAppx -PackageName SkypeDesktop -InstallerArguments “/VERYSILENT”, “/NOLAUNCH”, “/SP-“,”/SUPPRESSMSGBOXES”,”/NOCANCEL”,”/NORESTART” -LogFile .\log.txt WARNING: DesktopAppConverter : warning ‘W_DISCOVERED_EXE_NOT_FOUND’: Discovered shortcut indicates the app executable

should be ‘\WINDOWS\Installer\{FC965A47-4839-40CA-B618-18F486F042C6}\SkypeIcon.exe’, but this file cannot be found.

MakeAppx will fail until you fix the Application Executable property in the AppxManifest.xml.

and so it feels like the converter is assuming that SkypeIcon.exe is the application’s executable here but I don’t think it is. I think that should, perhaps, be Skype.exe and I poked around the outputted folder structure within the VFS directory and could see that this seems to end up in ProgramFilesX86\Skype\Phone\Skype.exe.

So…maybe the .EXE is there but the converter isn’t finding it and there’s the –AppExectuable parameter which, I think, tells the converter to stop trying to work this out for itself. So, I tried that;

.\DesktopAppConverter\DesktopAppConverter.ps1 -Installer .\Apps\skypesetupfull.exe -Publisher “CN=mtaultyTest” -Version 1.0.0.0 -Destination .\SkypeOut -MakeAppx -PackageName SkypeDesktop -InstallerArguments “/VERYSILENT”, “/NOLAUNCH”, “/SP-“,”/SUPPRESSMSGBOXES”,”/NOCANCEL”,”/NORESTART” -LogFile .\log.txt -AppExecutable “c:\program files (x86)\Skype\Phone\Skype.exe”

and I can’t say that every one of those flags to the Skype installer is required as such but it worked out and I got an .appx out of it and got past my error.

I signed the .appx and installed Skype from the .appx package but I realised that my victory here had been short-lived as I saw;

So I think I’d need to revisit this one and try a bit harder if I wanted to get this one to work fully.

Trial 5 – VLC

I use VLC quite a bit and so I went and grabbed their installer;

which seemed to support a /S parameter for silent mode. I ran that first, interactively, on my system to see if it worked and it did seem so and so I uninstalled it and then set about running that installer through the app converter;

.\DesktopAppConverter\DesktopAppConverter.ps1 -Installer .\Apps\vlc-2.2.4-win32.exe -Publisher “CN=mtaultyTest” -Version 1.0.0.0 -Destination .\VLCOut -MakeAppx -PackageName VLC -InstallerArguments “/S” -LogFile .\log.txt

and that all worked out fine as far as I could tell. However, when I ran the signtool on the resulting .appx file I got an error which I checked by setting the APPXSIP_LOG environment variable to 1 and then re-running;

C:\temp\DAC\VLCOut>signtool sign -f ..\my.pfx -fd SHA256 -v .\VLC.appx

The following certificate was selected:

Issued to: mtaultyTest

Issued by: mtaultyTest

Expires: Sat Dec 31 23:59:59 2039

SHA1 hash: AB1863ED8ABB6280978B9D96A4690B8E50DC5634 Done Adding Additional Store

ERROR: [AppxSipCustomLoggerCallback] File has malformed certificate: VLC\uninstall.exe

So, I get a malformed certificate on this uninstall.exe which, ironically, I guess doesn’t really need to be there given that installation is now handled by .appx.

I figured that I could maybe address this for this particular instance by taking off the –MakeAppx parameter and re-running the command to make the output folder without the .appx file.

Then, I deleted the offending uninstall.exe so that it wouldn’t be packaged into the .appx before running;

MakeApp.exe /d VLCOut /p VLC.appx

to make the .appx myself and then signing it with the signing tool.

That seemed to work ok and so I ran the .appx file;

and let the app install and in so much as I could tell I got VLC installed;

Final Scores

Ok, from my initial experiments here it looks like it’s a 4-1 win to me in the sense that I got 4 out of 5 of these installers to play nice with me and the desktop app converter and I learned quite a lot along the way about the process and the sorts of things that I might look for in taking an installer like this and trying to convert it to .appx format.

There’s a lot more to learn but it’s a start