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...
Pour le cas des accès aux bases de données, c'est majoritairement une erreur sur la version du client de la base de données qui peut provoquer des différences (cf. Accès aux bases de données Client/Serveur, attention à la version du client). Et dans la quasi totalité des cas, une différence dans les dépendances de l'application sera à l'origine des complications.
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
]

// Recherche du PID du programme en cours ...
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

// Récupération des DLL pour le PID trouvé ...
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

// Récupération de la liste des composants utilisés par l'application...
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


// Visualisation du tableau dans une trace pour l'exemple
// le plus simple est de déclarer en global le tableau TabDépendance
// afin de le visualiser directement dans un champ table par databinding
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.

< Retour

1 commentaire

Jonathan LAURENT
24/04/2020 - 09:00 - Répondre
Très intéressant. Merci beaucoup :)

Publier un commentaire : 
Votre adresse email ne sera pas publiée