none
Déployement Click Once RRS feed

  • Question

  • Bonjour,

     

    Je déploie mon application WinForm / VS 2008 avec Click Once.

    Cela fonctionne dans les grandes lignes, pour ce que j'ai pu observer, mais j'ai deux problèmes :

    1. l'icône de l'appli dans le panneau de config "ajouter/supprimer des programmes" n'est pas celle de l'application, alors qu'elle est correcte dans le menu démarrer,
    2. il n'y a pas d'icône de l'application sur le bureau,

    Quelqu'un peut-il me dire comment résoudre ces deux problèmes ?

     

    Par ailleurs peut-on, avec Click Once, spécifier des "Custom Actions" comme l'exécution un programme spécifique avant l'installation de l'appli comme il est possible de le spécifier dans un programme de Setup classique ?

     

    Merci d'avance.

    lundi 30 juin 2008 06:10

Réponses

  • Bon voici un bout du code, si tu as des questions / remarques hésites pas...

    Il manque 2/3 trucs que je te mets pas pour simplifier ^^

     

    Code Snippet

    private void frmMain_Load(object sender, EventArgs e)

    {

    if (System.Deployment.Application.ApplicationDeployment.IsNetworkDeployed) //Click deployment

    {

    //Dirty code but well works ;)

    string SourceAppRef = Environment.GetFolderPath(Environment.SpecialFolder.StartMenu);

    SourceAppRef = SourceAppRef.EndsWith(@"\") ? SourceAppRef + @"Programs\Holcim\OteloClient.appref-ms" : SourceAppRef + @"\Programs\Holcim\OteloClient.appref-ms";

    string Desktop = Environment.GetFolderPath(System.Environment.SpecialFolder.DesktopDirectory);

    Desktop = Desktop.EndsWith(@"\") ? Desktop + "OteloClient.appref-ms" : Desktop + @"\OteloClient.appref-ms";

    string QuickLaunch = System.IO.Path.Combine(Environment.GetFolderPath(System.Environment.SpecialFolder.ApplicationData), @"Microsoft\Internet Explorer\Quick Launch\");

    QuickLaunch = QuickLaunch.EndsWith(@"\") ? QuickLaunch + "OteloClient.appref-ms" : QuickLaunch + @"\OteloClient.appref-ms";

    System.IO.File.Copy(SourceAppRef, Desktop, true);

    System.IO.File.Copy(SourceAppRef, QuickLaunch, true);

    //End of dirty code ;)

     

    label1.Text = "Lancement de OteloClient / Version " + System.Deployment.Application.ApplicationDeployment.CurrentDeployment.CurrentVersion.ToString(4);

    this.Show();

    this.Refresh();

    if (System.Deployment.Application.ApplicationDeployment.CurrentDeployment.IsFirstRun)

    {

    //Config a faire

    label2.Text = "Configuration en cours...";

    this.Show();

    this.Refresh();

    //Enregistrement des assemblies pour Otelo

    System.Runtime.InteropServices.RegistrationServices reg = new System.Runtime.InteropServices.RegistrationServices();

    reg.RegisterAssembly(System.Reflection.Assembly.LoadFile(AppDomain.CurrentDomain.BaseDirectory + "OteloApp\\OteloClient.dll"), System.Runtime.InteropServices.AssemblyRegistrationFlags.SetCodeBase);

    reg.RegisterAssembly(System.Reflection.Assembly.LoadFile(AppDomain.CurrentDomain.BaseDirectory + "OteloApp\\HToolsNet.dll"), System.Runtime.InteropServices.AssemblyRegistrationFlags.SetCodeBase);

    reg.RegisterAssembly(System.Reflection.Assembly.LoadFile(AppDomain.CurrentDomain.BaseDirectory + "OteloApp\\HToolsNetEventLogSourceInstaller.dll"), System.Runtime.InteropServices.AssemblyRegistrationFlags.SetCodeBase);

     

    if (string.IsNullOrEmpty(Properties.Settings.Default.Site))

    {

    //Par défaut Properties.Settings.Default.Site est null, donc : premier lancement de l'appli

    //!

    //<userSettings> <OteloClientLauncher.Properties.Settings> <setting name="Site" serializeAs="String"> <value /> </setting>

    //Properties.Settings.Default.Site = UserSettings

    //!

    SelectSite selectSite = new SelectSite(); //Chargement écran de config

    selectSite.ShowDialog();

    Properties.Settings.Default.Site = selectSite.SelectedSite;

    Properties.Settings.Default.Save();

    }

     

    //Idem pour gestion d'un .ini mais il est généré par rapport au "SelectedSite" et du "System.Security.Principal.WindowsIdentity.GetCurrent()...

    //on demande donc rien au user ;) je te met pas toute cette partie c'est pas nécessaire

    //Le .ini est sauver dans un userSettings, ca parait con mais voir le commentaire en bas de cette fonction sur le process.exit

    //Je laisse juste une partie que j'aime bien :

    if (System.Security.Principal.WindowsIdentity.GetCurrent().IsAuthenticated)

    {

    System.DirectoryServices.DirectoryEntry userInfo;

    string userTmp = Environment.UserName;

    userInfo = new System.DirectoryServices.DirectorySearcher("sAMAccountName=" + userTmp).FindOne().GetDirectoryEntry();

    Properties.Settings.Default.OteloIni = Properties.Settings.Default.OteloIni.Replace("#USER#", userInfo.Properties["mail"].Value.ToString());

    }

    else

    {

    Properties.Settings.Default.OteloIni = Properties.Settings.Default.OteloIni.Replace("#USER#", "anonymous@holcim.com");

    }

    Properties.Settings.Default.Save();

     

    //HACK: si touche shift au lancement, édition du fichier .ini ;)

    if ((System.Windows.Forms.Control.ModifierKeys & Keys.Shift) == Keys.Shift)

    {

    OteloIniUpdate iniUpdate = new OteloIniUpdate(Properties.Settings.Default.OteloIni);

    iniUpdate.ShowDialog();

    Properties.Settings.Default.OteloIni = iniUpdate.OteloIniContent;

    Properties.Settings.Default.Save();

    }

    sw = new System.IO.StreamWriter(AppDomain.CurrentDomain.BaseDirectory + @"OteloApp\Otelo.ini", false, Encoding.Default);

    sw.Write(Properties.Settings.Default.OteloIni);

    sw.Flush();

    sw.Close();

    sw.Dispose();

    }

    else

    {

    //Pas premier lancement ;) on fait rien... 

    }

    }

    else

    {

    //Pas du clickonce ;) debug!

    (...)

    }

    label2.Text = "... Ok, lancement de OteloClient...";

    this.Show();

    this.Refresh();

    OteloProcess.StartInfo.FileName = "OteloApp\\Otelo.exe";

    OteloProcess.EnableRaisingEvents = true;

    OteloProcess.Exited += new EventHandler(OteloProcess_Exited);  //Ceci permet de resauver le fichier .ini dans un userSettings car il peut être modifié par l'appli c++ et on ne voudrais perdre les configs a chaque mise à jour clickonce (le fichier .ini pouvant être redéployé par clickonce avec des paramères pas bon alors que le userSettings lui sera conservé modifié avec les mises à jour!!

    OteloProcess.Start();

    label2.Text = "... Ok, OteloClient lancé!";

    timerShutDown.Start();

    this.ShowInTaskbar = false;

    this.Hide();

    }

     

     

    Bien sur si quelqu'un a des commentaires sur le code ils sont les bienvenues !!! je dis pas que je fais tout nickel Wink

    A+,

          Stéphane

     

    vendredi 1 août 2008 08:49

Toutes les réponses

  • Bonjour,

      Pour l'icone sur le bureau il faut savoir que les raccourcis "click-once" ne sont pas des raccourcis normaux windows... il s'agit de fichier ".app-ref" (ou un truc du genre Wink ) ils contiennent une sorte de liens vers l'application en question (ouvre avec notepad Smile ). Une solution que j'ai trouvé (mais j'avous qu'elle n'est pas propre) c'est de copier le fichier généré dans le répertoire "StartMenu\Programs\Editeur\App\..." dans le répertoire "Desktop"... Si tu as besoin j'ai le code au boulot je pourrais te l'envoyer demain. Cette copie se fait au démarrage de l'appli grace a un test "ApplicationDeployement.IsFirstRun" (c'est approximatif, je n'ai pas visual studio ici Wink )

     

      Pour les "custom actions" : la meilleure solution est de le faire "a la main" dans le démarrage du programme, test si c'est le premier lancement de la version installé (IsFirstRun) et voilou Smile. Tu peux tout a fait faire une sorte de lanceur de ton appli (SplashWindow par exemple) qui s'occupe de faire les initialisations nécessaire avant de rediriger sur ton form principale Big Smile

     

      Voilou, je sais je répond un peu tard mais j'étais pas trop sur le forum avant ^^

     

      Cordialement,

            Stéphane

     

    jeudi 31 juillet 2008 19:49
  • Bonjour DarkAngel_FR, alias Stéphane,

     

    Merci de ta réponse qui m'apporte un éclairement sur cette question qui n'est pas encore résolue. Oui, je veux bien ton code qui réalise la copie en question.

     

    J'avais aussi pensé à faire les initialisations dans le FormSplach, comme tu le proposes. ça doit être la bonne solution !

     

    Bien cordialement

     

    jeudi 31 juillet 2008 20:03
  •  

    Ok j't'envoi ca demain Wink

    pour le splash je m'en suis surtout servi pour poser des questions a l'utilisateur et configurer un fichier ".ini" pour lancer une appli c++ mal faite mais impossible a recoder Wink

    a demain donc! Wink

       Stéphane

     

    jeudi 31 juillet 2008 21:16
  • Bon voici un bout du code, si tu as des questions / remarques hésites pas...

    Il manque 2/3 trucs que je te mets pas pour simplifier ^^

     

    Code Snippet

    private void frmMain_Load(object sender, EventArgs e)

    {

    if (System.Deployment.Application.ApplicationDeployment.IsNetworkDeployed) //Click deployment

    {

    //Dirty code but well works ;)

    string SourceAppRef = Environment.GetFolderPath(Environment.SpecialFolder.StartMenu);

    SourceAppRef = SourceAppRef.EndsWith(@"\") ? SourceAppRef + @"Programs\Holcim\OteloClient.appref-ms" : SourceAppRef + @"\Programs\Holcim\OteloClient.appref-ms";

    string Desktop = Environment.GetFolderPath(System.Environment.SpecialFolder.DesktopDirectory);

    Desktop = Desktop.EndsWith(@"\") ? Desktop + "OteloClient.appref-ms" : Desktop + @"\OteloClient.appref-ms";

    string QuickLaunch = System.IO.Path.Combine(Environment.GetFolderPath(System.Environment.SpecialFolder.ApplicationData), @"Microsoft\Internet Explorer\Quick Launch\");

    QuickLaunch = QuickLaunch.EndsWith(@"\") ? QuickLaunch + "OteloClient.appref-ms" : QuickLaunch + @"\OteloClient.appref-ms";

    System.IO.File.Copy(SourceAppRef, Desktop, true);

    System.IO.File.Copy(SourceAppRef, QuickLaunch, true);

    //End of dirty code ;)

     

    label1.Text = "Lancement de OteloClient / Version " + System.Deployment.Application.ApplicationDeployment.CurrentDeployment.CurrentVersion.ToString(4);

    this.Show();

    this.Refresh();

    if (System.Deployment.Application.ApplicationDeployment.CurrentDeployment.IsFirstRun)

    {

    //Config a faire

    label2.Text = "Configuration en cours...";

    this.Show();

    this.Refresh();

    //Enregistrement des assemblies pour Otelo

    System.Runtime.InteropServices.RegistrationServices reg = new System.Runtime.InteropServices.RegistrationServices();

    reg.RegisterAssembly(System.Reflection.Assembly.LoadFile(AppDomain.CurrentDomain.BaseDirectory + "OteloApp\\OteloClient.dll"), System.Runtime.InteropServices.AssemblyRegistrationFlags.SetCodeBase);

    reg.RegisterAssembly(System.Reflection.Assembly.LoadFile(AppDomain.CurrentDomain.BaseDirectory + "OteloApp\\HToolsNet.dll"), System.Runtime.InteropServices.AssemblyRegistrationFlags.SetCodeBase);

    reg.RegisterAssembly(System.Reflection.Assembly.LoadFile(AppDomain.CurrentDomain.BaseDirectory + "OteloApp\\HToolsNetEventLogSourceInstaller.dll"), System.Runtime.InteropServices.AssemblyRegistrationFlags.SetCodeBase);

     

    if (string.IsNullOrEmpty(Properties.Settings.Default.Site))

    {

    //Par défaut Properties.Settings.Default.Site est null, donc : premier lancement de l'appli

    //!

    //<userSettings> <OteloClientLauncher.Properties.Settings> <setting name="Site" serializeAs="String"> <value /> </setting>

    //Properties.Settings.Default.Site = UserSettings

    //!

    SelectSite selectSite = new SelectSite(); //Chargement écran de config

    selectSite.ShowDialog();

    Properties.Settings.Default.Site = selectSite.SelectedSite;

    Properties.Settings.Default.Save();

    }

     

    //Idem pour gestion d'un .ini mais il est généré par rapport au "SelectedSite" et du "System.Security.Principal.WindowsIdentity.GetCurrent()...

    //on demande donc rien au user ;) je te met pas toute cette partie c'est pas nécessaire

    //Le .ini est sauver dans un userSettings, ca parait con mais voir le commentaire en bas de cette fonction sur le process.exit

    //Je laisse juste une partie que j'aime bien :

    if (System.Security.Principal.WindowsIdentity.GetCurrent().IsAuthenticated)

    {

    System.DirectoryServices.DirectoryEntry userInfo;

    string userTmp = Environment.UserName;

    userInfo = new System.DirectoryServices.DirectorySearcher("sAMAccountName=" + userTmp).FindOne().GetDirectoryEntry();

    Properties.Settings.Default.OteloIni = Properties.Settings.Default.OteloIni.Replace("#USER#", userInfo.Properties["mail"].Value.ToString());

    }

    else

    {

    Properties.Settings.Default.OteloIni = Properties.Settings.Default.OteloIni.Replace("#USER#", "anonymous@holcim.com");

    }

    Properties.Settings.Default.Save();

     

    //HACK: si touche shift au lancement, édition du fichier .ini ;)

    if ((System.Windows.Forms.Control.ModifierKeys & Keys.Shift) == Keys.Shift)

    {

    OteloIniUpdate iniUpdate = new OteloIniUpdate(Properties.Settings.Default.OteloIni);

    iniUpdate.ShowDialog();

    Properties.Settings.Default.OteloIni = iniUpdate.OteloIniContent;

    Properties.Settings.Default.Save();

    }

    sw = new System.IO.StreamWriter(AppDomain.CurrentDomain.BaseDirectory + @"OteloApp\Otelo.ini", false, Encoding.Default);

    sw.Write(Properties.Settings.Default.OteloIni);

    sw.Flush();

    sw.Close();

    sw.Dispose();

    }

    else

    {

    //Pas premier lancement ;) on fait rien... 

    }

    }

    else

    {

    //Pas du clickonce ;) debug!

    (...)

    }

    label2.Text = "... Ok, lancement de OteloClient...";

    this.Show();

    this.Refresh();

    OteloProcess.StartInfo.FileName = "OteloApp\\Otelo.exe";

    OteloProcess.EnableRaisingEvents = true;

    OteloProcess.Exited += new EventHandler(OteloProcess_Exited);  //Ceci permet de resauver le fichier .ini dans un userSettings car il peut être modifié par l'appli c++ et on ne voudrais perdre les configs a chaque mise à jour clickonce (le fichier .ini pouvant être redéployé par clickonce avec des paramères pas bon alors que le userSettings lui sera conservé modifié avec les mises à jour!!

    OteloProcess.Start();

    label2.Text = "... Ok, OteloClient lancé!";

    timerShutDown.Start();

    this.ShowInTaskbar = false;

    this.Hide();

    }

     

     

    Bien sur si quelqu'un a des commentaires sur le code ils sont les bienvenues !!! je dis pas que je fais tout nickel Wink

    A+,

          Stéphane

     

    vendredi 1 août 2008 08:49
  • Merci beaucoup Stephane pour ce code.

     

    Il m'est utile, en particulier parce qu'il montre l'accès à plusieurs variables d'environnement, à l'enregistrement d'assembly et aux Properties.Settings. Autant de chose que je n'utilise pas encore.

     

    Je ne vois rien à y redire. Je l'essayerai prochainement et te ferai des commentaires si nécessaire.

     Quoi que : tel que tu l'as prévu, la copie de appref-ms vers Desktop et QuickLaunch est réalisée à chaque lancement de l'appli. Le faire sur IsFirstRun seulement serait peut-être suffisant ?

     

    Je travaille en VB.Net, je verrai si ton code est compatible.

     

    Merci encore.

    Bonne journée.

     

    Bien cordialement.

     

    vendredi 1 août 2008 13:11
  •  AchLog A écrit:

     Quoi que : tel que tu l'as prévu, la copie de appref-ms vers Desktop et QuickLaunch est réalisée à chaque lancement de l'appli. Le faire sur IsFirstRun seulement serait peut-être suffisant ?

    Salut,

      Oui en effet c'est suffisant ! Wink juste que les gens ici préférent être sur que si la personne supprime un des liens que ce dernier revienne au relancement pour éviter les appels au HelpDesk style "je n'ai plus le liens dans la tite barre en bas Crying "

      Mais oui sur IsFirstRun c'est largement suffisant ! et j'ai laissé volontairement les petites choses en plus histoire que tu gagnes un peu de temps car en général ces questions arrivent pas longtemps aprés ta question initiale :-)

     

      A+ et bon testing Big Smile

           Stéphane

     

    PS: penses a nous tenir au courant si ca a marché !

    vendredi 1 août 2008 14:07
  • Merci,

    Promis, je te tiens au courant si ça a marché (ou non).

    A+

     

    vendredi 1 août 2008 14:21
  • Déjà !

     

    Code Snippet

    SourceAppRef = SourceAppRef.EndsWith(@"\") ? SourceAppRef + @"Programs\Holcim\OteloClient.appref-ms" : SourceAppRef + @"\Programs\Holcim\OteloClient.appref-ms";

     

     

    Si c'est sous Vista, ça va ; Mais sous XP le répertoire programmes est "Programmes".

    Testes-tu l'OS ajuster cette instruction ?

     

    Merci

     

    vendredi 1 août 2008 15:07
  • re Wink

    regarde la ligne juste au dessus du morceau choisi :

    Code Snippet

    string SourceAppRef = Environment.GetFolderPath(Environment.SpecialFolder.StartMenu);

     

     

    StartMenu : le menu démarré...

    Je ne test pas l'OS non.

    Les applications clickonce ne s'installe pas dans "Program Files" mais dans un répertoire bizaroide dans "documents and settings".

    Je ne fais que copier le shortcut du menu démarré généré en automatique par le déploiement clickonce vers le bureau et la quicklaunch.

    2 choses :

    - Programs\Holcim\OteloClient = Programs\Nom Editeur\Nom Appli

    - L'appli est déployé sur des système XP anglais (avec patch MUI pour le french), aussi bien toi ce ne sera pas "Programs" mais "Programmes" Smile essaye d'ouvrir sur ton ordi le dossier que tu as dans SourceAppRef juste aprés la ligne que je t'ai mise histoire de voir sur ta machine la bonne structure ^^ l'idéal je suppose serait de checké la langue mais n'ayant pas de XP French ici je ne l'ai pas fait Wink

    A+,

         Stéphane

     

    PS: je serai pas trop la du weekend mais je pense passer quand même faire un coucou Big Smile

    vendredi 1 août 2008 15:38
  • Essai de publication ClickOnce et d'installation : Ok, l'appli se charge et s'exécute. J'ai même récupéré l'information "FisrtRun".

    Mais le répertoire "....Menu Démarrer/Programmes/editeur" ne contient qu'un lien vers l'application. Pas de ".appref-ms" !

     

    J'ai oublié quelque chose ?

    vendredi 1 août 2008 15:48
  • Oui, oui, j'ai bien compris qu'il s'agit de pointer sur le répertoire qui contient ls programmes dans le StartMenu.

    Je voulais seulement faire remarquer que ce répertoire porte des noms différents en fonction de l'OS ou de la langue, comme tu le dis toi-même.

     

    Il faudrait s'affranchir de cela.

     

    Merci et bon WE

    vendredi 1 août 2008 15:53
  • Mais oui, ça marche parfaitement !

    J'avais comis une petite erreur (évidement) dans mon code.

    Voici en VB.NET

     

    Code Snippet

    Private AppRac = "TestCO1.appref-ms"

     

    Private Sub InstalleRaccourcis()

    '--- Installation des raccourcis ---

    Dim SourceAppRef = Environment.GetFolderPath(Environment.SpecialFolder.StartMenu)

    If Not SourceAppRef.EndsWith("\") Then SourceAppRef += "\"

    SourceAppRef += "Programmes\<éditeur>\" + AppRac

     

    Dim Desktop = Environment.GetFolderPath(System.Environment.SpecialFolder.DesktopDirectory)

    If Not Desktop.EndsWith("\") Then Desktop += "\"

    Desktop += AppRac

     

    Dim QuickLaunch = System.IO.Path.Combine(Environment.GetFolderPath(System.Environment.SpecialFolder.ApplicationData), "Microsoft\Internet Explorer\Quick Launch\")

    If Not QuickLaunch.EndsWith("\") Then QuickLaunch += "\"

    QuickLaunch += AppRac

     

    Try

    System.IO.File.Copy(SourceAppRef, Desktop, True)

    System.IO.File.Copy(SourceAppRef, QuickLaunch, True)

    Catch ex As Exception

    End Try

    End Sub

     

     

     

    Merci encore et bon WE

    Bien cordialement

    vendredi 1 août 2008 16:22
  • J'ai un doute sur "Properties.Settings"

    A quel NameSpace se rapporte t'il ?

    Idem pour SelectSite !

     

    vendredi 1 août 2008 16:55
  •  

    Salut,

      Désolé gros weekend bien chargé je n'ai finalement pas eu le temps de passer Wink

      Pour Properties.Settings : il s'agit d'un truc généré tout seul par VS : va dans les propriétés de ton projet et cherche "Settings"...Tu peux en créer de plusieurs type (Application, User ; string, int, ...). Tu verras qu'aprés en avoir créé tu auras dans ton code accés a ces "Settings" par Properties.Settings.Default.MonSetting (de souvenir).

      Pour SelectSite c'est un winform tout béte que j'ai créé qui demande a l'utilisateur de quel site géographique il dépend (requête dans une base de donnée centrale pour avoir la liste des sites "en production" et d'autres paramètres du site pour permettre a la personne de choisir le bon Wink )

      ++,

            Stéphane

    dimanche 3 août 2008 19:46
  • Bonjour,

     

    Merci beaucoup pour toutes tes bonnes infos.

    Bien cordialement

    A++

     

    lundi 4 août 2008 17:22