Excel sans attendre la fin

Résolu
cs_Ptinico Messages postés 4 Date d'inscription vendredi 20 décembre 2002 Statut Membre Dernière intervention 31 mai 2007 - 3 mai 2007 à 21:03
cs_Ptinico Messages postés 4 Date d'inscription vendredi 20 décembre 2002 Statut Membre Dernière intervention 31 mai 2007 - 4 mai 2007 à 21:40
Salut,
Question toute bête :
- J'ai un fichier Excel ouvert contenant un macro déclenchée par un "Worksheet_SelectionChange"
- Depuis Delphi, je me connecte au fichier Excel ouvert (par OLE), je remplis la case qui va bien, puis je selectionne une autre case. Ca force donc le "Worksheet_SelectionChange" de Excel.
Par contre, je veux conserver la main sur mon application Delphi, sans attendre la fin de l'éxecution de la macro Excel....

Qq'un a une idée ? J'ai essayé les thread, mais le "GetActiveOleObject" ne semble pas fonctionner dans un thread !!
Merci d'avance.

6 réponses

florenth Messages postés 1023 Date d'inscription dimanche 1 août 2004 Statut Membre Dernière intervention 17 août 2008 2
4 mai 2007 à 13:33
Salut à tous

@Cari: il est possible d'utiliser OLE dans un thread. Il faut juste faire attention à plusieurs trucs:
- Si tu utilises le type TThread de Delphi, il faut absolument tout faire dans le méthode Execute() car c'est la seule qui est réellement threadée (donc, tu ne peux pas initialiser OLE dans le constructeur et l'utiliser dans Execute()).

- Ensuite, il ne faut pas oublier d'initialiser OLE et de le libérer DANS ce même thread (Delphi le fait par défaut dans le thread principal mais pas dans les autres)

- Donc, appel de CoInitialize(nil) au début et CoUnInitialize() à la fin.

- Donc, bien sûr, Variants, ActiveX et ComObj dans les uses.

- Et ensuite, tout fonctionne ! Faire gaffe à ne pas utiliser la même instance dans un autre thread, ça plante sinon ...

- Préférer CreateOLEObject('Excel.Application') plutôt que GetActiveOLEObject().

++
Flo
3
florenth Messages postés 1023 Date d'inscription dimanche 1 août 2004 Statut Membre Dernière intervention 17 août 2008 2
4 mai 2007 à 19:50
Oui ça a l'air correct car j'ai du mal à lire à cause de la mise en page ...
Par contre, pourquoi faire cela :

<hr size="2" width="100%" />// --- Connexion à Excel ---
thExcel1:=GetActiveOleObject('Excel.Application');
thEXCEL:=Unassigned;
thExcel1:=Unassigned;
thEXCEL:=GetActiveOleObject('Excel.Application');

<hr size="2" width="100%" />
Tu t'embettes pour rien. autant directement faire thEXCEL:=GetActiveOleObject('Excel.Application');sans le reste, non !
3
Caribensila Messages postés 2527 Date d'inscription jeudi 15 janvier 2004 Statut Membre Dernière intervention 16 octobre 2019 18
3 mai 2007 à 22:56
Salut!
Je crois que tu es mal barré, là.


L'idée de OLE est qu'une application en contienne une autre.
C'est une technique qui permet d'inclure dans ton application un document d'une autre application.


Mais, à ma connaissance, y'a pas de

threading possible.




Ton idée d'utilser un

thread secondaire me semble prouver que
ton problème, si j'ai bien compris, c'est plutôt un problème de multitâche...



Moi, perso, j'abandonnerais l'idée d'OLE et je lancerais les deux applications séparément. Ce qui revient à dire 2 processus ou 2 threads (Problème du multitâche résolu).

Ensuite, il suffira de les faire communiquer.

Et y'a plein de techniques pour ça dont tu trouveras les exemples ici.
0
jelume Messages postés 120 Date d'inscription mardi 3 avril 2007 Statut Membre Dernière intervention 15 novembre 2007 1
4 mai 2007 à 12:39
Bonjour

Ne serait-il pas possible d'envoyer une message à Excel par un sendmessage par exemple ? Juste pour le forcer à un refresh ?

J-L
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
cs_Ptinico Messages postés 4 Date d'inscription vendredi 20 décembre 2002 Statut Membre Dernière intervention 31 mai 2007
4 mai 2007 à 19:25
Flo, t'es un chef. Merci vraiment !
J'y étais presque, manquait que le CoInitialize et le CoUnInitialize. J'avais déjà remarqué que dans les DLL les librairies COM n'étaient pas forcément initialisées correctement.

Voilà mon unité du thread. Pour info, même le GetActiveOleObject fonctionne !


unit XlsSendWeightThreadUnit;


interface


uses


Classes, Variants, ComObj, IniFiles, SysUtils, ActiveX;


type


TXlsSendWeight = class(TThread)


private


{ Déclarations privées }


thMessage, thCfgFile : string;


thNewWeight : double;


procedure EcritMessage;


protected


procedure Execute; override;


public


constructor Create(dWeight : double; sCfgFile : string); overload;


end;


implementation


uses MainForm;


constructor TXlsSendWeight.Create(dWeight : double; sCfgFile : string);


begin


inherited Create(true);


// Initialisation des variables de poids et fichier de config


thCfgFile:=sCfgFile;


thNewWeight:=dWeight;


FreeOnTerminate := True;


end;


procedure TXlsSendWeight.EcritMessage;


begin


frmMain.ReProgramme.Lines.Add(thMessage);


end;


procedure TXlsSendWeight.Execute;


Var thEXCEL, thExcel1 : variant;


thWorkBook, thSheet : variant;


thFicIni : TIniFile;


i, index, iCellRow, iCellCol : integer;


s, sSheetName : string;


begin


// Initialisation libraire COM => manuelle car dans thread


CoInitialize(nil);


try


try


// --- Connexion à Excel ---


thExcel1:=GetActiveOleObject('Excel.Application');


thEXCEL:=Unassigned;


thExcel1:=Unassigned;


thEXCEL:=GetActiveOleObject('Excel.Application');


//thEXCEL.visible:=TRUE;


// --- Lecture des paramètres dans le fichier INI ---


If not FileExists(thCfgFile) then begin


thMessage:='Fichier de config inexistant (' + thCfgFile + ')...';


Synchronize(EcritMessage);


Exit;


end;


thFicIni:=TIniFile.Create(s);


try


sSheetName:=thFicIni.ReadString('Excel', 'NvPds_feuille', 'reglage');


iCellRow:=thFicIni.ReadInteger('Excel', 'NvPds_ligne', 21);


iCellCol:=thFicIni.ReadInteger('Excel', 'NvPds_colonne', 5);


finally


thFicIni.free;


end;


// --- Recherche de la feuille sSheetName dans Excel ---


thWorkBook:=thEXCEL.ActiveWorkBook;


index:=-1;


For i:=1 to thWorkBook.WorkSheets.Count do begin


s:=UpperCase(thWorkBook.WorkSheets.Item[i].Name);


If s = UpperCase(sSheetName) then index:=i;


end;


// --- Ecriture du poids ---


If index>-1 then begin


thWorkBook.WorkSheets.Item[index].Activate;


thSheet:=thEXCEL.ActiveSheet;


thSheet.Cells[iCellRow, iCellCol]:=thNewWeight;


thMessage:=Format('Poids transmis à Excel : %0.3f. Création du ' +


'du fichier d''échange avec la presse', [thNewWeight]);


Synchronize(EcritMessage);


// On force le "Worksheet_SelectionChange" sous Excel => prend du


// temps, d'où ce thread séparé


thSheet.Cells[iCellRow+1, iCellCol].Select;


end


else begin


thMessage:='Feuille ' + sSheetName + ' introuvable !';


Synchronize(EcritMessage);


Exit;


end;


except


thMessage:='Erreur dans l''écriture du poids sous Excel';


Synchronize(EcritMessage);


end;


finally


thEXCEL:=Unassigned;


CoUnInitialize; //Fermeture librairie COM


end;


end;


end.
0
cs_Ptinico Messages postés 4 Date d'inscription vendredi 20 décembre 2002 Statut Membre Dernière intervention 31 mai 2007
4 mai 2007 à 21:40
C'est un copier coller malencontreux d'un bout de code qui trainait chez moi ds un coin.
Ca marche effectivement juste avec la ligne indiquée.
Merci encore pour ton aide.

PS : le but de mon appli :
- aller chercher dans le port série un poids transmis par une balance, qui pèse des pièces produites en série par une presse
- compiler en temps réel ces poids, les faire manger à un algo qui décide s'il faut corriger le programme Excel de la presse
- envoyer le poids corrigé à Excel pour qu'il recalcule le nouveau programme
- envoyer enfin un message via TPC/IP à la presse pour qu'elle s'arrête, mange le programme recalculé, et redémarre.
Tout ça en temps réel.
Grace à toi je vois maintenant le bout du tunnel, tout ce qui était port série + tcp/ip marche déjà en multi-thread..
0
Rejoignez-nous