Fenetre ne s'affichant pas avec le style WS_EX_LAYERED

Le
Vincent Torri
Je desire me familiariser avec UpdateLayeredWindow et j'ai donc ecrit un
petit programme de test qui cree une fenetre dont le contenu est bleu.

Le programme se trouve ici:

www.maths.univ-evry.fr/pages_perso/vtorri/files/layer.c

Si je n'utilise pas WS_EX_LAYERED, la fenetre s'affiche sans probleme,
avec son contenu bleu

Si j'utilise WS_EX_LAYERED, la fenetre est cree, mais ne s'affiche pas.
Elle est neanmoins notifiee dans la barre des taches.

Ce n'est pas une fenetre fille

Quel est le probleme ?

merci
Vidéos High-Tech et Jeu Vidéo
Téléchargements
Vos réponses Page 1 / 2
Gagnez chaque mois un abonnement Premium avec GNT : Inscrivez-vous !
Trier par : date / pertinence
Christian ASTOR
Le #19248111
Vincent Torri wrote:
Je desire me familiariser avec UpdateLayeredWindow et j'ai donc ecrit un
petit programme de test qui cree une fenetre dont le contenu est bleu.

Le programme se trouve ici:

www.maths.univ-evry.fr/pages_perso/vtorri/files/layer.c

Si je n'utilise pas WS_EX_LAYERED, la fenetre s'affiche sans probleme,
avec son contenu bleu

Si j'utilise WS_EX_LAYERED, la fenetre est cree, mais ne s'affiche pas.
Elle est neanmoins notifiee dans la barre des taches.



WM_PAINT ne doit pas être géré si WS_EX_LAYERED

Par exemple, pour mettre la fenêtre du Wizard Win32 de VS en bleu
"layered", juste après le CreateWindowEx() (donc sans gérer le resizing)
=>

RECT rect;
SIZE size;
HDC hDCScreen = NULL;
HDC hDCLayered = NULL;
BITMAPINFO bmi;
POINT ptSrc;
POINT ptDst;
BLENDFUNCTION Blend;
HBITMAP hBitmapMem = NULL;
HBITMAP hBitmapOld = NULL;
LPVOID pDIBits;
typedef struct _BGRA {
BYTE nBlue;
BYTE nGreen;
BYTE nRed;
BYTE nAlpha;
} BGRA;
BGRA *pPixel = NULL;

GetWindowRect(hWnd, &rect);
size.cx = rect.right - rect.left;
size.cy = rect.bottom - rect.top;

hDCScreen = GetDC(NULL);
hDCLayered = CreateCompatibleDC(hDCScreen);

ZeroMemory(&bmi, sizeof(bmi));
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth = size.cx;
bmi.bmiHeader.biHeight = size.cy;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 32;
bmi.bmiHeader.biCompression = BI_RGB;
hBitmapMem = CreateDIBSection(hDCScreen, &bmi, DIB_RGB_COLORS, &pDIBits,
NULL, 0 );
if (pDIBits == NULL)
{
ReleaseDC(NULL, hDCScreen);
DeleteDC(hDCLayered);
return 1;
}
hBitmapOld = (HBITMAP)SelectObject(hDCLayered, hBitmapMem );
SendMessage(hWnd, WM_PRINT, (WPARAM)hDCLayered, PRF_CLIENT |
PRF_NONCLIENT | PRF_ERASEBKGND );
pPixel = (BGRA *)pDIBits;
BYTE nAlpha = 200;
for (int i = 0; i < size.cy; i++)
{
for (int j = 0; j < size.cx; j++)
{
pPixel->nBlue = 255;
pPixel->nAlpha = nAlpha;
pPixel++;
}
}
ptSrc.x = 0;
ptSrc.y = 0;
ptDst.x = rect.left;
ptDst.y = rect.top;
Blend.BlendOp = AC_SRC_OVER;
Blend.BlendFlags = 0;
Blend.SourceConstantAlpha = 255;
Blend.AlphaFormat = AC_SRC_ALPHA;
UpdateLayeredWindow(hWnd, hDCScreen, NULL, &size, hDCLayered, &ptSrc, 0,
&Blend, ULW_ALPHA);
SelectObject(hDCLayered, hBitmapOld );
DeleteObject(hBitmapMem);
ReleaseDC(NULL, hDCScreen);
DeleteDC(hDCLayered);
Vincent Torri
Le #19248411
Christian ASTOR news:49fc7f9d$0$290$:

Vincent Torri wrote:



Si je n'utilise pas WS_EX_LAYERED, la fenetre s'affiche sans
probleme, avec son contenu bleu

Si j'utilise WS_EX_LAYERED, la fenetre est cree, mais ne s'affiche
pas. Elle est neanmoins notifiee dans la barre des taches.



WM_PAINT ne doit pas être géré si WS_EX_LAYERED



il faut quand meme que je dessine le contenu de ma fenetre, et il me
semble que ca doit etre fait quand WM_PAINT est envoye.

mon but (preseque) final est de faire une petite api ainsi:

1) je dessine le contenu de ma fenetre sans transparence

2) je decide avec une fonction de gerer la tranparence en fonction du
contenu

exemple: j'ai un png avec un fond tranparent, je l'affiche sans gerer la
tranparence. puis si par exemple j'appuie sur la touche 't', je veux que
la fenetre devienne transparente la ou le png est transparent.

Donc j'avais l'idee suivante : je cree un bitmap supplementaire (depth de
32 bits), avec comme couleur soit 0, soit 0x00ffffff, avec 0 la ou le png
n'est pas transparent (donc je fais un boucle sur toutes les couleurs et
je definis la donnee de mon bitmap supplementaire ainsi). Une fois que
c'est fait, je fais un coup de UpdateLayeredWindow()

bon, par contre, pour les details, je ne sais pas s'il faut que j'utilise
0x00ffffff ou une autre valeur, ce qu'il faut que j'utilise pour les
valeur de la fonction de blend, etc...

sinon, concernant ma question initiale, mon probleme venait du fait que
je devais appeler SetLayeredWindowAttributes() ou UpdateLayeredWindow()
pour que la fenetre devienne visible.

Par exemple, pour mettre la fenêtre du Wizard Win32 de VS en bleu
"layered", juste après le CreateWindowEx() (donc sans gérer le
resizing)
=>

RECT rect;
SIZE size;
HDC hDCScreen = NULL;
HDC hDCLayered = NULL;
BITMAPINFO bmi;
POINT ptSrc;
POINT ptDst;
BLENDFUNCTION Blend;
HBITMAP hBitmapMem = NULL;
HBITMAP hBitmapOld = NULL;
LPVOID pDIBits;
typedef struct _BGRA {
BYTE nBlue;
BYTE nGreen;
BYTE nRed;
BYTE nAlpha;
} BGRA;
BGRA *pPixel = NULL;

GetWindowRect(hWnd, &rect);
size.cx = rect.right - rect.left;
size.cy = rect.bottom - rect.top;

hDCScreen = GetDC(NULL);
hDCLayered = CreateCompatibleDC(hDCScreen);

ZeroMemory(&bmi, sizeof(bmi));
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth = size.cx;
bmi.bmiHeader.biHeight = size.cy;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 32;
bmi.bmiHeader.biCompression = BI_RGB;
hBitmapMem = CreateDIBSection(hDCScreen, &bmi, DIB_RGB_COLORS,
&pDIBits, NULL, 0 );
if (pDIBits == NULL)
{
ReleaseDC(NULL, hDCScreen);
DeleteDC(hDCLayered);
return 1;
}
hBitmapOld = (HBITMAP)SelectObject(hDCLayered, hBitmapMem );
SendMessage(hWnd, WM_PRINT, (WPARAM)hDCLayered, PRF_CLIENT |
PRF_NONCLIENT | PRF_ERASEBKGND );
pPixel = (BGRA *)pDIBits;
BYTE nAlpha = 200;
for (int i = 0; i < size.cy; i++)
{
for (int j = 0; j < size.cx; j++)
{
pPixel->nBlue = 255;
pPixel->nAlpha = nAlpha;
pPixel++;
}
}
ptSrc.x = 0;
ptSrc.y = 0;
ptDst.x = rect.left;
ptDst.y = rect.top;
Blend.BlendOp = AC_SRC_OVER;
Blend.BlendFlags = 0;
Blend.SourceConstantAlpha = 255;
Blend.AlphaFormat = AC_SRC_ALPHA;
UpdateLayeredWindow(hWnd, hDCScreen, NULL, &size, hDCLayered, &ptSrc,
0, &Blend, ULW_ALPHA);
SelectObject(hDCLayered, hBitmapOld );
DeleteObject(hBitmapMem);
ReleaseDC(NULL, hDCScreen);
DeleteDC(hDCLayered);



Christian ASTOR
Le #19248921
Vincent Torri wrote:

Christian ASTOR
WM_PAINT ne doit pas être géré si WS_EX_LAYERED



il faut quand meme que je dessine le contenu de ma fenetre, et il me
semble que ca doit etre fait quand WM_PAINT est envoye.



Mais non, pas avec WS_EX_LAYERED
Dans l'exemple, je dessine la fenêtre par défaut en envoyant WM_PRINT
sur le layered DC.
Sylvain SF
Le #19249031
Christian ASTOR a écrit :

WM_PAINT ne doit pas être géré si WS_EX_LAYERED



il faut quand meme que je dessine le contenu de ma fenetre, et il me
semble que ca doit etre fait quand WM_PAINT est envoye.



Mais non, pas avec WS_EX_LAYERED
Dans l'exemple, je dessine la fenêtre par défaut en envoyant WM_PRINT
sur le layered DC.



ou pas, Christian ...

on peux très bien traiter WM_PAINT de la manière la plus classique
(avec des StretchBlt, des FillRect et autres LineTo ou Rectangle) et
laisser le système appliquer le masque de couleur ou la transparence.

une fenêtre sans contenu subclassé se contentera en effet d'un
traitement automatique par les routines standards, mais si le contenu
est "dessiné à la main" il est pertinent de répondre à WM_PAINT.

@ Vincent, le résultat serait normalement identique si layer_paint
remplissait tout en rouge et dessinait un rectangle rempli bleu dans
le coin.

Sylvain.
Christian ASTOR
Le #19249081
Sylvain SF wrote:

Christian ASTOR a écrit :
Mais non, pas avec WS_EX_LAYERED
Dans l'exemple, je dessine la fenêtre par défaut en envoyant WM_PRINT
sur le layered DC.




ou pas, Christian ...

on peux très bien traiter WM_PAINT de la manière la plus classique
(avec des StretchBlt, des FillRect et autres LineTo ou Rectangle) et
laisser le système appliquer le masque de couleur ou la transparence.



Oui, mais avec le style WS_EX_LAYERED et UpdateLayeredWindow(), WM_PAINT
n'est plus du tout reçu. (du moins sous XP...)
Vincent Torri
Le #19249301
Sylvain SF $:

Christian ASTOR a écrit :

WM_PAINT ne doit pas être géré si WS_EX_LAYERED



il faut quand meme que je dessine le contenu de ma fenetre, et il me
semble que ca doit etre fait quand WM_PAINT est envoye.



Mais non, pas avec WS_EX_LAYERED
Dans l'exemple, je dessine la fenêtre par défaut en envoyant WM_PRINT
sur le layered DC.



ou pas, Christian ...

on peux très bien traiter WM_PAINT de la manière la plus classique
(avec des StretchBlt, des FillRect et autres LineTo ou Rectangle) et
laisser le système appliquer le masque de couleur ou la transparence.

une fenêtre sans contenu subclassé se contentera en effet d'un
traitement automatique par les routines standards, mais si le contenu
est "dessiné à la main" il est pertinent de répondre à WM_PAINT.



et bien, je l'ai fait et ca a l'air de marcher (en utilisant
SetLayeredWindowAttributes() et mon programme de test)

@ Vincent, le résultat serait normalement identique si layer_paint
remplissait tout en rouge et dessinait un rectangle rempli bleu dans
le coin.



Donc, comme je le disais, j'aimerais maintenant faire en sorte que, si
j'ai une fenetre non layered qui a un certain contenu avec une partie qui
a de la transparence, si j'appuie sur la touche 't', cette partie
deviennent transparent.

Donc voici le code:

http://www.maths.univ-evry.fr/pages_perso/vtorri/files/layer.c

ce que ca fait :

1) la fenetre est creee
2) le bitmap qui gere le contenu (layer_bitmap) est cree
3) le bitmap qui est cense gerer la transparence (mask_bitmap) est cree
et sa donnee est initialisee a 0
4) je montre la fenetre
5) WM_PAINT est appele et le contenu est rempli par la fonction
layer_paint()
6) si j'appuis sur 't', layer_window_layered_set() est appelee
7) dans cette fonction, la fenetre devient "layered" et je remplis
mask_bitmap avec le pixel ayant la couleur 0x00ffffff si le pixel
correspondant de layer_bitmap a une composante alpha.

et c'est la que ca ne marche plus si j'utilise UpdateLayeredWindow().
Quand la fonction layer_window_layered_set() est appelee, la fenetre
disparait purememnt et simplement

Donc, evidemment, je dois mal utiliser l'API, mais, franchement, celle-ci
reste tres obscure pour moi... J'ai essaye de faire la meme chose que
certains codes que j'ai trouve sur le net, mais sans succes.

Vincent
Sylvain SF
Le #19250091
Vincent Torri a écrit :

Donc, comme je le disais, j'aimerais maintenant faire en sorte que, si
j'ai une fenetre non layered qui a un certain contenu avec une partie qui
a de la transparence, si j'appuie sur la touche 't', cette partie
deviennent transparent.

Donc voici le code:

http://www.maths.univ-evry.fr/pages_perso/vtorri/files/layer.c
[...]

et c'est la que ca ne marche plus si j'utilise UpdateLayeredWindow().
Quand la fonction layer_window_layered_set() est appelee, la fenetre
disparait purememnt et simplement



si tu fais simplement:

void layer_window_layered_set(int on)
{
DWORD style = GetWindowLong(layer_window, GWL_EXSTYLE);
if (on)
style |= WS_EX_LAYERED;
else
style &= ~WS_EX_LAYERED;
SetWindowLongPtr(layer_window, GWL_EXSTYLE, style);
if (on)
SetLayeredWindowAttributes(layer_window, RGB(255, 0, 0), 0,
ULW_COLORKEY);
}

cela fonctionne comme voulu.

je ne vois pas bien l'intérêt de UpdateLayeredWindow ici.
le code marche en bascule, il applique un layer transparent ou
non, SetLayeredWindowAttributes me semble être l'API pour cela.

concernant UpdateLayeredWindow, le point de Christian me fait comprendre
qu'elle fait le transfert entre HDC source et fenêtre et donc bypass
tout le process WM_PAINT, toutefois son usage m'échappe un peu, cela
voudrait ressembler à un BitBlt mais ne semble pas réagir pareil.
il y a sûrement quelque chose d'invalide dans les HDC utilisés dans
le code montré, ainsi que dans sa séquence - les coordonnées dans
'client' par exemple sont négative du fait de l'appel précédent à
SetWindowLongPtr(w, GWL_EXSTYLE, WS_EX_LAYERED).

Sylvain.
Vincent Torri
Le #19250181
Sylvain SF news:49fcc10b$0$12628$:

Vincent Torri a écrit :

Donc, comme je le disais, j'aimerais maintenant faire en sorte que,
si j'ai une fenetre non layered qui a un certain contenu avec une
partie qui a de la transparence, si j'appuie sur la touche 't', cette
partie deviennent transparent.

Donc voici le code:

http://www.maths.univ-evry.fr/pages_perso/vtorri/files/layer.c
[...]

et c'est la que ca ne marche plus si j'utilise UpdateLayeredWindow().
Quand la fonction layer_window_layered_set() est appelee, la fenetre
disparait purememnt et simplement



si tu fais simplement:

void layer_window_layered_set(int on)
{
DWORD style = GetWindowLong(layer_window, GWL_EXSTYLE);
if (on)
style |= WS_EX_LAYERED;
else
style &= ~WS_EX_LAYERED;
SetWindowLongPtr(layer_window, GWL_EXSTYLE, style);
if (on)
SetLayeredWindowAttributes(layer_window, RGB(255, 0, 0), 0,
ULW_COLORKEY);
}

cela fonctionne comme voulu.

je ne vois pas bien l'intérêt de UpdateLayeredWindow ici.
le code marche en bascule, il applique un layer transparent ou
non, SetLayeredWindowAttributes me semble être l'API pour cela.



evidemment, je n'ai pas ete assez precis :) Certe avec le contenu de la
fenetre du test (avec 2 couleurs, rouge et bleu), ca marche (j'avais deja
le code, qui est commente, d'ailleurs), mais je compte utiliser cette
methode dans une bibliotheque generique (plus precisement un canevas tres
optimise qui fonctionne sous linux et que je porte a Windows). Donc je ne
peux pas faire de suppositions sur le contenu de la fenetre. D'ou la
boucle et le test sur la composante alpha. Ce petit programme est pour
moi un prelude a l'integration de la gestion des fenetres non
rectangulaire est translucides dans cette bibliotheque, un programme de
test, donc. Donc je pense que je dois vraiment utiliser
UpdateLayeredWindow().

concernant UpdateLayeredWindow, le point de Christian me fait
comprendre qu'elle fait le transfert entre HDC source et fenêtre et
donc bypass tout le process WM_PAINT, toutefois son usage m'échappe un
peu, cela voudrait ressembler à un BitBlt mais ne semble pas réagir
pareil. il y a sûrement quelque chose d'invalide dans les HDC utilisés
dans le code montré, ainsi que dans sa séquence - les coordonnées dans
'client' par exemple sont négative du fait de l'appel précédent à
SetWindowLongPtr(w, GWL_EXSTYLE, WS_EX_LAYERED).



les HDC ont toujours ete pour moi un mystere. Bon, je regarderai les
valeurs de chacune des variables. Pour les HDC, ca va etre plus dur, car
je ne comprends pas trop comments ils agissent avec tous ces SelectObject
et autres fonctions. Je suis un codeur linux qui s'est improvise
mainteneur du port Windows de certaines bibliotheques...

par contre, si WM_PAINT n'est plus appele, ca veut dire que il n'est plus
possible de faire de l'animation dans la fenetre (vu que son contenu est
mis a jour dans la gestion de ce message). C'est plutot ennuyant.

Vincent
Sylvain SF
Le #19250371
Vincent Torri a écrit :



evidemment, je n'ai pas ete assez precis :) Certe avec le contenu de la
fenetre du test (avec 2 couleurs, rouge et bleu), ca marche (j'avais deja
le code, qui est commente, d'ailleurs), mais je compte utiliser cette
methode dans une bibliotheque generique (plus precisement un canevas tres
optimise qui fonctionne sous linux et que je porte a Windows). Donc je ne
peux pas faire de suppositions sur le contenu de la fenetre.



poser une couleur comme étant la transparence et jouer dessus
(avec SetLayeredWindowAttributes) ne me semble pas si contraignant.

soit, il peux être plus sympathique de jouer sur une transparence
per-pixel, le pb commence avec le fait que tu n'initialises nulle
part une transparence (le layer_bitmap en contient aucune).

les HDC ont toujours ete pour moi un mystere. Bon, je regarderai les
valeurs de chacune des variables. Pour les HDC, ca va etre plus dur, car
je ne comprends pas trop comments ils agissent avec tous ces SelectObject
et autres fonctions. Je suis un codeur linux qui s'est improvise
mainteneur du port Windows de certaines bibliotheques...



ta dernière compile était en C++ (une variable définie au milieu du
code), le reste étant en C, j'ai gardé cette règle et je le lis très
mal, je n'affirme pas que les DC sont faux mais cela m'a semblé bizarre.

j'ai un code qui tombe en marche avec UpdateLayeredWindow(...,ULW_ALPHA)
mais pas avec ULW_COLORKEY, je regarderais (p.e.) demain.

par contre, si WM_PAINT n'est plus appele, ca veut dire que il n'est plus
possible de faire de l'animation dans la fenetre (vu que son contenu est
mis a jour dans la gestion de ce message). C'est plutot ennuyant.



non c'est pas strictement cela, le déplacement et la modification du
canal alpha est géré par le système qui cache toute la fenêtre, ainsi
WM_PAINT n'est pas envoyé à ton code pour un move, un recouvrement,
ou encore une modif. de l'alpha.
par contre ton code peux bien sur invalider des zones et il les
redessinera dans un WM_PAINT ou via la procédure standard de
composants tels des static text.

Sylvain.
Vincent Torri
Le #19250481
Sylvain SF news:49fccc63$0$17784$:

poser une couleur comme étant la transparence et jouer dessus
(avec SetLayeredWindowAttributes) ne me semble pas si contraignant.

soit, il peux être plus sympathique de jouer sur une transparence
per-pixel,



en fait, je n'ai pas le choix, car c'est comme ca que ca fonctionne sous
linux. Le masque est defini par l'ensemble des pixels ayant une
transparence.

le pb commence avec le fait que tu n'initialises nulle
part une transparence (le layer_bitmap en contient aucune).



si, ligne 254:

*tmp = 0xffff0000;

la partie rouge a aussi une composante alpha. Tu cherchais une couleur du
style 0xff000000 ? En fait non, et c'est pour ca que je teste la
composante alpha avec if ((*tmp_window & 0xff000000) == 0xff000000) et
non if (*tmp_window == 0xff000000)

les HDC ont toujours ete pour moi un mystere. Bon, je regarderai les
valeurs de chacune des variables. Pour les HDC, ca va etre plus dur,
car je ne comprends pas trop comments ils agissent avec tous ces
SelectObject et autres fonctions. Je suis un codeur linux qui s'est
improvise mainteneur du port Windows de certaines bibliotheques...



ta dernière compile était en C++ (une variable définie au milieu du
code), le reste étant en C, j'ai gardé cette règle et je le lis très
mal, je n'affirme pas que les DC sont faux mais cela m'a semblé
bizarre.



ha, ok, c'etait un test rapide, et c'est le seul endroit ou je l'ai fait.
Et en effet, je code en C. Petit oubli de ma part.

j'ai un code qui tombe en marche avec
UpdateLayeredWindow(...,ULW_ALPHA) mais pas avec ULW_COLORKEY, je
regarderais (p.e.) demain.



Oui, pour le alpha, il n'y a pas de probleme, j'ai reussi a le faire,
mais pas avec une couleur. Merci beaucoup pour le temps passe.

par contre, si WM_PAINT n'est plus appele, ca veut dire que il n'est
plus possible de faire de l'animation dans la fenetre (vu que son
contenu est mis a jour dans la gestion de ce message). C'est plutot
ennuyant.



non c'est pas strictement cela, le déplacement et la modification du
canal alpha est géré par le système qui cache toute la fenêtre, ainsi
WM_PAINT n'est pas envoyé à ton code pour un move, un recouvrement,
ou encore une modif. de l'alpha.
par contre ton code peux bien sur invalider des zones et il les
redessinera dans un WM_PAINT ou via la procédure standard de
composants tels des static text.



ok, ca me rassure !
Publicité
Poster une réponse
Anonyme