begin process at 2008 05 16 06:30:52
1 173 216 membres
61 nouveaux aujourd'hui
13 970 membres club

Vous ne trouvez pas de réponse à votre problème ? Alors posez la question dans le forum.
Souvenez-vous qu'il n'y a jamais de question bête, mais rester dans l'ignorance parce que l'on n'ose pas poser une question, ça c'est une erreur !

CHARGER UNE POLICE DEPUIS UN FICHIER OU UNE RESSOURCE (WIN32)


Information sur la source

Catégorie :Astuces Classé sous : addfontmemresourceex, police, font, ressource, createfont Niveau : Débutant Date de création : 02/08/2006 Date de mise à jour : 12/08/2006 12:23:43 Vu / téléchargé: 5 317 / 386

Note :
Aucune note

Commentaire sur cette source (63)
Ajouter un commentaire et/ou une note


Description

Ce code montre comment utiliser la fonction AddFontMemResourceEx dans le but de créer une police a partir d'un fichier qui n'est pas dans le dossier des polices de Windows, ou bien depuis une ressource de l'exécutable.
Pour les "Membres Club", vous pouvez télécharger directement un fichier contenu dans le zip sans télécharger le zip en entier !

Télécharger le zip

12 août 2006 12:23:43 :
Appel de FreeResource Appel de RemoveFontMemResourceEx directement après CreateFont Remplacement memset par fonction perso
  • signaler à un administrateur
    Commentaire de MuPuF le 03/08/2006 01:25:27

    oh super !, merci, ça va vraiment me servir, je fais actuelle une classe pour gerer les skins, ta source va apporter un réel plus !

    La source compile sans probleme et fonctionne parfaitement.

    Encore une fois merci ;-)

  • signaler à un administrateur
    Commentaire de vecchio56 le 03/08/2006 01:27:33 administrateur CS

    Je savais que t'en avais besoin sinon je l'aurais jamais faite ;)

  • signaler à un administrateur
    Commentaire de MuPuF le 03/08/2006 01:30:11

    hey hey vecchiodamus ;-)

  • signaler à un administrateur
    Commentaire de MorbhAck le 03/08/2006 03:00:22

    Sa marche a merveille ! MERCI encore une fois ( a putin ce que chui leche cul ! ) :)

  • signaler à un administrateur
    Commentaire de mogwai93 le 03/08/2006 08:29:37

    Question par rapport à DevCpp :
    ca compile mais en remplacant :

    #ifdef _DEBUG
    int main()
    #else
    #pragma comment(linker, "/entry:myWinMain")
    int __stdcall myWinMain()
    #endif

    par :
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
       LPSTR lpCmdLine, int nCmdShow)

    et
    #ifdef _DEBUG
      return (int)msg.wParam;
    #else
      ExitProcess(msg.wParam);
    #endif

    par :
         return msg.wParam;


    sinon, j'ai une erreur :
      [Linker error] undefined reference to `WinMain@16'
      ld returned 1 exit status

    quelqu'un peut m'expliquer ?
    merci

  • signaler à un administrateur
    Commentaire de vecchio56 le 03/08/2006 10:35:19 administrateur CS

    Parce que le #pragma n'est pas compris par gcc

  • signaler à un administrateur
    Commentaire de deck_bsd le 04/08/2006 17:02:51

    sir vecchio est en grande forme ces temps si :D Bonne source :D (vivi je peut utiliser les ressources now mdr).

  • signaler à un administrateur
    Commentaire de racpp le 11/08/2006 22:25:23 administrateur CS

    Salut,
    Merci vecchio56 pour ce code. Je viens de me servir de la fonction AddFontMemResourceEx() dans mon dernier code source déposé il y'a un instant. Cette fonction m'a servi à ajouter une police au système à partir d'une ressource en mémoire. Je viens de remarquer qu'une fois la police ajoutée, la ressource peut être libérée sans problème. Donc un appel de FreeResource() juste après AddFontMemResourceEx() serait préférable.
    A propos du #pragma comment(linker, "/entry:myWinMain"), je ne crois pas qu'il soit d'une grande utilité dans ton code. Car même si le point d'entrée du programme évite l'utilisation de la CRT, cette dernière sera de toute façon utilisée dans ton programme. memset() par exemple. Et la taille de l'exe ne sera pas réduite.
    Y'a-t-il une autre raison de l'utilisation de cette option du linker?
    Merci.

  • signaler à un administrateur
    Commentaire de vecchio56 le 11/08/2006 22:34:45 administrateur CS

    Oui pour le  RemoveFontMemResourceEx j'ai vu qu'on peut l'appeler aussitot, le HFONT n'en a pas besoin.
    Pour l'option: si, elle diminue la taille de l'exécutable ici (103Ko au lieu de 134Ko avec WinMain)

  • signaler à un administrateur
    Commentaire de racpp le 11/08/2006 23:03:58 administrateur CS

    Je pense que non vecchio56, RemoveFontMemResourceEx() ne doit pas être appelée aussitôt. Je viens de tester. La police ne sera plus disponible et sera remplacée par la police par défaut. Moi je parlais de FreeResource():
    - Charger la ressource avec LoadResource().
    - Appeler AddFontMemResourceEx()
    - Libérer la ressouce avec FreeResource().
    - Créer la police.
    D'après mes tests, RemoveFontMemResourceEx() ne doit être appelée que si on n'aura plus besoin de notre police. Elle fera donc suite à DeleteObject(hPolice)
    Puisque tu cherchais à diminuer la taille de l'exe, pourquoi ne pas virer memset()?
    WNDCLASSEX wcex={0}; serait suffisant.
    Il est à noter que l'API RegisterClassEx() fait implicitement appel à memset() et fait donc augmenter la taille de l'exe. RegisterClass() quant à elle ne fait pas d'appel à la CRT. J'ai découvert tout ça dernièrement. Tu peux faire des tests pour en avoir le coeur net.

  • signaler à un administrateur
    Commentaire de BruNews le 11/08/2006 23:15:20 administrateur CS

    C'est fou cette histoire, l'autre jour je me suis retrouvé avec un exe lié à msvcrt8.dll pour cause que l'exe appelait _memset et _memcpy sur cette dll. J'ai viré la dépendance en fournissant mes funcs au lieu des 2 originalez.
    Faut dire que c'était la 1ere fois que je notais cela et l'exe de vecchio non plus n'a pas de dépendance.
    Je note pourtant le
    call _memset
    dans l'asm produit par le compilo.
    Mystique tout cela, sera à approfondir.

  • signaler à un administrateur
    Commentaire de vecchio56 le 11/08/2006 23:16:03 administrateur CS

    OK pour le FreeResource, je regarderai cela
    WNDCLASSEX wcex={0}; va sans doute générer un fichier plus gros, il signifie en fait WNDCLASSEX wcex={0, 0, 0, ..., 0}; (cela dit ta solution diminue la taille du fichier source)
    RegisterClassEx est une fonction, donc son appel est traduit par un call, rien de plus
    Heureusement d'ailleurs, pourquoi ferait-elle un memset? Elle pourrait plus lire les infos dans la structure

  • signaler à un administrateur
    Commentaire de vecchio56 le 11/08/2006 23:17:30 administrateur CS

    BruNews> Il en faudra des années avant de comprendre toutes ces options de VS2005. Tout était bien plus simple sous 2003, pas de mauvaises surprises

  • signaler à un administrateur
    Commentaire de BruNews le 11/08/2006 23:21:57 administrateur CS

    Mais le + fort, je viens de comparer les options linker et compilo de ton proj avec le mien, exactement les mêmes.
    S'il y a de l'alea dans le binaire maintenant, tout est perdu...

  • signaler à un administrateur
    Commentaire de racpp le 11/08/2006 23:49:50 administrateur CS

    vecchio56 >> Avec WNDCLASSEX wcex={0} la taille de l'exe est plus petite car memset() ajoute beaucoup plus d'octets. J'avais déja fait des tests. Je parle bien sûr d'un exe autonome sans aucune dépendance.
    brunews >> C'est justement à cause de cette msvcrt80.dll que j'ai découvert tout cela. Cette dll n'est pas présente sur tous les ordinateurs et cela nous oblige à la lier statiquement dans le programme. Même en virant toute référence à la CRT, mes programmes en dépendent toujours à cause de certaines APIs. RegisterClassEx() n'est pas la seule car j'ai remarqué le même comportement avec d'autres. J'ai l'intention de les répertorier et essayer de faire un tutorial à ce sujet.

  • signaler à un administrateur
    Commentaire de racpp le 12/08/2006 00:36:51 administrateur CS

    Il s'agit de msvcr80.dll et non msvcrt.dll. Désolé pour l'erreur.
    vecchio56 >> Je viens de compiler ton projet tel quel sans rien changer. Au linkage j'ai deux warnings du genre:
    warning LNK4210: .CRT section exists; there may be unhandled static initializers or terminators

    Ca prouve bien qu'il y'a de la dépendance à la CRT. Pourtant, Depends n'affiche aucune dépendance. En remplaçant WNDCLASSEX par WNDCLASS et RegisterClassEx() par RegisterClass() les warnings disparaissent et la taille de l'exe descend à 100ko. Ca veut dire que RegisterClassEx() provoque implicitement l'ajout du code de _memeset à l'exéutable. C'est vrai qu'on se demande pouquoi cette API appellerait _memset().


  • signaler à un administrateur
    Commentaire de racpp le 12/08/2006 00:51:42 administrateur CS

    Je viens de remarquer qu'on ne peut pas déscendre sous les 100ko car la ressource seule fait 97ko.

  • signaler à un administrateur
    Commentaire de vecchio56 le 12/08/2006 11:29:46 administrateur CS

    En effet plus de warning avec RegisterClassEx (en fait je pensais que le warning était présent dès lors qu'on personnalisait le point d'entrée). Comment sais-tu que c'est memset qui est appelée par RegisterClassEx?
    De toutes facons je comprends pas: le code de RegisterClassEx est situé dans user32.dll, et donc même si cette api utilise la CRT, ce devrait être indépendant de notre programme, non?

  • signaler à un administrateur
    Commentaire de vecchio56 le 12/08/2006 11:41:53 administrateur CS

    En fait le warning apparait quand on utiliser à la fois memset et RegsiterClassEx

    RegisterClassEx -> pas de warning
    memset et RegisterClassEx -> warning
    memset et RegisterClass -> pas de warning

    Je regarderait les sorties asm pour voir

  • signaler à un administrateur
    Commentaire de vecchio56 le 12/08/2006 11:57:50 administrateur CS

    Le memset est inlinée pour WNDCLASS et pas pour WNDCLASSEX
    Parce que WNDCLASSEX est plus grande et doit donc dépasser la limite pour être inlinée

  • signaler à un administrateur
    Commentaire de vecchio56 le 12/08/2006 12:02:21 administrateur CS

    A partir de 44 octets memset n'est plus inlinée en fait

  • signaler à un administrateur
    Commentaire de vecchio56 le 12/08/2006 12:12:44 administrateur CS

    racpp, même en écrivant WNDCLASSEX wcex = {0}; le compilo appelle memset
    Je crois qu'il faut donc employer la méthode de BruNews: une fonction perso

  • signaler à un administrateur
    Commentaire de racpp le 12/08/2006 16:47:39 administrateur CS

    Bonjour,
    Chez moi le warning apparait avec RegisterClassEx(), seule ou avec memset().
    A propos de RegisterClassEx(), je suis tout à fait d'accord. Si elle appelle _memset(), ça doit être en dehors de notre prog.
    Personnellement, quand je veux que mon exe soit le plus petit possibe, je mets le code en C, je mets l'option /NODEFAULTLIB pour le linker et /GS- pour le compilateur. Je fouris dans le code la fonction d'entrée WinMainCRTStartup(). Un jour, en étant sûr que mon code ne fait aucun appel à la CRT, je me retrouve devant des erreurs indiquant les fonctions de la CRT manquantes. J'ai alors mis en commentaire tout le code sauf la WinMain(). Et là je découvre qu'avec RegisterClassEx() le linker demande _memset(). En la remplaçant par RegisterClass(), l'erreur diparait et l'exe est généré.
    Dans le post suivant, je mettrai un petit exemple de code à tester.

  • signaler à un administrateur
    Commentaire de vecchio56 le 12/08/2006 16:55:33 administrateur CS

    Comme j'ai dit plus haut, c'est seulement du au fait que sizeof(WNDCLASSEX)>sizeof(WNDCLASSEX), et qu'a partir d'une certaine taille, memset n'est plus inlinée (sinon ca ferait du code trop gros)

  • signaler à un administrateur
    Commentaire de racpp le 12/08/2006 17:01:35 administrateur CS

    #include <windows.h>

    int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR cmd,int show)

    {
        WNDCLASSEX wc={0};
        RegisterClassEx(&wc);
        return 0;
    }


    int WINAPI WinMainCRTStartup(void)
    {
        int retour;
        retour = WinMain( GetModuleHandle(0),0,0,1 );  
        return retour;
    }

  • signaler à un administrateur
    Commentaire de racpp le 12/08/2006 17:06:43 administrateur CS

    Oui, tu as raison. Je viens de le voir. C'est plutôt à cause de ces 4 octets de plus de WNDCLASSEX. RegisterClassEx() n'a rien à voir là dedans. Je préfère comme ça car c'était la 1ère fois que je soupçonais une API.

  • signaler à un administrateur
    Commentaire de racpp le 12/08/2006 17:23:23 administrateur CS

    Conclusion:
    - Pour les tailles inférieures ou égales à 40 octets -> ={0}
    - Pour les autres, fournir une fonction perso.

    Tu as testé mon petit code? Tu as vu les fonctions manquantes affichées en clair?

  • signaler à un administrateur
    Commentaire de vecchio56 le 12/08/2006 17:27:11 administrateur CS

    Je n'ai aucune erreur avec ton exemple. Il est pour VC++ ou Dev-C++?

  • signaler à un administrateur
    Commentaire de racpp le 12/08/2006 17:31:21 administrateur CS

    Dans le cas de WNDCLASSEX on peut juste mettre les autres membres à 0 et virer memset(). Ca permet de gagner 3Ko. Sans la ressource, l'exe ne ferait pas plus de 3ko.
    Pourquoi ne pas choisir une police d'une dizaine de Ko?

  • signaler à un administrateur
    Commentaire de vecchio56 le 12/08/2006 17:36:25 administrateur CS

    Ben je sais pas, c'est grave qu'elle fasse 100Ko?
    Pour ton petit code, j'ai pas compris ce que tu voulais montrer avec

  • signaler à un administrateur
    Commentaire de racpp le 12/08/2006 17:59:36 administrateur CS

    Ce code est fait pour Visual C Express 2005. Ca doit être pareil avec la version complète car il utilise le même compilo et linker.
    J'ai donné le code pour répondre à ta question sur comment je sais que c'est que c'est _memset qui manque. Avec ce code, le linker affiche:
    error LNK2001: unresolved external symbol _memset
    Si ça t'interesse, je peux t'envoyer le petit projet complet. Avec cette méthode, on est sûr qu'aucune fonction de la CRT n'est ajouté à notre exe.
    A propos des 100ko, puisque tu cherches à diminuer la taille de l'exe en mettant ton point d'entrée, pourquoi ne pas choisir une police plus petite et gagner encore des dizaines de ko?

  • signaler à un administrateur
    Commentaire de vecchio56 le 12/08/2006 18:02:50 administrateur CS

    Diminuer la taille de l'exe pour moi c'est surtout enlever tout ce qui est inutile. Ici le fichier police est utile donc pas de problème.
    Je veux bien voir ton projet

  • signaler à un administrateur
    Commentaire de racpp le 12/08/2006 18:43:43 administrateur CS

    J'ai envoyé le projet.
    Certes le fichier police est utile, mais un autre de moindre taille sera aussi utile puisque cette police ne sert qu'à démontrer le fonctionnement d'une fonction. Ce serait préférable de choisir un fichier plus petit. Ainsi on gagnera en taille de l'exécutable et en occupation mémoire. C'est mon point de vue.

  • signaler à un administrateur
    Commentaire de BruNews le 12/08/2006 19:43:52 administrateur CS

    mov eax, adresse
    mov ecx, 44
    memZERO:
    mov dword ptr[eax], 0
    add eax, 4
    sub ecx, 4
    jnz short memZERO

    Changerait quoi qu'on mette 40 ou plus dans ECX ???
    Même pas de problème d'alignement puisque le compilo aura par force placé correctement une struct, donc aucun besoin de code de controle préalable.
    Ce code pourrait se mettre fort bien direct inline en place d'un appel de fonction.

    Un compilo reste un compilo, rassurant pour le codeur manuel...

  • signaler à un administrateur
    Commentaire de racpp le 12/08/2006 20:07:35 administrateur CS

    Brunews >> J'aimerais bien avoir ton avis aussi sur le petit projet que j'ai envoyé à vecchio56. C'est une méthode de contrôle total sur les dépendances. Le compilo ignore totalement la CRT et le linker affiche le nom de toute fonction tentant d'y accéder. Si ça t'intéresse, laisse une adresse émail par MP.

  • signaler à un administrateur
    Commentaire de BruNews le 12/08/2006 20:10:34 administrateur CS

    OK je vais regarder (après le resto), vecchio me l'a transmis.

  • signaler à un administrateur
    Commentaire de racpp le 12/08/2006 20:16:04 administrateur CS

    Ok merci
    Bon appétit

  • signaler à un administrateur
    Commentaire de BruNews le 13/08/2006 00:32:56 administrateur CS

    ATTENTION, compiler pour regarder listing ASM mais NE PAS LANCER dans cet état.

    void __fastcall bnzeromem(void *pmem, DWORD len)
    {
      BYTE *p = (BYTE*) pmem;
      DWORD r = len;
      if(!(len >>= 3)) goto prepm1SET;
    mem8SET:
      *((DWORD*) p) = 0;
      *((DWORD*) (p + 4)) = 0;
      p += 8;
      if(len -= 8) goto mem8SET;
    prepm1SET:
      if(!(r &= 7)) goto zeromemEXIT;
    mem1SET:
      *p++ = 0;
      if(--r) goto mem1SET;
    zeromemEXIT: return;
    }

    #pragma comment(linker, "/entry:myWinMain")
    void WINAPI myWinMain(void)
    {
      //WNDCLASSEX wc={0};
      WNDCLASSEX wc;
      //memset(&wc, 0, sizeof(WNDCLASSEX));
      //RtlZeroMemory(&wc, sizeof(WNDCLASSEX));
      //bnzeromem(&wc, sizeof(WNDCLASSEX));
      bnzeromem(&wc, GetTickCount());
      RegisterClassEx(&wc);
      ExitProcess(0);
    }

    Ce que je pense être le mieux si on ne veut pas de CRT et surtout ne pas sacrifier la vitesse (tout de même le + important).
    WNDCLASSEX wc={0}; comme vu + haut, provoque un appel memset, exclus puisque non inline.
    RtlZeroMemory(&wc, sizeof(WNDCLASSEX)); compilo remplace par memset, idem exclus.

    bnzeromem(&wc, sizeof(WNDCLASSEX)); incroyable, le compilo a mis 2 affectations de 4 octets et fini, mystère complet. Espérons que ne se produira pas dans un vrai prog complet, à vérifier.
    Voila tout ce qu'il en reste, histoire de fou:
    @bnzeromem@8 PROC
    ; _pmem$ = eax
    $mem8SET$77844:
       mov  DWORD PTR [eax], 0
       mov  DWORD PTR [eax+4], 0
    $prepm1SET$77843:
    $zeromemEXIT$77849:
       ret  0
    @bnzeromem@8 ENDP

    En forçant une valeur "aléatoire" (GetTickCount), alors là NICKEL !!!
    Passage correct en registres, tout se fait dans les 3 registres généraux donc pas de 'push pop', pas 1 cycle de perdu, parfait.
    @bnzeromem@8 PROC
    ; _pmem$ = eax
    ; _len$ = ecx
    ; 20 :   BYTE *p = (BYTE*) pmem;
    ; 21   :   DWORD r = len;
        mov edx, ecx
    ; 22   :   if(!(len >>= 3)) goto prepm1SET;
       shr   ecx, 3
       je   SHORT $prepm1SET$77843
       npad   9
    $mem8SET$77844:
       mov   DWORD PTR [eax], 0
       mov   DWORD PTR [eax+4], 0
       add   eax, 8
       sub   ecx, 8
       jne   SHORT $mem8SET$77844
    $prepm1SET$77843:
    ; 29   :   if(!(r &= 7)) goto zeromemEXIT;
       and   edx, 7
       je   SHORT $zeromemEXIT$77849
       npad   6
    $mem1SET$77850:
    ; 30   : mem1SET:
       mov   BYTE PTR [eax], 0
       add   eax, 1
    ; 32   :   if(--r) goto mem1SET;
       sub   edx, 1
       jne   SHORT $mem1SET$77850
    $zeromemEXIT$77849:
       ret   0
    @bnzeromem@8 ENDP
    Qu'il est bien ce compilo quand il ne nout fait pas des trucs à l'insu de notre plein gré...

  • signaler à un administrateur
    Commentaire de BruNews le 13/08/2006 00:40:44 administrateur CS

    J'oubliais de préciser qu'ainsi on obtient un exe de 2 Ko.
    Je remets le proj ici:
    http://bnmvp.free.fr/nocrt.zip
    ça permettra de vérifier les options de compilo et linker.

  • signaler à un administrateur
    Commentaire de vecchio56 le 13/08/2006 14:36:27 administrateur CS

    Je sais pas ce qu'a fait le compilo comme optimisation, c'est bizarre
    Mais ta fonction bnzeromem est fausse, car en l'occurence avec une zone de 48 octets elle va boucler:
    len >>= 3 donne 6, ensuite len -= 8 ne vaudra jamais 0

  • signaler à un administrateur
    Commentaire de BruNews le 13/08/2006 14:44:24 administrateur CS

    oups, c'est: if(--len) goto mem8SET;

  • signaler à un administrateur
    Commentaire de vecchio56 le 13/08/2006 14:48:34 administrateur CS

    Et voila, du coup le compilo nous sort un code potable:

    @bnzeromem@8 PROC ; COMDAT
    ; _pmem$ = eax

    ; 20   :   BYTE *p = (BYTE*) pmem;
    ; 21   :   DWORD r = len;
    ; 22   :   if(!(len >>= 3)) goto prepm1SET;

    mov ecx, 6
    xor edx, edx
    $mem8SET$77844:

    ; 23   : mem8SET:
    ; 24   :   *((DWORD*) p) = 0;

    mov DWORD PTR [eax], edx

    ; 25   :   *((DWORD*) (p + 4)) = 0;

    mov DWORD PTR [eax+4], edx

    ; 26   :   p += 8;

    add eax, 8

    ; 27   :   if(--len) goto mem8SET;

    sub ecx, 1
    jne SHORT $mem8SET$77844
    $prepm1SET$77843:
    $zeromemEXIT$77849:

    ; 28   : prepm1SET:
    ; 29   :   if(!(r &= 7)) goto zeromemEXIT;
    ; 30   : mem1SET:
    ; 31   :   *p++ = 0;
    ; 32   :   if(--r) goto mem1SET;
    ; 33   : zeromemEXIT: return;
    ; 34   : }

    ret 0
    @bnzeromem@8 ENDP


    Encore bien optimisé puisqu'il met direct un mov ecx, 6 et enlève toute la deuxième partie de l'algo.

  • signaler à un administrateur
    Commentaire de BruNews le 13/08/2006 14:54:33 administrateur CS

    moralité: pas de code après resto.

  • signaler à un administrateur
    Commentaire de vecchio56 le 13/08/2006 18:53:59 administrateur CS

    Nouvel épidose: j'utilise le code de racpp pour voir quelles sont les dépendances éventuelles.
    J'ai cette fonction, pour remplacer memset
    void MemSet(void* dst, int byte, int size)
    {
      char* end = (char*)dst + size, *p;
      for(p = (char*)dst; p != end; *p++ = byte);
    }
    Si je mets les deux lignes en commentaire, rien
    Si je laisse ces deux lignes: symbole externe non résolu _memset référencé dans la fonction _MemSet
    Je n'ai pas de ZeroMemory ou autre choses du genre ailleurs dans mon code

    Je trouve que le compilo prend vraiment trop libertés!

  • signaler à un administrateur
    Commentaire de BruNews le 13/08/2006 19:03:21 administrateur CS

    ça je l'ai déjà eu, si la signature complète de la fonction ressemble à une intégrée de la CRT, il met la sienne.
    J'avais résolu en mettant du code asm en remplacement.

  • signaler à un administrateur
    Commentaire de vecchio56 le 13/08/2006 19:40:30 administrateur CS

    C'est incroyable ca! Il arrive a 'voir' que ma fonction fait la même chose que memset?

  • signaler à un administrateur
    Commentaire de vecchio56 le 13/08/2006 19:52:29 administrateur CS

    Autant les pb précédents sont plus ou moins expliqué, autant cette fois je comprends pas. Voici le code généré par ma fonction MemSet:

    PUBLIC _MemSet
    EXTRN _memset:PROC
    ; Function compile flags: /Ogtpy
    ; COMDAT _MemSet
    _TEXT SEGMENT
    _dst$ = 8 ; size = 4
    _byte$ = 12 ; size = 4
    _size$ = 16 ; size = 4
    _MemSet PROC ; COMDAT

    ; 40   :   char* end = (char*)dst + size, *p;

    mov ecx, DWORD PTR _dst$[esp-4]
    mov eax, DWORD PTR _size$[esp-4]
    add eax, ecx

    ; 41   :   for(p = (char*)dst; p != end; *p++ = byte);

    cmp ecx, eax
    je SHORT $LN3@MemSet
    sub eax, ecx
    mov DWORD PTR _size$[esp-4], eax
    mov DWORD PTR _dst$[esp-4], ecx
    jmp _memset
    $LN3@MemSet:

    ; 42   : }

    ret 0
    _MemSet ENDP
    _TEXT ENDS

    Je ne pense pas que ce soit un pb de signature (même pb en inversant l'ordre des params)

    Sinon t'aurais pas une bonne memset perso sous la main?

  • signaler à un administrateur
    Commentaire de BruNews le 13/08/2006 19:55:47 administrateur CS

    Il fait tellement plus fort, on ne va plus s'étonner de si peu.
    Essaie la compil "profil guided optimization" et vérifie le listing asm à chaque étape, il déplace des bouts de code et réécrit si besoin pour gagner qlqs cycles, un truc de fou.
    Me semble que G. Vollant a mis des trucs là dessus sur son site.

  • signaler à un administrateur
    Commentaire de BruNews le 13/08/2006 20:00:10 administrateur CS

    he he, tu as sentis venir ??? je démarrais justement une lib perso pour memset et memcpy, n'y aura plus qu'à mettre la lib dans dossier du proj et inclure son h.
    Je vais faire 2 versions de chaque (enfin j'y réfléchis), aligné et non aligné.

  • signaler à un administrateur
    Commentaire de racpp le 13/08/2006 20:33:38 administrateur CS

    Salut,
    Moi aussi j'ai remarqué ce petit problème. Le pire c'est que, dans le même code, certains appels à ma fonction se font normalement alors que d'autres sont remplacés par _memeset. J'ai résolu le problème en ajoutant /Ob1 aux options du compilateur. Je comprends pas trop mais ça marche.

  • signaler à un administrateur
    Commentaire de racpp le 13/08/2006 20:39:52 administrateur CS

    Voici la fonction que j'utilise:
    void FillMem(void *destination, DWORD  longueur,BYTE octet)
    {
    // Obtenir un pointeur sur DWORD:
    DWORD*  destination32=(DWORD*)destination;
    // Calculer la taille en DWORDs:
    DWORD taille32=longueur/4;
    // Former un DWORD dont chaque octet contient la valeur de notre octet:
    DWORD groupe=(octet*0x1000000 | octet*0x10000 | octet*0x100 | octet);
    // Si la longueur est inférieure à 4 on met juste les octets qu'il faut:
    switch (longueur-(taille32*2)) // astuce:
    {
    case 3: ((BYTE*)destination)[longueur-3] = octet;
    case 2: ((BYTE*)destination)[longueur-2] = octet;
    case 1: ((BYTE*)destination)[longueur-1] = octet;
    }
    // Remplir par notre DWORD tant que la taille est supérieure à 0:
    while( taille32-- > 0 ) *(destination32++) = groupe;
    }

    Elle ne doit pas être aussi rapide que celle de Brunews, mais elle fonctionne très bien. Je la soumets à vos remarques.

  • signaler à un administrateur
    Commentaire de racpp le 13/08/2006 20:49:01 administrateur CS

    switch (longueur-(taille32*2)) // astuce: le bloc du switch n'accepte que les valeurs 3, 2 et 1. si taille32=1 (quand longueur=4) le resultat sera 3, ce qui faussera tout. On multiplie taille32 par 2 pour éviter ce cas.

  • signaler à un administrateur
    Commentaire de BruNews le 13/08/2006 21:11:45 administrateur CS

    C'est clair qu'il faut insérer 4 octets par passe.
    Par contre faudra remplacer les multiplications, tu peux obtenir 'groupe' en 3 MOV.

  • signaler à un administrateur
    Commentaire de racpp le 13/08/2006 21:18:44 administrateur CS

    J'ai mis les multiplication juste pour la clarté du code. Normalement, le compilo les remplace par des décalages à gauche. Les 3 MOV c'est mieux?

  • signaler à un administrateur
    Commentaire de BruNews le 13/08/2006 21:36:20 administrateur CS

    décalages + 4 OR

    Faisons que octet est dans AL et on met 'groupe' dans EAX:
    mov ah, al
    mov dx, ax
    shl eax, 16
    mov ax, dx
    J'avais oublié un shl avec les 3 mov.

    Comme d'hab, ne croyons rien et comparons, regarde ton listing asm et on sera certain de ce qui est préférable.

  • signaler à un administrateur
    Commentaire de vecchio56 le 25/08/2006 20:57:21 administrateur CS

    J'ai trouvé un autre moyen de régler ces problèmes de memset: carrément redéfinir memset
    Au début le compilo ne veut pas (il dit fonction intrinsèque, non définissable)
    J'ai trouvé qu'il faut juste mettre un pragma avant:
    #pragma function(memset)
    void* memset(void* buffer, int c, unsigned int num)
    {
      // notre fonction memset
    }

    Ca nous permet de pouvoir écrire des {0} ou ZeroMemory par exemple et de ne pas changer nos habitudes

    Mais cette solution a un gros onconvénient: elle est incompatible avec l'option /GL de compilo (optimisation globale du programme). On est alors obligé de la désactiver, et du coup /LTCG aussi

    Finalement cette solution ne vaut pas le coup, mais je voulais juste vous signaler l'existence de ce pragma

  • signaler à un administrateur
    Commentaire de HeavenForsaker le 26/06/2007 12:14:14

    Bon idem pour moi, le compilo remplace mes fonctions perso par de la CRT, les voici :

    char *asmemset(void *dest, int c, unsigned int count)
    {
    register char *st = (char *)dest;

    while (count-- > 0)
    *st++ = c;

    return (char *)dest;
    }
    //------------------------------------------------------------------------------

    char *asmemcpy(void *dest, const void *src, unsigned int count)
    {
    register char *des = (char *)dest;
    register const char *sr = (const char *)src;

    while (count-- > 0)
    *des++ = *sr++;

    return (char *)dest;
    }
    //------------------------------------------------------------------------------

    int asmemcmp(const void *buf1, const void *buf2, unsigned int count)
    {
    register const char *b1 = (const char *)buf1;
    register const char *b2 = (const char *)buf2;

    while (count-- > 0)
    {
    if (*b1++ != *b2++)
    return b1[-1] < b2[-1] ? -1 : 1;
    }

    return 0;
    }
    //------------------------------------------------------------------------------

    Est ce que par hasard vous auriez un set de fonction que le compilo ne detecte pas comme étant similaire a celle de la CRT ?
    Tu disais BruNews que tes fonction asm n'était pas détectée ? pourrais tu publier tes fonctions ? j'ai juste besoin de ces 3 la , memcpy, memset et memcmp.

  • signaler à un administrateur
    Commentaire de HeavenForsaker le 26/06/2007 13:50:16

    Rectification, seul ma fonction asmemset est détectée et remplacée par memset, les 2 autres sont bonnes.

    Aller BruNews fait péter memset en ASM ! :-)

  • signaler à un administrateur
    Commentaire de BruNews le 26/06/2007 17:21:44 administrateur CS

    trop lent par octet.
    Versions pour buffers alignés ou non. Utiliser les 'AL' quand tu es certain de l'alignement sur 4 de destination (souvent le cas dans code propre).

    void __fastcall bnzeromemAL(void *pmem, DWORD len)
    {
      BYTE *p = (BYTE*) pmem;
      DWORD r = len;
      if(!(len >>= 3)) goto prepm1SET;
    mem8SET:
      *((DWORD*) p) = 0;
      *((DWORD*) (p + 4)) = 0;
      p += 8;
      if(--len) goto mem8SET;
    prepm1SET:
      if(!(r &= 7)) goto zeromemEXIT;
    mem1SET:
      *p++ = 0;
      if(--r) goto mem1SET;
    zeromemEXIT: return;
    }

    void __fastcall bnzeromemUNAL(void *pmem, DWORD len)
    {
      BYTE *p = (BYTE*) pmem;
      DWORD r;
      if(!len) goto zeromemEXIT;
      r = ((DWORD) p) & 3;
      if(!r) goto okALIGN;
      *p++ = 0;
      if(--len == 0) goto zeromemEXIT;
      if(--r == 0) goto okALIGN;
      *p++ = 0;
      if(--len == 0) goto zeromemEXIT;
      if(--r == 0) goto okALIGN;
      *p++ = 0;
      if(--len == 0) goto zeromemEXIT;
    okALIGN:
      r = len;
      if(!(len >>= 3)) goto prepm1SET;
    mem8SET:
      *((DWORD*) p) = 0;
      *((DWORD*) (p + 4)) = 0;
      p += 8;
      if(--len) goto mem8SET;
    prepm1SET:
      if(!(r &= 7)) goto zeromemEXIT;
    mem1SET:
      *p++ = 0;
      if(--r) goto mem1SET;
    zeromemEXIT: return;
    }

    __declspec(naked) void __fastcall bnfillmemAL(void *pmem, BYTE v, DWORD len)
    { // ECX = pmem, EDX = v, [esp+4] = len
      __asm {
        mov     eax, ecx        ; EAX = pmem
        and     edx, 0FFh       ; octet seul
        mov     ecx, [esp+4]    ; ECX = len
        mov     [esp-8], esi
        mov     [esp-4], ebx
        mov     dh, dl
        test    ecx, ecx
        je      short fillEXIT
        mov     esi, ecx
        mov     ebx, edx
        shr     ecx, 3
        je      short prepf1SET
        shl     edx, 16
        mov     dx, bx
    f8SET:
        mov     [eax], edx
        mov     [eax+4], edx
        add     eax, 8
        sub     ecx, 1
        jnz     short f8SET
    prepf1SET:
        and     esi, 7
        je      short fillCLEAN
    f1SET:
        mov     [eax], dl
        add     eax, 1
        sub     esi, 1
        jnz     short f1SET
    fillCLEAN:
        mov     ebx, [esp-4]
        mov     esi, [esp-8]
    fillEXIT:
        ret   4
      }
    }

    __declspec(naked) void __fastcall bnfillmemUNAL(void *pmem, BYTE v, DWORD len)
    { // ECX = pmem, EDX = v, [esp+4] = len
      __asm {
        mov     eax, ecx        ; EAX = pmem
        and     edx, 0FFh       ; octet seul
        mov     ecx, [esp+4]    ; ECX = len
        mov     [esp-8], esi
        mov     [esp-4], ebx
        mov     dh, dl
        test    ecx, ecx
        je      short fillEXIT
        mov     ebx, eax
        and     ebx, 3
        je      short okALIGN
        mov     [eax], dl
        add     eax, 1
        sub     ecx, 1
        jz      short fillCLEAN
        sub     ebx, 1
        jz      short okALIGN
        mov     [eax], dl
        add     eax, 1
        sub     ecx, 1
        jz      short fillCLEAN
        sub     ebx, 1
        jz      short okALIGN
        mov     [eax], dl
        add     eax, 1
        sub     ecx, 1
        jz      short fillCLEAN
    okALIGN:
        mov     esi, ecx
        mov     ebx, edx
        shr     ecx, 3
        je      short prepf1SET
        shl     edx, 16
        mov     dx, bx
    f8SET:
        mov     [eax], edx
        mov     [eax+4], edx
        add     eax, 8
        sub     ecx, 1
        jnz     short f8SET
    prepf1SET:
        and     esi, 7
        je      short fillCLEAN
    f1SET:
        mov     [eax], dl
        add     eax, 1
        sub     esi, 1
        jnz     short f1SET
    fillCLEAN:
        mov     ebx, [esp-4]
        mov     esi, [esp-8]
    fillEXIT:
        ret   4
      }
    }

  • signaler à un administrateur
    Commentaire de BruNews le 26/06/2007 19:39:59 administrateur CS

    Marrant quand un sujet revient sur le devant de la scène...

    Je viens d'ajouter ceci (entre autre) dans mon taf en cours:
    JJ = pcurrArts->dateF - pPLAN[0];
    if(JJ < 0) JJ = 0;
    for(; JJ < NCOLS; JJ++) TPLANAR.jours[JJ] = 0;
    ben il m'a remplacé la boucle par un: call memset
    pénible...

  • signaler à un administrateur
    Commentaire de HeavenForsaker le 26/06/2007 22:45:00

    Cool merci BruNews ! j'ai plus le vilain message CRT :-)

    J'avais un autre message quand j'avais mis "Ignore All Default Libraries" à yes :
    error LNK2001: unresolved external symbol __chkstk

    Pour ceux qui l'ont eu c'est à cause d'un buffer trop gros, j'en avait un a 768 WCHAR je l'ai descendu a 256 et plus de message même avec cette option activée.

  • signaler à un administrateur
    Commentaire de HeavenForsaker le 27/06/2007 16:26:03

    J'ai regardé ta fonction bnzeromemAL de pret la, c'est du bon, par contre quand tu dit "Utiliser les 'AL' quand tu es certain de l'alignement sur 4 de destination" tu veux dire aligner sur 4 octets ? parce que la ça serais plutot 8 puisque tu efface 8 par passe :
      *((DWORD*) p) = 0;
      *((DWORD*) (p + 4)) = 0;

  • signaler à un administrateur
    Commentaire de BruNews le 27/06/2007 17:17:39 administrateur CS

    alignement sur une adresse multiple de 4 puisqu'on adressera par 4 octets.
    C'est visible ici:
    r = ((DWORD) p) & 3;

Ajouter un commentaire