begin process at 2012 02 13 02:28:31
  Trouver un code source :
 
dans
 
Accueil > 

Code

 > 

Astuces

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

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


 Information sur la source

Note :
Aucune note
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é :9 956 / 480

Auteur : vecchio56

Ecrire un message privé
Ce membre participe au partage de revenus publicitaires
Commentaire sur cette source (63)
Ajouter un commentaire et/ou une note


 Description

Cliquez pour voir la capture en taille normale
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.



 Fichier Zip

Les Membres Club peuvent télécharger directement un fichier contenu dans le zip sans télécharger le zip en entier !

Télécharger le zip


 Historique

12 août 2006 12:23:43 :
Appel de FreeResource Appel de RemoveFontMemResourceEx directement après CreateFont Remplacement memset par fonction perso

 Sources du même auteur

Source avec Zip COLORATION DE CODE C/C++ POUR LE FORUM DE CPPFRANCE
Source avec Zip SUPPRIMER LES # AJOUTÉS LORS D'UN COPIER/COLLER
Source avec Zip Source avec une capture CRÉER UN FICHIER ISO À PARTIR D'UN RÉPERTOIRE (WIN32)
Source avec Zip Source avec une capture EXPLORATEUR DE FICHIERS ISO
Source avec Zip Source avec une capture SHELL TREEVIEW (WIN32)

 Sources de la même categorie

Source avec Zip SCHEDULER RR FIFO par yvesB87
Source avec Zip ALGORITHMES RÉCURSIFS VS ALGORITHMES ITÉRATIFS par yvesB87
Source avec Zip Source avec une capture C++ FORMAT D'IMAGE AVEC QT par pop70
Source avec une capture EXEMPLE DE POINTEURS DE FONCTION par pop70
Source avec Zip Source avec une capture [C++] CLASS REGISTER par Miwik

 Sources en rapport avec celle ci

Source avec Zip Source avec une capture VOIR UNE IMAGE GIF C/C++ par nanonavich
Source avec Zip Source avec une capture [C++/WIN32] RECHERCHE DE FUITES DE MEMOIRE par yann_lo_san
Source avec Zip Source avec une capture TELNET EN API WIN32 POUR AUTOMATISATION DES TACHES AVEC MON ... par youpiyoyo
Source avec Zip DIALOGBOXINDIRECT AVEC DES CONTROLES (WIN32) par vecchio56
Source avec Zip ENUMERER FONTS par BruNews

Commentaires et avis

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 ;-)

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 ;)

Commentaire de MuPuF le 03/08/2006 01:30:11

hey hey vecchiodamus ;-)

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 ! ) :)

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

Commentaire de vecchio56 le 03/08/2006 10:35:19 administrateur CS

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

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).

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.

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)

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.

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.

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

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

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...

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.

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().


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.

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?

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

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

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

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

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.

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)

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;
}

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.

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?

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++?

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?

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

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?

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

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.

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...

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.

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.

Commentaire de racpp le 12/08/2006 20:16:04 administrateur CS

Ok merci
Bon appétit

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é...

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.

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

Commentaire de BruNews le 13/08/2006 14:44:24 administrateur CS

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

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.

Commentaire de BruNews le 13/08/2006 14:54:33 administrateur CS

moralité: pas de code après resto.

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!

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.

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?

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?

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.

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é.

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.

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.

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.

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.

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?

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.

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

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.

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 ! :-)

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
  }
}

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...

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.

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;

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


Discussions en rapport avec ce code source dans le forum

font dans mon fichier ressource [ par nipower ] Bonjour je travail avec Dev-c++ et j'ai besoin dans mon projet d'intégrer une police spéciale et non standard.Le problème et que je n'arrive pas à uti police et ListBox [ par JeriKo ] salut à tousça fait 2 heures que j'essaye de changer la police de ma listbox, y a rien à faire ça veut pas :(alors j'ai fait comme çaCListBox *list FOnt & police [ par youpiyoyo ] voila j'utilise caSetBkMode(dc, TRANSPARENT); SetTextColor(dc,clrB); //BeginPath(dc); TextOut(dc,(FreeImage_GetWidth(dibe)/2),FreeImage_GetHeight(dibe CreateFont + SetFont + font asia [ par drexi ] Mon application doit etre compatible pour un affichage sur un PC chinois...Le code créé automatiquement (Bouton Next d'une CPropertySheet est bien aff police en ressource [VC6] [ par leprov ] cest possible de mettre une police en ressource? c'est pitetre con comme question mais j'ai pas trop l'habitude de l'éditeur de ressources, et je sais problème police openGl [ par vodkapomme43 ] Bonjour,J'utilise le code suivant pour cr&#233;er une police avec OPenGL:GLvoid BuildFont(GLvoid)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Bu Messagebox et police VC++(pas de MFC) [ par Frenchy62620 ] Une question concernant la messagebox est ce q'uon peut modifier la font de la messagebox avant son affichage? (juste la font de cet objet)Frenchy Creer une ressource avec Borland builder6 [ par popi0016 ] Bonjours je voudrais associer a mon .exe des images (bmp ou jpeg) et aimerai savoir comment creer une ressource avec toutes mes images (60 environs) s C++! [ par Chaminouonw ] Bonjour je suis débutant en c++ et j'aimerais avoir des ressources pour commencer, étant donné que je ne m'y connais absolument pas dans ce milieu, je Fonction et Tableau [ par toff86 ] Salut !!J'suis débutant en C. Mon probleme est le suivant:Je sais comment fonctionne le passage de parametres d'une variable avec les foncions. Mais j


Nos sponsors


Sondage...

CalendriCode

Février 2012
LMMJVSD
  12345
6789101112
13141516171819
20212223242526
272829    

Consulter la suite du CalendriCode

Photothèque

 
Développement réalisé par Nicolas SOREL (Nix) avec l'aide de : Cyril DURAND et Emmanuel (EBArtSoft), Merci à Vincent pour ses précieux conseils.
CodeS-SourceS.com© Toute reproduction même partielle est interdite sauf accord écrit du Webmaster
CodeS-SourceS.com© est une marque déposée tous droits réservés

Google Coop CodeS-SourceS Google Coop CodeS-SourceS
Temps d'éxécution de la page : 1,934 sec (4)

Nous contacter | Annoncer sur CodeS-SourceS | Mentions légales