|
[Win API] Un carnet d'adresses
|
| Auteur |
Message |
acryline
Member
  
Messages : 68
Groupe : Membres
Inscription : Dec 2006
Statut :
Hors ligne
Réputation : 2
|
Non seulement je me sens moins seule quand je poste, mais en plus tes interventions sont toujours très utiles.
J'apprends, et si quelqu'un vient ici il pourra lire mon code et avoir le point de vue d'un pro.
C'est parfait ! 
Ce qui serait bien, mais il faudrait avoir plusieurs vies, comme les CrazyCat, ce serait de faire un tuto à partir de mon code
complètement revu et corrigé....Pour l'instant je me contente de vous présenter mes petites fonctions au quotidien.
Donc aujourd'hui voyons testCaracteres

et le code :
bool testcaracteres(char*nom)
{
long i=0,j=0,longueur=0;
longueur =strlen(nom);
for (i=0;i<longueur;i++)
{
for (j=-127; j<48;j++)
{
if (nom[i]==j) return false;
}
for (j=58; j<65;j++)
{
if (nom[i]==j) return false;
}
for (j=91; j<95;j++)
{
if (nom[i]==j) return false;
}
if (nom[i]==96) return false;
if (nom[i]>122) return false;
}
return true;
}
Si j'ai bien compris il ne faudrait retourner qu'une seule fois. Donc il serait bon de créer un variable et de la mettre à FALSE ou TRUE selon le cas.
|
|
| 22/12/2006 09:55 |
|
 |
Toam
Junior Member
 
Messages : 36
Groupe : Membres
Inscription : Nov 2006
Statut :
Hors ligne
Réputation : 0
|
[Hors Sujet]c'est amusant car je n'étais jamais vraiment allé sur le site du zéro. Pour ne pas mourir idiot je m'y suis inscrit ... et ô surprise, un certain xxx participant activement sur developpez.com si trouve également. Du coup mon commentaire sur le forum du SdZ est le même que pour celui de developpez.com, la convivialité est tuée par certains membres exaspérés d'aider des gens plus faibles qu'eux ... personnes qui n'ont donc pas compris, malgré leur grande expérience, que lorsque l'on vient aider, c'est pour aider et non détruire ou se pavaner...[/Hors Sujet]
Pour en revenir au sujet qui est ton programme , ta fonction me semble prévoir beaucoup de cas alors qu'on peut la simplifier.
Petit conseil, il vaut mieux utiliser la lettre entre guillemet (ex: 'a') pour désigner la valeur décimal d'un caractère plutôt que de manipuler directement.
Pourquoi?
Et bien si tu utilises 'a' au lieu de 97 (sa valeur décimal sous Windows), ton code reste portable quelque soit le système d'exploitation et l'encodage des caractères. Au moment de la compilation, 'a' sera converti vers sa valeur native de l'OS. En revanche, si tu utilises 97, rien n'assure que sur un autre OS, ce soit la caractère 'a'.
En plus c'est quand même plus lisible dans le code d'utiliser des 'a', 'b' que 97, 98 non?
Passons à l'analyse de ton code, ardue par l'utilisation des codes de caractères. En fait tu ne souhaites autorisés ques les caractères numérique 0 à 9, et alphabétiques (a-zA-Z).
Si on garde ton système, il est donc beaucoup plus clair et simple de réécrire ton code comme suit :
bool testcaracteres(char*nom)
{
long i=0,j=0,longueur=0;
longueur =strlen(nom);
for (i=0;i<longueur;i++)
{
if(nom[i]<'0') return false;
if(nom[i]>'9' && nom[i]<'a') return false;
if(nom[i]>'z' && nom[i]<'a') return false;
if(nom[i]>'z') return false;
}
return true;
}
enfin on pourrait utiliser les fonctions dã©diã©es ã ce genre de traitement ;d
bool testcaracteres(char*nom)
{
long i=0,j=0,longueur=0;
longueur =strlen(nom);
for (i=0;i<longueur;i++)
{
if(isalnum(nom[i])==0) return false;
}
return false;
}
|
|
| 22/12/2006 11:18 |
|
 |
acryline
Member
  
Messages : 68
Groupe : Membres
Inscription : Dec 2006
Statut :
Hors ligne
Réputation : 2
|
A propos du hors sujet : Je crois savoir de qui tu parles... j'ai dû quelques fois ronger mon frein , il est vrai. ;D
Sinon, pour ce qui est des conseils en programmation, tu triches ! ;D Tu me sors une fonction isalnum qui fait en une ligne ce que je me suis tuée à faire dans un labyrinthe de code !
Sans blague, super ça va me servir pour la suite. En plus tu as concrétisé une connaissance que je ne voulais pas retenir parce que pas dans ma logique arithmétique. Maintenant non seulement je sais mais en plus je conçois que 'a'<'b' quoi qu'il arrive ! 
Allez une petite fonction pour ce matin...où en suis-je ? Ah oui CreerNouveauCarnet, je vais ajouter
creerFermerCarnet et faire une petite auto critique pour cette fonction :

void creernouveaucarnet(hwnd hdlg,char *nom)
{
static char dossier[max_path]={0};
creerfermercarnet(nom,dossier);
nouveaucarnetconfig (dossier);
messagebox(hdlg,"la nouveau fichier a ã©tã© crã©ã© et rr enregistrã© dans la configuration rr du programme.", "information",mb_ok|mb_iconinformation);
enddialog(hdlg,0);
}
void creerfermercarnet(char *nom,char *dossier)
{
static handle hfichier=null;
getcurrentdirectory(max_path,(lptstr)dossier);
strncat(dossier,"\carnets\",max_path);
createdirectory (dossier,null);
strncat(dossier,nom,max_path);
strncat(dossier,".adr",max_path);
hfichier = createfile( dossier, generic_read, 0,null,
open_always, file_attribute_normal, null);
closehandle(hfichier);
}
Je pense qu'il y aurait sans doute plus à dire sur cette fonction mais je viens de remarquer que je ne teste même pas l'existence
du nouveau carnet d'adresses ! S'il existait déjà , le fichier ne serait pas écrasé je pense puisque j'utilise OPEN_ALWAYS et non CREATE_ALWAYS. En revanche, le but recherché (c'est à dire créer un nouveau carnet vierge) ne serait pas atteint. :-
|
|
| 23/12/2006 06:19 |
|
 |
acryline
Member
  
Messages : 68
Groupe : Membres
Inscription : Dec 2006
Statut :
Hors ligne
Réputation : 2
|
Bonjour
Voici la dernière fonction utilisée pour le traitement de l'option Fichier/nouveau du menu: nouveauCarnetConfig Elle enregistre
le chemin d'accès du nouveau carnet d'adresses dans le fichier carnet.config.

void nouveaucarnetconfig (char *dossier)
{
static char dossierconfig[max_path]={0};
static dword nbcharwrite ;
static handle hfichier=null;
getcurrentdirectory(max_path,(lptstr)dossierconfig);
strncat(dossierconfig,"\carnet.config",max_path);
hfichier = createfile( dossierconfig, generic_write|generic_read, 0,null,
open_existing, file_attribute_normal, null);
setfilepointer(hfichier,sizeof(char) *10 +sizeof(colorref)*6,0,file_begin);
writefile(hfichier, (lptstr) dossier,sizeof(char)*(max_path), &nbcharwrite, null);
closehandle(hfichier);
}
j'ai oubliã© de vã©rifier si strlen(dossier)>0 dans le code ! on devrait avoir
if(strlen(dossier)>0)setfilepointer(hfichier,sizeof(char) *10 +sizeof(colorref)*6,0,file_begin);
|
|
| 24/12/2006 08:53 |
|
 |
acryline
Member
  
Messages : 68
Groupe : Membres
Inscription : Dec 2006
Statut :
Hors ligne
Réputation : 2
|
Bonjour !
Aujourd'hui, comme j'ai terminé de traiter l'option "Fichier/Nouveau" je vais vous présenter l'option "Fichier/Ouvrir"...un carnet d'adresses qui existe déjà . Tout d'abord voici la fonction chargerCarnet qui ressemble bcp à CreerNouveauCarnet puis ouvrirFichier.

void chargercarnet(hwnd hwnd)
{
static char dossier[max_path]={0};
ouvrirfichier(hwnd,dossier,"fichier source adr *.adr ","\carnets\");
if(strlen(dossier)>0) nouveaucarnetconfig (dossier);
}
nouveaucarnetconfig a ã©tã© traitã©e hie, on enregistre l'adresse du carnet dans carnet.config pour utiliser ce fichier pour
toutes les opã©rations ã partir de ce moment.
void ouvrirfichier(hwnd hwnd,char *dossier,char* extension,char* origine)
{
static char repcourant[max_path]={0};
static char repcourantorigine[max_path]={0};
openfilename ofn;
static char szfile[max_path]={0};
getcurrentdirectory(max_path,(lptstr)repcourantorigine);
getcurrentdirectory(max_path,(lptstr)repcourant);
strncat(repcourant,origine,max_path);
zeromemory(&ofn, sizeof(openfilename));
ofn.lstructsize = sizeof(openfilename);
ofn.hwndowner = hwnd;
ofn.lpstrfile = szfile; //chemin du fichier--> ce qu'on cherche
ofn.nmaxfile = max_path;
ofn.lpstrfilter =extension;
ofn.nfilterindex = 1;
ofn.lpstrinitialdir =repcourant; //dossier initial
ofn.flags = ofn_pathmustexist | ofn_filemustexist | ofn_hidereadonly;
if (getopenfilename(&ofn)==true)
{
strncpy(dossier,szfile,max_path);
}
setcurrentdirectory(repcourantorigine);
}
GetOpenFileName est une fonction de Win API qui me pose pas mal de problèmes et apparemment je ne suis pas la seule.
Faites bouger la boite de dialogue commune d'ouverture de fichiers et vous verrez que la fenêtre principale en arrière
se décolore. J'ai tout essayé pour ne pas avoir ce bogue mais je n'ai rien trouvé. Sur certains forum on m'a conseillé de
créer ma boite de dialogue à moi... je devrais le faire effectivement.
En tout cas j'attends toujours LA solution.
|
|
| 25/12/2006 08:16 |
|
 |
Toam
Junior Member
 
Messages : 36
Groupe : Membres
Inscription : Nov 2006
Statut :
Hors ligne
Réputation : 0
|
GetOpenFileName est une fonction de Win API qui me pose pas mal de problèmes et apparemment je ne suis pas la seule.
Faites bouger la boite de dialogue commune d'ouverture de fichiers et vous verrez que la fenêtre principale en arrière
se décolore. J'ai tout essayé pour ne pas avoir ce bogue mais je n'ai rien trouvé. Sur certains forum on m'a conseillé de
créer ma boite de dialogue à moi... je devrais le faire effectivement.
En tout cas j'attends toujours LA solution.
Si tu veux tu peux rajouter le projet dans ton zip où me l'envoyer par MP et je regarderais. Je n'ai jamais rencontré ce problème de décoloration
|
|
| 26/12/2006 08:55 |
|
 |
acryline
Member
  
Messages : 68
Groupe : Membres
Inscription : Dec 2006
Statut :
Hors ligne
Réputation : 2
|
En fait j'avais presque terminé mon carnet d'adresses et je n'arrivais pas à résoudre le problème. Alors j'ai recommencé tout le programme de A à Z autrement, avec moins de fenêtre à cause de ça. Et bien j'ai toujours le même problème ! :-
Ok je t'envoie le projet par MP.
Aujourd'hui je mets en ligne l'option Fichier/Quitter du menu.

void fermeapplication (hwnd hwnd)
{
supprimerfichiertemporaire ();
postquitmessage(0);
}
void supprimerfichiertemporaire()
{
static char dossier[max_path]={0};
getcurrentdirectory(max_path,(lptstr)dossier);
strncat(dossier,"\~fichier.tmp",max_path);
deletefile(dossier);
}
Pour ne pas tjrs passer plein de paramètres et pour ne pas avoir de globale j'ai afit un petit fichier
temporaire ou je place la photo des fiches par exemple. Donc il faut le supprimer en fermant l'application
sinon il ne serait pas temporaire
|
|
| 26/12/2006 11:27 |
|
 |
Toam
Junior Member
 
Messages : 36
Groupe : Membres
Inscription : Nov 2006
Statut :
Hors ligne
Réputation : 0
|
;D
Bon je dois bien avoué que j'ai mis presque 30 minutes pour trouver le problème ... et c'est vrai que c'est assez tordu mais ça montre bien à quel point il faut toujours se poser la question de l'interaction des évènements.
En fait ton problème ne se situe absolument pas au niveau de cette brave fonction GetOpenFileName, ou disons plutôt qu'elle n'y est pour rien.
N'as tu jamais remarqué que dans le répertoire d'installation de ton logiciel tu as un carnet.config, mais que tu en as également un dans le sous-répertoire carnets? Ne t'es tu jamais demandé pourquoi la fenêtre se re-colore avec les couleurs par défaut?
En fait ton problème est lié à l'utilisation d'une fonction très dangereuse : GetCurrentDirectory.
Cette fonction te renvoie non pas le répertoire dans lequel ton programme est installé, non pas le répertoire dans lequel tu as pointé la dernière fois, mais le répertoire définit par n'importe quel processus avec la fonction SetCurrentDirectory, que ce processus soit ouvert volontairement ou indirectement.
Maintenant voyons l'impact dans ton programme de ce phénomène.
A chaque fois que la couverture à besoin d'être dessinée, tu charges les paramètres (tailles & couleurs) depuis le fichier de configuration que tu localises à l'aide la fonction GetCurrentDirectory. Jusqu'ici pas de problème, le répertoire renvoyé est bien celui de ton exécutable et donc le fichier de configuration avec les bons paramètres est bien trouvé.
Que se passe t-il lorsque tu ouvres un carnet d'adresse existant avec la fonction GetOpenFileName?
Regardons ton code allégé:
void ouvrirfichier(hwnd hwnd,char *dossier,char* extension,char* origine)
{
...
ofn.lpstrinitialdir =repcourant;
...
if (getopenfilename(&ofn)==true){
...
}
...
}
Donc lorsque tu appelles cette fonction tu paramètres la fonction GetOpenFileName pour qu'elle s'ouvre dans le répertoire repCourant ... et comment fait GetOpenFileName pour s'y placer ;D ben oui, elle fait un petit SetCurrentDirectory.
Tu vas me dire "Oui mais après je fais un SetCurrentDirectory(repCourantOrigine); pour revenir au répertoire de l'exécutable "
Oui je suis d'accord avec toi, mais lorsque cette fenêtre est ouverte et qu'on la déplace, que se passe-t-il? Et bien on demande à l'image dessous de se dessiner ... et pour le dessin tu relis les paramètres et tu fais donc appel à la fonction GetCurrentDirectory, qui te renvoie le répertoire en cours par le fenêtre ouverte GetOpenFileName, c'est à dire le répertoire où tu choisis le fichier d'adresse.
On peut donc en déduire un autre effet de bord un peu facheu, c'est que si quelqu'un à mis son carnet d'adresse dans un répertoire compliqué, qu'il cherche le répertoire avec le sélecteur de fichier (fenêtre ouverte à GetOpenFileName) et qu'il déplace cette fenêtre à chaque répertoire, et bien il va créer des fichiers carnet.config un peu partout sur son disque.
Je te laisse trouver comment résoudre le problème.
|
|
| 26/12/2006 15:09 |
|
 |
acryline
Member
  
Messages : 68
Groupe : Membres
Inscription : Dec 2006
Statut :
Hors ligne
Réputation : 2
|
Merci ! Je me disais toujours, mais qu'est ce qu'il fiche là ce fichier carnet.config. Mais je n'ai jamais pensé aller plus loin dans ma réflexion... Bravo pour avoir trouvé LA solution. OK je me penche dessus dès que possible, où alors si j'en ai besoin pour mon programme actuel. (j'ai une petite idée.. ne faudrait-il pas prendre le répertoire racine de l'application au début du lancement du programme et la mémoriser dans une variable globale ?)
Aujourd'hui je vais présenter l'ouverture d'une nouvelle fiche avec les 3 petites fonctions ouvrirNouvelleFiche
modifierTemoins et menuAJour

void ouvrirnouvellefiche (hwnd hwnd)
{
static bool t[3]={false,false,true};
modifiertemoins(hwnd,t);
menuajour (hwnd,mf_grayed,mf_enabled);
sendmessage(hwnd,wm_create,0,0);
}
pour commencer je modifie le tã©moins d'ouverture de fenãªtre qui dã©terminera la crã©ation de telle ou telle fenãªtre
en rã©ponse au message wm_create dans la procã©dure principale.
ensuite je mets le menu ã jour (options grisã©es ou non)
pour finir j'envoie un message wm_create ã la procã©dure pricipale pour qu'elle crã©e la fenãªtre fiche.
pour celã j'ai ã©crit deux petites fonctions :
void modifiertemoins(hwnd hwnd,bool*t)
{
long i=0;
for(i=0;i<3;i++)
{
sendmessage(hwnd,wm_temoins,i,t[i]);
}
}
j'envoie ã la procã©dure principale un message que j'ai crã©e wm_temoins pour dã©finir l'ã©tat des 3 tã©moins de fenãªtre fille.
void menuajour (hwnd hwnd,uint fiche,uint retour)
{
enablemenuitem(getmenu(hwnd),idm_nouvellefiche,fiche);
enablemenuitem(getmenu(hwnd),idm_retour,retour);
}
MF_GRAYED,MF_ENABLED ont été transmis à la fonction, pour griser l'option "Nouvelle fiche" et activer l'option "Retour à la couverture" dans le menu.
|
|
| 27/12/2006 12:41 |
|
 |
acryline
Member
  
Messages : 68
Groupe : Membres
Inscription : Dec 2006
Statut :
Hors ligne
Réputation : 2
|
Bonjour,
aujourd'hui c'est le tour du traitement du message IDM_RETOUR, message envoyé par le menu
pour revenir à la couverture du carnet d'adresses. Je ne présenterai qu'une fonction puisque les autres ont
déjà été vues précédemment (d'où l'utilité des fonctions...on peut les utiliser plusieurs fois et quand
on écrit une seule ligne au lieu de tout un code, on a une petite impression de magique )

void ouvrircouverture(hwnd hwnd)
{
static bool t[3]={true,false,false};
modifiertemoins(hwnd,t);
menuajour (hwnd,mf_enabled,mf_grayed);
supprimerfichiertemporaire ();
sendmessage(hwnd,wm_create,0,0);
}
Ici on passe aux fonctions menuAjour et ModifierTemoins les paramètres correspondant à l'ouverture
de la couverture.
|
|
| 28/12/2006 07:34 |
|
 |
|
|