| 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 structuresExtension 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 RCTrace(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 RCSI 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.     |