Porting Win32 applications to the Microsoft Store with Desktop App Converter
How to convert classic Win32 applications for the Microsoft Store.
Part 1
Col Desktop Bridge Microsoft dà la possibilità di fare il porting di applicazioni e games dalla classica piattaforma Win32 allo Store.
Naturalmente, sebbene una classica applicazione Win32 per desktop possa essere ammessa nel Microsoft Store, questa non diventa un'applicazione UWP (Universal Windows Platform),
piuttosto essa verrà inserita in package (un file compresso) il quale potrà essere installato in Windows 10.
E' possibile predisporre un'applicazione Win32 in un package per lo Store o per l'installazione sideload in due modi:
- Manualmente, usando il tool Desktop App Converter
- Col supporto per Visual Studio 2017 (vers.15.9)
Una volta convertita e "impacchettata" l'applicazione può essere distribuita attraverso due canali:
- Microsoft Store
- Sideload
Il processo conversione di un'applicazione avviene in due passaggi:
- 1) Esecuzione del tool Desktop App Converter
- 2) Esecuzione del tool Windows App Certification Kit
Per poter essere accettata nello Store, la nostra applicazione Win32 deve avere precisi requisiti (consultare il sito Microsoft).
La certificazione di un'applicazione convertita per lo Store è a discrezione di Microsoft che, quand è il caso, comunica gli aspetti critici
da correggere per poterla accettare o ne rigetta il package.
Per essere certi che un' applicazione sia idonea per lo Store è necessario sottoporla ai medesimi test a
cui sarà sottoposta da Microsoft stessa, ed
allo scopo, c'è un altro tool che verifica se l'applicazione convertita potrà essere certificata: Windows App Certification Kit.
Nella parte 2 di questo tutorial vedremo che Visual Studio 2017 integra i due tools ed in maniera automatica crea
tutta l'infrastruttura necessaria per la conversione e la certificazione di un'applicazione Windows desktop.
Partenza
1)
Se nel vostro sistema non avete già installato il tool Desktop App Converter installatelo.
2)
Creiamo in Visual Studio 2017 un nuovo progetto Win32 Desktop così strutturato:
- un exe
- due dll
- nella directory di deploy ci dovrà essere subdirectory in cui metteremo un file di help.
- un paio di files a corredo dell'applicazione (readme.txt e license.txt)
RootFolder\ | | exe dll_1 dll_2 txt_1 txt_2 | | HelpFolder\ | |---- help.html | | HelpFolderSubdir\ | |---- file_1 file_2
Nota
Lo scopo di avere un progetto che sia così strutturato ( punto 2 ) lo capiremo meglio nella parte 2 di questo tutorial quando vedremo come aggiungere al package gestito da Visual Studio 2017 dei files a corredo dell'applicazione. Per ora sappiate che Visual Studio 2017 inserisce nel package di default il solo file exe, tutto il resto che fa parte integrante dell'applicazione (dlls etc.) no.
Crieamo l'applicazione Win32 "DoNothingApp" da convertire per lo Store
Nota
Per comodità userò un template per Visual Studio che creerà un progetto Win32 Dialog Application C/C++.
Scaricate ed installate il template da questo stesso sito all'indirizzo:
Apriamo Visual Studio 2017, dal menu File -> New Project -> Visual C++ -> Win32DlgProject
Chiamerò il progetto DoNothingApp
Settiamo Solution Configuration a Release, quindi dal menu Project scegliamo DoNothingApp Properties
andiamo al nodo Manifest Tool alla voce Input and Output
- nell'opzione Additional Manifest Files settiamo (*) win10-and-dpi.xml
- nell'opzione DPI Awareness settiamo Per Monitor High DPI Aware
Eseguiamo questo stesso passaggio per entrambe le configurazioni (Release Win32 e Release x64).
* Nota
Il file win10-and-dpi.xml integra il file manifest dell'applicazione e contiene le dichiarazioni di compatibilità con Windows 10 (ed altre versioni di Windows).
Le impostazioni di compatibilità del file manifest e DPI Awareness sono necessarie in quanto il tool Windows App Cert Kit verificherà tra le altre cose se è stata dichiarata la compatibilità con Windows 10 nel file manifest e che l'applicazione sia compatibile con i monitors ad alta risoluzione (oltre i 96 dpi).
<!-- win10-and-dpi.xml file content --> <assembly> <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"> <application> <!-- Windows 10 --> <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" /> <!-- Windows 8.1 -->> <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" /> <!-- Windows Vista --> <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}" /> <!-- Windows 7 --> <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" /> <!-- Windows 8 --> <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" /> </application> </compatibility> </assembly>
Aggiungiamo due progetti DLL Win32 al progetto DoNothingApp
Aggiungiamo alla soluzione i due progetti DLL Win32 che chiameremo MyDLL_1 e MyDLL_2
Aggiungiamo due semplici funzioni da esportare in entrambe le dll
// MyDLL_1.h : Defines the exported functions for the DLL application. // #pragma once #include "stdafx.h" __declspec(dllexport) VOID MyDLL_1_GetMessage(); //----------------------------------------------------------- // MyDLL_1.cpp : Defines the exported functions for the DLL application. // #include "stdafx.h" #include "MyDLL_1.h" __declspec(dllexport) VOID MyDLL_1_GetMessage() { MessageBox(0, L"Hello from MyDLL_1", L"Message", MB_OK); }
// MyDLL_2.h : Defines the exported functions for the DLL application. // #pragma once #include "stdafx.h" __declspec(dllexport) VOID MyDLL_2_GetMessage(); //-------------------------------------------------- // MyDLL_2.cpp : Defines the exported functions for the DLL application. // #include "stdafx.h" #include "MyDLL_2.h" __declspec(dllexport) VOID MyDLL_2_GetMessage() { MessageBox(0, L"Hello from MyDLL_2", L"Message", MB_OK); }
Includiamo gli headers delle due dll nel progetto DoNothingApp
// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
//
#pragma once
.......
.......
#include "..\MyDLL_1\stdafx.h"
#include "..\MyDLL_2\stdafx.h"
#pragma comment(lib,"MyDLL_1.lib")
#pragma comment(lib,"MyDLL_2.lib")
Aggiungiamo nella dialog 2 Buttons dalla Toolbox
Implementiamo l'evento OnClick di entrambi i buttons:
//MainFuncDialog.h
..........
..........
//DLLs imported functions
__declspec(dllimport) VOID MyDLL_1_GetMessage();
__declspec(dllimport) VOID MyDLL_2_GetMessage();
//MainDialogFunc.cpp
..........
..........
case IDC_BUTTON1:
MyDLL_1_GetMessage();
break;
case IDC_BUTTON2:
MyDLL_2_GetMessage();
break;
Settiamo l'ordine di build dei tre progetti:
In project properties settiamo la directory dove il linker potrà trovare i files MyDLL_1.lib e MyDLL_2.lib
Mandiamo in run l'applicazione
Ora nella cartella Release abbiamo (tra gli altri) il file exe e le due dll
Creiamo i due file (readme.txt e license.txt) a corredo dell'applicazione
I due file txt sono stati creati e si trovano nella stessa directory del progetto DoNothingApp.
Tuttavia (per comodità) vogliamo che tutti i files che fanno parte dell'applicazione risiedano nella stessa cartella di deploy che nel caso del progetto x86 è la cartella Project_Name\Release mentre per la versione x64 è Project_Name/x64/Release.
A tale scopo settiamo nel progetto DoNothingApp un Post-Build Event. Chiederemo a Visual Studio di copiare i due files txt nella stessa cartella di deploy del progetto. Il settaggio dovrà essere ripetuto per entrambe le configurazioni Release x86 ed x64.
Per mettere ordine (visivamente) al progetto DoNothingApp aggiungiamo un nuovo nodo (filtro) dentro cui sposteremo
(facendo drag&drop) i due files txt.
Eseguito il rebuild della soluzione, le directories ...\Release e ...\x64\Release contengono tutti i files che fanno parte della nostra applicazione nelle versioni rispettivamente x86 ed x64.
Creazione manuale del package col tool Desktop App Converter
Per comodità copiamo il file exe le due dll e i due txt files in una cartella facilmente raggiungibile via commandline che chiameremo donothingapp.
Nella cartella donothingapp creiamo le cartelle packagesourcex86, packagesourcex64, packageoutx86 e packageoutx64
In packagesourcexXX metteremo i files da inserire nei packages (rispettivamente x86 e x64), nella cartella packageoutxXX troveremo
i rispettivi packages alla fine del processo di creazione.
Avviamo il tool Desktop App Converter con i diritti di Administrator e cancelliamo il testo di help di default.
I parametri del tool sono molti e variano a seconda del package che vogliamo creare. Per i nostri scopi
useremo i seguenti:
- -Installer (cartella in cui si trovano i files da mettere nel package)
- -AppExecutable (nome del file exe)
- -Destination (cartella di output del package)
- -PackageName (nome del package per il sistema)
- -Publisher (nome del publisher per il sistema)
- -Version (versione del package)
- -MakeAppx (esegue lo strumento MakeAppx)
- -Appid (id dell'app)
- -PackageDisplayName (nome del package per l'utente)
- -PackagePublisherDisplayName (nome del publisher per l'utente)
- -AppDisplayName (nome dell'app per l'utente)
- -AppDescription (descrizione dell'app)
Nota
Quando si riserva il nome dell'applicazione per lo Store questo assegna dei valori univoci
simili ai seguenti (da assegnare obbligatoriamente ai parametri qui sotto, pena il rigetto
della validazione del package da parte dello strumento di verifica packages dello Store)
Dato che comunque la nostra applicazione di esempio (DoNothingApp) non dovrà essere pubblicata
nello Store e non ha un nome riservato, possiamo usare dei valori di fantasia.
Componiamo la nostra commandline per il tool ed eseguiamo:
DoNothingApp package x86
DesktopAppConverter.exe -Installer D:\donothingapp\packagesourcex86 -AppExecutable "DoNothingApp.exe" -Destination D:\donothingapp\packageoutx86\DoNothingApp -PackageName "DoNothingAppx86.DoNothingApp" -Publisher "CN=Your Name Here" -Version 1.0.0.0 -MakeAppx -Appid "DoNothingApp" -PackageDisplayName "DoNothing App" -PackagePublisherDisplayName "YourName Here" -AppDisplayName "DoNothing App" -AppDescription "How useless is this application?"
DoNothingApp package x64
DesktopAppConverter.exe -Installer D:\donothingapp\packagesourcex64 -AppExecutable "DoNothingApp.exe" -Destination D:\donothingapp\packageoutx64\DoNothingApp -PackageName "DoNothingAppx64.DoNothingApp" -Publisher "CN=Your Name Here" -Version 1.0.0.0 -MakeAppx -Appid "DoNothingApp" -PackageDisplayName "DoNothing App" -PackagePublisherDisplayName "YourName Here" -AppDisplayName "DoNothing App" -AppDescription "How useless is this application?"
Nota
DesktopAppConverter emette un warning avvisandoci che non tutti i devices supportano applicazioni a 64 bit.
I due packages sono stati creati:
Project Dependencies
DoNothingApp è un'applicazione C++ Win32 che dipende (volutamente) dal runtime di Visual C++ 2017 la cui
presenza nella macchina dei nostri users è necessaria, tuttavia non è possibile installare il classico
runtime VC++ 2017, magari prelevato dal sito Microsoft od incorporato in un programma di setup.
Per ovviare, dovremo dichiarare nel file xml di entrambe le configurazioni (x86 ed x64) che la nostra applicazione dipende da tale runtime
e quindi produrre un nuovo package.
Andiamo nel percorso D:\donothingapp\packageoutx86\DoNothingApp\DoNothingAppx86.DoNothingApp\PackageFiles
Apriamo il file AppxManifest.xml e cerchiamo il nodo <Dependencies> ed all'interno
di questo aggiungiamo:
<PackageDependency Name="Microsoft.VCLibs.140.00.UWPDesktop" MinVersion="14.0.24217.0" Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US" />
Ripetiamo l'operazione per il file di configurazione x64.
Ora, quando verrà richiesto di installare la nostra app verrà verificata la presenza di VC++ 2017 e qualora
non ci fosse, l'utente sarà invitato ad installare il runtime.
Rifare i packages
Una volta apportate modifiche al file manifest del package è necessario ricrearlo.
Per farlo useremo il tool MakeAppx, il tool a riga di comando che troviamo tra gli strumenti della SDK
di Windows 10.
Avviamo dunque una sessione del prompt dei comandi di Visual Studio e rifacciamo entrambi i packages:
x86
makeappx pack -d "D:\donothingapp\packageoutx86\DoNothingApp\DoNothingAppx86.DoNothingApp\PackageFiles" -p "D:\donothingapp\packageoutx86\DoNothingApp\DoNothingAppx86.DoNothingApp\DoNothingAppx86.DoNothingApp.appx"
x64
makeappx pack -d "D:\donothingapp\packageoutx64\DoNothingApp\DoNothingAppx64.DoNothingApp\PackageFiles" -p "D:\donothingapp\packageoutx64\DoNothingApp\DoNothingAppx64.DoNothingApp\DoNothingAppx64.DoNothingApp.appx"
I nuovi package sono stati creati.
Ora è necessario validare i due packages con il tool Windows App Cert Kit
Dopo aver avviato il tool, scegliamo l'opzione "Validate Store App"
Selezioniamo il nostro primo package, lasciamo le impostazioni de default (tutti i test selezionati).
Una volta finita la validazione avremo il responso.
Conclusa positivamente la validazione dei due packages (x86 e x64) possiamo procedere all'installazione nella
nostra macchina di test tramite la seguente riga di comando in una sessione di PowerShell con diritti di Admin:
Add-AppxPackage –Register AppxManifest.xml
Nota
E' possibile anche installare il package facendo doppio click sul file .appx.
A tale scopo è necessario firmare il package con un certificato autoprodotto.
Il certificato va poi installato nella macchina di test come attendibile.
Viceversa, utilizzando PowerShell non è necessario firmare il package in fase di test.
Nella parte 2 di questo tutorial vedremo come Visual Studio 2017 (vers. 15.9 minimo) consenta la conversione
di applicazioni nate per desktop in applicazioni compatibili con Microsoft Store in maniera
molto più semplice e diretta.
Processing request, please wait...
Giuseppe Pischedda 2018