software-on-demand-ita.com

Giuseppe Pischedda

Software Engineer

software-on-demand-ita.com

Giuseppe Pischedda

Software Engineer

Porting Win32 applications to the Microsoft Store with Visual Studio 2017

Part 2

How to convert classic Win32 applications for the Microsoft Store.



Strutturare la Soluzione di Visual Studio
Nella parte 1 di questo tutorial abbiamo scritto un'applicazione Win32 DoNothingApp che poi abbiamo impacchettato manualmente, con lo strumento Desktop App Converter, in packages .appx (x86 e x64) pronti per essere distribuiti via Sideload o Microsoft Store.

La creazione manuale dei packages ha comportato una serie di passaggi che invece Visual Studio 2017 avrebbe eseguito automaticamente. Tale automatismo comunque necessita di una corretta struttura dell'intera soluzione affinchè ciò che Visual Studio produce al posto nostro sia perfettamente aderente alla struttura logica dell'applicazione.

Per fare un esempio, immaginiamo che la nostra applicazione una volta distribuita abbia una logica secondo la quale debba essere obbligatoriamente strutturata in una directory root e varie subdirectories in cui si trovano dll, file dati, file di database etc.
In tali casi, qualora la soluzione di Visual Studio non fosse ben strutturata, la nostra applicazione verrebbe si inserita nei rispettivi packages (x86 / x64), ma sicuramente non avrebbe la struttura logica che necessita (per esempio i files che dovrebbero trovarsi in una data subdirectory potrebbero invece trovarsi nella directory root od all'esterno di essa e così via).

Inoltre ci sono altre complicazioni : come indicare a Visual Studio i files che non siano exe affinchè vengano inseriti nei packages? (Visual Studio automaticamente può impacchettare solo file exe), nonchè, come fare inserire nei relativi packages, a Visual Studio, le corrette versioni (x86 ed x64) di tutta la struttura logica della nostra applicazione?

Prima di vedere come rispondere ai quesiti qui sopra, proseguiamo il progetto DoNothingApp affinchè questo assuma la struttura desiderata (vedi parte 1 alla sezione Struttura della directory di deploy).


Nota
Chi non fosse interessato ai vari passaggi relativi alla creazione da zero dell'applicazione DoNothingApp descritti nella parte 1 può scaricare direttamente il progetto (parte 1) per Visual Studio 2017 a questo link:


e quindi proseguire da qui in avanti.


DoNothingApp Part 2
Apriamo il progetto DoNothingApp e per prima cosa facciamo in modo che si possano facilmente distinguere le versioni x86 ed x64 dell'applicazione.
Faremo in modo che visualizzando le proprietà dei file della nostra app in Windows Explorer, la versione x64 sia contrassegnata con la dicitura (vers. x64).

A tale scopo aggiungeremo alle risorse di ogni progetto due nuove risorse di tipo Version.

Assicuriamoci di aver selezionato in Solution Configurations Release e x86

Selezioniamo il progetto, facciamo click sulla tab Resource poi click destro sul progetto DoNothingApp -> Add -> Resource.

DoNothingApp Add Resource DoNothingApp Add Resource DoNothingApp Add Resource


Ora in Properties del progetto apriamo il nodo Resources -> General -> Preprocessor Definition
ed aggiungiamo una nuova definizione: DONOTHINGAPPVERS_X86 (assicuriamoci che la configurazione sia Release e Win32) quindi salviamo.

DoNothingApp Add Resource


Rimaniamo in Preprocessor Definition ma cambiamo configurazione scegliendo stavolta Release e x64.
Aggiungiamo una nuova definizione DONOTHINGAPPVERS_X64 e salviamo.


DoNothingApp Add Resource


Selezioniamo la risorsa Version creata in precedenza, click destro su essa quindi in Properties e nella proprietà Condition indichiamo la direttiva del preprocessore (per la versione x86).

DoNothingApp Add Resource DoNothingApp Add Resource DoNothingApp Add Resource


Aggiungiamo una copia della risorsa facendo click destro sul nome della risorsa Version e quindi Insert Copy e mettendo in Condition la direttiva per la versione x64 DONOTHINGAPPVERS_X64.

Modifichiamo il contenuto della risorsa Version aggiungendo la stringa vers. x64.


DoNothingApp Add Resource DoNothingApp Add Resource DoNothingApp Add Resource


Ripetiamo il passaggio di creazione delle risorse Version per le due dll del progetto e ricordiamo di aggiungere le direttive per il preprocessore nel nodo Resources di entrambe le dlls.
Quando finito ricompiliamo entrambe le configurazioni x86 ed x64.
Ora da proprietà file di Windows Explorer possiamo distinguere la versione x86 della nostra applicazione da quella x64 (exe e dll).


DoNothingApp Add Resource DoNothingApp Add Resource DoNothingApp Add Resource



Fatto ciò creaimo nella directory root della soluzione due cartelle che chiameremo dll_x86 e dll_x64.


DoNothingApp Add Resource

In queste copieremo le rispettive versioni x86 e x64 delle nostre dll e siccome vogliamo che le copie siano sempre aggiornate alla versone più recente e certamente non vogliamo dopo ogni compilazione fare manualmente copia incolla, delegheremo questa incombenza a Visual Studio assegnando un evento postbuild per entrambe le dlls e per ogni versione (x86 e x64).


DoNothingApp Copy DLLs DoNothingApp Copy DLLs DoNothingApp Copy DLLs DoNothingApp Copy DLLs



Ricompiliamo entrambe le configurazioni x86 ed x64 e verifichiamo che Visual Studio abbia copiato corettamente nelle relative cartelle le DLLs.



DoNothingApp Copy DLLs



Aggiungiamo un Help System
Creiamo una nuova cartella nella directory root del progetto e chiamiamola Help.
All'interno di questa creiamo un help file di nome help_index e di tipo html quindi una subdirectory che conterrà i restanti file del sistema di help.



DoNothingApp Help System DoNothingApp Help System DoNothingApp Help System



Aggiungiamo al progetto DoNothingApp una voce di menu nelle risorse e gli impostiamo come ID : IDM_HELP



DoNothingApp Help System


Aggiungiamo due includes:


#include <shellapi.h>
#include <shlwapi.h>

implementiamo l'evento onclick del menu help:


    ......
    ......

    case IDM_HELP:
    {

    TCHAR szFileName[MAX_PATH];

    GetModuleFileName(NULL, szFileName, MAX_PATH);

    PathRemoveFileSpec(szFileName);

    lstrcat(szFileName, L"\\Help\\help_index.htm");

    SHELLEXECUTEINFO pExecInfo;
    pExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);
    pExecInfo.lpVerb = L"open";
    pExecInfo.lpFile = szFileName;

    pExecInfo.fMask = NULL;
    pExecInfo.hwnd = NULL;


    pExecInfo.lpParameters = NULL;
    pExecInfo.lpDirectory = NULL;
    pExecInfo.nShow = SW_NORMAL;
    pExecInfo.hInstApp = NULL;


    ShellExecuteEx(&pExecInfo);
    }
    break;
    .......
    .......

Ciò che fa questo pezzo di codice è elementare: ricava la directory corrente dell'applicazione quindi la concatena con la sottodirectory Help e setta il nome del file da aprire help_index.htm, infine chiede alla shell di Windows di aprire il file htm nel browser predefinito.
Naturalmente è necessario che la directory Help sia una sottodirectory della directory root dell'applicazione.



Da Win32 (exe) a UWP package



Ora che la struttura della soluzione DoNothingApp ha la forma attesa vediamo come creare con Visual Studio 2017, partendo da un progetto Win32, i packages UWP (x86/x64) da distribuire via Microsoft Store o Sideload.



Alla soluzione DoNothingApp aggiungiamo un nuovo progetto dai templates Visual C++ -> Windows Universal di tipo Windows Application Package Project e di nome DoNothingAppDeploy.



DoNothingApp UWP DoNothingApp UWP DoNothingApp UWP


Aggiungiamo la reference all'applicazione DoNothingApp.


DoNothingApp UWP DoNothingApp UWP DoNothingApp UWP


Ora per vedere che succede creiamo i packages per lo Store:
dal menu Project -> Store -> Create App Packages, lasciamo tutto di default tranne lincremento automatico del numero di versione e confermiamo la creazione dei packages



DoNothingApp UWP DoNothingApp UWP DoNothingApp UWP DoNothingApp UWP


Ora se andiamo in esplora risorse vediamo che i packages sono stato creati ma il contenuto non è completo.
Mancano infatti le due DLLs, la cartella Help, il file htm, la relativa subdirectory html_index_file ed tutti i file contenuti in essa.



DoNothingApp UWP


Ciò è del tutto normale ed è dovuto al fatto che il progetto UWP della soluzione non può avere referenziati i progetti delle nostre DLLs come avviene invece per il progetto dell'exe.



Per ovviare al problema aggiungiamo al progetto DoNothingApp due nuovi filtri i cui nomi saranno (a titolo di esempio ovviamente): dlls_x86 e dlls_x64.
All'interno dei filtri aggiungiamo le rispettive dll (che si trovano nelle cartelle dlls_x86 e dlls_x64 create in precedenza).



DoNothingApp UWP DoNothingApp UWP


Ora in entrambi i filtri abbiamo due dll.
Per ognuna di esse dovremo fare in modo che che:

  • a) non partecipino al build
  • b) facciano parte del contenuto del rispettivo progetto (x86 e x64)

Per chiarire meglio il punto b) qui sopra, si tratta semplicemente di far capire a Visual Studio 2017 che le versioni x86 delle dll devono essere incluse nel package UWP x86 e,ovviamente, le verisioni x64 nel package x64.


Allo scopo facciamo click destro sul nome della prima dll (MyDLL_1.dll) nel filtro dlls_x86 e scegliamo Properties.
Nella dialog assicuriamoci che sia selezionato Configuration : Release e Win32.
Alla voce Content mettiamo YES.

Cambiamo Configuration da Win32 a x64 e mettiamo NO.



Per farla breve per ogni dll inclusa nei rispettivi filtri dlls_x86 e dlls_x64 si dovrà fare in modo che:

  • le versioni x86 delle dll siano settate a YES nella riga Content nella configurazione Win32
  • le versioni x86 delle dll siano settate a NO nella riga Content nella configurazione x64
  • le versioni x64 delle dll siano settate a YES nella riga Content nella configurazione x64
  • le versioni x64 delle dll siano settate a NO nella riga Content nella configurazione Win32



DoNothingApp UWP DoNothingApp UWP


Concluso questo passaggio ripetiamo il deploy per lo store e stavolta le dll sono presenti nella directory di ouput (e nei rispettivi packages x86 ed x64).



DoNothingApp UWP DoNothingApp UWP


Per avere un'applicazione completa però manca all'appello ancora l'Help System, che anch'esso deve essere presente nella directory root dell'applicazione e nei packages UWP.

Si tratta in pratica di includere la cartella Help e tutto il suo contenuto nei packages UWP e per far ciò è sufficiente creare nel progetto UWP della soluzione DoNothingAppDeploy una nuova cartella il cui nome però dev'essere obbligatoriamente identico a quello del progetto dell'applicazione (exe). Nel nostro caso la nuova cartella avrà come nome DoNothingApp.


All'interno della directory DoNothingApp del progetto UWP DoNothingAppDeploy creiamo un'altra cartella che chiameremo, appunto Help. Dentro quest'ultima aggiungiamo un item esistente: il file help_index.htm.
Sempre all'interno dell cartella Help creiamo un'altra cartella che chiameremo help_index_file.
All'interno della cartella help_index_file aggiungiamo tutti i restanti file dell'help system.



DoNothingApp UWP DoNothingApp UWP DoNothingApp UWP DoNothingApp UWP



Creiamo nuovamente i packages : dal menu Project -> Store -> Create App Packages


DoNothingApp UWP DoNothingApp UWP DoNothingApp UWP DoNothingApp UWP


Visual Studio ha creato per noi tutta l'infrastruttura (dipendenze da runtimes comprese) per la distribuzione dell'applicazione via Store o Sideload.

Il file .appxbundle (che è un file compresso) creato da Visual Studio, contiene (tra le altre cose) i due packages x86 ed x64 dell'applicazione affinchè di essa venga installata, nella macchina dell'utente finale, la versione corretta per il sistema operativo di quest'ultimo.


DoNothingApp .appxbundle DoNothingApp .appxbundle content


Per distribuire la nostra applicazione dovremo semplicemente fare l'upload del file .appxbundle sul sito Partner Microsoft.
Chi non è iscritto al programma Partner Microsoft può distribuire in proprio il file .appxbundle (per esempio dal proprio sito web).





Processing request, please wait...


Download DoNothingApp part-2 Source





Giuseppe Pischedda 2018


Ehi, se ti va puoi offrirmi un caffè.


Ehi, se ti va puoi offrirmi un caffè.

Informativa estesa art.13 d.lgs. 196/03 ed art. 13 del Regolamento UE 2016/679 del 27 aprile 2016 (privacy)