IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Windows Discussion :

[Win Api32] [C] Une énigme (pour moi)


Sujet :

Windows

  1. #1
    Membre régulier Avatar de acryline
    Profil pro
    Inscrit en
    Août 2006
    Messages
    200
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 200
    Points : 101
    Points
    101
    Par défaut [Win Api32] [C] Une énigme (pour moi)
    Bonjour,

    je réalise un petit programme en C avec Win Api 32. J'essaie de remplir un structure SHFILEOPSTRUCT pour utiliser la fonction SHFileOperation qui entre autres copie des fichiers.

    Dans une fonction je fais un appel de sous fonction pour trouver l'adresse du dossier à copier :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
        shf.pFrom=NULL;
        shf.pFrom=definirAdresseOrigine(p_gadget->dossier[i],p_action->user); 
        printf("%s\n",shf.pFrom);//vérification dans une console si l'adresse est bien définie
    Voici la fonction appelée :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    //--------------------------------------------------------------------------
    
    // Trouver l'adresse d'un dossier à sauvegarder
    
    //--------------------------------------------------------------------------
    
    LPCTSTR definirAdresseOrigine(TCHAR *dossier,TCHAR *user)
    
            {
    
                TCHAR adresse[256]={0};
    
    
    
                strcat(adresse,"C:\\DOCUME~1\\");
    
                strcat(adresse,user);
    
                strcat(adresse,"\\");
    
                strcat(adresse,dossier);
    
                strcat(adresse,"\\*\0");
    
               // printf("adresse:%s\n",adresse); //vérification console
              return (LPCTSTR)adresse;
    
    
              }
    Mon problème :
    Si je n'active pas la ligne du printf de la sous fonction l'adresse retournée est fausse. Dans la console j'obtiens :

    Alors que si j'active le printf de la sous fonction (alors qu'à mes yeux normalement ça ne devrait rien changer au résultat), mon adresse est juste et j'obtiens :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    C:\DOCUME~1\user\dossier\*
    Petite pécision, j'appelle ma sous fonction plusieurs fois dans une boucle, et l'adresse recherchée n'est fausse qu'au premier passage.

    Ma question : pourquoi je n'obtiens pas le même résultat avec ou sans printf et surtout comment faire pour ne pas user de ce subterfuge..j'aimerais avoir un code le plus propre possible et aussi le comprendre un minimum.

    Merci pour vos réponses.

  2. #2
    Membre actif Avatar de Twindruff
    Inscrit en
    Janvier 2005
    Messages
    216
    Détails du profil
    Informations forums :
    Inscription : Janvier 2005
    Messages : 216
    Points : 237
    Points
    237
    Par défaut
    Dans ta fonction definirAdresseOrigine tu retournes l'adresse d'une variable locale adresse. Tu ne peux pas l'utiliser en dehors de la portée de la variable, le compilo a le droit de faire ce qu'il veut avec cet espace mémoire lorsque la variable n'existe plus.

  3. #3
    Membre régulier Avatar de acryline
    Profil pro
    Inscrit en
    Août 2006
    Messages
    200
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 200
    Points : 101
    Points
    101
    Par défaut
    Merci pour ta réponse rapide !
    Je viens de tester ça et j'ai exactement lemême résultat :

    Appel de sous fonction :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
       shf.pFrom=NULL;     
         
    shf.pFrom=definirAdresseOrigine(shf.pFrom,p_gadget->dossier[i],p_action->user);
    Sous fonction :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    //--------------------------------------------------------------------------
    // Trouver l'adresse d'un dossier à sauvegarder
    //--------------------------------------------------------------------------
    LPCTSTR definirAdresseOrigine(LPCTSTR pFrom,TCHAR *dossier,TCHAR *user)
            {
                TCHAR adresse[256]={0};
    
                strcat(adresse,"C:\\DOCUME~1\\");
                strcat(adresse,user);
                strcat(adresse,"\\");
                strcat(adresse,dossier);
                strcat(adresse,"\\*\0");
               //printf("adresse:%s\n",adresse);
               pFrom=(LPCTSTR)adresse;
              return pFrom;
        }
    ET j'ai aussi essayé en passant shf.pFrom en pointeur sans que la fonction ne retourne le résultat... tjrs le même problème.

  4. #4
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Tu fais toujours la même erreur: Retourner l'adresse d'un tableau local.

    De plus, tu mélanges des char et des TCHAR. Utilise les fonctions de <tchar.h> au lieu des fonctions de <string.h>, et tu pourras avoir des résultats corrects: _tcscat() au lieu de strcat(), _tprintf() au lieu de printf(), la macro _T() pour tes chaînes littérales, etc.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  5. #5
    Rédacteur
    Avatar de Neitsa
    Homme Profil pro
    Chercheur sécurité informatique
    Inscrit en
    Octobre 2003
    Messages
    1 041
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Chercheur sécurité informatique

    Informations forums :
    Inscription : Octobre 2003
    Messages : 1 041
    Points : 1 956
    Points
    1 956
    Par défaut
    Bonjour,

    Même constat que Twindruff et Médinoc pour ton deuxième exemple. En sortant de la fonction definirAdresseOrigine() le tampon "adresse" n'existe plus.

    Qu'il soit assigné à un pointeur n'y change rien puisque "adresse" est une variable locale à la fonction definirAdresseOrigine(). En sortie de la fonction "pFrom" pointe donc sur du vide (plus précisément: sur n'importe quoi !).

    Tu devrais allouer "pFrom" à l'extérieur de la fonction puis y copier tes chaînes dans la fonction qui retournera ensuite "pFrom". Un fois que "pFrom" n'est plus utilisé, tu le libères.

    En gage de sécurité:

    - Vérifie que le chemin final n'est pas plus long que MAX_PATH (attention au buffer overflow lors des copies !).

    - Remplace le premier strcat() par un strcpy(), c'est mieux même si tous les octets du buffer sont à zéro, cela prévient un problème éventuel lors de modification de code ultérieures par exemple.

    - pFrom ne devrait pas être de type LPCTSTR (le 'C' veut dire "const").

    - Si tu utilises des TCHAR alors les chaînes peuvent être en Unicode ou MBCS, ce qui implique que strcat() (et strcpy) n'aura pas le comportement attendu avec des chaînes Unicode. Tu devrais donc utiliser les fonctions pour TCHAR (ex: _tcscat() ).

    - Utilise les fonctions sécurisées: _tcscat_s() et consorts.

  6. #6
    Membre régulier Avatar de acryline
    Profil pro
    Inscrit en
    Août 2006
    Messages
    200
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 200
    Points : 101
    Points
    101
    Par défaut
    Ok, merci pour les réponses,je vais essayer de corriger mon code.

    pFrom est une variable de la structure que j'aimerais remplir, c'est pour cela que j'ai mis LPCTSTR.
    Donc si j'ai bien compris , j'alloue une variable (et pas pFrom) en dehors de la sous fonction et c'est elle que je vais récupérer.
    Et ensuite je passe ma variable dans shf.pFrom..

    Je teste.

  7. #7
    Membre régulier Avatar de acryline
    Profil pro
    Inscrit en
    Août 2006
    Messages
    200
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 200
    Points : 101
    Points
    101
    Par défaut
    Voilà ça a l'air de fonctionner .

    Ma correction :
    - déjà j'ai remplacé tous les TCHAR de mon programme par CHAR (bon j'avoue ça faisait longtemps que je n'avais pas touché un p'tit code pour windows, alors j'ai cru...)

    - ensuite voici l'appel de la sous fonction, puis la sous fonction elle-même :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     adresseFrom=malloc(MAX_PATH*sizeof(CHAR));
    //[...]
    
    definirAdresseOrigine(adresseFrom,p_gadget->dossier[i],p_action->user);
    shf.pFrom =(LPCTSTR)adresseFrom;
    //[...]
    free(adresseFrom);
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    //--------------------------------------------------------------------------
    
    // Trouver l'adresse d'un dossier à sauvegarder
    
    //--------------------------------------------------------------------------
    
    void definirAdresseOrigine(CHAR *adresseFrom,CHAR *dossier,CHAR *user)
    
     {
    
                strcpy(adresseFrom,"C:\\DOCUME~1\\");
    
                strcat(adresseFrom,user);
    
                strcat(adresseFrom,"\\");
    
                strcat(adresseFrom, dossier);
    
                strcat(adresseFrom,"\\*\0");
    
      }
    Je pense que je peux mettre résolu ... sinon vous corrigerez dessous

  8. #8
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Citation Envoyé par acryline Voir le message
    - déjà j'ai remplacé tous les TCHAR de mon programme par CHAR (bon j'avoue ça faisait longtemps que je n'avais pas touché un p'tit code pour windows, alors j'ai cru...)
    C'est l'inverse que tu aurais du faire...
    La preuve, les casts explicites en LPCTSTR.

    Ensuite, tu ferais peut-être mieux de faire le malloc() dans la fonction definirAdresseOrigine... Et mettre des const (ou des LPCSTR ou LPCTSTR) dans ses deux derniers paramètres.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  9. #9
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    adresseFrom = definirAdresseOrigine(p_gadget->dossier[i], p_action->user);
    shf.pFrom = adresseFrom;
    /*[...]*/
    free(adresseFrom);
    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    LPTSTR definirAdresseOrigine(LPCTSTR dossier, LPCTSTR user)
    {
    	LPTSTR adresseFrom = NULL;
     
    	/* Calculer la longueur de chaîne à allouer, 
    	   caractère nul supplémentaire compris. */
    	size_t cchLength = _sctprintf(_T("C:\\DOCUME~1\\%s\\%s\\*%c"), user, dossier, _T('\0'));
    	size_t cchLengthWithSecondNull = cchLength+1;
    	/* Calculer la taille en octets à allouer, 
    	   avec les DEUX caractères nuls. */
    	size_t cbSize = (cchLengthWithSecondNull+1) * sizeof *adresseFrom;
     
    	/* Allouer le buffer à retourner */
    	adresseFrom = malloc(cbSize);
    	if(adresseFrom != NULL)
    	{
    		/* Faire le formattage pour de bon cette fois-ci */
    		_stprintf(adresseFrom, _T("C:\\DOCUME~1\\%s\\%s\\*%c"), user, dossier, _T('\0'));
    	}
    	return addresseFrom;
    }
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  10. #10
    Membre régulier Avatar de acryline
    Profil pro
    Inscrit en
    Août 2006
    Messages
    200
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 200
    Points : 101
    Points
    101
    Par défaut
    aie aie mais c'est que...
    - mon programme n'a pas que ces fonctions et j'ai utilisé quelques fois strcat()
    - en plus je n'ai pas trouvé de doc sur "_tcscat_s() et consorts. "
    - et si je fais le malloc dans ma sous fonction je dois aussi libérer la mémoire à cet endroit... je ne vois pas comment je vais pouvoir utiliser la chaîne de caractères après ça, j'aurai le même problème qu'avant non ?.

  11. #11
    Membre régulier Avatar de acryline
    Profil pro
    Inscrit en
    Août 2006
    Messages
    200
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 200
    Points : 101
    Points
    101
    Par défaut
    OK Merci, nous avons posté ensemble
    Je ne pensais pas pouvoir faire mon alloc dans une fonction et libérer la mémoire dans une autre .

    je teste.

  12. #12
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Citation Envoyé par acryline Voir le message
    Je ne pensais pas pouvoir faire mon alloc dans une fonction et libérer la mémoire dans une autre.
    C'est pourtant ce que fait la fonction malloc() elle-même...
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  13. #13
    Membre régulier Avatar de acryline
    Profil pro
    Inscrit en
    Août 2006
    Messages
    200
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 200
    Points : 101
    Points
    101
    Par défaut
    P'tite question, dans la fonction que tu proposes que représente
    - length : est ce que c'est cchLength ?
    - ret ? --> je peux mettre sizeof(CHAR) ?

    (un moment de honte est bien vite passé, j'envoie ... )

  14. #14
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Citation Envoyé par acryline Voir le message
    P'tite question, dans la fonction que tu proposes que représente
    - length : est ce que c'est cchLength ?
    - ret ? --> je peux mettre sizeof(CHAR) ?

    (un moment de honte est bien vite passé, j'envoie ... )
    Oups! Des variables que j'ai renommées. Je corrige.
    Edit: corrigé.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  15. #15
    Membre régulier Avatar de acryline
    Profil pro
    Inscrit en
    Août 2006
    Messages
    200
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 200
    Points : 101
    Points
    101
    Par défaut
    J'ai bien ajouté <TCHAR.h> dans mon fichier mais codeblocks ne trouve pas les fonctions...
    J'ai trouvé la doc en revanche, elle est bien cachée sur le web , sur le site msdn ici

    Je crois que je ne vais pas utiliser SHFileOperation mais à la place je vais prendre les bonnes vieilles fonctions c'est trop prise de tête. (ça sera peut être aussi prise de tête..)

    Merci pour votre aide.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 0
    Dernier message: 21/03/2013, 21h38
  2. créer une requête pour regrouper par mois
    Par kuhnden dans le forum Requêtes et SQL.
    Réponses: 12
    Dernier message: 26/01/2008, 13h41
  3. Réponses: 2
    Dernier message: 18/02/2007, 21h30
  4. Une requête bien compliquée pour moi
    Par bellande dans le forum Requêtes et SQL.
    Réponses: 4
    Dernier message: 01/02/2007, 21h51

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo