Désinstallation custom pour Windows Mobile (CustomAction for Windows Mobile)

Les seuls projets d’installation pour Windows Mobile qui sont fournis par Visual Studio sont les projet “Smart Device CAB project”. Malheureusement pour les développeurs DotNet ce type de projets ne supporte pas les custom actions comme le font les projet MSI classiques pour les applications Desktop. Ces customs actions nous permette d’intervenir lors de l’installation et/ou de la désinstallation. Ma problématique pour Windows mobile, c’est que lors de la désinstallation de mon application, les fichiers de données utilisateurs crées par l’application empêche la suppression totale du répertoire de l’application. D’une part ce n’est pas “propre” et d’autre part mon application ne sera pas validée pour les règles du MarketPlace par exemple si je compte publier sur cette plateforme mon application. Heureusement, il est tout de même possible de personnaliser notre projet CAB en ajoutant une DLL faite en C++ natif qui va utiliser le SDK de Windows Mobile et proposer des méthodes appelées automatiquement par l’installeur ou le désinstalleur :

Le principe est donc simple, et la procédure la suivante : (source http://msdn.microsoft.com/en-us/library/aa924308.aspx )
– créer un projet de type C++ Smart Device :

image– inclure les SDK des plateforme ciblées :

image

– choisir un projet de type DLL :

image

– dans le fichier cpp, inclure le header "ce_setup.h"

– en fin de fichier cpp coller le code suivant :

codeINSTALL_INIT Install_Init(
        HWND        hwndParent,
        BOOL        fFirstCall,     // is this the first time this function is being called?
        BOOL        fPreviouslyInstalled,
        LPCTSTR     pszInstallDir
        )
        {
        // TODO: Add custom installation code here

        // To continue installation, return codeINSTALL_INIT_CONTINUE
        // If you want to cancel installation,
        // return codeINSTALL_INIT_UNINSTALL;
        return codeINSTALL_INIT_CONTINUE;

        }



        codeINSTALL_EXIT Install_Exit(
        HWND    hwndParent,
        LPCTSTR pszInstallDir,
        WORD    cFailedDirs,
        WORD    cFailedFiles,
        WORD    cFailedRegKeys,
        WORD    cFailedRegVals,
        WORD    cFailedShortcuts
        )
        {
        // TODO: Add custom installation code here


        // To exit the installation DLL normally,
        // return codeINSTALL_EXIT_DONE
        // To unistall the application after the function exits,
        //return codeINSTALL_EXIT_UNINSTALL;

        return codeINSTALL_EXIT_DONE;
        }

        codeUNINSTALL_INIT Uninstall_Init(
        HWND        hwndParent,
        LPCTSTR     pszInstallDir
        )
        {
        // TODO: Add custom uninstallation code here

        // To continue uninstallation, return codeUNINSTALL_INIT_CONTINUE
        // If you want to cancel installation,
        // return codeUNINSTALL_INIT_CANCEL
        return codeUNINSTALL_INIT_CONTINUE;
        }

        codeUNINSTALL_EXIT Uninstall_Exit(
        HWND    hwndParent
        )
        {
        // TODO: Add custom uninstallation code here

        return codeUNINSTALL_EXIT_DONE;
        }

– ajouter un fichier.def à votre projet  :

image

– et coller le code suivant à la fin de ce fichier def :

EXPORTS
        Install_Init @1
        Install_Exit @2
        Uninstall_Init @3
        Uninstall_Exit @4

– dernière étape, indiquer à notre projet CAB d’utiliser cette dll lors de l’installation et désinstallation, pour cela on a 2 options:

soit vous utilisez un projet de type Smart Device CAB, et dans ce cas vous pouvez spécifier directement la dll dans les propriétés du projet CAB: image

soit vous générez le CAB vous même à partir d’un fichier inf, et dans ce cas on a une directive à ajouter dans la section [DefaultInstall] : CESetupDLL=nom de la dll.dll

Et voilà, on dispose maintenant de 4 méthodes prêtes à coder pour insérer notre logique au début de l’installation, à la fin de l’installation, au début de la désinstallation et à la fin de la désinstallation. Vous constaterez que :

– dans la signature de ces méthodes qu’on reçoit en paramètre le chemin d’installation de l’application, indispensable pour agir sur le contenu des dossiers…

– des codes de retours différents sont possible pour demander par exemple l’échec de l’installation (et donc un rollback)

Après il ne reste plus qu’à savoir faire un peu de C++ pour intégrer la logique désirée. Pour ma part mon problème initial est bien de pouvoir supprimer mon dossier d’application à la désinstallation de l’application, même si ce dossier contient des données utilisateurs générées par l’application elle même.

Comme je suis un mec sympa 😉 je vous donne le code d’une fonction qui va bien pour supprimer le contenu d’un dossier de manière récursive, et oui on est en C++ ici et c’est tout même un peu plus fastidieux qu’en C#  : (bon j’avoue, en fait j’ai récupéré ce code ici et ensuite l’ai adapté à mon besoin 😉 )

BOOL DeleteDirectory(const TCHAR* sPath) {

        WIN32_FIND_DATA ffd;
        LARGE_INTEGER filesize;
        TCHAR szDir[MAX_PATH];
        TCHAR FileName[MAX_PATH];
        size_t length_of_arg;
        HANDLE hFind = INVALID_HANDLE_VALUE;
        DWORD dwError=0;

        // Check that the input path plus 3 is not longer than MAX_PATH.
        // Three characters are for the "\*" plus NULL appended below.
        StringCchLength(sPath, MAX_PATH, &length_of_arg);
        if (length_of_arg > (MAX_PATH - 3))
        {
        return FALSE;
        }

        // Prepare string for use with FindFile functions.  First, copy the
        // string to a buffer, then append '\*' to the directory name.
        StringCchCopy(szDir, MAX_PATH,sPath);
        StringCchCat(szDir, MAX_PATH, TEXT("\\*"));
        StringCchCopy(FileName, MAX_PATH,sPath);
        StringCchCat(FileName, MAX_PATH,TEXT("\\"));

        // Find the first file in the directory.
        hFind = FindFirstFile(szDir, &ffd);
        if (INVALID_HANDLE_VALUE == hFind)
        {
        return FALSE;
        }
        // List all the files in the directory with some info about them.
        do
        {
        _tcscat(FileName,ffd.cFileName);
        if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
        {
        DeleteDirectory(FileName);
        RemoveDirectory(FileName);
        StringCchCopy(FileName, MAX_PATH,sPath);
        StringCchCat(FileName, MAX_PATH,TEXT("\\"));
        }
        else
        {
        DeleteFile(FileName);
        StringCchCopy(FileName, MAX_PATH,sPath);
        StringCchCat(FileName, MAX_PATH,TEXT("\\"));
        }
        }
        while (FindNextFile(hFind, &ffd) != 0);
        FindClose(hFind);
        return dwError;
        }

Et l’utilisation dans ma désinstallation :

codeUNINSTALL_INIT Uninstall_Init(
        HWND        hwndParent,
        LPCTSTR     pszInstallDir
        )
        {
        try
        {
        DeleteDirectory(pszInstallDir);
        RemoveDirectory(pszInstallDir);
        }
        catch(...)
        {}
        return codeUNINSTALL_INIT_CONTINUE;
        }

Enjoy !

Publié dans Développement divers Tagués avec : ,

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

*

Verifions que vous êtes un humain * Time limit is exhausted. Please reload CAPTCHA.

Archives

Social

  • Twitter
  • LinkedIn
  • Flux RSS
  • mvp
  • technet
  • Google+