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

MuPuF Messages postés 536 Date d'inscription mercredi 27 avril 2005 Statut Membre Dernière intervention 22 août 2008 - 3 août 2006 à 01:25
BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019 - 27 juin 2007 à 17:17
Cette discussion concerne un article du site. Pour la consulter dans son contexte d'origine, cliquez sur le lien ci-dessous.

https://codes-sources.commentcamarche.net/source/38897-charger-une-police-depuis-un-fichier-ou-une-ressource-win32

BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
27 juin 2007 à 17:17
alignement sur une adresse multiple de 4 puisqu'on adressera par 4 octets.
C'est visible ici:
r = ((DWORD) p) & 3;
HeavenForsaker Messages postés 223 Date d'inscription mercredi 13 juillet 2005 Statut Membre Dernière intervention 8 août 2011
27 juin 2007 à 16:26
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;
HeavenForsaker Messages postés 223 Date d'inscription mercredi 13 juillet 2005 Statut Membre Dernière intervention 8 août 2011
26 juin 2007 à 22:45
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.
BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
26 juin 2007 à 19:39
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...
BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
26 juin 2007 à 17:21
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
}
}
HeavenForsaker Messages postés 223 Date d'inscription mercredi 13 juillet 2005 Statut Membre Dernière intervention 8 août 2011
26 juin 2007 à 13:50
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 ! :-)
HeavenForsaker Messages postés 223 Date d'inscription mercredi 13 juillet 2005 Statut Membre Dernière intervention 8 août 2011
26 juin 2007 à 12: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.
vecchio56 Messages postés 6535 Date d'inscription lundi 16 décembre 2002 Statut Membre Dernière intervention 22 août 2010 14
25 août 2006 à 20:57
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
BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
13 août 2006 à 21:36
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.
racpp Messages postés 1909 Date d'inscription vendredi 18 juin 2004 Statut Modérateur Dernière intervention 14 novembre 2014 17
13 août 2006 à 21:18
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?
BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
13 août 2006 à 21:11
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.
racpp Messages postés 1909 Date d'inscription vendredi 18 juin 2004 Statut Modérateur Dernière intervention 14 novembre 2014 17
13 août 2006 à 20:49
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.
racpp Messages postés 1909 Date d'inscription vendredi 18 juin 2004 Statut Modérateur Dernière intervention 14 novembre 2014 17
13 août 2006 à 20:39
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.
racpp Messages postés 1909 Date d'inscription vendredi 18 juin 2004 Statut Modérateur Dernière intervention 14 novembre 2014 17
13 août 2006 à 20:33
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.
BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
13 août 2006 à 20:00
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é.
BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
13 août 2006 à 19:55
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.
vecchio56 Messages postés 6535 Date d'inscription lundi 16 décembre 2002 Statut Membre Dernière intervention 22 août 2010 14
13 août 2006 à 19:52
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?
vecchio56 Messages postés 6535 Date d'inscription lundi 16 décembre 2002 Statut Membre Dernière intervention 22 août 2010 14
13 août 2006 à 19:40
C'est incroyable ca! Il arrive a 'voir' que ma fonction fait la même chose que memset?
BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
13 août 2006 à 19:03
ç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.
vecchio56 Messages postés 6535 Date d'inscription lundi 16 décembre 2002 Statut Membre Dernière intervention 22 août 2010 14
13 août 2006 à 18:53
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!
BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
13 août 2006 à 14:54
moralité: pas de code après resto.
vecchio56 Messages postés 6535 Date d'inscription lundi 16 décembre 2002 Statut Membre Dernière intervention 22 août 2010 14
13 août 2006 à 14:48
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.
BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
13 août 2006 à 14:44
oups, c'est: if(--len) goto mem8SET;
vecchio56 Messages postés 6535 Date d'inscription lundi 16 décembre 2002 Statut Membre Dernière intervention 22 août 2010 14
13 août 2006 à 14:36
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
BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
13 août 2006 à 00:40
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.
BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
13 août 2006 à 00:32
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é...
racpp Messages postés 1909 Date d'inscription vendredi 18 juin 2004 Statut Modérateur Dernière intervention 14 novembre 2014 17
12 août 2006 à 20:16
Ok merci
Bon appétit
BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
12 août 2006 à 20:10
OK je vais regarder (après le resto), vecchio me l'a transmis.
racpp Messages postés 1909 Date d'inscription vendredi 18 juin 2004 Statut Modérateur Dernière intervention 14 novembre 2014 17
12 août 2006 à 20:07
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.
BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
12 août 2006 à 19:43
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...
racpp Messages postés 1909 Date d'inscription vendredi 18 juin 2004 Statut Modérateur Dernière intervention 14 novembre 2014 17
12 août 2006 à 18:43
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.
vecchio56 Messages postés 6535 Date d'inscription lundi 16 décembre 2002 Statut Membre Dernière intervention 22 août 2010 14
12 août 2006 à 18:02
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
racpp Messages postés 1909 Date d'inscription vendredi 18 juin 2004 Statut Modérateur Dernière intervention 14 novembre 2014 17
12 août 2006 à 17:59
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?
vecchio56 Messages postés 6535 Date d'inscription lundi 16 décembre 2002 Statut Membre Dernière intervention 22 août 2010 14
12 août 2006 à 17:36
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
racpp Messages postés 1909 Date d'inscription vendredi 18 juin 2004 Statut Modérateur Dernière intervention 14 novembre 2014 17
12 août 2006 à 17:31
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?
vecchio56 Messages postés 6535 Date d'inscription lundi 16 décembre 2002 Statut Membre Dernière intervention 22 août 2010 14
12 août 2006 à 17:27
Je n'ai aucune erreur avec ton exemple. Il est pour VC++ ou Dev-C++?
racpp Messages postés 1909 Date d'inscription vendredi 18 juin 2004 Statut Modérateur Dernière intervention 14 novembre 2014 17
12 août 2006 à 17:23
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?
racpp Messages postés 1909 Date d'inscription vendredi 18 juin 2004 Statut Modérateur Dernière intervention 14 novembre 2014 17
12 août 2006 à 17:06
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.
racpp Messages postés 1909 Date d'inscription vendredi 18 juin 2004 Statut Modérateur Dernière intervention 14 novembre 2014 17
12 août 2006 à 17:01
#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;
}
vecchio56 Messages postés 6535 Date d'inscription lundi 16 décembre 2002 Statut Membre Dernière intervention 22 août 2010 14
12 août 2006 à 16:55
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)
racpp Messages postés 1909 Date d'inscription vendredi 18 juin 2004 Statut Modérateur Dernière intervention 14 novembre 2014 17
12 août 2006 à 16:47
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.
vecchio56 Messages postés 6535 Date d'inscription lundi 16 décembre 2002 Statut Membre Dernière intervention 22 août 2010 14
12 août 2006 à 12:12
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
vecchio56 Messages postés 6535 Date d'inscription lundi 16 décembre 2002 Statut Membre Dernière intervention 22 août 2010 14
12 août 2006 à 12:02
A partir de 44 octets memset n'est plus inlinée en fait
vecchio56 Messages postés 6535 Date d'inscription lundi 16 décembre 2002 Statut Membre Dernière intervention 22 août 2010 14
12 août 2006 à 11:57
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
vecchio56 Messages postés 6535 Date d'inscription lundi 16 décembre 2002 Statut Membre Dernière intervention 22 août 2010 14
12 août 2006 à 11:41
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
vecchio56 Messages postés 6535 Date d'inscription lundi 16 décembre 2002 Statut Membre Dernière intervention 22 août 2010 14
12 août 2006 à 11:29
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?
racpp Messages postés 1909 Date d'inscription vendredi 18 juin 2004 Statut Modérateur Dernière intervention 14 novembre 2014 17
12 août 2006 à 00:51
Je viens de remarquer qu'on ne peut pas déscendre sous les 100ko car la ressource seule fait 97ko.
racpp Messages postés 1909 Date d'inscription vendredi 18 juin 2004 Statut Modérateur Dernière intervention 14 novembre 2014 17
12 août 2006 à 00:36
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().
racpp Messages postés 1909 Date d'inscription vendredi 18 juin 2004 Statut Modérateur Dernière intervention 14 novembre 2014 17
11 août 2006 à 23:49
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.
BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
11 août 2006 à 23:21
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...
vecchio56 Messages postés 6535 Date d'inscription lundi 16 décembre 2002 Statut Membre Dernière intervention 22 août 2010 14
11 août 2006 à 23:17
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
vecchio56 Messages postés 6535 Date d'inscription lundi 16 décembre 2002 Statut Membre Dernière intervention 22 août 2010 14
11 août 2006 à 23:16
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
BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
11 août 2006 à 23:15
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.
racpp Messages postés 1909 Date d'inscription vendredi 18 juin 2004 Statut Modérateur Dernière intervention 14 novembre 2014 17
11 août 2006 à 23:03
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.
vecchio56 Messages postés 6535 Date d'inscription lundi 16 décembre 2002 Statut Membre Dernière intervention 22 août 2010 14
11 août 2006 à 22:34
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)
racpp Messages postés 1909 Date d'inscription vendredi 18 juin 2004 Statut Modérateur Dernière intervention 14 novembre 2014 17
11 août 2006 à 22:25
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.
deck_bsd Messages postés 1243 Date d'inscription jeudi 31 mars 2005 Statut Membre Dernière intervention 3 août 2016 2
4 août 2006 à 17:02
sir vecchio est en grande forme ces temps si :D Bonne source :D (vivi je peut utiliser les ressources now mdr).
vecchio56 Messages postés 6535 Date d'inscription lundi 16 décembre 2002 Statut Membre Dernière intervention 22 août 2010 14
3 août 2006 à 10:35
Parce que le #pragma n'est pas compris par gcc
mogwai93 Messages postés 362 Date d'inscription mardi 31 décembre 2002 Statut Membre Dernière intervention 4 novembre 2023
3 août 2006 à 08:29
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
MorbhAck Messages postés 127 Date d'inscription jeudi 16 juin 2005 Statut Membre Dernière intervention 5 août 2007
3 août 2006 à 03:00
Sa marche a merveille ! MERCI encore une fois ( a putin ce que chui leche cul ! ) :)
MuPuF Messages postés 536 Date d'inscription mercredi 27 avril 2005 Statut Membre Dernière intervention 22 août 2008
3 août 2006 à 01:30
hey hey vecchiodamus ;-)
vecchio56 Messages postés 6535 Date d'inscription lundi 16 décembre 2002 Statut Membre Dernière intervention 22 août 2010 14
3 août 2006 à 01:27
Je savais que t'en avais besoin sinon je l'aurais jamais faite ;)
MuPuF Messages postés 536 Date d'inscription mercredi 27 avril 2005 Statut Membre Dernière intervention 22 août 2008
3 août 2006 à 01:25
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 ;-)
Rejoignez-nous