Cirec
Messages postés3833Date d'inscriptionvendredi 23 juillet 2004StatutModérateurDernière intervention18 septembre 202250 30 janv. 2007 à 13:37
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
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;
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.
florenth
Messages postés1023Date d'inscriptiondimanche 1 août 2004StatutMembreDernière intervention17 août 20083 31 janv. 2007 à 14:10
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.
florenth
Messages postés1023Date d'inscriptiondimanche 1 août 2004StatutMembreDernière intervention17 août 20083 31 janv. 2007 à 16:53
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
Vous n’avez pas trouvé la réponse que vous recherchez ?
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
Cirec
Messages postés3833Date d'inscriptionvendredi 23 juillet 2004StatutModérateurDernière intervention18 septembre 202250 1 févr. 2007 à 17:48
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;
cs_Loda
Messages postés814Date d'inscriptionvendredi 3 novembre 2000StatutMembreDernière intervention30 juillet 20093 30 janv. 2007 à 11:22
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.
obitskater
Messages postés45Date d'inscriptionlundi 29 janvier 2007StatutMembreDernière intervention13 mars 2009 30 janv. 2007 à 12:03
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)
obitskater
Messages postés45Date d'inscriptionlundi 29 janvier 2007StatutMembreDernière intervention13 mars 2009 30 janv. 2007 à 13:22
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 !!!
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...
obitskater
Messages postés45Date d'inscriptionlundi 29 janvier 2007StatutMembreDernière intervention13 mars 2009 30 janv. 2007 à 17:15
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:
Cirec
Messages postés3833Date d'inscriptionvendredi 23 juillet 2004StatutModérateurDernière intervention18 septembre 202250 30 janv. 2007 à 19:54
@ 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;
obitskater
Messages postés45Date d'inscriptionlundi 29 janvier 2007StatutMembreDernière intervention13 mars 2009 31 janv. 2007 à 12:42
@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à!!!
obitskater
Messages postés45Date d'inscriptionlundi 29 janvier 2007StatutMembreDernière intervention13 mars 2009 31 janv. 2007 à 14:20
Trés bien je te remercie, là ça va mieux, pfiou....
Reste plus qu'à attendre que delphi.developpez.com/ remarche (car inaccessible pour le moment) pour voir les explications de CreateProcess et je pourrais tester tout ça.
En attendant je me balade sur delphi3000.com voir ce qu'il propose sur le CreateProcess.