40 1 1MB
A propos du Guide... Les auteurs, qui sommes-nous ? Conventions d'écriture de l'ouvrage Déclarations de variables - Ecriture du code Déclarations de structures Fichiers externes .WL Fichiers externes .INI Fichiers REP Librairies WinDev WDL Utilisation du débogueur interne Programmation en réseau Résolution des problèmes sur les bases HyperFile Importation et Exportation de fichiers Dates et Heures Les Timers Création et utilisation de Classes Programmation des ActiveX Utilisation des API Windows Liens OLE avec Word Liens OLE avec Excel Les Tree-View : Drag & Drop et Impression Fichiers xBase Gestion des documents RTF WinDev - Développement Internet WinDev et le Minitel Faxer avec WinDev Scanner avec WinDev Utilisation des Codes-Barres Effets spéciaux sur images Plus de 70 Routines ou Fonctions Les secrets de SendMessage() Protection des applications développées Développer une application fonctionnant sur Cd-rom InfoObjet(), une fonction non documentée Valeurs des constantes Windows Liste des messages d'erreurs Windows Trucs et Astuces Windows Outils externes complémentaires du développeur Sites ou forums pour développeurs
Le Guide ! Ce guide a pour objectif de faire gagner un temps précieux aux programmeurs, débutants ou chevronnés, qui développent des applications avec l'outil L4G WinDev. Hormis la documentation « officielle » de PcSoft, il n'existe actuellement aucun ouvrage en librairie, virtuelle ou non, traitant de WinDev et c'est fort dommage. Nous avons souhaité combler cette lacune avec cette première édition et nous sommes certains que vous apprécierez ce livre et y trouverez matière à réutilisation, sinon à réflexion. Il a été élaboré en utilisant la dernière version de WinDev, la version 5.5b qui était disponible lors de la rédaction de cet ouvrage. Aussi, tous les efforts ont été mis en œuvre pour vous offrir des procédures, fonctions et classes fonctionnant parfaitement avec cette version. Les sources fournies pour chacun des sujets traités dans ce livre sont largement commentées et réutilisables immédiatement dans vos applications WinDev. Vous n'avez pas de royalties ou de licence à payer, ni à citer les sources utilisées dans vos applications. Chaque développeur ou société ayant acquis la version électronique ou papier du Guide est titulaire d'un N° personnel unique correspondant à l'installation sur UNE machine. Toute personne de la société en question peut donc lire et utiliser les informations sur cette machine. Il est toutefois interdit de vendre ou donner les sources et projets fournis à toute personne n'ayant pas acheté le Guide. En clair, VOUS avez acheté le guide, vous pouvez utiliser les sources et exemples dans VOS projets mais vous ne pouvez pas les donner / vendre à une autre personne / société. C'est pourquoi, nous vous fournissons un code de débridage qui vous est personnel. Nous avons voulu vous offrir des sources prêtes à l'emploi, dans les domaines les plus variés, domaines qui sont le pain quotidien dans nos activités de développement. Tous les exemples ont été plusieurs fois testés en environnement Windows 98 2ème édition, avant d'être intégrés dans cet ouvrages. Ils ont été compilés en 32 bits sur des machines à processeurs Intel III, 700 Mhz, avec 128 Mo de Ram et disques durs IDE 15 Go. En principe, ces exemples fonctionnent également parfaitement sous Windows 95, Windows NT4. Cependant, selon la configuration de votre machine, quelques ajustements peuvent s'avérer nécessaires. Développeurs WinDev depuis l'aube, nous avons apporté le plus grand soin à la rédaction de ce livre et nous vous remercions de bien vouloir nous faire part de vos rermarques, critiques, suggestions et, pourquoi pas, de vos compliments. Nous espérons avoir atteint l'objectif de vous faire gagner du temps et de mieux faire connaître WinDev, à notre avis largement méconnu !
Bons développements à tous avec WinDev ! Les auteurs… Alain Duglas
Fabrice Harari
WINDEV® est un logiciel de développement RAD produit par PC-SOFT® Les mots ''Windows, ''NT'', "WINDEV®", "PC-SOFT®" "HyperFile" et "LST®" sont la Propriété de leurs propriétaires respectifs et ne sont utilisés ici qu'en tant que références. Il n'y a aucun lien direct ou d'affiliation entre la société PC-SOFT® et les auteurs du présent ouvrage.
Fabrice HARARI ___________________________________________________________________ Titulaire d'un simple DUT informatique, Fabrice Harari a commencé sa carrière d'informaticien en 1985 directement comme chef du service informatique d'une SSII Niçoise. Sa volonté d'indépendance l'a amené en 1987 à créer sa propre société, Axlinfo. Cette société travaillait à l'origine dans le monde Prologue, en Bal, Abal pour développer des logiciels de gestion, mais aussi en assembleur pour développer des outils systèmes. Le virage vers Windows sera pris en 1994 avec WinDev 1.5, le C/C++ et l'assembleur. Depuis cette date de nombreux logiciels de gestion mais aussi des utilitaires (comme AxlSauve, logiciel gratuit de sauvegarde sur disque amovible) auront été développé avec WinDev. Il a créé en décembre 1999 et administre depuis cette date, le site Internet devenu depuis http://www.WinDevasso.org. Impliqué depuis plusieurs années dans le WinDev-Forum, LA mailing liste technique sur WinDev, il a activement participé à la création de l'Association des Développeurs WinDev (WinDevAsso) en octobre 2000. Aujourd'hui président de cette association, il effectue, en plus de son travail au sein d'Axlinfo, des missions de Conseil / Audit et de gestion de projet de développement WinDev en France et à l'étranger. La rédaction de ce livre sur WinDev s'inscrit donc totalement dans l'évolution de sa carrière, en mettant au service de tous les développeurs WinDev les fruits de son expérience. Contact : [email protected]
Alain DUGLAS ___________________________________________________________________ Commercial de formation et d'expérience, Alain Duglas a travaillé jusqu'en 1985 au sein de multinationales étrangères comme Rothmans International ou Colgate Palmolive en tant que directeur des ventes et de la promotion, directeur de filiale, directeur commercial… Après l'achat de son premier micro-ordinateur au début des années 80 (un Apple IIe..), il est très vite passionné par l'informatique. Pur autodidacte, créateur et animateur de deux clubs micro (Institut Français de Gestion, Automobile Club du Rhône), il crée sa première SSII en 1985, Microfil, société qu'il animera jusqu'en 1995. Cette SSII de 8 personnes est spécialisée dans le développement de programmes de gestion spécifiques destinées aux PME et aux industriels. Le langage phare utilisé alors est Clipper (Summer 87) puis Nantucket Clipper 5, toujours sur des bases de données xBase. Puis arrive Windows et on passe alors au langage DbFast de l'éditeur Computer Associates, puis à WinDev, qui promet un gain de temps de développement énorme…
En 1995, souhaitant se consacrer à des développements plus « personnels » et plus attractifs, il crée DIACOM International, une société lyonnaise d'édition, spécialisée dans les développements créatifs destinés au grand public, logiciels diffusés via d'autres éditeurs et la grande distribution. Il est également auteur depuis près de 5 ans auprès d'éditeurs prestigieux comme GT Interactive Software, Sybex... et développe exclusivement avec WinDev depuis 1994, mais ne refuse pas, à l'occasion, à mettre les mains dans le cambouis d'autres langages, comme Visual Basic ou Delphi... Il est l'auteur en 1999 de la classe RichText WinDev, diffusée avec succès à plusieurs centaines d'exemplaires auprès de la communauté WinDev en France et à l'étranger. Il est également l'auteur du seul générateur aléatoire de grilles de Mots Croisés français au monde, développé en WinDev « pur sucre », Super Mots Croisés, vendu à plusieurs milliers d'exemplaires depuis Avril 1999, via GT Interactive et le réseau commercial de TF1 Vidéo. Ce logiciel a nécessité deux ans de réflexion et une année complète de développement. Pratiquant assidu et expérimenté de WinDev, il souhaite, avec cet ouvrage écrit à quatre mains, faire partager son expérience et son plaisir de développer avec WinDev. Contact : [email protected]
Conventions d'écriture de l'ouvrage Afin de vous repérer rapidement dans cet ouvrage et dans leurs chapitres, la notation suivante a été adoptée, les polices correspondantes avec les tailles et les couleurs ci-dessous :
1. Chapitres, 2. explications et commentaires concernant le sujet traité, 3. points importants à retenir, 4. des commentaires supplémentaires, 5. procédures ou étapes à suivre, 6. sources WinDev : chaque début de source est signalé par l'icône 7. exemples du cédérom compagnon : ils sont repérés par l'icône 8. notes particulières : elles sont repérées par l'icône
,
.
9. liens à des sites Internet ou adresses e-mail : www.site_internet.com .
OoOoOoOoOoOoOoOoO
Déclarations de Variables - Ecriture du Code « Tous les chemins mènent à Rome... » indique l'expression populaire. C'est particulièrement vrai dans notre métier ! C'est certain, chaque développeur a ses petites habitudes, sa méthodologie (ou parfois... l'absence de méthodologie !), sa façon d'écrire son code ainsi que son style propre. Evidemment, à priori, ce style n'a pas d'incidence sur le bon fonctionnement de l'application finale. Pourtant, parfois, lorsque l'on regarde le code de certaines applications, on prend peur ! Imaginez la reprise d'un source vieux de quelques années, source dont il n'existe pas de dossier, et qui n'a pas été écrit par vous ! C'est pourquoi, nous avons jugé utile de rappeler quelques conseils de base, notamment concernant la notation hongroise. Ce terme savant recouvre simplement une façon d'écrire son code, un style universel (ou qui devrait l'être !) reconnaissable immédiatement par des programmeurs avertis. La notation hongroise est un ensemble de conventions popularisé il y a de nombreuses années par Charles Simonyi lorsqu'il travaillait chez Microsoft. WinDev n'étant pas un langage fortement typé, cette convention de codage comporte énormément d'avantages : • • • •
lisibilité et compréhension immédiate d'un source, différenciation des variables globales et locales, identification d'un seul coup d'œil du type d'une variable, gain de temps appréciable lors de la modification de sources.
Si vous n'utilisez pas (pas encore...) la notation hongroise, vous pouvez, en quelques jours, acquérir des réflexes d'écriture qui vous aideront grandement... En voici les règles principales, simples à utiliser : si vous avez, par exemple, une variable numérique pour un total mensuel, nommez-la ngTotalMensuel. Qu'y a-t-il de spécial dans cette notation ? Tout d'abord, pour une meilleure lisibilité le début de chaque « mot » constituant la variable commence toujours par une Majuscule. Ensuite, les deux premiers caractères de cette variable, toujours en minuscules, indiquent sa nature : la première, son type : n pour numérique, la seconde, sa portée : g pour globale.
Nous avons donc ici une variable ngTotalMensuel globale de type numérique correspondant à la somme d'un total mensuel. Autre exemple : clNomUtilisateur indique qu'il s'agit d'une variable locale, de type chaîne correspondant vraisemblablement au nom d'un utilisateur. Par ailleurs, le choix du nom de cette variable est très utile car d'une simple lecture, vous savez à quoi sert celle-ci, même si vous n'êtes pas l'auteur du source. « Le style, c'est l'homme » disait Buffon. C'est pourquoi, sans vouloir choquer quiconque, certains développeurs feraient bien de s'inspirer de cette maxime ! On peut ainsi « typer » chaque variable selon sa nature : c d l m n t etc.
Chaîne, Date, Booléen, Monétaire, Numérique, Tableau
Bien évidemment, la notation hongroise n'apporte aucun avantage en vitesse de traitement, mais elle est fortement recommandée pour tous les avantages décrits précédemment. N'hésitez pas à utiliser des noms longs sous WinDev, vous avez droit à 33 caractères (information donnée par le ST de PcSoft). : lors de la description de vos fichiers, le nom de vos rubriques (champs...) ne peuvent dépasser 23 caractères... Ainsi, les deux variables cgUtilisateurDirection et cgUtilisateurServiceTechnique seront parfaitement différenciées lors de l'exécution de votre code. Certains programmeurs utilisent le caractère souligné « _ » pour encore mieux séparer et « éclaircir » leur code, comme par exemple : cg_Utilisateur_Direction ou cg_Utilisateur_Service_Technique Cette notation a le mérite d'être encore plus lisible, simplement faites attention à la longueur maximale de la variable, ne dépassez jamais 33 caractères !
Les noms de fichiers et les Alias Les noms de fichiers et les alias sont toujours en MAJUSCULES, comme CLIENTS, FACTURES, CL. , FC. GL. etc.
Les noms de champs
Les noms de champs sont eux aussi en majuscules : CL.NOMCLIENT, FC.NUMFACT
Les procédures et les fonctions Dans l'écriture de vos fonctions ou procédure acceptant des paramètres en entrée, il est judicieux de préfixer les noms des paramètres par « p » : Fonction Arrondi (pnValeur1, pnValeur2) Ici, on sait que l'on attend en entrée de fonction 2 valeurs numériques et qu'il s'agit de paramètres... Indiquez, également, immédiatement au-dessous de la déclaration de chaque fonction ou procédure A QUOI SERT celle-ci ! En effet, trop souvent, on lit des sources avec des noms de procédures ou de fonctions abscons, obscurs, incompréhensibles en première lecture. Donnez des noms « parlants » à vos procédures et fonctions, n'omettez pas d'expliquer en une ligne ou deux ce que fait cette fonction ou procédure. Vous vous en porterez mieux, gagnerez énormément de temps et aurez la satisfaction personnelle de pouvoir vous relire instantanément. Nous ne parlons même pas ici du travail de développement en groupware ! Imaginez si pour des tas de raisons, vous passez du statut de développeur indépendant isolé à celui de développeur en équipe... Vous risquez d'avoir beaucoup de mal à vous faire accepter au sein du groupe !
Les déclarations Les variables sont regroupées par type et par fonctionnalités. Elles peuvent être déclarées sur une ou plusieurs lignes : Local // Dates de l'agenda clMoisEnCours, clMoisSuivant sont des chaines = ""
Les commentaires Que celui qui n'a jamais hésité à la relecture d'un de ses sources après quelque temps se lève ! Notre métier étant assez particulier, il nous arrive fréquemment d'avoir une idée et de la mener jusqu'à son terme, afin de vérifier la validité de cette idée. Et puis, si cette idée est viable, on
poursuit... Seulement, les pensées sont fugitives et si vous ne commentez pas cette brillante idée immédiatement après l'avoir écrite et testée, il y a de fortes chances pour que dans 6 mois, lors de modifications, vous vous grattiez la tête avec quelques hésitations ! Alors, commentez vos sources, commentez, commentez !!! Le gain de temps apporté par des commentaires est inestimable et vous vous féliciterez tous les jours de l'avoir fait. La bonne méthode pour commenter ses sources est de faire des phrases en français, comme par exemple : // Boucle d'itération sur le nombre de lignes // en lecture du fichier externe FRAMES.TXT Il est également important (pour le futur...) de commenter ses variables par une courte description, comme par exemple : Global nCarteBancaire, nNumeroCarte sont des entiers longs = 0 // Gestion des Cartes de Crédit cDateValidité est une chaine = "" // Date limite d'utilisation des cartes de crédit Vous n'aurez ainsi aucun mal à vous relire et si une autre personne d'autre doit intervenir sur vos sources, vous lui faciliterez grandement la tâche... Pensez également à faire en sorte que chaque ligne soit directement lisible dans la fenêtre de l'éditeur, sans qu'il soit nécessaire de faire appel à l'ascenseur horizontal (autre gain de temps ...) que ce soit dans l'écriture de vos commentaires comme dans le source proprement dit : N'écrivez pas : // Début de la procédure de scrutation du port série, nécessitée par la lecture... Ici, le lecteur est obligé de faire appel à l'ascenseur pour lire la totalité du commentaire... Ecrivez plutôt : // Début de la procédure de scrutation du port série, // nécessitée par la lecture en entrée octet par // octet du poids issu de la balance marchandises. Dans vos sources, utilisez la continuation des lignes, en interrompant le code par « ... » et continuez sur la ligne suivante
Les Classes Les classes, elles aussi, gagnent à être commentées... Que préférez-vous ?
Ce code :
PlanningJournalier est une Classe // Dépendances //======================================= // Nom du champ image destination (obligatoire) NomChampImage est une chaine // Nom de la fenêtre qui contient le champ NomFenetre est une chaine //Nom du champ Bulle NomChampBulle est une chaine // Numéro de poste NumPoste est un entier // Dates //======================================= // Date affichée en 1ère colonne ou celui-ci : Planj est une classe NCIM, NCF,NCB sont des chaines NCPest un entier Le résultat sera le même, mais......... !
Le caractère de soulignement Comme dit, précédemment, vous pouvez utiliser le caractère de soulignement « _ » à l'intérieur d'une variable. Cependant, il est préférable de ne pas commencer un nom de variable par ce caractère. En effet, PcSoft donnant au compte-gouttes le nom de certaines de ses variables internes, vous risquez de rentrer en collision avec celles-ci.
L'indentation L'indentation fait partie également des bons principes à adopter. Elle assure une meilleure lisibilité de votre code, permet de vérifier les débuts et fins de boucles et, dans des boucles imbriquées compliquées, elle est fort utile. A ce propos, n'hésitez pas à ajouter un commentaire à vos fins de boucle comme par exemple : FIN // Fin de Si FIN // Fin de Selon
FIN // Fin de TantQue Visual Basic intègre en natif cette particularité d'écriture, permettant d'écrire, par exemple : End If End Select bien pratique pour se repérer dans un source long et compliqué, mais WinDev n'ayant pas celle-ci, vous pouvez y suppléer avec des commentaires. : vous pouvez régler la largeur de chaque tabulation dans le menu WinDev par « Outils », « Options », sélectionnez l'onglet Code puis saisissez la valeur souhaitée d'une tabulation dans le champ « Largeur des tabulations » en nombre de caractères...
Conclusion En appliquant ces quelques règles simples, vous améliorerez votre style, gagnerez du temps, et aurez du plaisir à vous relire (et en procurerez à ceux qui vous liront !). Comme quoi, les bons outils font (parfois...) les bons ouvriers. La notation hongroise fait partie de ces bons outils !
oOoOoOoOoOoOoOo
Déclaration de structures Les structures sont très utilisées en programmation. Elles sont parfois indispensables dans certains traitements, et notamment dans le passage de paramètres lors de certains appels faits à des fonctions API Windows. Une structure correspond à un type abstrait de données défini par le développeur et non implémenté dans un langage de programmation. Vous pouvez déclarer une ou plusieurs structures en gardant à l'esprit : • • •
Qu'une structure, dès qu'elle est déclarée, sera publique. Ce qui signifie qu'elle sera accessible n'importe où dans votre application, Qu'il n'est pas possible de déclarer une structure locale ou privée dans WinDev, à la différence d'autres langages, Si une structure est déclarée dans le code d'initialisation d'une fenêtre, elle restera publique et reconnue dans tous les autres traitements, même si la fenêtre dans laquelle la structure a été déclarée a été fermée.
Ces notions ont énormément d'importance et notamment en terme de mémoire vive, car toutes les structures déclarées dans une application, restent en mémoire, où qu'elles aient été déclarées. Les variables typées peuvent être passées en paramètres à des fonctions et le typage de la variable dans la fonction est automatique. La syntaxe pour déclarer une structure est la suivante : « NomStructure » est une structure « NomMembreStructure1 » est un « TypedeVariable1 » « NomMembreStructure2 » est un « TypedeVariable2 » « NomMembreStructure3 » est un « TypedeVariable3 » ....... Fin « NomStructure » est le nom identifiant la structure, « NomMembreStructure1 » est le nom du 1er membre de la structure, « TypedeVariable1 » est le type du 1er membre de la structure.
Note importante : Une structure peut faire référence à une autre structure (ou à plusieurs autres structures..) déjà définie(s). La syntaxe permettant de déclarer une structure faisant appel à une autre structure est : « NomStructure » est une structure Un objet « NomAutreStructure » Un objet « NomEncoreUneAutreStructure » « NomMembreStructure1 » est un « TypedeVariable1 » Fin « NomAutreStructure » et « NomEncoreUneAutreStructure » sont les noms des autres structures déjà définies... La syntaxe pour déclarer une variable typée (structurée) est la suivante : « NomVariable » est une « NomStructure » « NomVariable » est le nom de la variable typée. Une variable typée se manipule par les membres de sa structure. La syntaxe pour utiliser une variable typée est : « NomVariable » : « NomMembre »
Exemple de déclaration de structure: // Déclaration de la structure Coord est une Structure PosX est un entier PosY est un entier Fin // Utilisation de la structure PosSouris est une Coord PosSouris :PosX=25 PosSouris :PosY=15 Autre exemple de déclaration de structure : _SystemTime est une structure Wyear est entier WMonth est un entier WDOW est un entier Wday est un entier Whour est un entier Wminute est un entier Wsecond est un entier Wmsec est un entier FIN Autre exemple de déclaration de structure : _W32FileDATA est une structure DWFA est un entier long ZHCdwLowDateTime est un entier Long ZHCdwHighDateTime est un entier long ZLAdwLowDateTime est un entier Long ZLAdwHighDateTime est un entier long ZLWdwLowDateTime est un entier Long ZLWdwHighDateTime est un entier long NfSh est un entier long NfSl est un entier long RES0 est un entier long RES1 est un entier long NOMCOMP est une chaine fixe sur 260 Nomcour est une chaine fixe sur 14 Fin Autre exemple de déclaration de structure :
Fichiers externes WL Vous le saviez sans doute déjà, mais n'importe quel fichier externe contenant du texte ASCII peut être inclus dans une application WinDev par la déclaration EXTERNE Fichier.Extension : EXTERNE WINCONST.WL Le résultat est identique à une copie du fichier texte sous l'éditeur de code, à la place de la ligne "EXTERNE". Vous pouvez donc inclure des instructions WinDev au point d'insertion représenté par EXTERNE... Il est possible de spécifier un chemin complet : Exemple : "D:\PROJET\DATA\MESCONST.WL"). Si le chemin n'est pas spécifié, le fichier est recherché successivement : · dans le répertoire du projet · dans le répertoire de WinDev Remarques : - Le fichier doit être un fichier texte classique, créé sous n'importe quel éditeur de texte. - L'inclusion de fichier est particulièrement utile pour décrire des constantes communes à plusieurs projets ou au système d'exploitation. Dans ce cas, l'endroit idéal pour placer la ligne EXTERNE "fichier" est le code d'initialisation du projet, ce qui permettra aux constantes d'être accessibles partout dans le projet. Rien ne vous empêche, par exemple, d'insérer la ligne suivante dans un fichier nommé « CODE.WL » : Info("Il est "+ heureverschaine(heuresys())+ "! "+RC+"Il serait temps de vous mettre au travail ! ") Cette ligne sera alors interprétée comme du code WinDev « en dur » dans votre application. A l'ouverture de l'application, la boite de dialogue correspondante s'ouvrira avec la valeur d'HeureSys()... Mais vous pouvez également écrire ceci dans un fichier externe : GLOBAL rect est compose de l est un entier long t est un entier long r est un entier long
fin
b est un entier long
puis dans votre application, n'importe où, écrire, par exemple : RECT.R = 80 RECT.L=30 HORZRES est un entier long = rect.r - rect.l INFO(HORZRES) La seule restriction concerne bien évidemment du code externe faisant appel à des variables non encore déclarées ou non initialisées, et, bien sûr la présence du fichier en question... Par ailleurs, si une modification du fichier externe à lier est effectuée, vous devez à chaque modification, réinitialiser le lien vers ce fichier en ouvrant l'éditeur de code WinDev. Ces quelques lignes vous montrent tout l'intérêt de l'usage de fichiers externes dans lequel il n'y a que la limite de votre imagination (ou de vos besoins... ) ! Insérer des constantes dans une application Deux fichiers définissant des constantes sont fournis avec WinDev : "WinConst.wl" (constantes standard de Windows), et "Except.wl" (constantes des exceptions W-Langage). Mais rien ne vous empêche de déclarer des constantes personnelles, relatives à votre application. Il vous suffit de respecter les règles définies ci-avant... Vous pouvez donc avoir des constantes globales identiques à tous vos projets, si vous les placez dans un fichier externe et que vous insérez la ligne suivante dans le code d'initialisation de ces projets : EXTERNE "C:\PROJETS\CONSTANT.TXT" Déclarer un objet externe Le mot clé EXTERNE sert à déclarer une variable que n'est pas réellement déclarée. Par exemple dans un projet qui charge une analyse ou une bibliothèque et utilise ses éléments. Lors de la compilation, ces éléments sont inconnus. Externe permet de les déclarer pour éviter un Warning lors de la compilation. Voilà, vous connaissez l'essentiel à présent sur les fichiers WL et comment les utiliser avec profit ! oOoOoOoOoOoOo
Fichiers externes .INI Les fichiers INI, qui sont des fichiers textes externes à n'importe quelle application Windows, sont encore souvent peu utilisés par les développeurs. C'est fort dommage car leur utilisation permet de paramétrer, de façon externe, toutes sortes de fonctionnalités dans vos applications. Vous pouvez utiliser ou plusieurs fichiers INI dans une application. Vous pouvez également utiliser le fichier WIN.INI (par défaut…). Ces fichiers peuvent être placés dans le répertoire d'installation de votre application, dans le répertoire Windows, ou dans tout autre endroit qu'il vous plaira, sous réserve d'indiquer le chemin complet du fichier INI que vous voulez traiter. Vous pouvez y placer une foultitude de choses : paramètres d'initialisation de vos applications, mots de passe cryptés, préférences utilisateur et bien d'autres choses encore ! Les fichiers INI peuvent être utilisés dans les versions de Windows 3.1, 9x, NT… N'oubliez pas cependant que la taille maximale d'un fichier INI est limité à 64 Ko… Les fichiers INI sont structurés de cette façon : [SECTION_1] Mot Clé_1=…………… Mot Clé_2=…………… [SECTION_2] Mot Clé_1=…………… Mot Clé_2=…………… etc… WinDev possède deux fonctions simples et puissantes permettant de créer des fichiers INI, d'en lire le contenu ou de modifier celui-ci. INIECRIT() permet d'écrire dans un fichier INI. Si le fichier INI n'existe pas et si le chemin donné à ce fichier est correct, il est créé automatiquement. INILIT() permet de lire un Mot Clé d'une SECTION d'un fichier INI.
Vous pouvez : • • •
Créer ou supprimer une SECTION, Créer ou supprimer un Mot Clé, Lire ou écrire pour un Mot Clé.
Attention, lors de la lecture ou de l'écriture pour un mot-clé, n'oubliez pas que le contenu des motsclés est toujours une chaîne… N'omettez donc pas de passer aux fonctions INIEcrit() et INILit() une chaîne, et non pas une valeur, sous peine d'erreur garantie, comme par exemple : FicIni = FRepEncours()+''\DATA\PARAM.INI'' // Fichier autre que WIN.INI.... Syntaxe erronée : CoulFond est un entier long=255 INIECRIT(''COULEURS'',''Fond'' ,CoulFond, FicIni) La bonne syntaxe est : INIECRIT(''COULEURS'',''Fond'' ,VersChaine(CoulFond), FicIni) En lecture, c'est la même chose , n'oubliez pas de transformer le contenu du Mot Clé (qui est toujours une chaîne..) avant de le réaffecter : 1ère syntaxe : Coulfond=Val(INILIT(''COULEURS'',''Fond'' , '''' , FicIni)) Vous récupérez le contenu du Mot Clé Fond à la section COULEURS, mais si le Mot Clé est vide, la variable CoulFond sera à 0 ! Il vaut donc mieux utiliser la syntaxe ci-dessous, qui permet d'affecter une valeur par défaut, si le contenu du Mot Clé est vide : 2ème syntaxe : Coulfond=Val(INILIT(''COULEURS'',''Fond'' , ''255'' , FicIni)) Vous pouvez directement écrire lors du code de fermeture d'une fenêtre, l'enregistrement des couleurs des objets de cette fenêtre, comme par exemple : INIECRIT(''COULEURS'', "Combo2",VersChaine(Combo2..CouleurFond),FicIni) Ou INIECRIT(''COULEURS'', "Champ",VersChaine(Champ..Couleur),FicIni) Pour créer une nouvelle SECTION avec un nouveau Mot Clé : INIECRIT(''NOUVELLE_SECTION'',''Nouveau_Mot Clé,'','',FicIni) Pour supprimer un Mot Clé existant :
INIECRIT(''SECTION'',''MotCle'',Null, FicIni) Pour supprimer une SECTION existante : INIECRIT(''SECTION'',Null,Null, FicIni) Dans la syntaxe des exemples ci-dessus, si ''FicIni'' n'est pas précisé, alors les opérations de lecture et d'écriture ont lieu dans le fichier WIN.INI, ce qui signifie que sans précision du fichier à utiliser, c'est WIN.INI qui sera utilisé.
Mais en plus de l'utilisation 'mécanique' des fichiers ini, il convient de réfléchir à une gestion globale cohérente de ceux-ci… Comment choisir entre un fichier ini propre à l'application ou partagé entre plusieurs applications, voire même un fichier ini du système (win.ini, system.ini…) ? Quelles sont les limites de l'utilisation des fichiers ini ? C'est ce que nous allons voir maintenant…
Limite des 64 Ko Tout d'abord, il faut considérer la limite des 64 Ko des fichiers ini… Si chaque application présente sur un ordinateur écrit ses paramètres dans win.ini, il est clair que celui-ci sera vite saturé. Donc, le premier principe, qui parait évident mais n'est malheureusement pas toujours suivi par les développeurs, c'est de ne placer dans les fichiers ini du système que ce qui est strictement indispensable (par exemple un nouveau périphérique d'impression, l'installation d'un driver particulier propre à votre application…). Ces cas sont relativement rares. Dans la majorité des cas, il faut donc préférer un fichier ini propre à votre application.
Ou placer un fichier ini ? Ou placer un fichier ini ? Dans le répertoire Windows, dans celui de l'application ? Dans le cas (rare) ou vous devez partager des informations entre plusieurs applications installées dans des répertoires différents (ou mettre des informations à disposition d'applications externes), il est clair que placer le fichier ini dans le répertoire Windows est une solution simple pour que chacun puisse y accéder. Par contre, dans la majorité des cas, les paramètres à inscrire dans le fichier ini sont propres à l'application. Dans ce cas, il est clair que placer le fichier ini dans le répertoire de l'application est beaucoup plus pratique.
En cas de déplacement ou de désinstallation, il ne restera pas de fichier dans le répertoire de Windows. De plus, si jamais le répertoire Windows devait être supprimé et recréé (mais personne n'a jamais besoin de réinstaller Windows, n'est ce pas ?), votre application ne sera pas perturbée, son fichier de paramétrages étant intact. Enfin, vous ne ferez pas parti de ces programmeurs qui font désespérément grossir le répertoire système pour rien (n'oubliez pas que le temps de chargement de Windows dépend en partie de la taille du répertoire Windows et de ses sous-répertoires).
Fichiers ini et programmation réseau Dans le cas d'un programme réseau, les fichiers ini sont bien évidemment réservés aux paramètres 'locaux'. Si par contre vous souhaitez enregistrer des paramètres de fonctionnement par utilisateur, et que ceux ci sont susceptibles de travailler sur plusieurs ordinateurs, il est clair que l'utilisation d'un fichier ini n'est plus vraiment adaptée. Dans ce cas, préférez leur un fichier HyperFile situé sur le serveur de fichier… Ce système vous permettra de conserver des séries de paramètres communs à tous les utilisateurs ou propre à chaque utilisateur mais utilisables depuis n'importe quel poste du réseau. Pour vous faciliter la tache, voici deux procédures ParamLit et ParamEcrit construites avec pratiquement la même syntaxe qu'Inilit et IniEcrit mais travaillant sur un fichier paramètre.
Tout d'abord, la structure du fichier paramètre : Nom des zones du fichier param PACLEUNIK Section Ligne ValeurTexte ValeurNum ValeurMemo ValeurMonetaire ValeurBinaire UnikKey=Section+Ligne
Type Entier Long Texte Texte Texte Entier Long Mémo Texte Monetaire Mémo binaire Clé Composée unique
Lg. 4 30 30 30 4 4 10 4 60
Cette structure comporte plus de champs qu'il n'est nécessaire pour gérer simplement l'équivalence avec les IniLit et IniEcrit, mais puisqu'on gère un fichier de paramètres, autant augmenter la puissance de ces fonctions. Si vous désirez remplacer vos IniLit et IniEcrit existant par des appels à ParamLit et ParamEcrit avec un minimum de travail, il vous suffit de faire deux remplacements successifs dans tout votre projet (pour chaque fonction) :
-
D'abord remplacer IniLit par ParamLit (ou IniEcrit par ParamEcrit)
-
Puis remplacer NomDuFichierIni par la chaine "ValeurTexte", puisque les lectures/écritures d'origines dans les fichiers ini n'acceptaient que des valeurs textes.
Voici donc les fonctions que vous pouvez intégrer dans vos sources, et tout d'abord, la fonction de lecture de paramètre.
Procédure ParamLit(Section,Ligne,ValeurInit,NomDuChampDuFichier="TextValue") //Cette procédure remplace IniLit pour conserver des informations dans //une table hyperfile qui sera accessible via le réseau //(Même information pour tous les utilisateurs ou différente pour chaque //utilisateur (en mettant le nom d'utilisateur dans le champ 'Section') mais //accessible sur n'importe quel point du réseau //Le paramètre 'Section' peut contenir le nom d'utilisateur, ou "Fenêtre'... //Le paramètre 'Ligne' peut contenir la clé secondaire, comme par exemple 'Position Hor' //La clé unique est composée de Section+Ligne //La procédure lit l'enregistrement dont la clé est Section+Ligne et //renvoie la valeur trouvée dans le champ du fichier NomDuChampDuFichier. //Le paramètre NomDuChampDuFichier contient le nom exact de la //zone fichier (utilisation de l'indirection pour accéder au contenu) //et détermine donc aussi le type de valeur renvoyée //Le NomDuChampDuFichier peut être : "ValeurTexte", "ValeurNum", //"ValeurMemo", "ValeurMonetaire" ou "ValeurBinaire" TrSection est une chaîne=Section TrSection=Majuscule(TrSection)
TrLigne est une chaîne=Ligne TrLigne=Majuscule(TrLigne)
//Transforme la valeur qui peut //arriver en numérique en une chaîne //Transforme la chaîne qui peut contenir //des minuscules en majuscules. Ceci permet //de ne pas se préoccuper de la casse lors des //appels à ParamLit et ParamEcrit, comme //c'était le cas pour IniLit et IniEcrit //Comme pour la section
//Recherche de la ligne dans le fichier HLitRecherche("Param", "UnikKey", Complete(TrSection,Dimension(Param.Section))+… complete(TrLigne,Dimension(ParamsLigne))) Tantque HdejaBloque() HLitRecherche("Param", "UnikKey", Complete(TrSection, … Dimension(Params.Section))+ complete(TrLigne,Dimension(Params.Ligne))) Fin //Si on ne trouve pas la ligne, on renvoi le valeur init passée en paramètre Si pas h.trouve alors Renvoyer ValeurInit Sinon //Si on travaille sur une valeur de type texte, on enlève les espaces //ajoutés automatiquement dans les champs de fichiers HyperFile Si NomDuChampDuFichier="ValeurTexte" ou …
Fin
NomDuChampDuFichier="ValeurMemo" alors Renvoyer sansespace({"Param."+NomDuChampDuFichier}) Sinon Renvoyer {"Param."+NomDuChampDuFichier} Fin
Puis la fonction d'écriture de paramètre :
Procédure ParamEcrit(Section,Ligne,ValeurAEcrire,ChampDuFichier="ValeurTexte") //Cette procédure remplace IniEcrit quand vous voulez enregistrer des informations //dans une table HyperFile qui sera accessible via le réseau //(Même information pour tous les utilisateurs ou différente pour chaque //utilisateur (en mettant le nom d'utilisateur dans le champ 'Section') mais //accessible sur n'importe quel point du réseau //Le paramètre 'Section' peut contenir le nom d'utilisateur, ou "Fenêtre'... //Le paramètre 'Ligne' peut contenir la clé secondaire, comme par exemple 'Position Hor' //La clé unique est composée de Section+Ligne //La procédure écrit l'enregistrement dont la clé est Section+Ligne et //place la valeur dans le champ du fichier ChampDuFichier. //Le paramètre ChampDuFichier contient le nom exact de la //zone fichier (utilisation de l'indirection pour accéder au contenu) //et détermine donc aussi le type de valeur //Le ChampDuFichier peut être : "ValeurTexte", "ValeurNum", //"ValeurMemo", "ValeurMonetaire" ou "ValeurBinaire"
//Exemple : ParamEcrit("GENERAL","IntroFacture",IntroFacture,"ValeurMemo") // Section (ici les paramètres généraux à l'application) // Ligne (le texte d'introduction des factures) // La chaine contenant La valeur à écrire // Sera placé dans le mémo texte //Tout d'abord, on traite les paramètres en entrée TrSection est une chaîne=Section //Transforme la valeur qui peut //arriver en numérique en une chaîne TrSection=Majuscule(TrSection) //Transforme la chaîne qui peut contenir //des minuscules en majuscules. Ceci permet //de ne pas se préoccuper de la casse lors des //appels à ParamLit et ParamEcrit, comme //c'était le cas pour IniLit et IniEcrit TrLigne est une chaîne=Ligne //Même chose TrLigne=Majuscule(TrLigne) //que pour la section // Puis, on lit l'enregistrement et on le bloque HLitRechercheBloque("Param", "UnikKey", Complete(TrSection, …
Dimension(Param.Section))+ complete(TrLigne,Dimension(Param.Ligne))) Tantque hdejabloqué() HLitRechercheBloque("Param","UnikKey", Complete(TrSection,… Dimension(Params.Section))+ complete(TrLigne,Dimension(Params.Ligne))) Fin Si pas H.trouve alors //L'enregistrement n'existe pas, on le créé hRaz("Param") Param.Section=Complete(TrSection,Dimension(Param.Section)) Param.Ligne=Complete(TrLigne,Dimension(Param.Ligne)) {"Param."+ChampDuFichier}=ValeurAEcrire Hajoute("Param") Sinon //L'enregistrement existe, on le modifie {"Param."+NomDuChamp}=ValeurAEcrire hmodifie("Param") //Débloque l'enregistrement par la même occasion Fin
Fonctions supplémentaires En plus de simplement remplacer la gestion des fichiers ini en cas de programme réseau, l'utilisation des zones ValeurNum, ValeurMemo, ValeurMonetaire et ValeurBinaire vous permet de stocker énormément de choses dans vos fichiers paramètres, comme des fichiers curseurs ou des fichiers sons que vous extrairez très simplement au moment ou votre application en a besoin… Les fonds de pages, logos et autres enrichissements de vos application trouvent ainsi une place bien à l'abri des manipulations hasardeuses et située à une instruction (binairesauve/binairecharge) du disque dur "classique"… Si vous ne les utilisez pas encore, testez donc la vitesse et la puissance de cette instruction qui vous surprendra… Ces possibilités supplémentaires vous permettent de décupler la puissance habituelle des fichiers ini, en augmentant par exemple la sécurité de vos applications, puisqu'il n'est plus question qu'un utilisateur ait supprimé les fichiers curseurs ou autres qui traînaient dans un sous-répertoire de votre application… Vous les extrairez à la volée ou en début de programme et serez ainsi à peu prés certain de disposer de ce dont vous avez besoin au moment opportun. Augmentation des possibilités de vos programmes ? Augmentation de la sécurité ? N'hésitez plus, paramétrez ☺ !
oOoOoOoOoOoOoOo
Fichiers REP Tout d'abord, qu'est ce qu'un fichier "REP" ? En fait, il s'agit d'un fichier texte que WinDev utilise pour stocker des informations sur l'emplacement des fichiers HyperFile utilisés. La gestion des fichier "REP" étant optionnelle (hGereRepNon), il est important de connaître les tenants et aboutissants de ces fichiers pour décider en connaissance de cause si on souhaite de les utiliser ou pas, et si c'est nécessaire... Ces fichiers portent normalement le nom de votre analyse et sont situés dans le répertoire HSF du disque où est installé votre programme, sauf bien sûr si vous avez choisi un autre emplacement par programmation. Chaque fois que vous créez un fichier HyperFile, les caractéristiques de celui-ci sont enregistrées dans le fichier "REP" (et en particulier son emplacement physique). Ces informations seront nécessaires pour le bon fonctionnement de différents utilitaires PCSoft, et en particulier le module de modification automatique des fichiers de données, lorsque vous avez effectué des modifications dans l'analyse de votre projet. Quand vous lancez une modification automatique des fichiers de données, l'utilitaire WdModfic recherche le fichier "REP" pour savoir où se trouvent les fichiers à modifier. S'il ne trouve pas le fichier "REP", il suppose que les fichiers se trouvent dans le répertoire défini dans l'analyse. Donc, le choix est clair : Si vous voulez pouvoir modifier la structure de vos fichiers en automatique et que l'emplacement de ces fichiers est paramétrable (en particulier en fonctionnement réseau), il est obligatoire que le fichier "REP" soit correctement renseigné. Dans certains cas, il se peut que votre fichier "REP" ne contienne pas tous les emplacements de fichiers à modifier, et vous pouvez même être amené à modifier manuellement ces informations. Avant d'en arriver à cette extrémité, n'oubliez pas qu'un module de WdOutil.exe permet justement de modifier les fichiers "REP", de vérifier la validité des informations qu'ils contiennent, et même de rajouter des lignes… Si vous tenez quand même à effectuer les modifications à la main, voici la structure des fichiers "REP" : ils sont constitués de lignes séparées par des RC/LF. Chaque ligne a une longueur de 117 caractères sans les RC/LF, soit 119 caractères pour une ligne complète. La structure d'une ligne est : • •
2 espaces, Le nom logique du fichier sur 8 caractères,
• • • •
• •
• • •
1 espace, Le nom physique COURT du fichier (si le fichier physique s'appelle "MonFichier", on aura ici quelque chose comme MonFic~1) sur 8 caractères, 1 espace, Le chemin (ou tout au moins le début de celui-ci) tel que déclaré dans l'analyse sur 30 caractères. Cette zone est vide si on déclare les fichiers comme étant dans le répertoire courant du programme. De plus, cette zone est codée en utilisant les noms de dossiers longs (C:\PROGRAM FILES\MONPROGRAMME\…), ce qui fait que dès que les 30 caractères sont atteints, l'information est incomplète… Donc, préférez les noms/chemins courts, 1 espace, Le chemin courant du fichier sur 64 caractères… Ici, le chemin est inscrit en utilisant les noms courts, par exemple C:\PROGRA~1\MONPRO~1\… avec le "\" final… Malgré tout, la place disponible n'est que de 64 caractères, donc bien inférieure à la taille possible d'un nom de dossier. Evitez donc les emplacements de fichiers un peu trop "exotiques" si vous souhaitez que tout fonctionne comme il faut, 1 espace 1 point d'exclamation LE RC/LF.
Par défaut, la gestion du fichier "REP" est active… Donc sans rien faire de particulier, lorsque vous assignez / créez vos fichiers au début de votre projet (ou lorsque le RAD le fait pour vous), tout est automatiquement mis en place pour que la modification automatique des fichiers de données fonctionne parfaitement. Dans la très grande majorité des cas, vous n'aurez donc jamais à mettre les mains dans un fichier "REP". Sachez aussi qu'un programme n'utilisant ni les journaux (HGereJnlNon), ni le fichier "REP" (HGereRepNon), ni les transactions (HGereTrsNon) peut voir sa vitesse d'exécution augmenter de 10% en mono poste et 25% en réseau (extrait de l'aide en ligne de WinDev). Donc vous pouvez améliorer les performances de votre programme, et si vous voulez quand même profiter du système de modification automatique des fichiers, il ne vous reste qu'à installer aussi votre programme sur le serveur de fichier. Les fichiers doivent alors être placés dans le répertoire décrit dans l'analyse (je vous conseille le répertoire courant du programme). La modification des données se fera alors sur le serveur, lors de l'installation de la nouvelle version.
Si vous travaillez en réseau, sachez que la gestion du fichier "REP" ne supporte pas la notation UMC (c'est le nom du système d'appellation des répertoires réseau qui permet, au lieu de devoir assigner une lettre à un lecteur, de les atteindre grâce à un nom composé du nom du serveur précédé de "\\" suivi du nom du répertoire). Ainsi, vous pouvez parfaitement assigner un fichier (ou tous) dans un répertoire s'appelant \\NomServeur\NomRepertoire\ mais le fichier "REP" n'enregistrera pas cet emplacement dans ce cas. Pour travailler en réseau avec la gestion du fichier "REP" activée, il faut donc assigner une lettre (par exemple "R:") au disque de la machine "\\NomServeur" dans l'explorateur WinDows et assigner le fichier au répertoire "R:\NomRepertoire". Lors de la création des fichiers, R:\NomRepertoire sera donc enregistré dans le fichier "REP". Il conviendra bien sûr que cette lettre soit assignée automatiquement au disque réseau à chaque démarrage de la machine.
oOoOoOoOoOoOo
Fichiers REP Tout d'abord, qu'est ce qu'un fichier "REP" ? En fait, il s'agit d'un fichier texte que WinDev utilise pour stocker des informations sur l'emplacement des fichiers HyperFile utilisés. La gestion des fichier "REP" étant optionnelle (hGereRepNon), il est important de connaître les tenants et aboutissants de ces fichiers pour décider en connaissance de cause si on souhaite de les utiliser ou pas, et si c'est nécessaire... Ces fichiers portent normalement le nom de votre analyse et sont situés dans le répertoire HSF du disque où est installé votre programme, sauf bien sûr si vous avez choisi un autre emplacement par programmation. Chaque fois que vous créez un fichier HyperFile, les caractéristiques de celui-ci sont enregistrées dans le fichier "REP" (et en particulier son emplacement physique). Ces informations seront nécessaires pour le bon fonctionnement de différents utilitaires PCSoft, et en particulier le module de modification automatique des fichiers de données, lorsque vous avez effectué des modifications dans l'analyse de votre projet. Quand vous lancez une modification automatique des fichiers de données, l'utilitaire WdModfic recherche le fichier "REP" pour savoir où se trouvent les fichiers à modifier. S'il ne trouve pas le fichier "REP", il suppose que les fichiers se trouvent dans le répertoire défini dans l'analyse. Donc, le choix est clair : Si vous voulez pouvoir modifier la structure de vos fichiers en automatique et que l'emplacement de ces fichiers est paramétrable (en particulier en fonctionnement réseau), il est obligatoire que le fichier "REP" soit correctement renseigné. Dans certains cas, il se peut que votre fichier "REP" ne contienne pas tous les emplacements de fichiers à modifier, et vous pouvez même être amené à modifier manuellement ces informations. Avant d'en arriver à cette extrémité, n'oubliez pas qu'un module de WdOutil.exe permet justement de modifier les fichiers "REP", de vérifier la validité des informations qu'ils contiennent, et même de rajouter des lignes… Si vous tenez quand même à effectuer les modifications à la main, voici la structure des fichiers "REP" : ils sont constitués de lignes séparées par des RC/LF. Chaque ligne a une longueur de 117 caractères sans les RC/LF, soit 119 caractères pour une ligne complète. La structure d'une ligne est : • •
2 espaces, Le nom logique du fichier sur 8 caractères,
• • • •
• •
• • •
1 espace, Le nom physique COURT du fichier (si le fichier physique s'appelle "MonFichier", on aura ici quelque chose comme MonFic~1) sur 8 caractères, 1 espace, Le chemin (ou tout au moins le début de celui-ci) tel que déclaré dans l'analyse sur 30 caractères. Cette zone est vide si on déclare les fichiers comme étant dans le répertoire courant du programme. De plus, cette zone est codée en utilisant les noms de dossiers longs (C:\PROGRAM FILES\MONPROGRAMME\…), ce qui fait que dès que les 30 caractères sont atteints, l'information est incomplète… Donc, préférez les noms/chemins courts, 1 espace, Le chemin courant du fichier sur 64 caractères… Ici, le chemin est inscrit en utilisant les noms courts, par exemple C:\PROGRA~1\MONPRO~1\… avec le "\" final… Malgré tout, la place disponible n'est que de 64 caractères, donc bien inférieure à la taille possible d'un nom de dossier. Evitez donc les emplacements de fichiers un peu trop "exotiques" si vous souhaitez que tout fonctionne comme il faut, 1 espace 1 point d'exclamation LE RC/LF.
Par défaut, la gestion du fichier "REP" est active… Donc sans rien faire de particulier, lorsque vous assignez / créez vos fichiers au début de votre projet (ou lorsque le RAD le fait pour vous), tout est automatiquement mis en place pour que la modification automatique des fichiers de données fonctionne parfaitement. Dans la très grande majorité des cas, vous n'aurez donc jamais à mettre les mains dans un fichier "REP". Sachez aussi qu'un programme n'utilisant ni les journaux (HGereJnlNon), ni le fichier "REP" (HGereRepNon), ni les transactions (HGereTrsNon) peut voir sa vitesse d'exécution augmenter de 10% en mono poste et 25% en réseau (extrait de l'aide en ligne de WinDev). Donc vous pouvez améliorer les performances de votre programme, et si vous voulez quand même profiter du système de modification automatique des fichiers, il ne vous reste qu'à installer aussi votre programme sur le serveur de fichier. Les fichiers doivent alors être placés dans le répertoire décrit dans l'analyse (je vous conseille le répertoire courant du programme). La modification des données se fera alors sur le serveur, lors de l'installation de la nouvelle version.
Si vous travaillez en réseau, sachez que la gestion du fichier "REP" ne supporte pas la notation UMC (c'est le nom du système d'appellation des répertoires réseau qui permet, au lieu de devoir assigner une lettre à un lecteur, de les atteindre grâce à un nom composé du nom du serveur précédé de "\\" suivi du nom du répertoire). Ainsi, vous pouvez parfaitement assigner un fichier (ou tous) dans un répertoire s'appelant \\NomServeur\NomRepertoire\ mais le fichier "REP" n'enregistrera pas cet emplacement dans ce cas. Pour travailler en réseau avec la gestion du fichier "REP" activée, il faut donc assigner une lettre (par exemple "R:") au disque de la machine "\\NomServeur" dans l'explorateur WinDows et assigner le fichier au répertoire "R:\NomRepertoire". Lors de la création des fichiers, R:\NomRepertoire sera donc enregistré dans le fichier "REP". Il conviendra bien sûr que cette lettre soit assignée automatiquement au disque réseau à chaque démarrage de la machine.
oOoOoOoOoOoOo
Bibliothèques WDL Lors de la phase de création de l'exécutable, WinDev propose de mystérieuses options concernant les "bibliothèques"…
Tout d'abord qu'est ce qu'une bibliothèque au sens WinDev ? Une bibliothèque est un fichier dont l'extension est "wdl". Ce fichier est généré lors de la création de l'exécutable et va contenir jusqu'à 1000 objets dont l'exécutable aura besoin… Ces objets peuvent être : •
Des fenêtres,
•
Des images,
•
Des états…
Donc, quand vous créez une fenêtre dans un de vos projet et que cette fenêtre contient tout un tas d'images (sur les boutons, en fond de fenêtre, en icône dans la barre de titre, etc…) vous ne stockez pas UN objet dans la bibliothèque mais "N" objets.
Interne, Externe ou pas du tout Au moment de la création de l'exécutable, WinDev vous propose 3 options concernant les bibliothèques : •
Pas d'utilisation de bibliothèque
•
Utilisation de la bibliothèque externe
•
Intégration de la bibliothèque dans l'exécutable
Si vous choisissez la première option, aucune intégration des objets n'est effectuée… Vous vous retrouvez donc avec un exécutable tout petit (puisqu'il ne s'agit plus en fait que d'un "lanceur") mais vous devez fournir toutes les fenêtres, les images et autres ressources nécessaires, en même temps que votre exécutable, chaque fenêtre ou état contenant tout son code source… Pour d'évidentes raisons de sécurité, cette option ne devrait être utilisée qu'en cas de développement interne à une entreprise, et encore… Le seul avantage qu'elle présente est de pouvoir remplacer
UNE FENETRE (par exemple) seule, sans changer l'exécutable ni quoi que ce soit d'autre… Vous avez donc ici une flexibilité de mise à jour très grande. En choisissant l'option "bibliothèque externe", WinDev créé le fichier WDL regroupant tous les objets du projet… Ce fichier devra être fourni à vos clients en même temps que l'exécutable… Quel avantage par rapport à l'intégration dans l'exécutable ? Certains vous diront que de ce fait vous pouvez ne mettre à jour que la wdl chez vos clients (mais comme l'exécutable seul ne pèse que quelques dizaines de Ko, le gain est négligeable). Par contre, l'aide en ligne de WinDev indique que "Attention : pour les exécutables fonctionnant en réseau, la bibliothèque doit être externe." Notre expérience nous indique qu'il faut comprendre ici que les exécutables placés sur le serveur et appelés depuis les postes clients doivent être séparés de la WDL. Or, cette configuration est à éviter au maximum si vous ne voulez pas dégrader inutilement les performances de votre réseau… Ce que nous avons appris au moment où les réseaux étaient lents est toujours aussi vrai maintenant : "un réseau bien configuré est un réseau qui n'est pas utilisé" ☺… Quand vous "pensez" réseau, il faut effet faire en sorte que les programmes et les données soient placés de telle manière que l'utilisation du réseau soit minimisée… Faire transiter toutes les fenêtres, les images, les icônes, les sons… par le réseau alors que le programme peut être installé sur tous les postes est donc une aberration… Au pire, si vous avez 500 postes à installer, un système d'installation automatique des nouvelles versions intégré à votre exécutable résoudra le problème.
1000 objets Revenons sur la limite des 1000 objets dans une bibliothèque. Il s'agit là d'une limite due à la structure des fichiers WDL actuels. Vous pouvez donc un jour vous retrouver confronté à un problème si votre projet a vraiment trop grossi ! Que faire dans ce cas ? Tout simplement, séparer votre projet en plusieurs sous-projets ou utiliser plusieurs bibliothèques WDL…
Utilisation de plusieurs WDL Avec les instructions ChargeWDL et DechargeWDL, WinDev nous fournit un moyen pour utiliser jusqu'à 10 bibliothèques différentes simultanément. La bibliothèque principale du projet ne pouvant être déchargée, il nous reste 9 bibliothèques "amovibles" avec lesquelles travailler. A vous de séparer en modules "logiques" les différents objets (par exemple un module vente, un module achat, un module compta…) Mais un certain nombre de contraintes sont à prendre en compte avant de choisir une organisation de ce genre :
•
Vous devrez gérer le contenu des bibliothèques à la main ! En effet, si WinDev peut se charger de générer une bibliothèque contenant tous les objets du projet, il n'offre aucun outil (en tout cas dans sa version actuelle) pour affecter les fenêtres et autres objets à telle ou telle bibliothèque…
•
Vous ne devez pas utiliser de noms longs pour les objets placés dans des bibliothèques secondaires, sous peine de comportements erratiques.
Si vous ne voulez pas de ces contraintes, envisagez plutôt de créer plusieurs projets regroupant des fonctionnalités logiques… Un projet principal se charge des paramétrages et des fichiers de base tandis que des projets secondaires contiennent des unités de traitements logiques… Depuis votre projet principal, vous serez donc amenés à appeler des exécutables secondaires, ce qui pour l'utilisateur sera totalement transparent. Avec cette méthode, plus besoin de gérer des listes d'objets à la main, ni de vous restreindre aux noms courts… Par contre, quand vous modifierez votre analyse (commune à tous les projets), vous devrez mettre à jour et recompiler tous les sous-projets… A vous donc de choisir la méthode de travail qui vous paraît la plus appropriée à vos besoins ou contraintes…
Mise à jour partielle de programme Nous avons vu qu'il était possible de séparer les objets du projet en plusieurs bibliothèques. Cette fonctionnalité permet par exemple de faire des mises à jour partielles chez vos clients, en n'envoyant que la ou les wdl modifiées. Tout en considérant que cette mise à jour partielle serait tout aussi possible en gérant plusieurs exécutables, voyons comment faire mieux… Chaque WDL va en général être relativement grosse (parfois plusieurs Mo) et l'amélioration de vitesse d'envoi restera donc limité… Pourquoi, dans ce cas, ne pas envoyer seulement les fenêtres modifiés (ou les états) : •
Parce que WinDev charge en priorité l'objet contenu dans sa bibliothèque,
•
Parce que vous envoyez alors en même temps les sources de votre objet.
Le premier problème peut être résolu en remplaçant les fonctions Ouvre, OuvreFille et OuvreSoeur par des procédures globales qui se chargeront de tester si des fenêtres de remplacement renommées se trouvent dans le répertoire de l'application (ou dans un sous répertoire)… Ainsi, si vous utilisez dans votre application une fenêtre Client.wdw, vous pouvez fournir à vos client une fenêtre m_Client.wdw corrigée et améliorée… La procédure globale d'ouverture fera donc les traitements suivants : •
Ajout de "m_" au nom de la fenêtre à ouvrir,
•
Test de la présence de cette fenêtre dans le répertoire des Mise à jour,
•
Si elle y est, ouverture de RepMAJ\m_NomFen.wdw,
•
Sinon, ouverture de NomFen.wdw.
Le problème de sécurité des sources peut être résolu de deux manières : •
Vous considérez que les sources d'une ou deux fenêtres ne sont pas vraiment un problème et ne servent à rien sans le reste des sources de l'application et de l'analyse et vous placez dans votre programme de quoi supprimer automatiquement les fenêtres de mise à jour quand vous faîtes une mise à jour majeure.
•
Vous supprimez les sources de vos fenêtres ou états avant de les envoyer… Pour cela, deux méthodes : o
Vous générez un exécutable en supprimant les sources sur votre machine de développement et vous extrayez ensuite la fenêtre sans son source grâce à un des utilitaires présents sur le site de WinDevAsso
o
Vous utilisez le tout nouvel outil écrit par Ugo Gennuso (en phase de test au moment où ces lignes sont écrites) et qui permet justement de supprimer les sources d'un objet WinDev isolé, et donc, de faire des mises à jour beaucoup plus sûres.
Bien sûr, dans les deux cas, vous prenez vos responsabilités car ces manipulations ne sont pas dans le manuel WinDev… Personne ne peut donc vous certifier que tout se passera sans problème ! Voilà, vous savez tout sur les wdl, ou presque… Mais quelques tests personnels vous apprendront sûrement ce que vous ne savez pas encore à ce sujet important… oOoOoOoOoOoOoO
Utilisation du débogueur Ca chapitre n'a pas pour but de vous apprendre à utiliser le débogueur, l'aide en ligne et la documentation de WinDev faisant déjà cela très bien. Nous allons plutôt étudier ici les limites du débogueur, les problèmes que l'on peut rencontrer en l'utilisant, et voir comment optimiser son utilisation Le débogueur est la plupart du temps très largement suffisant pour trouver l'origine des problèmes rencontrés, toutefois, son utilisation pose parfois des problèmes et nous allons en étudier quelquesuns de plus prés…
Focus Vous rencontrerez peut-être parfois des cas où votre code fonctionnera parfaitement sous le débogueur, alors qu'il ne fonctionnera pas en mode test ou en exécution. Vous pouvez d'ailleurs aussi rencontrer parfois le problème inverse… Très souvent, genre de facétie se produit quand vous placez du code dans les zones "prise de focus" et "perte de focus" de vos fenêtres. Mais quand vous utilisez le débogueur, il faut penser que celui-ci ne va pas cesser de prendre le focus et de le rendre aux fenêtres de votre application… L'ordre d'exécution de ces types de codes est donc très fortement perturbé… Vous pouvez donc avoir des effets de bandes comme : •
Un code n'a pas encore été exécuté alors que vous avez besoin du résultat qu'il produit,
•
Un code a été exécuté plusieurs fois au lieu d'une seule et un cumul est faux…
Donc si vous avez besoin de placer du code dans ces zones, méfiance… Dans ce cas, l'utilisation de Trace est parfois beaucoup plus efficace que le débogueur.
Timer Les timers ne font pas non plus très bon ménage avec le débogueur : •
Ils perturbent l'exécution linéaire du code en déclenchant des procédures à tout bout de
champs (une procédure d'affichage de l'heure toutes les secondes est parfaite pour rendre hystérique tout informaticien stressé ☺), •
Pour déboguer le code d'une procédure appelée par Timer, il faut remplacer les points d'arrêts classiques par l'instruction "Stop".
Si le deuxième point ne pose pas de problème particulier (à part de s'en souvenir ☺), le premier peut vous obliger à ne pas déclencher les timers quand vous êtes en mode test ou en mode de déboguage… Ceci peut être fait en utilisant le code suivant : Si PAS EnModeTest() alors Timer(… Ou encore, en ayant déclaré une variable globale booléenne EnModeDebug : Si PAS EnModeDebug alors Timer(… Dans ce dernier cas, avant de lancer votre séance de déboguage, il vous suffit de modifier votre source pour mettre EnModeDebug à vrai. Vous pouvez même disposer d'une fonction cachée (qui n'apparaît qu'en mode test) qui vous permet de modifier la valeur de cette variable de manière dynamique, ce qui vous permet d'activer ou de désactiver les timers en fonction de vos besoins.
Visualisation de variables Le débogueur affiche automatiquement le contenu des variables "courantes" (celles qui sont utilisées dans le code en cours) dans une zone de visualisation. Les variables apparaissent et disparaissent donc dans cette zone au gré du code exécuté. Vous pouvez de plus demander à surveiller le contenu d'une ou de plusieurs variables même si elles ne sont pas utilisées précisément à ce moment dans votre code. Cette pratique courante peut toutefois vous réserver de mauvaises surprises. En effet, le débogueur conserve la liste des variables en questions d'une exécution sur l'autre. Vous pouvez donc vous retrouver dans le cas où il essaye d'afficher le contenu d'une variable qui n'existe plus dans votre projet. Vous vous retrouvez alors avec un message d'erreur qui apparaît à chaque "pas d'exécution"… Si cela vous arrive, pensez à examiner la zone des variables et à supprimer ce qui y traîne encore.
Repousser les limites La fonction permettant de visualiser et modifier le contenu des variables du débogueur est beaucoup plus puissante qu'elle n'en a l'air… En effet, en plus de pouvoir saisir le nom d'une variable locale, globale, fichier ou d'un champ d'une
fenêtre, vous pouvez aussi y saisir des expressions ! Ces expressions peuvent être l'appel à une fonction : Majuscule(SansEspace(MaVariable)) est ainsi parfaitement accepté… Cet exemple peut vous permettre de vérifier comment est traité le contenu de MaVariable dans une expression complexe dans le cas où cette variable contient des minuscules accentués… Obtiendrez-vous des majuscules simples ou des majuscules accentuées ? Mais ces expressions peuvent aussi être des TESTS ! Ainsi, si vous saisissez MaVariable=23, vous obtiendrez 1 ou 0 selon que le test est vérifié ou pas… Inutile ? Ne croyez pas ça ! En cochant en même temps la case "autostop", vous obtenez le moyen de lancer le code en fonctionnement normal (bouton GO), tout en sachant qu'il s'arrêtera automatiquement dés que MaVariable atteindra la valeur 23 (ou la quittera si elle valait 23 au départ)… Inutile donc de passer 250 itérations d'une boucle en mode pas à pas… Commencez par repérer grâce à un affichage quelle est la valeur qui pose problème, puis posez lui un piège pour étudier en détail le code fautif, et uniquement lui ! Avec ces quelques informations importantes, vous êtes maintenant parés pour déboguer en toute tranquillité vos merveilleux programmes.
oOoOoOoOoOoOoO
Programmation en réseau Dans ce chapitre, nous allons étudier les subtilités de la programmation réseau… Il s'adresse donc à tous ceux qui doivent faire le saut entre des applications mono-postes et des applications multiutilisateurs. Au niveau de la programmation, le principe est le même si l'on se trouve dans une configuration réseau ou multiposte, et même si on lance plusieurs occurrences d'un même programme sur un seul poste. Réseau ou Multiposte ? Mais tout d'abord, voyons quelle est la différence entre réseau et multiposte. Lorsque l'on parle d'une application fonctionnant en réseau, cela signifie que les différentes occurrences d'un programme fonctionnent sur différentes unités centrales d'un même réseau physique, chacune d'elle utilisant le processeur et la mémoire vive de SON unité centrale. Par contre, lorsqu'un programme fonctionne dans un environnement multiposte, toutes les occurrences du programme fonctionnent sur la même unité centrale, dans la même mémoire vive et avec les ressources d'un seul processeur. Dans ce cas, seules les entrées/sorties sont déportées sur d'autres machines, qu'il s'agisse de terminaux passifs ou d'ordinateurs faisant fonctionner un logiciel d'émulation de terminal. Dans le monde Windows, le meilleur exemple de multiposte est Windows NT TSE (Terminal Server Edition)… Pourquoi établir cette distinction entre deux modes de fonctionnements multi-utilisateurs ? Tout d'abord pour vous rassurer ! En effet, 99% du code que vous écrirez fonctionnera de la même manière dans les deux cas… Et le 1% qui reste ne concerne pas la programmation réseau à proprement parler, mais plutôt le paramétrage du fonctionnement… En effet, si en mode réseau on peut la plupart du temps se remettre à un fichier ini unique se trouvant dans le répertoire de l'application pour gérer le paramétrage du fonctionnement, il est clair que dans le cas du multiposte, ce n'est plus vrai, tous les utilisateurs partageant la même copie du programme et donc le même répertoire…
Ce problème peut d'ailleurs aussi se poser en mode réseau, si l'application ne se trouve pas physiquement sur le poste local mais sur un serveur d'applications. Donc, pour programmer proprement le paramétrage de fonctionnement, il est clair qu'il faut privilégier l'usage d'un fichier de paramétrage HyperFile par utilisateur, tel que décrit dans le chapitre des fichiers INI, afin d'être sûr que le programme fonctionnera correctement quelle que soit la plate forme matérielle. Réseau / mono poste : les différences théoriques Il est bien évident qu'au delà de la programmation du paramétrage de fonctionnement, il faut maintenant s'attacher à la programmation des accès fichiers… Que se passe-t-il en environnement multi-utilisateurs simultanés, puisqu'on a vu précédemment que le terme d'environnement réseau ne recouvrait qu'une partie des cas rencontrés… Le problème se pose bien évidemment au niveau de la gestion des fichiers de données, que ceux-ci soient des fichiers HyperFile, xBase ou qu'il s'agisse d'une base SQL. Dans notre cas, il faut prendre en compte les éventualités suivantes : •
Plusieurs utilisateurs peuvent accéder au même fichier simultanément
•
Pire que cela, plusieurs utilisateurs peuvent accéder au même enregistrement d'un même fichier simultanément
Bien sûr, si les utilisateurs ne faisaient que lire des enregistrements, il n'y aurait pas de problème… Mais comme ils en modifient, en ajoutent et en suppriment, il faut mettre en place du code particulier pour gérer ces éventualités.
Blocages En fait, toute la programmation réseau repose sur le blocage de certains enregistrements et sur la détection des enregistrements bloqués. Il faut donc bien comprendre quand et combien de temps il faut bloquer un enregistrement ! Nous allons donc étudier les différents types d'accès à un enregistrement ou à un fichier : • • • •
Lecture : Quand on lit un enregistrement (pour l'afficher à l'écran ou pour l'imprimer), il est clair qu'il est inutile de le bloquer Ajout : Quand on ajoute un enregistrement, il n'y a aucune notion de blocage, l'enregistrement n'existant pas encore Modification : il est obligatoire de bloquer l'enregistrement avant de le modifier, de manière à éviter que deux utilisateurs écrasent mutuellement leurs modifications Suppression : là encore, il faut bloquer l'enregistrement avant d'effectuer la suppression… Il
ne faut pas supprimer un enregistrement qui est en train d'être lu/modifié par quelqu'un d'autre. On a aussi la possibilité de bloquer un fichier en totalité, mais cette option ne devient nécessaire que si on doit effectuer des traitements lourds sur celui ci : •
Réindexation
•
Suppression/vidage du fichier
•
Calculs nécessitant le parcours de la totalité ou d'une partie d'un fichier et nécessitant plusieurs passages entre lesquels le contenu doit obligatoirement être identique…
Comme vous le voyez, il s'agit là de cas rares mais auxquels vous devrez quand même penser… Résumons nous : la programmation réseau consiste donc à bloquer certains enregistrements ou fichiers avant d'effectuer certains traitements et, bien sûr, de vérifier TOUT LE TEMPS si les enregistrements/fichiers auxquels on désire accéder sont déjà bloqués par un autre utilisateur. L'objectif étant bien sûr de ne bloquer des enregistrement que lorsque cela devient vraiment nécessaire, et uniquement le temps nécessaire. Par exemple, si un utilisateur demande à modifier un enregistrement d'un fichier, votre programme va tout d'abord l'afficher, puis laisser la main à l'utilisateur. Si votre programme a déjà bloqué l'enregistrement à ce moment, la durée du blocage peut être TRES longue… L'utilisateur peut être dérangé, voire même partir en catastrophe et laisser l'enregistrement bloqué pendant des heures… La bonne "stratégie" est donc de ne bloquer l'enregistrement que quand l'utilisateur clique sur le bouton déclenchant l'enregistrement dans le fichier. A ce moment, le code doit suivre la logique suivante : •
Vérification de la validité du contenu des zones de saisies, messages d'erreurs ou d'avertissements et retours en saisie éventuels,
•
Blocage de l'enregistrement fichier courant,
•
Si l'enregistrement ne peut pas être bloqué, on peut, selon les cas : o
Afficher un message d'erreur et sortir
o
Boucler jusqu'à que ce que l'enregistrement puisse être bloqué (risque de boucle infinie)
o
Avertir l'utilisateur et lui demander ce qu'il veut faire : réessayer, abandonner la
modification,… o
Mixer plusieurs des stratégies ci-dessus (par exemple, on essaye plusieurs fois avec une attente entre chaque essai, et au bout de n essais, on avertit l'utilisateur, puis…)
•
Une fois l'enregistrement bloqué, on affecte les zones de saisies aux zones fichiers
•
On enregistre la modification
•
Enfin on débloque l'enregistrement
Sur les machines actuelles, il est clair que le temps écoulé entre le blocage et le déblocage de l'enregistrement se chiffre en millièmes de secondes, au pire en centièmes ! En appliquant une "stratégie réseau" correcte, on va donc diminuer très fortement le risque de conflits entre utilisateurs.
Cette stratégie réseau peut se résumer en deux points : 1. Diminuer autant que possible le risque de conflits entre utilisateurs (diminution de la durée de blocage par exemple) 2. Gérer ces risques de blocages sur TOUS LES ACCES aux fichiers, même si le risque est minime.
Logique de fonctionnement Examinons maintenant la logique de fonctionnement d'une application tout à fait courante : une gestion commerciale. Le but de cet examen est de mettre en lumière les différents niveaux de risques de conflits entre utilisateurs et de trouver des méthodes pour les réduire au minimum possible. 1. Prenons tout d'abord l'exemple de la gestion de documents comme des devis ou des factures. En toute logique, il est très improbable que deux utilisateurs veuillent simultanément modifier un même devis ou une même facture, soit parce qu'une seule personne est chargée de cette tâche (et a les autorisations pour cela), soit parce que chaque personne qui est chargée de cette tâche ne s'occupe que de son groupe de clients. Dans ce cas, on voit bien qu'une modification simultanée est logiquement très improbable… On pourrait donc en toute logique envisager de se passer de la gestion des blocages… Malheureusement, la logique et la vie réelle faisant rarement bon ménage, il faudra tout de même prévoir ce cas improbable… Ici, il n'y a pas de moyen de diminuer le risque de conflit qui est au niveau minimum. Par contre, un point à considérer ici est "Que faut-il bloquer ?"… En effet, un document de ce type est en général constitué d'informations provenant de deux fichiers : • Une ligne d'entête/Pied de page dans un fichier principal
•
'n' lignes de devis ou de factures dans un fichier secondaire
Bloquer les lignes de détail (l'une après l'autre ou toutes ensembles) ne servirait à rien puisqu'il suffit de bloquer la ligne d'entête pour que tout le document devienne inaccessible. Bien sûr cela suppose que tous les traitements qui accèdent aux lignes du documents accèdent d'abord à l'entête… Mais si la logique est respectée, cela doit être le cas ! 2. Voyons maintenant ce qui se passe au niveau des fichiers "de base", comme par exemple le fichier clients. Là encore, il est clair que les utilisateurs vont très rarement modifier simultanément la même fiche client. D'abord, parce que soit une seule personne est chargée de saisir les modifications d'adresse ou de téléphone, soit chacun gère ses clients, ensuite parce que même si plusieurs personnes veulent faire des modifications sur la même fiche, la fréquence de ces modifications étant peu importante, il est très peu probable que les tentatives d'accès se fassent au même moment. 3. Enfin, voyons ce qui se passe au niveau des informations de cumuls/statistiques. Dans ce cas, il est clair que, selon la logique de programmation employée, on peut se trouver face à des accès concurrentiels fréquents. Ainsi, si chaque saisie de devis/facture met à jour des cumuls en temps réel, les compteur de cumuls vont être très sollicités et les blocages vont s'avérer primordiaux. Par contre, si les cumuls sont fait lors d'un traitement effectué soit la nuit, quand personne ne travaille, soit à la demande sur une période précise, seul ce traitement accèdera en modification aux zones de cumuls et les risques de conflits sont quasi inexistants. Bien sûr, il faut aussi considérer l'endroit où ces zones de cumuls se trouvent… Prenons le cas d'un compteur de chiffre d'affaires par client. Si ce compteur se trouve (assez logiquement) dans l'enregistrement client, il est tout à fait possible que quelqu'un essaye de modifier cette fiche pendant que le traitement de cumul est effectué sur un autre poste… Avec cette configuration de fichiers, on augmente le risque de conflits. Pour respecter notre stratégie réseau, il conviendra donc de gérer deux fichiers : • •
Le fichier client principal Le fichier de cumuls par client
Comme vous le voyez la nécessité réelle de blocage est dépendante de la logique de fonctionnement de l'application. Sans enlever en quoi que ce soit la nécessité de gérer les blocages lors de tous les accès, on peut très fortement diminuer les cas d'accès concurrentiels en séparant les informations dans des enregistrement "logiques", ce qui simplifiera très fortement les schémas de fonctionnement. C'est vrai, nous insistons beaucoup sur ce point ! Mais pour programmer "confortablement" en réseau, il est très important de "penser réseau" ! Ce que vous devez toujours avoir en tête, c'est que, en diminuant les probabilités de conflit d'accès sur un enregistrement, on diminue en même temps :
• •
Les risques d'erreurs (dues à une erreur de programmation, ça c'est votre domaine) Les risques d'inconvénients pour l'utilisateur (enregistrement bloqué, message d'erreur ou d'avertissement, traitement impossible… Cà, c'est la face utilisateur).
En pratique, avec HyperFile Tout d'abord, voyons comment accéder aux fichiers… Ces fichiers sont partagés (autrement, ce n'est pas de la programmation réseau ☺), donc ils doivent se trouver quelque part sur le réseau… L'emplacement des fichiers n'est donc plus fixe, et il faut donc commencer par gérer un paramétrage d'emplacement. Typiquement, cela se fait dans un fichier ini (et nous vous conseillons de vous reporter au chapitre qui leur est consacré si vous n'êtes pas familier de leur utilisation)… Le code Wlangage suivant permet de gérer cette situation. Vous pouvez le placer dans le code d'initialisation du projet, ou encore mieux, dans une procédure globale que vous pourrez appeler d'où vous voulez dans votre programme, en plus de l'appeler depuis le code d'initialisation du projet…
Pourquoi cette astuce ? Parce que ce système vous permet aussi de gérer très simplement plusieurs séries de fichiers situés à des emplacement différents, soit pour une gestion multi-sociétés, soit pour une gestion multi-exercices, ceci sans rien changer aux possibilités d'accès réseau ! Tout le code de ce chapitre a été regroupé dans un projet ProgRes que vous pourrez installer directement depuis l'interface du Guide : GDWProgRes Ce projet utilise des fichiers générés automatiquement par WinDev (groupe carnet d'adresse) et des fenêtres volontairement très simples pour illustrer les traitements réseau. Donc, nous choisissons de placer ce code dans la procédure globale RADProjetInit (si vous utilisez le RAD à n'importe quel moment, WinDev l'aura déjà créée, donc inutile d'en créer une autre, autant tout regrouper sous ce nom standard. Dans ce code, TrRepFichiers et TrFifchierIni sont des variables globales au projet. Vous trouverez leur déclaration et leur initialisation dans le projet d'exemple.
Procedure RadProjetInit() // Cette procédure s'occupe de gérer l'initialisation du système de fichiers // On commence par lire dans le fichier de paramétrage TrRepFichiers=inilit("Général","Répertoire des fichiers","",TrFichierIni) Si TrRepFichiers"" alors //// On l'a trouvé, mais...
// Vérifie si on peut accéder au répertoire en question Si frep(TrRepFichiers,FrRepertoire)="" alors bip Si ouinon("Le répertoire "+sansespace(TrRepFichiers)+... " est inaccessible ou inexistant ! Vous pouvez : ",... "- En choisir un autre en répondant OUI",... "- Sortir du programme en répondant NON")=Non alors FinProgramme() Fin // Ici, on ouvre la fenêtre qui permet de choisir et d'enregistrer le répertoire //pour les fichiers HyperFile Ouvre("Param")
fin
fin
// Puis on vérifie si cette fois ci tout va bien TrRepFichiers=inilit("Général","Répertoire des fichiers","",TrFichierIni) Si TrRepFichiers"" alors // Vérifie si on peut accéder au répertoire en question Si frep(TrRepFichiers,FrRepertoire)="" alors Erreur("Le répertoire des fichiers n'est toujours pas "+… "accessible ! Exécution du programme abandonnée !") finprogramme() fin fin
// On a donc un nom de répertoire valide, on indique // au système de fichiers que tous les fichiers HyperFile // se trouvent dans ce répertoire hsubstrep("?",TrRepFichiers)
// Puis on met en place les options de fonctionnement du moteur HyperFile // c'est ici que vous pouvez rajouter tout un tas d'options (réplication, mémos,...) // en fonction de vos besoins HModePerso(Vrai)) HGereIntégritéOui() // Et enfin, on crée tous les fichiers s'ils n'existent pas Hcreationsiinexistant("*")
Voilà, vous savez maintenant travailler sur des fichiers HyperFile dont l'emplacement est quelconque… Voyons maintenant comment les utiliser ! Un code classique en réseau, pour ajouter un enregistrement dans un fichier, va être : hAjoute(Fichier) tantque hdejabloque() hAjoute(Fichier)
// On essaye d'ajouter // Comme on est en mode personnalisé, il faut tester, même // si un blocage est impossible
FIN si hdoublon() alors
// Si on gère des clés uniques, il faut aussi vérifier // Si la clé n'existe pas déjà
bip info("Erreur de doublon en ajout d'enregistrement sur fichier "+Fichier+"!") FIN si herrintegrite() alors
// Si on gère des liaisons entre fichiers, il faut aussi // vérifier si il n'y a pas d'erreur d'intégrité
bip info("Erreur d'intégrité en ajoute d'enregistrement sur fichier "+Fichier+"!") FIN
Etudions maintenant les points intéressants de ce code : 1. On est en mode personnalisé : En effet, dans la fonction d'initialisation du système de fichier, on a placé l'instruction HModePerso(vrai). Les instructions HModePerso, HModeSemiPerso et HModeAuto permettent de choisir un mode de fonctionnement particulier du moteur HyperFile, et ce point mérite qu'on s'y attarde. Bien sûr, vous trouverez beaucoup d'informations dans l'aide en ligne de WinDev sur les subtilités de ces différents modes… Nous n'allons ici que souligner des points très importants et vous indiquer NOS préférences : •
HModePerso(Vrai) : Dans ce mode, il faut tester HDejaBloque après chaque fonction d'accès au fichier ou à un enregistrement du fichier, même non bloquante (extrait de l'aide en ligne). A vous la plomberie sur TOUTES LES FONCTIONS D'ACCES AUX FICHIERS !
•
HModePerso(Faux) : Dans ce mode, les fonctions de lecture (HLit*) ne retournent aucune erreur de blocage. Ainsi, il n'est pas nécessaire de tester HdejaBloque après chaque fonction (extrait de l'aide en ligne). C'est déjà mieux ? Pas si sûr ! En effet, savez vous précisément quelles sont les fonctions à tester et celles à ne pas tester ? Etes vous sûr de ne jamais confondre et donc oublier des tests ?
•
HModeSemiPerso() : Ce mode permet de faire gérer tous les problèmes d'accès concurrentiels par le moteur HyperFile… Vous n'avez rien à faire de particulier, le moteur bloque les enregistrements quand c'est nécessaire et se débrouille tout seul… Fantastique ? Pas tant que ça ! Si le moteur ne peut bloquer correctement un enregistrement, un message va s'afficher et le programme pourra être interrompu. Si vous aviez des traitements un peu complexes en cours, tant pis pour vous… Vous ne pouvez pas reprendre la main en cas de problème, le moteur se débrouillant tout seul avec l'utilisateur. Ce mode est donc à réserver uniquement aux applications TRES SIMPLES !
•
HModeAuto() : uniquement pour les accès mono postes et les fichiers sur CD/ROM (avec le paramètre FAUX)
Pourquoi avoir choisi le mode personnalisé avec le paramètre VRAI qui donne le plus de travail à faire dans le code ? Nous avons vu-ci-dessus que HModeAuto et HModeSemiPerso étaient à écarter pour toute application réseau conséquente. HModePerso s'imposait donc de lui même.
Le choix du paramètre VRAI implique en principe plus de codage, mais permet d'éviter de se poser des questions : le travail est à faire SYSTEMATIQUEMENT, pas d'ambiguïté ou d'erreur possible ! Mais rassurez vous, nous allons vous livrer des trucs pour que le travail à effectuer se réduise au minimum.
2. Après un Hajoute, on a en fait TROIS groupes de traitements à effectuer : • Test de blocage et traitement éventuel • Test d'erreur de doublon et traitement éventuel • Test d'erreur d'intégrité et traitement éventuel Beaucoup de tests et de codes pour une seule ligne d'instruction intéressante. Votre code va donc rapidement ressembler à une véritable jungle… Ce qui est vrai pour un hAjoute l'est aussi pour les autres instructions d'accès fichiers… A chaque fois, il sera nécessaire de vérifier si on a trouvé l'enregistrement recherché, s'il n'est pas bloqué, si … 3. Que se passe-t-il si on OUBLIE de tester le blocage ? Ce qui est très amusant dans ce cas, c'est qu'il ne se passe rien ! En fait, il ne se passe rien tout de suite, mais par contre, lors de l'accès suivant à un fichier, vous allez récolter une très jolie ERREUR 5, et ce même si sur cet accès vous avez bien testé les blocages !!! Ce mode de fonctionnement est très perturbant quand vous commencez à programmer en réseau, car l'erreur survient sur du code correct, alors qu'à l'emplacement incorrect rien ne s'est produit ! La recherche de l'erreur peut parfois prendre du temps ! Que faire pour résoudre tous ces problème en une seule fois ? Et bien, la solution est l'encapsulation ! Pour ce faire, vous pouvez utiliser des procédure globales ou une classe, selon votre goût… Nous avons choisi ici de vous fournir des procédures globales, afin que tous ceux qui ne sont pas familiers avec l'utilisation des classes ne soient pas perturbés. Mais qu'est ce que l'encapsulation ? Un exemple sera plus parlant qu'un long discours ! Voici donc la procédure globale GDWHajoute extraite du projet d'exemple :
Procédure GDWhAjoute(Fichier,Commande="") // Commande peut indiquer des variations de fonctionnement // Si Commande contient : // NOMESS : on ne fait pas les messages // ... Commande=majuscule(Commande) TrBoolSv est un booleen
TrBoolSv=AffMessage
// On sauvegarde AffMessage qui contient le mode // de fonctionnement courant : Affichage des messages // ou pas
Si position(Commande,"NOMESS")>0 alors AffMessage=faux FIN TrResult est un booleen=Vrai hAjoute(Fichier) tantque hdejabloque() hAjoute(Fichier) FIN si hdoublon() alors bip Si AffMessage alors info("Erreur de doublon en ajout "+… "d'enregistrement sur fichier "+Fichier+"!") TrResult=faux FIN si herrintegrite() alors bip Si AffMessage alors Si AffMessage alors info("Erreur d'intégrité en ajout "+… "d'enregistrement sur fichier "+Fichier+"!") Fin TrResult= faux FIN // On restaure l'état initial AffMessage=TrBoolSv renvoyer TrResult Vous avez compris ? Dans votre code, il vous suffira de remplacer tous les hAjoute par des GDWHajoute… Ceux ci-se chargent d'effectuer les tests de blocage et d'autres tests obligatoires… Bien entendu, d'autres procédures (GDWHlitRecherche, GDWHlitSuivant, GDWHmodifie…) effectueront le même travail en remplaçant les ordres fichiers "classiques"… En faisant un rechercher/remplacer dans tout le projet des ordres standards par les ordres "encapsulés", vous transformerez du code monoposte en code réseau très rapidement… Il vous restera à ajouter avant certains traitement (modification, suppression), des ordres de blocage… Examinez attentivement le code de la fenêtre "client" fournie dans le projet d'exemple et vous verrez que le travail est très simple.
Les avantages de ce système sont nombreux : •
Vous pouvez appliquer le même traitement standard très rapidement et partout…
•
Si vous avez des cas particuliers, vous pouvez ajouter des paramètres de fonctionnement à vos procédures d'encapsulation, comme c'est le cas dans GDWHajoute, où on peut afficher ou pas les messages d'erreurs
•
En sortie de ces procédures, les flags classiques sont toujours actifs, vous pouvez donc tester vous même hdoublon, h.errintegrite… et coder le traitement spécifique dont vous avez besoin à certains endroits.
•
Le jour où vous décidez de changer le comportement global de votre programme vis à vis des blocages, vous ne devez le changer que dans les procédures globales, ce qui sera très rapide. Dans nos exemples de procédures globales, nous partons du principe que les enregistrements ne restent bloqués que très peu de temps… La boucle de test de blocage ne comporte donc pas de sortie en time out… Mais si vous pensez que, dans votre cas, le blocage peut durer longtemps, rien ne vous empêche de rajouter un compteur du nombre d'itérations, un message demandant des instructions, l'enregistrement de l'information dans un fichier de logs pour vous permettre d'optimiser plus tard les accès réseaux…
Les fonctions fournies dans l'exemple sont simples mais opérationnelles… A vous de les enrichir en fonction de vos besoins. De plus, comme vous pouvez le voir, il n'y en a qu'un petit nombre si on le compare au nombre de fonctions fichiers disponibles en Wlangage… Seules les fonctions essentielles ont été encapsulées ici, mais en vous basant sur ces exemples, vous pourrez très facilement ajouter les fonctions qui manqueraient pour VOS traitements. Voilà, vous savez programmer en réseau, il ne vous manque plus qu'un peu de pratique ☺ !
oOoOoOoOoOoOo
Résolution des Problèmes sur fichiers HyperFile Dans ce chapitre, nous allons essayer de trouver des solutions aux différents types de problèmes qui se posent parfois sur les fichiers Hyperfile. Nous allons donc étudier tout d'abord les causes des problèmes et comment y remédier, puis nous allons vous fournir quelques solutions pour réparer des fichiers endommagés. Les problèmes et leurs causes Voici un extrait de l'aide en ligne de WinDev, dans la rubrique "Erreur:Fichiers au format Hyper File"… Ce sont ces cas d'erreurs que nous allons étudier ici… En étudiant la totalité de cette rubrique du fichier d'aide, vous comprendrez que les autres cas peuvent être résolus assez simplement. 07: ERREUR DE LECTURE Cette erreur intervient généralement lorsqu'il y a un problème sur disque (secteur endommagé) ou un problème de lecture sur le réseau (problème temporaire réseau, réessayer) ou que le numéro d'enregistrement à lire est nul. 08: ERREUR D'ECRITURE Cette erreur intervient généralement lorsqu'il y a un problème sur disque (secteur endommagé) ou un problème d'écriture sur le réseau (problème temporaire réseau, réessayer) ou que le numéro d'enregistrement à écrire est nul. 11: CLE INCORRECTE Lors d'une fonction HModifie, la clé constituée à partir de l'enregistrement en mémoire n'est pas retrouvée dans l'index. Il s'agit soit d'une erreur de programmation (aucun enregistrement n'a été lu) soit d'un index défectueux (le réindexer avec WD411NDX.EXE ou WDOutil). H.ErrIgnore est sans effet pour cette erreur. Quand ces erreurs surviennent lors d'un accès fichier, il faut intervenir rapidement… Les causes peuvent être diverses, mais dans tous les cas, c'est un problème d'origine externe au programme lui même, sauf bien entendu si vous essayer de lire ou d'écrire un enregistrement dont le numéro est 0. Dans ce dernier cas, sachez que l'enregistrement 0 des fichiers hyperfile est un
enregistrement réservé pour le moteur hyperfile qui y stocke des informations particulières (dernier n° d'identifiant automatique attribué par exemple). Dans tous les autres cas, il convient de faire 2 choses : réparer les fichiers abîmés et, si possible, trouver la cause du problème de manière à éviter que celui-ci ne se répète. Pour réparer des fichiers abîmés, la manipulation de base est bien entendu la réindexation. Elle peut se faire à partir de l'utilitaire fourni avec WinDev (WdOutil) ou directement dans votre programme grâce à l'instruction hReindexe. Malheureusement, il peut arriver différents cas où cette réindexation ne résout pas le problème. Rassurez vous, il y a des solutions et nous vous les dévoilerons dans la deuxième partie de ce chapitre. Mais voyons maintenant les causes de ces problèmes… Ce type d'erreur ne provient pas d'une erreur de programmation, donc, ne cherchez pas dans votre code… Bien sur, il y a des moyens de diminuer les risques d'erreurs de ce genre, en fermant les fichiers inutilisés par exemple. Mais ce n'est qu'un palliatif ! Vous diminuerez peut-être la fréquence des erreurs, mais vous ne les résoudrez pas comme ça. Il faut commencer par comprendre l'origine de ce type d'erreurs… Que ce soit en réseau ou en mono poste, Windows se charge de gérer les accès aux disques durs et donc aux fichiers… Lorsque des problèmes physiques ou logiques surviennent dans la gestion du disque, la gestion du réseau ou tout simplement dans le noyau de Windows, il arrive que celui-ci ne puisse tout simplement pas effectuer une écriture. Quelles peuvent être les conséquences de cette écriture manquante : •
Au mieux, il manque un enregistrement dans le fichier, mais sa cohérence est intacte (le problème s'est produit avant que les fichiers de données et d'index ne soient modifiés)
•
Par contre, si les informations qui étaient en attente d'écriture étaient destinées au fichier d'index alors que celle destinées au fichier de données ont déjà été écrites, les résultats sont imprévisibles… En effet le fichier d'index étant organisé en arbre binaire, vous pouvez avoir un enregistrement qui a disparu (voire un groupe d'enregistrement ou la plus grande partie du fichier). Les informations sont bien dans le fichier de données, mais l'arbre qui décrit leur ordonnancement ayant été abîmé, un nœud et tous ses sous-nœuds et feuilles a disparu. Ce problème peut d'ailleurs se produire sans qu'aucun message d'erreur n'apparaisse… Ceci arrive quand un nœud à disparu mais que la structure restante de l'index est cohérente… En réindexant, les données réapparaissent comme par magie.
•
Encore plus grave, il se peut que le CONTENU d'un enregistrement soit abîmé, soit que Windows n'ait écrit qu'une partie de l'enregistrement, soit que le contenu de l'enregistrement lui même ait été altéré… Ceci peut aussi bien arriver lors de l'écriture dans le fichier d'index (le .ndx) que dans le fichier de données (le .fic) ou même dans le
fichier des mémos (le .mmo). Dans ce dernier cas, si la réindexation permet de réparer un fichier d'index cassé (plus précisément, permet de le recréer), elle ne peut rien pour réparer le contenu du fichier de données ou du fichier mémo… Il faudra parfois avoir recours à d'autres stratégies qui seront décrites dans la deuxième partie de ce chapitre. Que faire pour éviter que le problème ne se reproduise ? Examinons les différentes causes : •
Problème disque : il faudra reformater, changer le disque, ou toute autre solution analogue
•
Problème électrique : une coupure de courant peut se reproduire, il faut donc envisager de mettre en place un onduleur, ou de mettre à l'abri les câbles électriques qui ont été arrachés, ou encore de remplacer l'alimentation de l'ordinateur…
•
Problèmes réseau : il faut séparer deux types de problèmes très différents : o
Les problèmes physiques. Ces problèmes peuvent eux même être très variables. Dans tous ces cas, le plus dur n'est pas de dépanner, mais de trouver la cause précise du problème. Citons : Un réseau 10 Mbit surchargé va occasionner de nombreuses collisions sur le réseau… Le gestionnaire réseau de Windows étant ce qu'il est, ces circonstances peuvent assez facilement dégénérer en erreur fichier. La solution est simple, passez en réseau 100 Mbits. Un câblage de type coaxial est souvent sensible aux perturbations extérieures. Un bouchon de terminaison mal fixé, un câble réseau placé trop près d'un câble de téléphone ou électrique, d'un néon ou d'un moteur électrique (vive les frigos dans les bureaux)… Des cartes réseaux de mauvaise qualité, ou tout simplement paramétrées de manière différentes les unes des autres (half duplex/full duplex) Un câblage mal réalisé, dont l'exemple typique est le câblage 100 Mbits en RJ 45 réalisé par l'électricien du quartier. Comme ce câblage est droit (1-1, 2-2…8-8), il est souvent réalisé n'importe comment, alors que le câble pour ce type de réseau est du câble blindé par paire, et qu'il faut utiliser les deux fils d'une paire pour les connecteurs 1 et 2, une autre paire pour les connecteurs 7 et 8, une troisième paire pour les connecteur 3 et 6 et enfin la quatrième paire pour les connecteur 4 et 5. Si on respecte pas ce schéma, le câble réseau se parasite lui même ! Pour résoudre ces différents types de problèmes, il faut réussir à isoler la cause… Pour cela, testez les câbles, vérifiez les schémas de câblages utilisés, les endroits où passent les câbles, les paramétrages des cartes. Vous pouvez aussi essayer d'isoler la source en séparant une à une chaque machine du réseau… Bien sûr cette méthode risque d'être longue puisqu'il faut à chaque fois attendre un certain temps (plusieurs jours souvent) pour vérifier si de nouveaux problèmes
surviennent, mais c'est souvent la seule solution A part bien sûr installer une bonne fois pour toute un réseau de qualité en changeant toutes les cartes, les câblages et les hubs… Il s'agit d'ailleurs souvent d'une évolution logique chez les clients… On va par exemple remplacer un vieux réseau 10 Mbits en coaxial poste à poste par un réseau 100 Mbits en RJ 45 en étoile autour d'un hub, et comme par magie, les problèmes disparaissent… Ne riez pas, c'est du vécu ☺ ! o
Les problèmes logiques peuvent eux aussi être très variables. Citons les plus courants : Pas de serveur sur le réseau… On se trouve malheureusement encore parfois confrontés à des installations sur des sites équipés en réseau poste à poste en Windows 9x (voir 3.1x). Rien ne permet d'améliorer vraiment les choses sur ce type de réseau, car ce sont les modules logiques de gestion réseau propres à ces versions de Windows qui sont en cause… Sachez que pour obtenir un bon niveau de fiabilité, il faut mettre en place un serveur de fichier sous Windows NT, Novell, TwinServer ou Linux, les solutions ne manquent pas… Couches réseaux surabondantes : Très souvent, quand on examine la configuration réseau des postes (et du serveur), on se rend compte que tous les protocoles disponibles sur la machine sont installés (TCP/IP, Netbeui, IPX/SPX, etc…). Or, sauf cas exceptionnel, un seul est nécessaire pour que tout fonctionne. Par expérience, le plus simple est de ne mettre en place que le protocole TCP/IP, en attribuant une adresse IP fixe à chaque poste du réseau, de manière à pouvoir se passer aussi du service d'attribution dynamique d'adresse IP. Au passage, quand vous choisissez les adresses IP pour vos postes, choisissez les bien dans les plages d'adresses réservées pour les réseaux locaux, ça vous évitera des problèmes lors de la connexion de votre réseau à Internet : • • •
La classe A numéro 10 : 10.0.0.0 - 10.255.255.255 16 classes B entre 172.16 et 172.31. : 172.16.0.0 - 172.31.255.255 : 256 classes C commençant par 192.168. : 192.168.0.0 192.168.255.255
Encore un mot au niveau d'Internet : NetBeui installé avec un accès Internet, ça s'appelle tout simplement une faille de sécurité ! Le serveur NT mal configuré : Très souvent, le serveur ne suit pas les recommandations faites par Microsoft pour la configuration des couches réseau ! Nous n'allons pas réécrire ici ce qui l'est déjà, par contre, nous vous avons mis sur le CD/ROM une copie de la compilation de toutes ces informations fournie par Philippe FEON et déjà disponible sur le site de WinDevAsso.
Pour vous éviter un téléchargement de plus, vous le trouverez sur le CD/Rom à l'emplacement : OUTILS\Reseau.zip Linux +Samba : Nous ne nous étendrons pas sur ce sujet car, à ce jour, nous ne prétendons pas avoir la compétence suffisante pour prôner systématiquement le remplacement du serveur sous WinDows NT par un serveur Linux avec Samba pour émuler le serveur de fichier de Windows. Tout ce que nous pouvons vous dire, c'est que les expériences relatées par ceux qui ont sauté le pas indiquent que : •
Il y a beaucoup moins (voire plus du tout) d'incidents réseaux
•
A matériel égal, le serveur Linux+Samba est nettement plus rapide que Windows NT
•
Linux et Samba sont gratuits, donc, pour le prix d'un Windows NT serveur + licences / poste, vous pouvez peut être payer un pro de Linux pour l'installation et votre formation ☺.
Comme vous avez pu le constater, les causes des erreurs 7, 8 et 11 sont nombreuses et toutes dues au matériel ou au système… Si des détracteurs de WinDev prétendent que les problèmes de configuration de réseau sont imaginaires car uniquement perceptibles avec WinDev, vous pouvez leur répondre, au choix : •
C'est faux, d'autres logiciels de gestion ont les même problèmes avec les mêmes causes (vous trouverez un certain nombre de références à des logiciels très répandus du commerce dans les archives de la ML WinDev Forum)
•
Si c'était le cas, on se demande pourquoi Microsoft aurait mis ces informations à disposition sur son site, dans les articles cités dans la compilation d'informations faite par Philippe Feon.
•
Si jamais on vous a opposé le fait que travailler avec Word ou une autre application ne pose pas de problème, répondez leur de comparer ce qui est comparable : travailler seul sur un document texte, même s'il est situé sur un autre poste n'a techniquement RIEN de comparable à travailler à plusieurs sur les enregistrements d'un même fichier. De plus, un document Word reste rarement ouvert toute la journée, contrairement aux fichiers d'une application de gestion. Enfin, le jour où le problème se produira sur un document bureautique, le résultat sera très simple, il n'y aura plus de document bureautique du tout (êtes-vous sûr que vous n'avez jamais eu un document Word ou Excel carrément disparu après une coupure de courant ou un plantage de Windows ?).
16: LE FICHIER NE CORRESPOND PAS A SA DESCRIPTION Cette erreur s'affiche lorsque la version du fichier de données est plus récent que la version de l'analyse du programme. Avec WDOutil (option "informations sur le fichier"), il faut vérifier que le numéro de génération du
fichier mémorisé dans le fichier de données et celui mémorisé dans le WDD sont les mêmes. Si le numéro de génération du fichier de données est plus récent que le numéro de génération du WDD, les causes sont les suivantes: - le fichier n'a pas été mis à jour car les disquettes de mises à jour n'ont pas été lancées sur le poste Solution: lancer les disquettes d'installation clients - la bibliothèque (qui contient le WDD), si elle existe, n'a pas été régénérée, Solution: régénérer la bibliothèque - le fichier de données ne se trouve pas dans le répertoire attendu (celui défini dans la description du fichier ou celui indiqué par HSubstRep). Le chemin d'accès au fichier attendu est mémorisé dans le .REP. Solution: modifier le .REP s'il ne correspond pas ou installer les fichiers dans le bon répertoire. Attention: il ne faut jamais déplacer "manuellement" un fichier de données: si un fichier est décrit dans un répertoire et qu'il doit être installé dans un autre répertoire, il faut utiliser la fonction HSubstRep. - en programmation en langage externe, le programme n'a pas été recompilé avec les derniers .WDI et WDR générés. Solution: recompiler le programme avec les WDI et WDR adéquats 17: LE FICHIER NE CORRESPOND PAS A SA DESCRIPTION Cette erreur s'affiche lorsque la version du fichier de données est plus ancien que la version de l'analyse du programme. Avec WDOutil (option "informations sur le fichier"), il faut vérifier que le numéro de génération du fichier mémorisé dans le fichier de données et celui mémorisé dans le WDD sont les mêmes. Si le numéro de génération du fichier de données est plus ancien que le numéro de génération du WDD, les causes sont les suivantes: - le fichier n'a pas été mis à jour car les disquettes de mises à jour n'ont pas été lancées sur le poste Solution: lancer les disquettes d'installation clients - le fichier de données ne se trouve pas dans le répertoire attendu (celui défini dans la description du fichier ou celui indiqué par HSubstRep). Le chemin d'accès au fichier attendu est mémorisé dans le .REP. Solution: modifier le .REP s'il ne correspond pas ou installer les fichiers dans le bon répertoire. Attention: il ne faut jamais déplacer "manuellement" un fichier de données: si un fichier est décrit dans un répertoire et qu'il doit être installé dans un autre répertoire, il faut utiliser la fonction HSubstRep. - en programmation en langage externe, le programme n'a pas été recompilé avec les derniers .WDI et WDR générés. Solution: recompiler le programme avec les WDI et WDR adéquats 50: LE FICHIER NE CORRESPOND PAS À SA DESCRIPTION (FICHIER AU FORMAT D'ةCHANGE). La taille de l'enregistrement indiquée dans l'en-tête du fichier est différente de celle indiquée dans le .WDD Reportez-vous aux consignes indiquées en cas d'erreur 16 ou 17.
Les erreurs 16, 17 et 50 sont très différentes des précédentes. Ces trois erreurs résultent en fait d'un outil formidable inclus dans WinDev, la modification automatique des fichiers de données. En effet, si WinDev vous permet de modifier à volonté la description des fichiers dans vos analyses, il ne se contente pas de cela ! Au passage, il modifie la structure des fichiers de données présents sur votre poste de développement, mais vous permet aussi d'effectuer les mêmes modifications sur les postes de vos clients simplement en cochant une option dans le module d'installation. Prenons un exemple : La première version de votre analyse comprend une zone adresse de 20 caractères. Vous vous rendez ensuite compte que cette zone est trop courte et vous augmentez sa taille à 40 caractères. Si vous livrez une nouvelle version de votre programme à un client qui utilisait l'ancienne, le format de ses fichiers ne correspond plus au format nécessaire pour la nouvelle version de votre application ! Si vous avez oublié de demander la modification automatique des fichiers de données dans votre module d'installation, lorsque votre client lancera son nouveau programme, il se trouvera confronté à l'une de ces erreurs. La cause peut donc être un simple oubli de votre part mais il peut y en avoir d'autres. Commencez donc par consulter l'aide en ligne de WinDev au chapitre "Modification automatique des fichiers de données". Tout le mécanisme y est expliqué en détail. Voyons maintenant les points importants… Si vous obtenez une erreur 16, 17 ou 50, vous savez qu'il y a une incohérence entre le format des fichiers et leur description dans l'analyse. Si vous avez bien demandé la modification automatique des fichiers, c'est que quelque chose s'est mal passé. La plupart du temps, le problème provient de la localisation des fichiers de données au moment de la tentative de modification. En effet, l'utilitaire qui réalise ce traitement (wdModFic) se base sur le contenu du fichier ".REP" pour trouver les fichiers… Si ce contenu n'est pas à jour, si vous utilisez des fichiers qui ne sont pas listés dans le .REP ou qui ne sont pas accessibles au moment du traitement (sur des supports amovibles, sur des disques réseaux non "montés", etc.…), le traitement ne peut être réalisé. Pour résoudre tous ces problèmes, nous vous invitons à consulter en détail le chapitre consacré aux fichiers REP. Deux autres cas peuvent encore se produire : •
Vous avez dû récupérer une sauvegarde d'un fichier de données et le fichier récupéré utilise un format plus ancien…
•
Vous avez récupéré une sauvegarde du programme ou réinstallé une version en vous servant d'un CD autre que le dernier, et vous vous retrouvez avec une version de fichiers de données plus récente que celle de votre programme.
Dans les deux cas, une solution très simple : installez la dernière version de votre programme en demandant la modification automatique des fichiers de données et tout rentrera dans l'ordre. Maintenant que nous avons examiné les cas d'erreur les plus récurrents, voyons comment y faire face.
La réparation Nous n'aborderons pas ici le cas des erreurs 16, 17 et 50 dont les solutions sont largement traitées dans le chapitre sur les fichiers ".REP". Par contre les erreurs 7, 8 et 11 méritent largement de prendre le temps de chercher des solutions. La première solution à essayer est de réindexer les fichiers… Si l'erreur persiste, le plus simple est bien évidemment de récupérer une sauvegarde du fichier abîmé. Vous ne pouvez pas récupérer de sauvegarde , Il n'y en pas, il y a eu trop de travail effectué depuis la dernière ? C'est le moment pour vous de mettre en place un système de sauvegarde automatique (vous trouverez un logiciel gratuit, AxlSauve, qui fait cela très bien sur le CD/ROM à l'emplacement : \OUTILS\AXLSAUVE.Zip) ! Mais comme il est trop tard pour s'en sortir avec une sauvegarde, il faut réparer le fichier… Il faut tout d'abord séparer les différents types de problèmes que vous allez peut être devoir réparer : 1. Le fichier de données est abîmé, il est impossible de le réindexer :Vous avez non seulement des erreurs pendant les accès normaux, mais en plus vous en avez pendant la réindexation. 2. Le fichier de données est abîmé, il est impossible d'afficher certains enregistrements : Lorsque vous affichez un enregistrement à l'écran, un message d'erreur indique que le contenu d'une zone ne correspond pas à ce qu'il devrait être… 3. Le fichier de données est abîmé, la numérotation de l'identifiant automatique ne fonctionne plus : lorsque vous ajoutez un enregistrement dans le fichier, une erreur de doublon survient alors que la seule clé unique est l'identifiant automatique ou que toutes les autres clés uniques sont correctes. 4. Le fichier mémo est abîmé : La réindexation se passe normalement, mais quand vous essayer
d'afficher un ou des enregistrements, vous avez quand même une erreur. Si vous débranchez temporairement la gestion des doublons, vous n'avez plus d'erreur. Vous pouvez exporter le projet nommé GDWProbHF à partir de l'interface du Guide. Ce projet regroupe différentes fenêtres de réparation pour gérer les différents cas ci-dessus. Incroyable ? Nous vous avons mâché le travail ☺ ! Il est basé sur des fichiers standard de WinDev à peine modifiés et contient toutes les fenêtres RAD de gestion de fichier pour vous permettre de créer/parcourir/modifier des fiches. La fenêtre de menu à été modifiée pour permettre d'appeler 4 fenêtres de traitement correspondant à : •
la réindexation des fichiers (c'est la fenêtre standard générée par WinDev)
•
le test et la correction des enregistrements (.FIC)
•
le test et la correction des mémos (.MMO)
•
la correction de l'identifiant automatique
Ces 4 fenêtres sont intégrables telles quelles dans vos applications, mais vous gagnerez sûrement à les modifier pour adapter leur traitement (qui se veut générique) à vos cas particuliers. Mais examinons d'abord les différentes stratégies à employer : Dans les cas 1 et 2, il faut réussir à déterminer quels sont les enregistrements en erreur et choisir ensuite entre les supprimer ou en écraser le contenu. Nous préférons cette dernière solution car les enregistrements peuvent être reliés à d'autre fichiers et supprimer en aveugle ces enregistrements peut déclencher des erreurs en cascade. Pour cela, il faut parcourir tout le fichier et afficher le contenu de chaque enregistrement. Il faut de plus intercepter les erreurs de manière à pouvoir déterminer quels enregistrements sont abîmés et doivent être remis à zéro ou à blanc. Dans le cas numéro 4, le problème est le même, à ceci prés que ce sont les zones mémos qui sont concernées au lieu des zones de l'enregistrement principal. Comme le contenu des zones mémos peut être très divers, il n'est pas possible de les afficher/tester dans un traitement générique. Dans notre exemple, nous avons donc choisi de séparer les cas 1 et 2 d'une part et 4 d'autre part… Ne sachant pas au départ si les enregistrements seuls sont abîmés et/ou si les mémos le sont, il faut commencer par effectuer le traitement sur les enregistrements en débranchant la gestion des mémos, puis, une fois que l'on est certain que les enregistrements sont techniquement valides, on peut alors
lancer le parcours du fichier avec la gestion des mémos branchés. En essayant de tout faire dans le même traitement on ne saurait pas si le problème provient d'une enregistrement ou d'un mémo, et on remettrait donc à zéro des zones qui n'en ont pas besoin. Nous avons donc choisi une méthode permettant de minimiser la perte d'information. Le cas numéro 3 est très différent… Il faut comprendre comment les identifiants automatiques sont gérés : Dans l'enregistrement numéro 0 de chaque fichier HF, les octets 0F à 12 contiennent le plus grand numéro d'identifiant automatique attribué pour ce fichier. Si une erreur système a empêché l'écriture de cette information ou provoqué l'écriture d'une information erronée, chaque fois que le moteur hyperfile essaye d'ajouter un enregistrement, vous vous retrouverez avec une erreur de doublon sur clé unique. Pour résoudre ce problème, il faut remettre la bonne valeur dans l'entête du fichier. Vous pouvez bien sur le faire à la main, avec un éditeur hexadécimal, mais nous vous avons concocté un petit utilitaire qui le fait pour vous. Dans le projet d'exemple, une fenêtre se charge de parcourir le fichier de votre choix, sans utiliser de clé (nous sommes dans le cas où le fichier a des problème et nous ne sommes donc pas sûr à ce moment de la validité des informations d'index). La plus grande valeur de l'identifiant automatique est conservée puis écrite dans l'entête du fichier à la fin du traitement. Bien sûr, vous pouvez vous servir de cet exemple pour modifier le contenu de cette zone si vous en avez envie, mais nous vous le DECONSEILLONS FORMELLEMENT ! Cette zone ne devrait être modifiée que EN CAS DE PROBLEMES GRAVES sur le fichier !
Lorsque le traitement implique l'affichage des informations contenues dans les zones du fichier, il est nécessaire que la fenêtre XX_FIC générée par le RAD et comportant TOUS les champs du fichier soit disponible, même si vous ne l'utilisez pas habituellement dans votre programme. Ceci est nécessaire pour rendre le traitement générique. Comme vous disposez des sources du projet, rien ne vous empêchera de modifier ce fonctionnement par défaut pour l'adapter à votre cas, et même l'affiner.
Vous pouvez envisager beaucoup d'améliorations dans ces traitements et nous allons vous proposer un certain nombre d'idées ci-après. Nous avons choisi de ne pas les implémenter dans notre exemple pour plusieurs raisons : •
Certaines de ces idées nécessitent des adaptations spécifiques à une application
•
L'implémentation de certaines d'entre elles dépend d'un choix du mode de réparation que
vous seul ou vos clients peuvent faire •
Nous n'allons quand même pas faire tout le travail à votre place ☺ !
Mais voyons plutôt ces idées : •
Au lieu de faire un hRaz de l'enregistrement complet dans le traitement des fichiers FIC, on pourrait envisager de faire une boucle sur les champs de chaque enregistrement et de les afficher l'un après l'autre… En faisant ainsi, on pourrait déterminer précisément LE champ qui est en erreur et ne vider que CELUI-CI.
•
La réparation des fichiers mémos pourrait passer par une phase d'affichage/contrôle spécifique au contenu de chaque champ pour améliorer le contrôle et ne pas vider TOUS les champs mémos d'un fichier si un seul est en erreur
•
Il serait possible de faire un traitement qui traite/vérifie complètement un ou tous les fichiers en combinant ces différents traitements : o Traitement du fichier FIC, o puis du fichier MMO, o au passage vérification/correction de l'identifiant automatique o et finalement réindexation avec compactage
Et nous sommes certain que vous en trouverez beaucoup d'autres… Voilà, vous connaissez maintenant les causes de la plus grande partie des problèmes rencontrés sur des fichiers hyperfile et comment les réparer, vous vous sentirez sûrement beaucoup mieux quand un client vous appellera au secours… Mais rassurez vous quand même ! Ce n'est pas parce qu'un chapitre entier est consacré à ces problème qu'ils surviennent souvent… Notre plus gros problème pour mettre au point ces modules de réparation a été de réussir à casser suffisamment les fichiers hyperfile pour pouvoir faire des tests valables ☺.
C'est pour cette raison que nous ne pouvons en aucun cas vous garantir que ces modules seront toujours capables de réparer vos fichiers. Ils nous ont permis de le faire dans les cas que nous avons pu tester, mais vous les utiliserez sous votre seul et entière responsabilité. Et n'oubliez pas de faire une (ou plusieurs) copies de sauvegardes de vos fichiers avant de les traiter ☺. Si vous trouvez des cas de problèmes sur les fichiers HF qui ne sont pas résolus par ces modules, des améliorations à ces programmes ou des idées intéressantes à ce sujet, n'hésitez pas à en faire profiter la communauté des développeurs WinDev.
oOoOooOoOoOoOo
Importation et Exportation Ascii Dans ce chapitre, nous allons vous fournir des solutions simples d'importation et d'exportation de données, car nous savons que ces solutions sont très souvent nécessaires dans la plupart des applications développées avec WinDev… De plus en plus, les applications doivent être capables de communiquer entre elles et d'utiliser des données provenant de sources externes, comme par exemple, fournir des données à d'autres logiciels. De nombreuses possibilités s'offrent à vous quand vous abordez ce chapitre de la programmation WinDev… En effet, WinDev fournit différents mécanismes sophistiqués permettant l'échange d'informations avec d'autres applications comme les liens DDE et la gestion de L'OLE… Certains chapitres de cet ouvrage traitant en profondeur de ces techniques, nous nous contenterons de traiter ici de l'importation et de l'exportation de données au format Ascii qui reste, malgré son grand âge, une des méthodes les plus utiles pour partager des informations. Puisque aujourd'hui pratiquement toutes les applications disposent de fonctions d'importation et d'exportation ascii, vous devez sérieusement envisager d'en incorporer dans vos propres développements. Mais pas d'inquiétude… Si nous allons effectivement décortiquer un peu les tenants et les aboutissants de ces traitements, nous vous fournissons aussi en annexe un projet d'exemple GDWImpEx (que vous pouvez installer sur votre machine depuis l'interface du Guide…) comportant en particulier deux fenêtres très intéressantes, l'une pour l'importation, l'autre pour l'exportation. Si elles sont très largement perfectibles, elles représentent malgré tout une solution d'import/export basique directement incorporable à vos applications, sans aucune modification.. Mais vous en saurez plus à ce sujet à la fin de ce chapitre.
Formats des fichiers ascii Examinons tout d'abord la structure des fichiers ascii les plus courants. Un fichier ascii étant un simple fichier texte, il est clair que son contenu peut prendre n'importe quel format (et certains éditeurs ou administrations n'hésitent pas à compliquer ce format à plaisir ☺).
Toutefois, dans la grande majorité des cas, on rencontre deux types de fichiers : • •
Les fichiers en "longueur fixe". Dans ce cas, chaque enregistrement du fichier à la même taille, et une zone de l'enregistrement est caractérisée par une position et une longueur… Les enregistrements sont parfois séparés les uns des autres par un caractère de fin d'enregistrement, mais cela n'est pas obligatoire, puisque leur taille fixe permet de les repérer précisément. Un fichier de ce type ressemble donc à quelque chose comme cela : DUGLAS HARARI …
• •
ALAIN FABRICE
DIACOM INTERNATIONAL AXLINFO
[email protected] [email protected]
Les fichiers "délimités". Dans ce cas, les enregistrements peuvent avoir des tailles variables et sont en général séparés les uns des autres par un retour chariot. Chaque zone est séparée des autres par un caractère "délimiteur" (; TAB ou autre). De plus, le contenu des zones est souvent encadré par des guillemets ("). Dans ce cas, le fichier ressemblerait plutôt à ceci : "DUGLAS";"ALAIN";"DIACOM INTERNATIONAL";"[email protected]" "HARARI";"FABRICE";"AXLINFO";"[email protected]"
Bien sûr, de nombreuses variantes peuvent exister (en particulier pour le type délimité) et vous pouvez être confronté à : •
Des séparateurs très variés (: ; , TAB ou autre),
•
La présence ou l'absence des guillemets, parfois remplacés par d'autres caractères,
•
La présence d'une ligne d'en-tête (header) comportant les noms des différentes zones…
Sachez tout de même que l'ascii délimité est le format que l'on rencontre le plus souvent…
Si vous êtes amené à exporter des données sans savoir quel logiciel va les lire, vous pouvez utiliser un "truc" pour rendre votre fichier plus "universel" ! Combinez les deux méthodes ! Utilisez des longueurs fixes pour toutes les zones, mais séparez les quand même par des séparateurs… Vous obtiendrez alors quelque chose qui ressemblera à ceci : "DUGLAS ";"ALAIN ";"DIACOM INTERNATIONAL "HARARI ";"FABRICE";"AXLINFO …
";"[email protected] ";"[email protected]
Ce format mixte pourra alors être lu par n'importe quel programme implémentant l'importation de l'un ou de l'autre de ces deux formats… En longueur fixe, on indiquera que la zone nom commence au caractère 2 (pour éviter le guillemet) et à une longueur de 7 caractères et que la zone suivante ne commence qu'au caractère 12, évitant
ainsi les guillemets et le séparateur. En délimité, il y aura simplement des espaces en fin des différentes zones, ce qui ne devrait pas poser de problème.
Lecture d'un fichier ascii Pour WinDev, un fichier ascii est un fichier externe tout ce qu'il y a de classique. WinDev fournit d'ailleurs deux méthodes pour lire dans ces fichiers, les instructions fLit et fLitLigne. Nous ne nous étendrons pas sur le sujet, l'aide en ligne de ces instructions et les exemples fournis dans le guide étant largement suffisants pour l'apprentissage de leur utilisation… Examinons-les plutôt par rapport à nos différents besoins : la lecture d'un fichier délimité et la lecture d'un fichier en longueur fixe… FLitLigne vous permet de lire le contenu d'une ligne d'un fichier externe, la définition d'une ligne étant une zone de texte terminée par un RC+LF (retour chariot plus Line Feed, soit les caractères ascii 13 et 10). Cette instruction est donc parfaitement adaptée au traitement des fichiers ascii délimités qui sont justement structurés de cette manière. Par contre, les fichiers en longueur fixe ne comprennent pas toujours des RC+LF entre les enregistrements. Dans ce cas, il convient donc d'utiliser l'instruction fLit qui permet quant à elle de définir précisément le nombre de caractères que l'on souhaite lire. Le traitement à effectuer pour l'importation d'un fichier ascii peut se résumer ainsi : •
Ouverture du fichier ascii en mode lecture (instruction fouvre),
•
Boucle en lecture des différents enregistrements (instructions flit ou flitligne selon le cas), o
Traitement de l'enregistrement, à savoir : Contrôles éventuels, Affectation des informations dans les zones du ficher HyperFile, Ajout de l'enregistrement dans le fichier HyperFile,
•
Quand le fichier ascii a été traité en totalité, fermeture de celui-ci (instruction fferme).
On parle ici d'ajout d'enregistrement dans le fichier HyperFile, car c'est le cas le plus courant, mais dans certains cas, vous pouvez être amenés à utiliser ce système pour modifier des
enregistrements existants, voire en supprimer, en fonction du contenu d'une des zones du fichier ascii. Un système de ce genre peut donc permettre de gérer la réplication d'informations entre différentes bases de données de manière très souple.
Il convient aussi d'examiner l'instruction hImporteTexte qui a la prétention de pouvoir remplacer tout le traitement ci-dessus par une seule ligne de code. En théorie, c'est fantastique, mais en pratique, vous ne pourrez l'utilisez que dans un nombre de cas très restreints. En effet, elle ne traite que des fichiers délimités, et gère un certain nombre de cas bien précis, sans aucune possibilité d'intervention de votre part. Si un problème non prévu survient lors de l'importation d'un fichier avec cette méthode, vous n'obtiendrez qu'un compte rendu d'erreur. Avec un traitement "manuel", vous pourrez déterminer précisément quoi faire dans ce cas (ignorer la ligne et continuer, demander l'avis de l'utilisateur, etc, etc) Enfin, bien entendu, cette instruction ne fonctionne que pour l'importation dans un fichier HyperFile, alors que le traitement "manuel" vous permet d'importer tout aussi bien dans un fichier xBase, une base Access, une base SQL, voire tout simplement dans une table mémoire si l'utilisateur veut pouvoir vérifier / modifier les données avant l'importation…
Ecriture dans un fichier ascii Pour l'exportation de données dans un fichier ascii, le schéma est exactement "parallèle" : •
Ouverture du fichier ascii en mode écriture (instruction fouvre),
•
Boucle en lecture des différents enregistrements du fichier HyperFile à exporter, o
Traitement de l'enregistrement, à savoir : Contrôles éventuels, Préparation d'une chaîne de caractères au bon format (délimité ou longueur fixe), Ecriture de cette chaîne dans le fichier ascii (instructions fecrit),
•
Quand le fichier HyperFile a été traité en totalité (ou au moins tous les enregistrements à exporter), fermeture de celui-ci (instruction fferme).
Vous voyez, rien de bien compliqué ! Bien sûr, vous trouverez un exemple complet d'exportation GDWImpEx que vous pouvez exporter depuis l'interface du Guide
OEM ANSI Autres formats Souvent lors de traitement d'importation ou d'exportation de données, on se trouve confrontés aux limites des "standards". En effet, on pourrait croire qu'à partir du moment où on parle de fichier ASCII, leur encodage est toujours identique… Et bien ce n'est pas le cas ! Voyons donc ensemble les problèmes que vous pouvez rencontrer : Vous obtenez des caractères bizarres à la place des caractères accentués ? Si votre fichier provient d'un PC, c'est certainement un problème d'encodage ANSI / OEM… S'il provient d'un ordinateur plus "exotique" (MacIntosh par exemple), le problème sera peut être plus compliqué à résoudre. Il existe en effet de nombreuses variantes de la norme ASCII. Rien que sur plate-formes PC, vous pouvez vous trouver face à de l'ascii OEM (typiquement norme MS/DOS) ou à des caractères à la norme ANSI (norme WINDOWS). WinDev fournit deux instructions très utiles dans ce cas : OEMVersAnsi et AnsiVersOEM… Ces deux instructions permettent de transcoder très facilement une chaîne d'un format à l'autre… Par contre, si votre fichier est plus exotique, il vous faudra, soit obtenir une version plus classique (sur MacIntosh par exemple, il existe des outils permettant de transformer du texte "Mac" en texte PC), soit transcoder vous-même vos fichiers lors de l'importation. Mais vous n'en avez pas encore fini avec les fichiers ascii… En effet, vous pouvez avoir tout un tas de variantes pour les délimiteurs d'enregistrement. Par exemple, certains fichiers provenant du monde Unix peuvent utilisent un simple LineFeed comme délimiteur (caractère 10), voire un LF+CR (caractères 10 + 13)… Enfin, méfiez vous ! Fichier texte ne veut pas forcément dire fichier Ascii ! Il existe d'autres "standards" d'encodage dans le monde informatique, comme par exemple l'EBCDIC…Ce dernier est un standard provenant des gros systèmes IBM et est totalement différent de la norme ascii… Fort heureusement, il devient de plus en plus rare de se trouver confronté à des fichiers de ce type, autrefois fort répandus.
Projet WinDev d'Import/Export Maintenant que nous avons bien insisté sur tous les problèmes que vous risquez de rencontrer, passons aux bonnes nouvelles : vous pouvez donc exporter, depuis l'interface du Guide, le projet d'exemple GDWImpEx, permettant l'importation et l'exportation de fichiers ascii.
Examinons ensemble ses caractéristiques : Sa base a été générée par le RAD à partir de fichiers d'exemple de WinDev… Ceci pour vous permettre de faire des essais avec des fichiers que vous pourrez examiner ou modifier à volonté. Vous pouvez réutiliser les fenêtres d'import et d'export (GDWImpor et GDWExpor) directement dans n'importe laquelle de vos applications. En effet, les routines utilisées sont génériques et se chargent de retrouver de manière dynamique les noms des fichiers et de leurs champs. Ces exemples traitent uniquement des fichiers délimités d'un type particulier (; et "), mais il vous sera facile de modifier ce code en fonction de vos besoins. Les modules d'import et d'export vous permettent de choisir quelles rubriques traiter et dans quel ordre. Le module d'import vous permet par ailleurs de visualiser le début du fichier ascii à importer, de façon à faciliter le travail de mise en correspondance des zones. Le module d'import permet en outre d'ignorer certaines zones du fichier ascii, en ajoutant l'information "Rubrique à ignorer" dans la liste, ce qui vous permet de n'importer que les zones qui vous intéressent. L'étude des différentes fonctions de ces exemples devraient vous permettre de bien comprendre ces différents traitements et de les améliorer en fonction de vos besoins spécifiques…
Quelles améliorations ? Par exemple : •
Ajout de tests pour sélectionner les enregistrements à exporter,
•
Implémentation des traitements pour les fichiers en longueur fixe,
•
Choix des délimiteurs à utiliser,
•
Traitement d'exportation utilisant une des clés du fichier HyperFile au lieu de faire une boucle sur hlit,
•
Exportation complexe de fichiers liés,
•
Importation d'un fichier ascii dans plusieurs fichiers HyperFile reliés,
•
Traitements d'importation différents en fonction d'une des zones du fichier à importer (ajout, modification, suppression), ce qui, lié à une fonction d'exportation de tous les enregistrements
modifiés / supprimés / ajoutés dans une base, conduit à une puissante fonction de réplication Comme vous le voyez, les possibilités sont immenses, et nous sommes sûrs que vous trouverez encore bien d'autres idées à ce propos… oOoOoOoOoOoOo
Dates et Heures en WinDev Les fonctions de gestion des dates et des heures en WLangage sont nombreuses et souvent suffisantes pour la grande majorité des traitements courants. Nous allons essayer ici de vous apporter des informations complémentaires et des routines utiles dans les problèmes de gestion courante en vous offrant des fonctions complémentaires. Tout d'abord, sachez que WinDev stocke les dates et les heures sous forme de chaînes. Une date comme le 27/12/2000 est stockée dans une chaîne de 8 caractères sous la forme 20001227. WinDev permet également d'utiliser un format de date court avec l'année stockée sur 2 chiffres, mais maintenant que nous avons passé le cap du bug de l'an 2000, plus personne ne devrait l'utiliser. De la même façon, une heure comme 16h15m25s12c est stockée dans une chaîne au format 16152512. Ces deux formats permettent un tri facile des informations que ce soit dans une table ou dans une clé de fichier. Lors de l'utilisation de champs de saisie de type date et heure, deux formats sont gérés : le format de stockage interne et le format de saisie / affichage. Ainsi, les utilisateurs saisiront la date au format JJ/MM/AAAA (ou MM/JJ/AAAA si nécessaire), mais quel que soit le format de saisie utilisé, elle sera stockée sous la forme AAAAMMJJ. Ceci est vrai également pour les heures. Les fonctions DateVersChaine et ChaineVersDate sont là pour vous permettre de passer d'un de ces formats à l'autre quand vous devez gérer des dates à un autre niveau que des champs de saisie (extraction depuis un fichier texte par exemple). Dans les fichiers HyperFile, lorsque vous déclarez un champ comme étant de type date, il s'agit donc d'une chaîne de 8 octets. Par contre, soyez méfiants à cet égard : si vous déclarez un champ comme étant de type heure, seuls 4 octets sont utilisés et vous ne pourrez donc stocker que les heures et les minutes. Si vous avez besoin de stocker aussi les secondes et/ou les centièmes de secondes, il vous faudra le faire dans un simple champ chaîne de longueur 6 ou 8. Lorsque vous avez besoin de faire des calculs sur des dates / heures, vous disposez des fonctions DateVersEntier et HeureVersEntier qui vous permettent, comme leur nom l'indique, de transformer vos chaînes en entiers, chaînes que vous pouvez ensuite additionner ou soustraire…
Le résultat est un entier long, mais vous devez vous méfier de ces fonctions dans plusieurs cas : • DateVersEntier ne fonctionne que pour une date supérieure au 1er janvier 1800 (qui correspond à la valeur 1) • HeureVersEntier ne fonctionne que pour une heure comprise entre 00h00 et 23h59m59s99c • Ces deux fonctions affichent un message dans le cas où on leur fournit une date ou une heure invalide. Si vous les utilisez dans une formule de calcul, ce n'est sûrement pas ce que vous souhaitez...
Que peut-on faire pour résoudre ces problèmes ? Pour les deux premiers, il faudra faire vos calculs vous-même en contournant le problème… Par exemple, si vous devez additionner des heures mais que le résultat peut dépasser 24 heures :
TrEntier est un entier long // qui contient le résultat de vos additions TrNbJour est un entier=0 // // Le code ci-dessous incrémente un compteur de jours tantque TrEntier ne // contient pas une valeur correspondant à un nombre d'heures inférieur à 24. Tantque TrEntier>=8640000 alors TrNbJour++ TrEntier=TrEntier-8640000 Fin En ce qui concerne les messages affichés, imaginons que vous deviez placer des formules de calcul dans votre code et que ces formules travaillent sur des zones saisies par l'utilisateur. Ce dernier peut saisir une date ou laisser la zone vide… Si votre code contient la ligne : TrEntier=TrEntier+DateVersEntier(DateSaisie) et que l'utilisateur a laissé la zone "DateSaisie" vide, vous obtiendrez un superbe message d'erreur pendant l'exécution. Vous pouvez bien sûr tester chaque date et chaque heure avant de l'utiliser, mais si vous avez de nombreuses zones, votre code ressemblera vite à un plat de spaghettis. Nous vous proposons une formule un peu plus "élégante". Il suffit d'encapsuler la fonction DateVersEntier dans une procédure globale que nous appellerons GDWDateVersEntier :
Procédure GDWDateVersEntier(DateChaine) //Teste si la date est correcte //Renvoie un entier si c'est le cas, 0 Sinon Si DateValide(DateChaine) alors renvoyer (dateversentier(DateChaine)) Sinon renvoyer 0 Fin
Ainsi que vous le constatez, cette procédure se charge de faire le test de validité et renvoie 0 dans le cas où la date n'est pas valide. Dans une formule de calcul, si l'utilisateur a laissé la zone vide, cela veut dire qu'il ne faut rien additionner et écrire : TrEntier=TrEntier+GDWDateVersEntier(DateSaisie) est donc maintenant suffisant. De la même façon, la procédure GDWHeureVersEntier renverra 0 ou la bonne valeur en fonction de la validité du paramètre.
Procédure GDWHeureVersEntier(HeureChaine) //Teste si l'heure est correcte //Renvoie un entier si c'est le cas, 0 Sinon Si HeureValide(HeureChaine) alors renvoyer (HeureVersEntier(HeureChaine)) Sinon renvoyer 0 Fin La suite de ce chapitre se propose de vous fournir "clé en mains" un certain nombre de fonctions qui travaillent sur les dates et les heures… Elles vous épargneront sûrement quelques heures de travail. Les procédures AjouteJour, AjouteMois et AjouteAnnee vous permettent en une seule instruction d'ajouter à une date quelconque un nombre quelconque de Jours, de Mois ou d'Années ; ce nombre pouvant bien sûr être négatif. En retour, elles renvoient la date correspondant au résultat trouvé. Si la date initiale n'est pas valide, ces fonctions la renvoient telle quelle, sans faire aucune addition. AjouteJour :
Procédure AjouteJour(TrDate,NbreJours) // Ajoute le nbre de jours (positif ou négatif) à la date passée en paramètre et // renvoie la date correspondante // Si la date n'est pas valide, la renvoie telle quelle Si pas datevalide(TrDate) alors renvoyer TrDate Renvoyer entierversdate(dateversentier(TrDate)+NbreJours) AjouteMois :
Procédure AjouteMois(TrDate,NbreMois) // Ajoute le nbre de mois (positif ou négatif) à la date passée en paramètre et // renvoie la date correspondante
// Si la date initiale est incorrecte, la renvoit telle quelle Si pas datevalide(TrDate) alors Renvoyer TrDate TrChaine est une chaine TrEntier est un entier TrAnnee est un entier TrAnnee=gauche(TrDate,4) TrEntier=val(Milieu(TrDate,5,2))+NbreMois tantque TrEntier>12 TrEntier=TrEntier-12 TrAnnee=TrAnnee+1 Fin tantque TrEntier0 alors //le jour d'échéance est il supérieur au jour courant (même mois) TrJour=droite(TrDate,2) TrMois=milieu(TrDate,5,2) TrAnnee=gauche(TrDate,4) Si JourEcheance>TrJour alors TrJour=JourEcheance Sinon //Passage au mois suivant en plus TrJour=JourEcheance Si TrMois> ShowDateSelectors = 0 3. pour gérer un évènement du contrôle ActiveX : La plupart des contrôles ActiveX, à travers des évènements, permettent d'interagir sur la saisie des utilisateurs et de connaître à tout moment ce qui vient d'être frappé au clavier, cliqué, double-cliqué, etc... Dans notre exemple, nous allons récupérer, à chaque clic sur le contrôle Calendrier, quelle est la date sur laquelle l'utilisateur a cliqué.
Placez l'appel à l'évènement dans le code d'ouverture de la fenêtre :
EXTERN "WINCONST.wl" Evenement("DbClick","Calendrier",WM_LBUTTONDBLCLK) Ici, l'évènement est basé sur un double-clic (WM_LBUTTONDBLCLK) (la valeur de WM_LBUTTONDBLCLK étant récupérée par la lecture du fichier "WINCONST.wl", qui, nous le rappelons, contient les valeurs des constantes Windows...) de la souris dans le contrôle Calendrier, la procédure
associée étant la procédure DbClick... Voici le code de la procédure associée DbClick :
Procédure DbClick() jDay, mMonth, yYear sont des entiers longs =0 Date est une chaine = “” jDay = Calendrier >> Day() // on récupère le Jour cliqué, mMonth = Calendrier >> Month() // on récupère le Mois cliqué, yYear = Calendrier >> Year() // on récupère l'année. // Transformation en chaine Si jDay