Ce billet rejoint un thème déjà abordé dans le blog, et revenant régulièrement à notre support : pourquoi la même application peut donner le résultat attendu sur 20 postes, mais sur le 21ième une différence apparaît (effet d'affichage, formatage de donnée, communication avec un périphérique, échange avec une base tierce, un webservice ...).
Dans ce cas bien sûr il faut orienter les recherches sur la configuration elle-même, et non pas sur l'application. Il ne faudrait pas inverser la tendance en modifiant l'application à la hâte, et se retrouver avec le bon résultat sur 1 poste, et non pas sur les 20...
Voici donc un bout de code que je conseille vivement de placer dans les applications, suivant le cas avec une option "avancée", ou une option d'administration, ou un raccourci caché. Il permet d'obtenir une liste complètes avec emplacements et versions des :
- DLL du framework WINDEV,
- DLL de Windows qui sont instanciées par l'application,
- DLL des éventuels clients des bases de données utilisées,
- composants externes.
Par comparaison entre un poste sain et une configuration récalcitrante, il devient ainsi immédiatement possible de repérer les différences : un client base de données trop ancien, un composant qui n'a pas été mis à jour, un framework chargé qui n'est pas celui pour lequel l'application est prévue...
strFramework est une structure sExtension est une chaîne sModule est une chaîne sRépertoire est une chaîne sVersion est une chaîne sVI est une chaîne sInfo est une Buffer FIN
TabDépendance est un tableau de strFramework UnElement est un strFramework
sListeProcessus est une chaîne nPID est un entier sAppli est une chaîne
sDLLInfo est une chaîne sDLLListe est une chaîne sNomDLL est une chaîne sInfoElement est une chaîne = [ Copyright : %1 Description : %2 Mode : %3 Société : %4 VI : %5 Commentaires : %6 ]
sListeProcessus = ExeListeProcessus(exePID, exeNomCourt) POUR TOUTE chaîne sProcessus de sListeProcessus SEPAREE PAR RC nPID = ExtraitChaîne(sProcessus, 1, TAB) sAppli = ExtraitChaîne(sProcessus, 2, TAB) SI sAppli ~= (EnModeTest() ? "WDTST.EXE" SINON ProjetInfo(piNomEXE)) ALORS SORTIR FIN
sDLLListe = ExeListeDLL(nPID) POUR TOUTE chaîne sDLL de sDLLListe SEPAREE PAR RC sNomDLL = Majuscule(fExtraitChemin(sDLL, fFichier+fExtension)) sDLLInfo += [RC] + sNomDLL + " " + ExeInfo(exeVersion, sDLL) UnElement.sExtension = fExtraitChemin(sDLL, fExtension) UnElement.sModule = sNomDLL UnElement.sVersion = ExeInfo(exeVersion, sDLL) UnElement.sVI = ExeInfo("VersionVI", sDLL) UnElement.sRépertoire = fExtraitChemin(sDLL, fDisque+fRépertoire) UnElement.sInfo = ChaîneConstruit(sInfoElement, ExeInfo(exeCopyright, sDLL), ExeInfo(exeDescription, sDLL), ExeInfo(exeMode, sDLL), ExeInfo(exeSociété, sDLL), ExeInfo("VersionVI", sDLL), ExeInfo("Commentaires", sDLL)) TableauAjoute(TabDépendance, UnElement) FIN
sComposantNom, sComposantChemin, sComposantRépertoire sont des chaînes POUR TOUTE chaîne sUnComposant de ComposantListe() SEPAREE PAR RC sComposantNom = ExtraitChaîne(sUnComposant, 1, TAB) sComposantChemin = ExtraitChaîne(sUnComposant, 2, TAB) sComposantRépertoire = fExtraitChemin(sComposantChemin, fDisque+fRépertoire) UnElement.sModule = sComposantNom UnElement.sRépertoire = sComposantRépertoire UnElement.sVersion = ComposantInfo(sComposantNom, ciVersion, sComposantRépertoire) UnElement.sVI = ComposantInfo(sComposantNom, ciVersionInterne, sComposantRépertoire) UnElement.sInfo = ChaîneConstruit("Société émettrice : %1", ... ComposantInfo(sComposantNom, ciSociété, sComposantRépertoire), ComposantInfo(sComposantNom, ciCopyright, sComposantRépertoire), ComposantInfo(sComposantNom, ciLibellé, sComposantRépertoire), ComposantInfo(sComposantNom, ciVersion, sComposantRépertoire), ComposantInfo(sComposantNom, ciVersionCompatible, sComposantRépertoire), ComposantInfo(sComposantNom, ciVersionInterne, sComposantRépertoire), ComposantInfo(sComposantNom, ciVersionProjet, sComposantRépertoire), ComposantInfo(sComposantNom, ciNuméroPatch, sComposantRépertoire), ComposantInfo(sComposantNom, ciNomPhysique, sComposantRépertoire),"") TableauAjoute(TabDépendance, UnElement) FIN
POUR TOUT ELEMENT UnElement de TabDépendance Trace(UnElement.sModule+"//"+UnElement.sVersion) FIN
Le code est autonome et peut être directement copié/collé dans un bouton par exemple.
- Mise à jour 24/4/2020 -
Une "version courte" du code permettant d'avoir les DLL utilisées par le processus courant :
POUR TOUT CHAÎNE sDLL de ExeListeDLL(ExeDonnePID(exePID)SEPAREE PARAR RC Trace(sDLL+" - "+ExeInfo(exeVersion, sDLL)+ sDLL [~] "\WD"+Val(VersionWINDEV())+"0" ? " "+ExeInfo("versionvi", sDLL) SINON "" ) FIN
Je l'utilise très régulièrement pour isoler des différences entre des configurations.
- Mise à jour 8/7/2020 - Lorsqu'une application se connecte à une base de données tierce par un connecteur natif ou un provider OLE DB, quand la connexion est effective (donc après HOuvreConnexion), il est possible de contrôler le client chargé. Par exemple avec SQL SERVER :
POUR TOUT CHAÎNE sDLL de ExeListeDLL(ExeDonnePID(exePID)SEPAREE PARAR RC SI sDLL [~] "\sqlncli" ALORS Trace(sDLL+" - "+ExeInfo(exeVersion, sDLL)) FIN
Le principe s'applique à une base de données quelconque, Oracle, MySQL, MariaDB, PostgreSQL (...), il suffit de repérer la DLL principale du Client.
|