NomChampTable.NomColonne..OptionTri = ccRespecteNumérique
TableTrie(NomChampTable, "+"+NomChampTable.NomColonne..NomComplet)
- Le masque "099,99" affiche un résultat de la forme "012.34" et pas "12.34".
- Le masque "999,00" affiche un résultat de la forme "999" et pas "999.00".
- Le masque "+999;-999" affiche un résultat de la forme "+999" et pas "999".
- Le masque "999,99%" affiche "12.3%" et retourne un résultat de la forme "0.123".
- Le masque "999,99%%" affiche "12.3%" et retourne un résultat de la forme "12.3".
ST_Point3D est une Structure
nX est un entier
nY est un entier
nZ est un entier
FIN
stUnPoint3D est un ST_Point3D = [0, 0, 50]
L'affichage du champ ou de la fenêtre n'est demandé qu'après le traitement.
NomChampTable..AffichageActif = Faux
POUR i = 1 À 1000
TableAjouteLigne(NomChampTable, TraitementPourLaLigne(i))
FIN
NomChampTable..AffichageActif = Vrai
Le séparateur n'est pas concaténé si la chaîne de départ est une chaîne vide.
sUneChaîne est une chaîne
POUR i = 1 À 10
sUneChaîne += [":"] + NumériqueVersChaîne(i)
FIN
// La variable sUneChaîne vaut "1:2:3:4:5:6:7:8:9:10"
tab1 est un tableau de chaîne = ["Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi"]
sUneChaîne est une chaîne = TableauVersChaîne(tab1, ";")
// La variable sUneChaîne vaut "Lundi;Mardi;Mercredi;Jeudi;Vendredi"
Inversement, pour transformer une chaîne en tableau avec un séparateur connu :
sUneChaîne est une chaîne = "5,4,3,2,1"
tab1 est un tableau de chaîne
ChaîneVersTableau(sUneChaîne, tab1, ",")
// La variable tab1 vaut ["5", "4", "3", "2", "1"]
// A placer dans le code de l'événement clic sur une colonne de type image d'un champ table
TableSelectPlus(NomChampTable, NomChampTable)
Trace( TableSelect(NomChampTable) )
// A placer dans le code de l'affichage d'une ligne du haut de rupture dans un champ table
NomChampTable[TableIndiceRupture(NomHautDeRupture)].NomChamp = NomChampTable.NomColonne
Cette fonction doit être appelée avant le début d'une impression (exemple : avant la fonction iImprime() ou iImprimeEtat(), ...).
iFenêtreAbandon(Faux)
Voici comment intercepter le déplacement de l'ascenseur dans la table 1 pour le transmettre à la table 2 :
Dans le code d'initialisation du champ Table1 :
// On intercepte le déplacement de l'ascenseur
Evénement("DeplaceTable1", NomChampTable1..Nom, 276) // WM_HSCROLL=276
Dans une nouvelle procédure locale nommée "DeplaceTable1" :
// On transmet ce déplacement à une seconde table
PROCÉDURE DeplaceTable1(nMessage, WPARAM , LPARAM)
SendMessage(Handle(NomChampTable2..Nom), nMessage, WPARAM, LPARAM)
Depuis la version 19 de WINDEV® et grâce à la nouvelle fonction AscenseurPosition() :
AscenseurPosition(NomChampTable2, ascHorz, AscenseurPosition(NomChampTable1, ascHorz))
S'il y a une utilisation de l'IHM (thread principal) dans une des tâches parallèles alors la fonction TâcheParallèleAttendToutes() ne fonctionnera pas. Il faut alors utiliser le code ci-dessous.
tabTP est un tableau de TâcheParallèle
// La ligne ci-dessous ne fonctionne pas
//TâcheParallèleAttendToutes(tabTP)
nIndice est un entier = 1
TANTQUE (nIndice = 1 À tabTP..Occurrence)
SI tabTP[nIndice]..Terminée ALORS
nIndice++
SINON
Temporisation(25, tempoSourisEtClavier)
FIN
FIN
S'il y a une utilisation de l'IHM (thread principal) dans le thread secondaire alors la fonction ThreadAttend() sera bloquante. Il faut alors utiliser le code ci-dessous.
// La ligne ci-dessous ne fonctionne pas
//ThreadAttend(sThreadIdentifiant, 100)
nChrono est un entier = DonneIdentifiant()
ChronoDébut(nChrono)
// Si le thread secondaire n'existe plus ou que la durée d'attente est supérieure à 1 seconde alors sortir de la boucle
TANTQUE (ThreadEtat(sThreadIdentifiant) <> threadInexistant) _ET_ (ChronoValeur(nChrono) < 100)
Temporisation(5, tempoSourisEtClavier)
FIN
ChronoFin(nChrono)
L’exécution d'une fonction d'attente (ThreadPause / Multitâche / SignalAttend / ...) provoque un interblocage (deadlock).
Dans le code de l'événement "Enroulé, déroulé d'un nœud" d'un champ arbre, ajouter le code suivant :
RENVOYER Faux
Trace( dbgInfo(dbgElément, dbgTraitementAppelant) )
HLitDernier(NomTableBDD)
SI PAS HEnDehors(NomTableBDD) ALORS
// L’identifiant automatique est fixé au dernier enregistrement
HModifie(NomTableBDD, hNumEnrEnCours, hFixeIdAuto)
FIN
L'opérateur d'échange permet d'échanger le contenu de deux éléments.
// Affecte la valeur 5 à la variable i et la valeur 6 à la variable j
i, j est un entier = (5, 6)
// Le résultat de la trace vaut "i=5 j=6"
Trace("i="+i, "j="+j)
i <=> j
// Le résultat de la trace vaut "i=6 j=5"
Trace("i="+i, "j="+j)
Le séparateur des miliers peut être un séparateur insécable, ce qui peut fausser l'affichage dans les états ou dans les champs.
// Si le séparateur insécable - Caract(160) [Windows 11] - est le séparateur des milliers alors ...
// ... forcer le séparateur des milliers par un Espace - caract(32) [Windows 10] -
SI (Milieu(NumériqueVersChaîne(1000, "4S"), 2, 1) = Caract(160)) ALORS
ChangeSéparateur(sepMILLIER, Caract(32))
FIN
sUrl_à_tester est une chaîne = "<URL>"
sUrl_urlDomaine est une chaîne = URLExtraitChemin(sUrl_à_tester, urlDomaine)
sUrl_urlCheminComplet est une chaîne = URLExtraitChemin(sUrl_à_tester, urlCheminRessource+urlNomRessource+urlExtensionRessource)
sMessage est une chaîne = [
HEAD /%1 HTTP/1.1
Host: %2
Connection: Close
] // Message à transmettre
sMessage = ChaîneConstruit(sMessage, sUrl_urlCheminComplet, sUrl_urlDomaine) +RC+RC
SI SocketExiste("MaSocketHTTP") ALORS
SocketFerme("MaSocketHTTP")
FIN
SI SocketConnecte("MaSocketHTTP", 80, sUrl_urlDomaine, 5000) ALORS
// Le marqueur de fin est la chaîne de caractères "<EOF>"
SocketChangeTransmissionMode("MaSocketHTTP", SocketMarqueurFin)
SI SocketEcrit("MaSocketHTTP", sMessage) ALORS
Trace( ExtraitChaîne(SocketLit("MaSocketHTTP"), 2, " ") )
FIN
SocketFerme("MaSocketHTTP")
FIN
Depuis la version 20 de WINDEV® et grâce aux nouvelles variables httpRequête et httpRéponse :
cMaRequête est un httpRequête
cMaRequête..URL = "<URL>"
cMaRequête..Méthode = httpHead
cMaRéponse est un httpRéponse = HTTPEnvoie(cMaRequête)
SI PAS ErreurDétectée() _ET_ (cMaRéponse..CodeEtat = 200) ALORS
Trace( cMaRéponse..CodeEtat )
FIN
cMaRequête est un httpRequête
cMaRequête..URL = "<URL>" // Lien vers un fichier sur le web
cMaRéponse est un httpRéponse = HTTPEnvoie(cMaRequête)
SI PAS ErreurDétectée() _ET_ (cMaRéponse..CodeEtat = 200) ALORS
sTempFichier est une chaîne = fRepTemp() +[fSep]+ fExtraitChemin(cMaRequête.URL, fFichier+fExtension)
SI fSauveTexte(sTempFichier, cMaRéponse..Contenu) ALORS
Trace(sTempFichier)
FIN
FIN
sImageOrigine est une chaîne = "C:\logo.jpg" // lien vers un fichier image
sTempFichier est une chaîne = fRepTemp() +[fSep]+ fExtraitChemin(sImageOrigine, fFichier+fExtension)
SI fEstUneImage(sTempFichier) ALORS
img est une Image = dChargeImage(sImageOrigine) // Charge le fichier dans une variable de type Image
dRedimensionne(img, img..Largeur/2, img..Hauteur/2, drHauteQualite) // Permet de réduire les dimensions de l'image
dSauveImageJPEG(img, sTempFichier, 60) // Taux de compression de 40 %
Trace(sTempFichier)
FIN
// Effectuer une requête HTTP de type GET avec autorisation via socket
sMessage est une chaîne = [
GET %1 HTTP/1.1
Host: %2
User-Agent: %3
Connection: keep-alive
Authorization: Basic %4
] // Message à transmettre
sMessage = ChaîneConstruit(sMessage, "<URL>", "UneAdresseIP", "", Crypte("UnIdentifiant:UnMotDePasse", "", crypteAnsi, encodeBASE64)) +RC+RC
SI SocketExiste("MaSocketHTTP") ALORS
SocketFerme("MaSocketHTTP")
FIN
SI SocketConnecte("MaSocketHTTP", UnNuméroDePort, "UneAdresseIP", 5000) ALORS
// Aucun marqueur n'est ajouté/enlevé au message
SocketChangeModeTransmission("MaSocketHTTP", SocketSansMarqueurFin)
SI SocketEcrit("MaSocketHTTP", sMessage) ALORS
Trace( SocketLit("MaSocketHTTP", Vrai) )
FIN
FIN
Nous allons prendre comme exemple un fichier au format PDF :
- Ouvrir la base de registre grâce à la commande "regedit"
- Accéder à "HKEY_CLASSES_ROOT\.pdf"
- Lire le contenu de la chaîne par défaut, dans mon cas "AcroExch.Document.11"
- Accéder à "HKEY_CLASSES_ROOT\AcroExch.Document.11\shell\Print\command"
- Lire le contenu de la chaîne par défaut
Exemples de contenu de la base de registre pour l'impression d'un fichier PDF :
"C:\Program Files (x86)\Adobe\Reader 11.0\Reader\AcroRd32.exe" /p /h "%1"
"C:\Program Files (x86)\Foxit Software\Foxit Reader\Foxit Reader.exe" /p "%1"
"C:\Program Files\Adobe\Acrobat DC\Acrobat\Acrobat.exe" /p /h "%1"
Sous l'AGL WINDEV®, le code suivant exécute les étapes ci-dessus :
LanceAppliAssociée(sCheminEtNomDuFichier, "print")
Si vous souhaitez intercepter les touches enfoncées du clavier en dehors d'une interface WINDEV®, voici un petit exemple :
Dans le code d'initialisation du projet :
EXTERNE "keyconst.wl" // Constantes standard utilisées pour les touches du clavier
EXTERNE "winconst.wl" // Constantes standard
gnHandleHook est un entier système
gnHandleHook = API("User32", "SetWindowsHookExA", WH_KEYBOARD_LL, &KeyboardHook, Instance(), 0)
Dans le code de fermeture du projet :
// Retirer la procédure de traitement de la chaîne de procédures de traitement
API("user32","UnhookWindowsHookEx", gnHandleHook)
Création d'une procédure globale :
PROCÉDURE KeyboardHook(nCode est un entier système, wparam est un entier système, lparam est un entier système)
nCaractTouche est un entier système
SI (nCode = 0) ALORS
Transfert(&nCaractTouche, lparam, 4)
// ... Le traitement à exécuter
Trace( nCaractTouche, ToucheEnfoncée(VK_LCONTROL, Vrai), ToucheEnfoncée(VK_LSHIFT, Vrai) )
FIN
RENVOYER API("user32", "CallNextHookEx", gnHandleHook, nCode, wparam, lparam)
// Renvoyer Vrai afin de permettre le traitement de l'appui par la fenêtre d'origine
Si vous souhaitez optimiser l'initialisation de plusieurs variables de type tableau avec les mêmes valeurs, voici un petit exemple :
tab1, tab2, tab3, tab4, tab5 est un tableau de chaîne
// Code non optimisé :
POUR i = 1 À 100 000
TableauAjoute(tab1, NumériqueVersChaîne(i))
TableauAjoute(tab2, NumériqueVersChaîne(i))
TableauAjoute(tab3, NumériqueVersChaîne(i))
TableauAjoute(tab4, NumériqueVersChaîne(i))
TableauAjoute(tab5, NumériqueVersChaîne(i))
FIN
// Code optimisé :
POUR i = 1 À 100 000
TableauAjoute(tab1, NumériqueVersChaîne(i))
FIN
TableauCopie(tab1, tab2)
TableauCopie(tab1, tab3)
TableauCopie(tab1, tab4)
TableauCopie(tab1, tab5)
En bonus, voici le code pour optimiser la déclaration d'une variable de type structure d'un tableau de structure comportant un ou plusieurs tableaux :
ST_Structure est une Structure
nEntier est un entier
schaîne est une chaîne
tabchaîne est un tableau de chaîne
FIN
gtabStructure est un tableau de ST_Structure
PROCÉDURE TrtTableau(LOCALE i est un entier)
// Code non optimisé :
stS est un ST_Structure
stS = gtabStructure[i]
... // Traitement
// Code optimisé :
stS est un ST_Structure dynamique
stS <- gtabStructure[i]
... // Traitement
sdReq est une Source de Données
sReq est une chaîne = "SELECT * FROM SOCIETE WHERE IDSOCIETE IN ({pListe_IDSOCIETE})"
sListe_IDSOCIETE est une chaîne
POUR i = 1 À 7000
sListe_IDSOCIETE += [","]+ NumériqueVersChaîne(i)
FIN
// Si la connexion n'est pas sur une base MSSQL Serveur alors exécuter le code classique :
HAnnuleDéclaration(sdReq)
sdReq.pListe_IDSOCIETE = sListe_IDSOCIETE
HExécuteRequêteSQL(sdReq, hRequêteDéfaut, sReq)
POUR TOUT sdReq
// Traitement
FIN
HAnnuleDéclaration(sdReq)
// Pour contrer la limitation des 2100 paramètres en MSSQL Server en utilisant l'accès natif de WINDEV® :
// "The incoming tabular data stream (TDS) remote procedure call (RPC) protocol stream is incorrect.
// Too many parameters were provided in this RPC request. The maximum is 2100."
// Si la connexion est sur une base MSSQL Serveur alors exécuter le code suivant :
sListeIDSOCIETE_MssqlLimiteParam est une chaîne
POUR TOUTE CHAÎNE sUnIDSOCIETE, nPos, nCompteur DE sListe_IDSOCIETE SEPAREE PAR ","
sListeIDSOCIETE_MssqlLimiteParam += [","]+ sUnIDSOCIETE
SI (Modulo(nCompteur, 2098) = 0) _OU_ (nCompteur = ChaîneOccurrence(sListe_IDSOCIETE, ",")+1) ALORS
HAnnuleDéclaration(sdReq)
sdReq.pListe_IDSOCIETE = sListeIDSOCIETE_MssqlLimiteParam
HExécuteRequêteSQL(sdReq, hRequêteDéfaut, sReq)
POUR TOUT sdReq
// Traitement
FIN
HAnnuleDéclaration(sdReq)
sListeIDSOCIETE_MssqlLimiteParam = ""
FIN
FIN
Pour sauvegarder l'état d'un champ table :
PROCÉDURE TableSauveParam(champTable est un Champ) : tableau associatif de chaîne
taParam est un tableau associatif de chaîne
taParam["Trie"] = TableColonnesTriées(champTable)
taParam["Filtre"] = TableColonnesFiltrées(champTable)
taParam["PosSel"] = TableSauvePositionEtSélection(champTable)
taParam["AscPos_Vert"] = AscenseurPosition(champTable, ascVert)
taParam["AscPos_Horz"] = AscenseurPosition(champTable, ascHorz)
RENVOYER taParam
Pour restaurer l'état d'un champ table :
PROCÉDURE TableRestaureParam(champTable est un Champ, LOCALE taParam est une tableau associatif de chaîne)
SI (PAS taParam["Trie"]..Vide) _ET_ (PAS taParam["Trie"] ~= "") ALORS
sValeur est une chaîne = ""
POUR TOUTE CHAÎNE sColonne DE taParam["Trie"] SEPAREE PAR TAB
SI (sColonne[[1]] = "-") ALORS //Sens du tri : décroissant
sValeur += [TAB]+ "-"+ champTable..NomComplet +"."+ sColonne[[2 À]]
SINON
sValeur += [TAB]+ champTable..NomComplet +"."+ sColonne
FIN
FIN
TableTrie(sValeur)
FIN
SI (PAS taParam["Filtre"]..Vide) _ET_ (PAS taParam["Filtre"] ~= "") ALORS
POUR TOUTE CHAÎNE sFiltre DE taParam["Filtre"] SEPAREE PAR RC
TableActiveFiltre(champTable..NomComplet +"."+ ExtraitChaîne(sFiltre, 1, ";"), Val(ExtraitChaîne(sFiltre, 2, ";")), ExtraitChaîne(sFiltre, 3, ";"))
FIN
FIN
SI (PAS taParam["PosSel"]..Vide) _ET_ (PAS taParam["PosSel"] ~= "") ALORS
TableRestaurePositionEtSélection(champTable, taParam["PosSel"])
FIN
SI (PAS taParam["AscPos_Vert"]..Vide) _ET_ (Val(taParam["AscPos_Vert"]) = 0 À AscenseurPositionMax(champTable, ascVert)) ALORS
AscenseurPosition(champTable, ascVert, Val(taParam["AscPos_Vert"]))
FIN
SI (PAS taParam["AscPos_Horz"]..Vide) _ET_ (Val(taParam["AscPos_Horz"]) = 0 À AscenseurPositionMax(champTable, ascHorz)) ALORS
AscenseurPosition(champTable, ascHorz, Val(taParam["AscPos_Horz"]))
FIN
Un exemple d'utilisation :
taParam est un tableau associatif de chaîne
taParam = TableSauveParam(NomChampTable)
TableAffiche(NomChampTable, taInit)
TableRestaureParam(NomChampTable, taParam)
Pour obtenir le dernier jour d'un mois, il suffit d'affecter le nombre 31 à la propriété ..Jour.
dTemp est une Date
dTemp..Année = 2016
dTemp..Mois = 2
dTemp..Jour = 31
Trace( DateVersChaîne(dTemp) )
Depuis la version 16 de WINDEV® et grâce à la nouvelle fonction DernierJourDuMois() :
dTemp est une Date
dTemp = DernierJourDuMois(2016, 2)
Trace( DateVersChaîne(dTemp) )
WINDEV® permet facilement d'ajouter un nombre entier d'années, de mois, de jours, d'heures, de minutes et de secondes à une variable de type dateheure. Mais il ne permet pas d'ajouter des nombres décimaux/flottants.
Dans une déclaration globale :
ENUM_PERIODE est une énumération
PERIODE_ANNEE
PERIODE_MOIS
PERIODE_JOUR
PERIODE_HEURE
PERIODE_MINUTE
PERIODE_SECONDE
FIN
Dans une procédure :
PROCÉDURE DateHeureAjoute(LOCALE dhAjout est une DateHeure, LOCALE ePeriode est un ENUM_PERIODE, LOCALE xNbAjout est un numérique (*)) : DateHeure
SI (xNbAjout <> 0) ALORS
SELON ePeriode
CAS ENUM_PERIODE.PERIODE_ANNEE :
dhAjout..Année += xNbAjout // ((xNbAjout > 0) ? PartieEntière(xNbAjout) SINON ArrondiSupérieur(xNbAjout, 0))
// Avec comme postulat que 1 an = 12 mois
dhAjout = DateHeureAjoute(dhAjout, ENUM_PERIODE.PERIODE_MOIS, PartieDécimale(xNbAjout) * 12 * ((xNbAjout < 0) ? -1 SINON 1))
CAS ENUM_PERIODE.PERIODE_MOIS :
dhAjout..Mois += xNbAjout // ((xNbAjout > 0) ? PartieEntière(xNbAjout) SINON ArrondiSupérieur(xNbAjout, 0))
// Avec comme postulat que 1 mois = 30 jours
dhAjout = DateHeureAjoute(dhAjout, ENUM_PERIODE.PERIODE_JOUR, PartieDécimale(xNbAjout) * 30 * ((xNbAjout < 0) ? -1 SINON 1))
CAS ENUM_PERIODE.PERIODE_JOUR :
dhAjout..Jour += xNbAjout // ((xNbAjout > 0) ? PartieEntière(xNbAjout) SINON ArrondiSupérieur(xNbAjout, 0))
// Avec comme postulat que 1 jour = 24 heures
dhAjout = DateHeureAjoute(dhAjout, ENUM_PERIODE.PERIODE_HEURE, PartieDécimale(xNbAjout) * 24 * ((xNbAjout < 0) ? -1 SINON 1))
CAS ENUM_PERIODE.PERIODE_HEURE :
dhAjout..Heure += xNbAjout // ((xNbAjout > 0) ? PartieEntière(xNbAjout) SINON ArrondiSupérieur(xNbAjout, 0))
// Avec comme postulat que 1 heure = 60 minutes
dhAjout = DateHeureAjoute(dhAjout, ENUM_PERIODE.PERIODE_MINUTE, PartieDécimale(xNbAjout) * 60 * ((xNbAjout < 0) ? -1 SINON 1))
CAS ENUM_PERIODE.PERIODE_MINUTE :
dhAjout..Minute += xNbAjout // ((xNbAjout > 0) ? PartieEntière(xNbAjout) SINON ArrondiSupérieur(xNbAjout, 0))
// Avec comme postulat que 1 minute = 60 secondes
dhAjout = DateHeureAjoute(dhAjout, ENUM_PERIODE.PERIODE_SECONDE, PartieDécimale(xNbAjout) * 60 * ((xNbAjout < 0) ? -1 SINON 1))
CAS ENUM_PERIODE.PERIODE_SECONDE :
dhAjout..Seconde += xNbAjout // ((xNbAjout > 0) ? PartieEntière(xNbAjout) SINON ArrondiSupérieur(xNbAjout, 0))
AUTRE CAS :
FIN
FIN
RENVOYER dhAjout
Un exemple d'utilisation :
// Ajoute 6 mois à la date du 01/01/2021 00h00 :
Trace( DateHeureAjoute("20210101000000", ENUM_PERIODE.PERIODE_MOIS, 6) )
// Retire 2 jours à la date du 02/03/2020 12h34 :
Trace( DateHeureAjoute("20200302123400", ENUM_PERIODE.PERIODE_JOUR, -2) )
// Pour extraire les intiales d'un nom/prénom
PROCÉDURE InitialesExtrait(LOCALE sNom est une chaîne) : chaîne
sInitiale est une chaîne = ""
// Recherche les mots séparés par un espace et/ou un tiret
POUR TOUTE CHAÎNE sUnMot DE sNom SEPAREE PAR [" ", "-"]
sInitiale += Majuscule(sUnMot[[1]]) +"."
FIN
RENVOYER sInitiale
Un exemple d'utilisation :
Trace( InitialesExtrait("yves dupont") ) // Affiche Y.D.
Trace( InitialesExtrait("Jean-Luc DE-VINCI") ) // Affiche J.L.D.V.
Ce code effectue une capture d'écran à l'emplacement d'un champ, c'est-à-dire que s'il y a un élément par dessus le champ alors cet élément sera aussi capturé dans l'image.
PROCÉDURE ChampCapture(cUnChamp est un Champ, LOCALE sCheminEtNomDuFichier est une chaîne) : booléen
bufImage est un Buffer
bufImage = dCopieImageEcran(FenIntPosX()+cUnChamp..X, FenIntPosY()+cUnChamp..Y, cUnChamp..Largeur, cUnChamp..Hauteur)
//bufImage = dCopieImageChamp(cUnChamp) // Nouveauté en version 28
SI PAS fEstUneImage(bufImage) ALORS
RENVOYER Faux
FIN
// Création du répertoire si inexistant
SI PAS fRépertoireExiste(fExtraitChemin(sCheminEtNomDuFichier, fDisque+fRépertoire)) ALORS
fRepCrée(fExtraitChemin(sCheminEtNomDuFichier, fDisque+fRépertoire))
FIN
RENVOYER fSauveBuffer(sCheminEtNomDuFichier, bufImage)
Un exemple d'utilisation :
Trace( ChampCapture(IMG_Logo, ComplèteRep(fDisqueEnCours())+"capture.jpg") )
Ce code est à utiliser avec la plus grande prudence.
nX est un entier = 0
SI (SysVersionWindows() _DANS_ ("NT 3.5", "NT 4", "NT 5", "XP", "2003S", "2008S", "VISTA")) ALORS
nX = API("KERNEL32", "GetCurrentProcess")
API("KERNEL32", "SetProcessWorkingSetSize", nX, -1, -1)
SI (SysVersionWindows(sysVersionPlateForme) = "NT") ALORS
API("psapi", "EmptyWorkingSet", nX)
FIN
FIN
// Créer tous les fichiers de la base de données.
PROCÉDURE HCréationSiInexistant() : booléen
bHCréationSiInexistant est un booléen = Vrai
SI PAS WL.HCréationSiInexistant("*") ALORS
sHListeFichier est chaîne = HListeFichier(hLstNormal)
POUR TOUTE CHAÎNE sHFichier DE sHListeFichier SEPAREE PAR RC
QUAND EXCEPTION DANS
SI PAS WL.HCréationSiInexistant(sHFichier) ALORS
bHCréationSiInexistant = Faux
FIN
FAIRE
ExceptionActive()
FIN
FIN
FIN
RENVOYER bHCréationSiInexistant
// Résumé : Surcharge la fonction PDFFusionne() au cas où il n'y ait qu'un élément dans le tableau.
// Paramètres :
// sFichierPdfResultat (chaîne ANSI) : Nom et chemin complet du fichier PDF à créer. Ce fichier contiendra la fusion des différents fichiers PDF.
// tabFichiersPdf (tableau (chaîne ANSI)) : Nom du tableau de chaînes contenant les chemins des fichiers PDF à fusionner.
// Valeur de retour :
// entier : 1: tout s'est bien passé ; -1 : Erreur sur PDFFusionne() ; -2 Erreur sur fCopieFichier() ; 0 : aucun élément dans le tableau
//
PROCÉDURE PDFFusionne(LOCALE sFichierPdfResultat est une chaîne, LOCALE tabFichiersPdf est un tableau de chaîne) : entier
SI fFichierExiste(sFichierPdfResultat) ALORS
fSupprime(sFichierPdfResultat, frLectureSeule)
FIN
SI (tabFichiersPdf..Occurrence > 1) ALORS
SI PAS WL.PDFFusionne(sFichierPdfResultat, tabFichiersPdf) ALORS
ErreurPropage()
RENVOYER -1
FIN
SINON SI (tabFichiersPdf..Occurrence = 1) ALORS
SI PAS fCopieFichier(tabFichiersPdf[1], sFichierPdfResultat) ALORS
ErreurPropage()
RENVOYER -2
FIN
SINON
ErreurDéclenche(1, "Aucun élément à fusionner.")
RENVOYER 0
FIN
RENVOYER fFichierExiste(sFichierPdfResultat)
Ne pas oublier d'initialiser les jours fériés avec la fonction JourFériéAjoute(). (exemple : https://doc.pcsoft.fr/?1000017304)
// Résumé : Calculer le nombre de jours (ouvrés, ouvrants, personnalisés) pour une période.
// ! Ne pas oublier d'initialiser les jours fériés avec la fonction JourFériéAjoute()
// Paramètres :
// dDebut (date) : date de début de la période de calcul
// dFin (date) : date de fin de la période de calcul
// tabJours (tableau) : numéros de jour de la semaine à ne pas prendre en compte (avec 1:Lundi, 2:Mardi, 3:Mercredi, 4:Jeudi, 5:Vendredi, 6:Samedi, 7:Dimanche)
// Valeur de retour :
// entier : nombre de jours calculés pour la période
//
PROCÉDURE NombreDeJoursOuvrés(LOCALE dDebut est une Date, LOCALE dFin est une Date, LOCALE tabJours est un tableau de entier) : entier
nNombreDeJoursCalculés est un entier = 0
SI DateValide(dDebut) _ET_ DateValide(dFin) ALORS
TANTQUE (dDebut <= dFin)
SI (TableauCherche(tabJours, tcLinéaire, DateVersJour(dDebut)) = -1) _ET_ PAS JourFérie(dDebut) ALORS
nNombreDeJoursCalculés++
FIN
dDebut..Jour++
FIN
FIN
RENVOYER nNombreDeJoursCalculés
Un exemple d'utilisation :
// Calculer le nombre de jours ouvrés entre le 01/01/2021 et le 31/01/2021 pour une semaine travaillée du lundi au vendredi :
Trace( NombreDeJoursOuvrés("20210101", "20210131", [6,7]) )
// Calculer le nombre de jours ouvrables entre le 01/01/2021 et le 31/01/2021 pour une semaine travaillée du lundi au vendredi :
Trace( NombreDeJoursOuvrés("20210101", "20210131", [7]) )
// Calculer le nombre de jours ouvrés entre le 09/01/2021 et le 27/01/2021 pour une semaine travaillée du mardi au samedi :
Trace( NombreDeJoursOuvrés("20210109", "20210127", [1,7]) )
PROCÉDURE TraitementDeTexteRemplace(LOCALE sSource est une chaîne, LOCALE sCible est une chaîne, LOCALE taMots est un tableau associatif de chaîne) : booléen
// Copier le fichier Source vers le fichier Cible
SI fFichierExiste(sSource) _ET_ fCopieFichier(sSource, sCible) _ET_ fFichierExiste(sCible) ALORS
SELON Minuscule(fExtraitChemin(sCible, fExtension))
CAS ".doc", ".docx" : // Word Microsoft Office
QUAND EXCEPTION DANS
autWorddoc est un objet Automation "Word.Application"
autWorddoc>>documents>>Open(sCible)
autWorddoc>>visible = Faux
autWorddoc>>Selection
POUR TOUT ELEMENT sMot, sCle DE taMots
// http://sepia.developpez.com/office/word/rechercherremplacer/
sMot = Remplace(sMot, RC, "^p")
sMot = Remplace(sMot, TAB, "^t")
autWorddoc>>Selection>>Find>>Execute(sCle, Faux, Vrai, Faux, Faux, Faux, Vrai, 1, Faux, sMot, 2)
FIN
autWorddoc>>ActiveDocument>>SaveAs(sCible, 16) // http://msdn.microsoft.com/en-us/library/office/bb238158%28v=office.12%29.aspx
autWorddoc>>ActiveDocument>>Close()
RENVOYER Vrai
FAIRE
SI (autWorddoc <> Null) ALORS
autWorddoc>>ActiveDocument>>Close()
FIN
FIN
CAS ".odt" : // OpenOffice ; LibreOffice ; etc...
QUAND EXCEPTION DANS
// Création d'un service OpenOffice si nécessaire
pautServiceManager est un objet OLE dynamique = allouer un objet OLE ("com.sun.star.ServiceManager")
pautDesktop est un objet OLE dynamique = pautServiceManager>>createInstance("com.sun.star.frame.Desktop")
pautDocument est un objet OLE dynamique
pautRecherche est un objet OLE dynamique
tabNoArgs_ est un tableau de 0 Variant = allouer un tableau dynamique de 0 Variant
tabNoArgs est un tableau de 1 objet Automation dynamique
sCheminFormate est une chaîne = "file:///"+Remplace(sCible, "\", "/") // Formatage du chemin du fichier
// Ouverture du fichier dans OpenOffice Writer
// Traitement de la visibilité du document
tabNoArgs[1] = pautServiceManager>>Bridge_GetStruct("com.sun.star.beans.PropertyValue")
tabNoArgs[1]>>Name = "Hidden"
tabNoArgs[1]>>Value = Vrai
pautDocument = pautDesktop>>LoadComponentFromURL(sCheminFormate, "_blank", 0, tabNoArgs)
SI (pautDocument <> Null) ALORS
//oDocument = oDesktop>>getCurrentComponent()
POUR TOUT ELEMENT sMot, sCle DE taMots
// Créer un objet JeCherche qui contiendra tous les paramètres nécessaires à ce remplacement
pautRecherche = pautDocument>>createReplaceDescriptor()
// Définir la balise à rechercher dans le document OpenOffice Word
pautRecherche>>SearchString = sCle
// Définir la valeur de remplacement
pautRecherche>>ReplaceString = sMot
// Distinguer les majuscules des minuscules dans la recherche
pautRecherche>>SearchCaseSensitive = Vrai
// Ne rechercher que des mots
pautRecherche>>SearchWords = Faux
// Rechercher à reculons
pautRecherche>>SearchBackwards = Faux
// Faire une recherche avec la méthode des expressions régulières
pautRecherche>>SearchRegularExpression = Faux
// Rechercher des paragraphes d’un style donné par SearchString
pautRecherche>>SearchStyles = Faux
// Rechercher un texte similaire au texte cherché
pautRecherche>>SearchSimilarity = Faux
// Remplacer toutes les balises
pautDocument>>replaceAll(pautRecherche)
FIN
// Enregistrement sous... du document (https://wiki.openoffice.org/wiki/FR/Documentation/BASIC_Guide/Saving_a_document)
pautDocument>>storeToURL(sCheminFormate, tabNoArgs_)
// Fermer le document
pautDocument>>Store()
pautDocument>>close(Vrai)
pautDesktop>>Terminate()
RENVOYER Vrai
FIN
FAIRE
SI (pautDocument <> Null) ALORS
// Fermer le document
pautDocument>>Store()
pautDocument>>close(Vrai)
pautDesktop>>Terminate()
FIN
FIN
AUTRE CAS :
FIN
// Si échec du rechercher/remplacer alors supprimer le fichier "Cible"
SI fFichierExiste(sCible) ALORS
fSupprime(sCible, frLectureSeule)
FIN
FIN
RENVOYER Faux
Un exemple d'utilisation :
sModeleDoc est une chaîne = ComplèteRep(fDisqueEnCours())+"Modele_TraitementDeTexte.doc"
sNouveauDoc est une chaîne = ComplèteRep(fDisqueEnCours())+"Doc_TraitementDeTexte.doc" // ou bien ComplèteRep(fDisqueEnCours())+"Doc_TraitementDeTexte.odt"
taMotsARemplacer est un tableau associatif de chaîne
taMotsARemplacer["<Mot_a_trouver_1>"] = "Mot 1 a remplacer"
taMotsARemplacer["<Mot_a_trouver_2>"] = "Mot 2 a remplacer"
taMotsARemplacer["<Date_Du_Jour>"] = DateVersChaîne(DateSys(), "JJ/MM/AAAA")
SI TraitementDeTexteRemplace(sModeleDoc, sNouveauDoc, taMotsARemplacer) ALORS
LanceAppliAssociée(sNouveauDoc)
FIN
Depuis la version 22 de WINDEV® et grâce au nouveau type de variable Document :
sModeleDoc est une chaîne = ComplèteRep(fDisqueEnCours())+"Modele_TraitementDeTexte.docx"
sNouveauDoc est une chaîne = ComplèteRep(fDisqueEnCours())+"Doc_TraitementDeTexte.doc" // ou bien ComplèteRep(fDisqueEnCours())+"Doc_TraitementDeTexte.odt"
taMotsARemplacer est un tableau associatif de chaîne
taMotsARemplacer["<Mot_a_trouver_1>"] = "Mot 1 a remplacer"
taMotsARemplacer["<Mot_a_trouver_2>"] = "Mot 2 a remplacer"
taMotsARemplacer["<Date_Du_Jour>"] = DateVersChaîne(DateSys(), "JJ/MM/AAAA")
docT2T est un Document = DocOuvre(sModeleDoc)
SI PAS ErreurDétectée() ALORS
POUR TOUT ELEMENT sMot, sCle DE taMotsARemplacer
DocRemplace(docT2T, sCle, sMot)
FIN
SI DocSauve(docT2T, sNouveauDoc) ALORS
DocFerme(docT2T)
LanceAppliAssociée(sNouveauDoc)
FIN
FIN
Il existe plusieurs approches pour savoir si un nombre particulier est contenu dans une chaîne (une liste de nombres séparés par un séparateur commun).
// La liste de nombres séparés par un séparateur commun
sListe_IDSOCIETE est une chaîne = "4;8;15;16;23;42"
// Le nombre particulier à rechercher dans la chaîne
sUnIDSOCIETE est une chaîne = "2"
bContient est un booléen
// Code le plus simple ...
// ... en utilisant la fonction Contient()
bContient = Contient(";"+sListe_IDSOCIETE+";", ";"+sUnIDSOCIETE+";")
Trace("Contient", bContient)
// ... en utilisant la fonction Position()
bContient = (Position(";"+sListe_IDSOCIETE+";", ";"+sUnIDSOCIETE+";") > 0)
Trace("Position", bContient)
// Code le plus rapide grâce à l'opérateur de comparaison [=]
bContient = (";"+sListe_IDSOCIETE+";" [=] ";"+sUnIDSOCIETE+";")
Trace("[=]", bContient)
// Code le plus sûr
tabEntier est un tableau de entier
ChaîneVersTableau(sListe_IDSOCIETE, tabEntier, ";")
bContient = (TableauCherche(tabEntier, tcLinéaire, Val(sUnIDSOCIETE)) <> -1)
Trace("TableauCherche", bContient)
Lors de la recherche sur les chaînes, les concaténations du séparateur (";") sont obligatoires sinon le nombre à rechercher ("2") est trouvé dans les nombres "23" et "42".
Si le développeur ne maitrise pas le contenu de la chaîne (exemples: sListe_IDSOCIETE = "4; 8;15;16;23;42" ou sListe_IDSOCIETE = "4;08;15;16;23;42") alors le code est plus sûr en utilisant un tableau.
PROCÉDURE VérifierCalcul(LOCALE sCalcul est une chaîne) : (booléen, numérique (*))
sSource est une chaîne = [
i est un numérique (*) = %1
RENVOYER i
]
bResultatValide est un booléen
xResutatDuCalcul est un numérique (*)
SI (Compile("CalculerFormule", ChaîneConstruit(sSource, sCalcul)) = "") ALORS
QUAND EXCEPTION DANS
xResutatDuCalcul = ExécuteTraitement("CalculerFormule", trtProcédure)
bResultatValide = Vrai
FAIRE
FIN
FIN
RENVOYER (bResultatValide, xResutatDuCalcul)
Un exemple d'utilisation :
Trace( VérifierCalcul("(1+2.5-0.25)") )
Trace( VérifierCalcul("( 3 * 0.5) / 2") )
Trace( VérifierCalcul("1 / 0") )
Non optimisé | Optimisé |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
→ De préférence, utiliser une requête SQL plutôt que les fonctions H*. → De préférence, utiliser les fonctions H* plutôt que les fonctions POUR TOUT. |
|
|
|
→ De préférence, utiliser une variable de type champ plutôt que les indirections de champs. | |
|
|
→ De préférence, typer toutes les indirections. | |
|
|
→ De préférence, utiliser les propriétés plutôt que les fonctions. | |
|
|
→ De préférence, utiliser les opérateurs de comparaison plutôt que les fonctions. | |
|
|
|
|
|
|
|
|
Lors de l'appel à une fonction WLangage®, tout un mécanisme se lance dans la machine virtuelle :
- recherche dans quel fichier DLL se trouve cette fonction
- vérification du chargement du fichier DLL
- recherche de la fonction
- empilement des paramètres
- appel de la fonction
- dépilement de la valeur de retour
- remontée jusqu’au WLangage®
A contrario, lors de l'utilisation d'un opérateur, celui-ci est directement dans la machine virtuelle. Le temps de traitement est donc réduit :
- l’opération est exécutée et le résultat renvoyé
Donc, si un opérateur existe, utilisez-le.
Par exemple, vous pouvez remplacer :
- la fonction Gauche() par l’opérateur [=
- la fonction ChaîneFinitPar() par l’opérateur ~] (termine par sans casse)
L'addition logique optimisée _OU_ ne doit pas être utilisée si une des expressions à comparer utilise le résultat d'une fonction pouvant renvoyer NULL.
https://doc.pcsoft.fr/?1512003&name=operateurs_logiques
PROCÉDURE INTERNE piInit(LOCALE nEntier est un entier)
// Si la valeur du paramètre nommé "nEntier" est impair alors renvoyer null sinon renvoyer 2
RENVOYER EstImpair(nEntier) ? Null SINON 2
FIN
// Avec _OU_ : le résultat de la trace vaut "OK" alors qu'elle devrait être "KO"
SI (piInit(1) = 3) _OU_ (piInit(2) = 4) ALORS
Trace("OK")
SINON
Trace("KO")
FIN
// Avec OU : le résultat de la trace vaut "KO" et c'est bien le résultat souhaité
SI (piInit(1) = 3) OU (piInit(2) = 4) ALORS
Trace("OK")
SINON
Trace("KO")
FIN
Avant pour désactiver le filtre déjà existant des codes précédents.
Après pour désactiver le filtre pour les codes suivants.
HDésactiveFiltre(NomTableBDD)
POUR TOUT NomTableBDD AVEC "condition(s)"
... // Instructions
SORTIR
FIN
HDésactiveFiltre(NomTableBDD)
Avant pour libérer les ressources de la requête SQL des codes précédents.
Après pour libérer les ressources (espace mémoire) de la requête SQL pour les codes suivants.
HAnnuleDéclaration(REQ_SELECT_SOCIETE)
HExécuteRequête(REQ_SELECT_SOCIETE)
POUR TOUT REQ_SELECT_SOCIETE
... // Traitement
FIN
HAnnuleDéclaration(REQ_SELECT_SOCIETE)
Attention à ne pas libérer la requête SQL trop tôt !
HAnnuleDéclaration(REQ_SELECT_SOCIETE)
HExécuteRequête(REQ_SELECT_SOCIETE)
TableAffiche(NomChampTable, taInit)
HAnnuleDéclaration(REQ_SELECT_SOCIETE)
Dans le code ci-dessus, après la fonction TableAffiche() la fonction HAnnuleDéclaration() est appelée trop tôt et le champ n'affichera pas la totalité des enregistrements.
sdReq est une Source de données
sReq est une chaîne
// Le code suivant n'est pas sécurisé :
sReq = ChaîneConstruit("SELECT * FROM SITE WHERE Libelle LIKE '%1'", "Paris")
HExécuteRequêteSQL(sdReq, hRequêteDéfaut, sReq)
// Les requêtes préparées permettent de sécuriser contre les failles de sécurité (exemple: injection SQL)
sReq = "SELECT * FROM SITE WHERE Libelle LIKE {pLibelle}"
sdReq.pLibelle = "Paris"
HExécuteRequêteSQL(sdReq, hRequêteDéfaut, sReq)
HChangeLocalisation("*", hDisque)
EXTERNE "WINCONST.wl" // Constantes standard de Windows
EXTERNE "KEYCONST.wl" // Constantes standard de Windows utilisées pour les touches du clavier
EXTERNE "EXCEPT.wl" // Constantes utilisées pour la gestion des exceptions
EXTERNE "LIMITES.wl" // Constantes correspondant aux limites des types de données WINDEV®
EXTERNE "ListeDefinitionHF.wl" // Constantes HFSQL utilisées pour la journalisation
//threadMultiProcesseur : Les threads sont automatiquement répartis entre les différents processeurs.
//threadSectionCritique : Chaque procédure pourra être exécutée par plusieurs threads simultanément.
// Il est nécessaire de protéger les accès aux ressources partagées entre les différents threads par des sections critiques.
ThreadMode(threadMultiProcesseur + threadSectionCritique)
// Nouveau mode d'exécution à appliquer
ModeExécution(modeNormal + AppelsExternesOptimisés)
// Modifie la priorité de l'application en cours d'exécution
ExePriorite(ExeDonnePID(exePID), exePrioritéSupérieureNormale)
SI (ExePriorite(ExeDonnePID(exePID)) <> exePrioritéSupérieureNormale) ALORS
ExePriorite(ExeDonnePID(exePID), exePrioritéHaute)
FIN
//http://faq.pcsoft.fr/8865-champ_oauth_activex_assemblage_ole_automation_coinitializeex-read.awp :
// Que faire si l'utilisation d'un module externe impacte des fonctionnalités d'une application WINDEV® ?
// Gestion du Drag and Drop // Connecteur Natif SQL Server : Spécificités et remarques
// Lors de l'utilisation de le Connecteur Natif SQL Server via SQLnCli, certaines fonctionnalités peuvent ne pas fonctionner.
// Pour retrouver un fonctionnement correct, il est conseillé d'ajouter ces lignes de code dans l'initialisation du projet :
SI (ChargeDLL("OLE32") <> 0) ALORS
SELON API("OLE32", "CoInitializeEx", Null, 2)
CAS 0 : // OK
CAS 1 :
API("OLE32", "CoUninitialize")
SI (API("OLE32", "CoInitializeEx", Null, 2) <> 0) ALORS
... // Erreur("Echec de CoInitializeEx", ErreurInfo())
FIN
AUTRE CAS :
... // Erreur("Echec de CoInitializeEx", ErreurInfo())
FIN
FIN
//ChargeDLL("ole32")
//API("ole32", "CoInitializeEx", 0, 2)
// Gestion des effets
SI EnModeTSE() ALORS
// Pour désactiver des effets non supportés en TSE
FenDésactiveEffet(effetAnimation + effetCadreTranslucide + effetGFI + effetHalo)
SINON
// Animation des champs, leurs effets de transitions
AnimationMinFPS(24)
// Les fenêtres ayant un cadre translucide sont affichées avec cet effet
StyleDessin(styleCadreFenTranslucide, Vrai)
// Chargement rapide : le temps de chargement des images est prioritaire sur leur qualité
StyleDessin(styleImageFaibleQualite, Vrai)
// Les icônes, images des boutons grisés sont affichées en niveau de gris.
// Si ce mode est sélectionné, l'affichage peut prendre un plus de temps mais le rendu est meilleur
StyleDessin(stylePictoGriseDegrade, Vrai)
FIN
// Aperçu avant impression
iParamètreAperçu(iBoutonTous - iBoutonHtml - iBoutonXml, 150)
// Afficher le volet des miniatures dans l'aperçu avant impression
iParamètreAperçu(iVoletMiniatures, Vrai)
// Génération PDF
iParamètrePDF("", "", iQualitéMaximale + iPDFUnicode)
// Génération XLS
iParamètreXLS(iAvecMiseEnForme)
// Paramétrer l'impression de l'état (et notamment la conservation de la mise en forme des cellules)
ParamètreFAA(faaImprimeEtatSurTable, 1)
// Génération pour le champ "table" XLS / Word / XML
ParamètreFAA(faaTableVersExcel, taAvecMiseEnForme + taColonneOrdreAffiche + taTitreColonnes)
ParamètreFAA(faaTableVersWord, taAvecMiseEnForme + taColonneOrdreAffiche + taTitreColonnes)
ParamètreFAA(faaTableVersXML, taAvecMiseEnForme + taColonneOrdreAffiche + taTitreColonnes)
// Désactivation ReconnaissanceVocale
DésactiveFAA(faaReconnaissanceVocale)
// Active la vérification d'orthographe pour toute l'application
ParamètreOrthographe(orthographeActif, Vrai)
// Sélectionne le dictionnaire du langage en cours
ParamètreOrthographe(orthographeNation, SysNation())
// Gestion des jours fériés
JourFériéSupprimeTout()
SELON SysNation()
CAS nationFrançais :
// Initialisation des 11 jours fériés communs aux départements français et DOM/TOM
JourFériéAjoute("0101") // 1er Janvier
JourFériéAjoute(jfLundiDePâques) // Lundi de Pâques
JourFériéAjoute("0501") // 1er Mai
JourFériéAjoute("0508") // 8 Mai
JourFériéAjoute(jfJeudiDeLAscension) // Jeudi de l'Ascension
JourFériéAjoute(jfLundiDePentecôte) // Lundi de Pentecôte
JourFériéAjoute("0714") // 14 Juillet
JourFériéAjoute("0815") // 15 Août (Assomption)
JourFériéAjoute("1101") // Toussaint
JourFériéAjoute("1111") // 11 Novembre
JourFériéAjoute("1225") // Noël
AUTRE CAS :
FIN
// Délai à attendre avant l'affichage des bulles d'aide
BulleDélai(bulleDuréeAvantOuverture, -1) // Valeur par défaut gérée par Windows
// Durée d'affichage des bulles d'aide des champs
BulleDélai(bulleDuréeAffichage, 32s) // Valeur maximale : 32,6s
// Initialisation du générateur de nombres aléatoires
InitHasard()
// Règle le timeout pour les fonctions WLangage® utilisant le protocole HTTP
HTTPTimeOut(10s)