Excel sans attendre la fin

[Résolu]
Signaler
Messages postés
4
Date d'inscription
vendredi 20 décembre 2002
Statut
Membre
Dernière intervention
31 mai 2007
-
Messages postés
4
Date d'inscription
vendredi 20 décembre 2002
Statut
Membre
Dernière intervention
31 mai 2007
-
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

Messages postés
1023
Date d'inscription
dimanche 1 août 2004
Statut
Membre
Dernière intervention
17 août 2008
2
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
Messages postés
1023
Date d'inscription
dimanche 1 août 2004
Statut
Membre
Dernière intervention
17 août 2008
2
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 !
Messages postés
2527
Date d'inscription
jeudi 15 janvier 2004
Statut
Membre
Dernière intervention
16 octobre 2019
18
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.
Messages postés
120
Date d'inscription
mardi 3 avril 2007
Statut
Membre
Dernière intervention
15 novembre 2007
1
Bonjour

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

J-L
Messages postés
4
Date d'inscription
vendredi 20 décembre 2002
Statut
Membre
Dernière intervention
31 mai 2007

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.
Messages postés
4
Date d'inscription
vendredi 20 décembre 2002
Statut
Membre
Dernière intervention
31 mai 2007

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..