Bar de progression lors de l'installation d'un MSI [Résolu]

obitskater 45 Messages postés lundi 29 janvier 2007Date d'inscription 13 mars 2009 Dernière intervention - 30 janv. 2007 à 11:15 - Dernière réponse : obitskater 45 Messages postés lundi 29 janvier 2007Date d'inscription 13 mars 2009 Dernière intervention
- 2 févr. 2007 à 11:19
Bonjour à tous, c'est mon premier post ici...


Voilà ma question, je suis en train de réaliser un setup avec plusieurs
pages: bienvenue, saisie d'information, acceptation de licence, etc...

Puis ma derniere doit representer une bar de progression qui tourne
jusqu'à ce que l'installation du .msi qui va avec soit terminée.

Pour executer le .msi je passe une execution de console comme dans cmd avec la commande msiexec, la ça marche!


Mon soucis est je ne sais pas trop comment réaliser cette bar de
progression qui tourne jusqu'à ce que l'installation soit terminée...


Pouvez vous s'il vous plait m'indiquer la marche à suivre, ou me dirigez vers des liens qui pourraient m'aider.

Merci d'avance.
Afficher la suite 

Votre réponse

41 réponses

Meilleure réponse
Cirec 4231 Messages postés vendredi 23 juillet 2004Date d'inscription 3 août 2018 Dernière intervention - 30 janv. 2007 à 13:37
3
Merci
en fait pour que ça fonctionne il faut impérativement avoir le paramètre "/c"  et pas le /k je me suis planté sur ce coup la

Ici tu démares ta ProbressBar
ShellExecute(Handle, Nil, 'CMD' , '/c "start /wait Ici le nom du prog a lancer"', Nil , SW_HIDE);
Ici tu la termines

donc tu lance la ProgressBar ensuite la commande
et grâce au paramètres '/c "start /wait
la ligne suivante ne sera pas executé avant la fin de la commande
tout simplement

 
@+
Cirec

<hr size="2" />

Merci Cirec 3

Avec quelques mots c'est encore mieux Ajouter un commentaire

Codes Sources a aidé 93 internautes ce mois-ci

Commenter la réponse de Cirec
Meilleure réponse
florenth 1105 Messages postés dimanche 1 août 2004Date d'inscription 17 août 2008 Dernière intervention - 30 janv. 2007 à 17:56
3
Merci
Salut,

Déjà, bienvenue sur Codes-Sources !

Pour ton problème de CreateProcess(), tu en as un très bon exemple ici (http://delphi.developpez.com/faq/?page=interexecution#lancercontroleapplication) qui fait justement ce que tu veux: attendre la fin d'execution du programme.

Après, pour avoir une progressbar qui "tourne en rond", Windows propose déjà une façon très simple de le faire, mais malheureusement, Delphi ne le gère pas nativement, il va falloir ajouter cette fonctionnalité.

Explications:
Tu crée une nouvelle unité contenant :
-------------------------------
unit NewProgressBar;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ComCtrls, ExtCtrls;

type
TProgressBar = class(ComCtrls.TProgressBar)
public
procedure CreateParams(var Params: TCreateParams); override;
procedure BeginAnim(Delay: Integer);
procedure StopAnim;
end;

implementation

const
PBS_MARQUEE = $08;
PBM_SETMARQUEE = WM_USER + 10;

procedure TProgressBar.CreateParams(var Params: TCreateParams);
begin
inherited CreateParams(Params);
Params.Style := Params.Style or PBS_MARQUEE;
end;

procedure TProgressBar.BeginAnim(Delay: Integer);
begin
SendMessage(Handle, PBM_SETMARQUEE, 1, Delay);
end;

procedure TProgressBar.StopAnim;
begin
SendMessage(Handle, PBM_SETMARQUEE, 0, 0);
end;
-------------------------------

Cette unité te parmet d'ajouter en RunTime la fonctionnalité que tu recherches. (Attention: elle doit être la DERNIERE unité de ta clause uses ET dans la partie interface)

Tu appelles ProgressB.BeginAnim(200) après avoir executé CreateProcess() et ProgressB.StopAnim() après que le .msi se soit executé pour stopper l'animation.

Voila, j'èspère avoir été clair.
A+
Flo

Merci florenth 3

Avec quelques mots c'est encore mieux Ajouter un commentaire

Codes Sources a aidé 93 internautes ce mois-ci

Commenter la réponse de florenth
Meilleure réponse
florenth 1105 Messages postés dimanche 1 août 2004Date d'inscription 17 août 2008 Dernière intervention - 31 janv. 2007 à 14:10
3
Merci
Salut,

Déjà, il faut savoir que ce "truc" pour coder une progressbar spéciale est une actuce pour rajouter des fonctionalités dans Delphi. En *RunTime* signifie qu'il n'y a aucun changement en conception (lorsque tu ajoutes et modifies les composants de ta fiche): la seule différence est à l'execution. Mais à la limite, ce n'est pas le plus important.

Alors ensuite, pour placer ton code: tout dépend comment tu organises cela.
Si ta fiche n°4 (celle de scr4.pas) ne sert qu'a afficher l'avancement, tu mets ProgressB.BeginAnim(200) dans le OnShow de la fiche et ProgressB.StopAnim dans le OnHide (évenements accessibles depuis l'éditeur de propriétés par double click dessus). "ProgressB" étant un TProgressBar dans la fiche Form4.

Après, dans main1.pas, à l'endroit voulu:
- tu appelles scr4.Form4.Show()
- tu effectues ton CreateProcess() et tu attends la fin de l'exécution de l'application (voir lien que je t'ai donné sur la FAQ Delphi)
- et enfin, tu appelles scr4.Form4.Hide pour arreter l'animation.

L'unité "NewProgressBar" doit être ajoutée en fin des uses de l'unité qui contient la fiche qui contient la ProgressBar, évidemment.

Voila ! Bonne chance !

Merci florenth 3

Avec quelques mots c'est encore mieux Ajouter un commentaire

Codes Sources a aidé 93 internautes ce mois-ci

Commenter la réponse de florenth
Meilleure réponse
Cirec 4231 Messages postés vendredi 23 juillet 2004Date d'inscription 3 août 2018 Dernière intervention - 31 janv. 2007 à 14:47
3
Merci
XPManifest est un composant    qui te permet d'avoir le thème XP dans ton application
mais n'est disponible qu'a partir de la version 7 de Delphi

si tu dispose d'une version antérieur de Delphi

regarde ici :
http://www.delphifr.com/codes/AVOIR-CONTROLES-AVEC-STYLE-WINDOWS-XP_11844.aspx

 
@+
Cirec

<hr size="2" />

Merci Cirec 3

Avec quelques mots c'est encore mieux Ajouter un commentaire

Codes Sources a aidé 93 internautes ce mois-ci

Commenter la réponse de Cirec
Meilleure réponse
florenth 1105 Messages postés dimanche 1 août 2004Date d'inscription 17 août 2008 Dernière intervention - 31 janv. 2007 à 16:53
3
Merci
hmmmm, bon code, c'est bien ce que je t'avais dit ...
Par contre, j'avais soublié un truc: en faisant WaitForSingleObject(), tu freeze l'application, c'est donc normal que rien ne s'affiche.

Il faut changer cela et appeler Application.ProcessMessages régulièrement (toutes les 100 ms).

Il faut donc que tu remplaces WaitForSingleObject(proc_info.hProcess, INFINITE) par un bout de code un peu plus long (nécéssite "Forms" dans les "uses"):

-----------
while True do
begin
Application.ProcessMessages;
if WaitForSingleObject(proc_info.hProcess, 100) <> WAIT_TIMEOUT then
Break;
end;
----------

Et là, ça devrait marcher. Le reste me semble tout à fait correct.

Une autre solution consisterait à ne plus utiliser WaitForSingleObject mais un timer qui teste périodiquement si l'application est en cours mais dans ton cas, comme tu n'as pas l'air de devoir pouvoir abandonner l'execution, ç'est OK.

A+
Flo

Merci florenth 3

Avec quelques mots c'est encore mieux Ajouter un commentaire

Codes Sources a aidé 93 internautes ce mois-ci

Commenter la réponse de florenth
Meilleure réponse
Cirec 4231 Messages postés vendredi 23 juillet 2004Date d'inscription 3 août 2018 Dernière intervention - 31 janv. 2007 à 17:27
3
Merci
je confirme un seul appel à Application.ProcessMessages ne suffit pas

il faut donc utiliser la dernière méthode de Florenth et la ça fonctionne parfaitement
 
@+
Cirec

<hr size="2" />

Merci Cirec 3

Avec quelques mots c'est encore mieux Ajouter un commentaire

Codes Sources a aidé 93 internautes ce mois-ci

Commenter la réponse de Cirec
Meilleure réponse
Cirec 4231 Messages postés vendredi 23 juillet 2004Date d'inscription 3 août 2018 Dernière intervention - 31 janv. 2007 à 18:56
3
Merci
le code fonctionne aussi bien avec un XPManifest qu'avec la ressource

 
@+
Cirec

<hr size="2" />

Merci Cirec 3

Avec quelques mots c'est encore mieux Ajouter un commentaire

Codes Sources a aidé 93 internautes ce mois-ci

Commenter la réponse de Cirec
Meilleure réponse
florenth 1105 Messages postés dimanche 1 août 2004Date d'inscription 17 août 2008 Dernière intervention - 31 janv. 2007 à 21:01
3
Merci
Et voila !
A chose promise, chose due.

Sources :
- New ProgressBar : http://www.delphifr.com/code.aspx?ID=41328
- Attendre programme : http://www.delphifr.com/code.aspx?ID=41329

Avec ça, tu devrais t'en sortir ...

Pas facile quand même comme truc, j'aurais jamais cru que cela aurait été si compliqué ...

Merci florenth 3

Avec quelques mots c'est encore mieux Ajouter un commentaire

Codes Sources a aidé 93 internautes ce mois-ci

Commenter la réponse de florenth
Meilleure réponse
obitskater 45 Messages postés lundi 29 janvier 2007Date d'inscription 13 mars 2009 Dernière intervention - 1 févr. 2007 à 17:11
3
Merci
Bon j'ai résolu mon probléme, j'indique la marche à suivre que j'ai suivi au cas où certains rencontrent le même probleme que moi.

Donc dans ma procedure qui execute le processus grâce à createprocess nous avons :

aCmdLine := PChar('cmd /c "start /wait '+Variables.Values['run']); // aCmdLine de type PChar

// ainsi c'est comme si j'executais dans démarrer/executer cmd /c "la ligne de commande"

// et le createProcess ressemble donc par la suite à ça :

CreateProcess(Nil, aCmdLine, Nil, Nil, False, 0, Nil, Nil, StartInfo,Proc_Info)

//*********************************

Voilà bon merci en tout cas à Florenth et Cirec pour l'aide que vous m'avez apporté, c'est génial un grand MERCI à tous les deux !!!!
Pfiou tout marche (pour le moment), j'ai cru que je n'en verrais jamais le bout!!!

PS: au cas où vous sauriez comment masquer (ou même cacher à l'utilisateur) la fenetre cmd toute vide qui s'ouvre lors de l'execution de ma ligne de commande, je suis preneur!!!  Encore merci

Merci obitskater 3

Avec quelques mots c'est encore mieux Ajouter un commentaire

Codes Sources a aidé 93 internautes ce mois-ci

Commenter la réponse de obitskater
Meilleure réponse
Cirec 4231 Messages postés vendredi 23 juillet 2004Date d'inscription 3 août 2018 Dernière intervention - 1 févr. 2007 à 17:48
3
Merci
donc sur le même principe avec CreateProcess

pour l'exemple je démarre la calculatrice par l'intermédiaire de CMD
procedure TForm1.Button1Click(Sender: TObject);
var
Si :STARTUPINFO;
Pi : PROCESS_INFORMATION    ;
begin
  zeromemory(@si,sizeof(STARTUPINFO));
// les deux lignes suivantes empêche de voir la fenêtre dos
  Si.dwFlags:= STARTF_USESHOWWINDOW;
  Si.wShowWindow:=SW_HIDE;
// Attention le paramètre /c est indispensable c'est grâce à lui que CMD se referme après l'utilisation

//de la calculatrice ou tout autre commande
  If CreateProcess(Nil,'cmd /c "start /wait %systemroot%\System32\calc.exe"',nil,nil,True, 0,nil,nil,Si,Pi) Then
  Begin
    while True do
    begin
      Application.ProcessMessages;
      if WaitForSingleObject(pi.hProcess, 100) <> WAIT_TIMEOUT then
        Break;
    end;
    CloseHandle(pi.hProcess);
  End;
end;
 
@+
Cirec

<hr size ="2" />

Merci Cirec 3

Avec quelques mots c'est encore mieux Ajouter un commentaire

Codes Sources a aidé 93 internautes ce mois-ci

Commenter la réponse de Cirec
cs_Loda 900 Messages postés vendredi 3 novembre 2000Date d'inscription 30 juillet 2009 Dernière intervention - 30 janv. 2007 à 11:22
0
Merci
salut,

bienvenue sur delphifr - Codes-Sources !

Pour ton problème, je pense pas que tu puisse faire un bar de progression qui indique l'avancement (%) de ton install si l'installation elle-même est faite par un programm tier (msiexec).

Tu peux "tricher" en faissant une bar de progression qui tourne en boucle (comme au démarrage de certain version de windows). ou juste afficher une animation image par image (gif), genre indiquant que le programme est pas planté.

Mais pour avoir une bar indiquant le % restant, je pense pas que cela soit possible si tu lance msiexec. Peut-être qqun d'autre personne aurront une solution magique pour toi...

bonne continuation,

Loda

PS: un très bon (et gratuit) installer : inno setup

<hr size="2" width="100%" />Se poser les bonnes questions est le premier pas pour trouver les bonnes réponses.
Commenter la réponse de cs_Loda
obitskater 45 Messages postés lundi 29 janvier 2007Date d'inscription 13 mars 2009 Dernière intervention - 30 janv. 2007 à 12:03
0
Merci
Oui en effet je ne cherche pas à realiser une progress bar qui indique le pourcentage de l'installation, mais plutot comme tu l'as dit une barre qui tourne en boucle jusqu'à ce que l'installation soit finie.

Mais comment savoir que l'installation est finie, et quand est ce qu'elle part pour démarrer la progressbar??? Là est mon gros probleme (ainsi que faire la progress bar qui tourne indéfiniment, je sais pas faire :s)

Désolé si je n'ai pas était plus clair.
Commenter la réponse de obitskater
Cirec 4231 Messages postés vendredi 23 juillet 2004Date d'inscription 3 août 2018 Dernière intervention - 30 janv. 2007 à 13:08
0
Merci
Salut,

si tu lances, comme tu dis, ton msiexec par l'intermédiaire de CMD tu en connais le point de départ

ensuite CMD te permet également de savoir quand l'éxecution est arrivé à son terme avec le paramètre /k

voir ici pour plus d'information : http://www.delphifr.com/codes/EXECUTER-TOUTES-COMMANDES-DOS-AUTRES-FACILEMENT-SANS-PROBLEMES_34484.aspx

sinon tu peux aussi utiliser un CreateProcess et en attendre la fin avec WaitForSingleObject / INFINITE

 
@+
Cirec

<hr size="2" />
Commenter la réponse de Cirec
obitskater 45 Messages postés lundi 29 janvier 2007Date d'inscription 13 mars 2009 Dernière intervention - 30 janv. 2007 à 13:22
0
Merci
Justement, Cirec, je mettais servi de ton code source, qui en passant est trés bien fait chapeau bas :D.
Je l'ai adapté à mon code.

En fait j'extrais la commande à executer dans un .ini que je stock dans une chaine de caractère "run". Cette ligne ressemble à ça :
msiexec /I Agent.msi /qn ...

Puis dans mon code (quand j'arrive au form avec la progress bar) je met :

aCmdLine := PChar(cmdSwitch + run); // aCmdLine étant de type PChar
ShellExecute(Handle, nil, 'CMD', aCmdLine, nil, sw_Hide);

Je n'ai pas encore testé mais ça devrait marché...

Ma question maintenant est que je devrais connaître mon point de départ de mon msiexec (comme tu me la signalé), or je n'en ai aucune idée...:s
Par ailleurs tu dis que CMD me permet également de savoir quand l'éxecution est arrivé à son terme, et ça je ne sais pas comment le savoir...

Désolé de vous embetter mais là je bloque depuis ce matin !!!
Commenter la réponse de obitskater
obitskater 45 Messages postés lundi 29 janvier 2007Date d'inscription 13 mars 2009 Dernière intervention - 30 janv. 2007 à 13:42
0
Merci
Ok merci bien, je m'en va essayer tout de suite!
Commenter la réponse de obitskater
obitskater 45 Messages postés lundi 29 janvier 2007Date d'inscription 13 mars 2009 Dernière intervention - 30 janv. 2007 à 16:58
0
Merci
Bon... J'ai un nouveau probleme!

Ta commande ShellExecute marche niquel... Mais le soucis est que pour appeler ma page je fais:

scr4.show // scr4 étant le nom de la page où il y a la progressbar

labelscr4:
     scr4.progressbar1.Position:=0;
     scr4.timer1.Enabled:=true;

     aCmdLine := PChar('/c "start /wait '+Variables.Values['run']); //Variables.Values['run'] renvoie la ligne de commande msiexec avec les parametres nécessaires.

     with scr4 do
     begin
        progressbar1.Position:=progressbar1.Position+1;;//mise à jour toutes les secondes en 5 secondes
        timer1.Enabled:=true;

        ShellExecute(Handle, Nil, 'CMD' , aCmdLine, Nil , SW_HIDE);
        if progressbar1.Position>= progressbar1.max  then timer1.Enabled:=false;// on arrete le timer à la fin
    end;
ShowMessage('ok!');

Donc deja comme vous pouvez le constater je ne SAIS PAS faire tourner la progressbar en boucle, et le msi s'execute ailleurs, ce qui fait que je vais direct au ShowMessage('ok!'); donc la progressbar n'a pas le temps de tourner en boucle...

C'est la galère....
Commenter la réponse de obitskater
obitskater 45 Messages postés lundi 29 janvier 2007Date d'inscription 13 mars 2009 Dernière intervention - 30 janv. 2007 à 17:15
0
Merci
Bon puisque l'execmsi se lance dans un nouveau processus et que je doit attendre qu'il se finisse, peut être que je vais passer par un createprocess pour pouvoir attendre la fin et ainsi arréter la progressbar.

Mais je ne sais toujours pas comment faire tourner la progressbar indéfiniment, et j'hésite pour utiliser le createprocess car il faut que je passe des infos lorsque j'execute le msi, je m'explique par un exemple, la ligne de commande que je doit rentrer ressemble à ça:

msiexec /I AgentSetup.msi /qn FIRSTBACKUP=0 EMAILADRESS=%UserMail% PSWD=%UserPassword%

Or je ne sais pas s'il est possible de passer FIRSTBACKUP / EMAILADRESS / PSWD avec un createprocess... Si oui comment on fait siouplé...????
Commenter la réponse de obitskater
florenth 1105 Messages postés dimanche 1 août 2004Date d'inscription 17 août 2008 Dernière intervention - 30 janv. 2007 à 17:57
0
Merci
Ah, un détail cependant: sous Windows XP et Vista uniquement. Il me semble pas que cela fonctionne sous un autre NT.

A+
Commenter la réponse de florenth
Cirec 4231 Messages postés vendredi 23 juillet 2004Date d'inscription 3 août 2018 Dernière intervention - 30 janv. 2007 à 19:54
0
Merci
@ Florenth : chouette cette astuce .. encore une que ne connaissais pas

Mais j'ai remarqué que ce code ne fonctionne qu'avec un XPManifest

@ ObitSkater :  ton problème d'affichage viens d'un mauvais  "placement" de ton code 

la mise à jour de ta PBar devrait se trouver dans l'évennement OnTimer dans la Form4
dans le OnShow de la Form4 tu mets Timer1.Enabled := True;
et dans le OnHide : Timer1.Enabled := False;

Ensuite tu fais l'appel depuis ta form principale

aCmdLine := PChar('/c "start /wait '+Variables.Values['run']);
Scr4.Show;
Application.ProcessMessages;
ShellExecute(Handle, Nil, 'CMD' , aCmdLine, Nil , SW_HIDE);
Src4.Hide;

Mais la solution du CreateProcess est quand même meilleur
 
@+
Cirec

<hr size="2" />
Commenter la réponse de Cirec
obitskater 45 Messages postés lundi 29 janvier 2007Date d'inscription 13 mars 2009 Dernière intervention - 31 janv. 2007 à 12:42
0
Merci
@Flo : Merci bien pour ton aide, ce code a l'air trés bien, mais il y a quelques points sur lesquels je bloque...
J'ai créé cette nouvelle unité NewProgressBar (comme tu m'as dit), mais je ne sais pas vraiment à quel endroit faire les appels. Je m'explique, Toutes mes forms sont créées, mais il m'a était demandé de mettre tout le code dans une unité indépendante : main1.pas, dans lequel je fais les appels successifs de chaque form.

Ma Progress Bar se trouve (comme précisé plus haut) dans le 4° form : scr4. Ainsi je compte, lors de l'appel de scr4 (par un scr4.Show) dans main1.pas faire mon create process, et je souhaite faire les appels nécessaires à ton unité à ce moment là.
Mais je ne sais pas si je dois faire ces appels dans main1.pas OU le form scr4 ???

Par ailleurs je ne vois pas trop comment bien "syntaxer" ces appels. Tu me dis d'appeler comme ceci: ProgressB.BeginAnim(200) par exemple, mais est ce que ProgressB correspond au nom de la progress bar de scr4??? Donc suivant où je dois faire mes appels, pourrais tu m'indiquer la bonne syntaxe que je dois adopter s'il te plaît.

Par ailleurs tu me parles de RunTime et ceci est un peu (voir beaucoup :p) flou pour moi (j'ai commencé le delphi il y a un mois dans le cadre de mon stage). Pourrais tu également s'il te plait m'éclairer à ce sujet.

De plus tu me dis que l'unité NewProgressBar doit être la DERNIERE unité de ta clause uses ET dans la partie interface, mais dans quel .pas??? Main.pas ou scr4???????

je tourne en rond j'en peu plus :'(

En tout cas merci énormément à tous pour l'aide que vous m'avez apporté jusque là!!!
Commenter la réponse de obitskater

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.