Click here to Skip to main content
Rate this: bad
good
Please Sign up or sign in to vote.
See more: VC8.0 C++ Windows
Hi guys,
 
I've been reading articles in this site for a while, but couldn't find what I need. Basically I want to create a non-rectangular window with a shadow along its edges (not the drop shadow, but a thick shadow all around the non-rectangular shape) using Win32 API. The shadow has to be click throughable.
 
I used windows region and a bitmap before to draw the non-rectangular shape, but that didn't give me a shadow and, according to some articles, it is not efficient. I have been digesting the layered window stuff, but can't quite understand how to use it.
 
Can someone point me to an article that deals with this? Or kindly show me some code snippet on how this is done? (I am using VC2008 and pure Win32 API)
 
Thanks!
 
me4dt
Posted 1-Apr-11 13:23pm
me4dt139
Rate this: bad
good
Please Sign up or sign in to vote.

Solution 2

A little example i use to create iconic windows from PNGs. Layered windows will not work with windows 95,98,Me. Layered windows with alpha channel (RGBA) need not a window region.
Example (the bitmap must be 32bit RGBA):
unsigned char    __alphatable[256][256] = { 42, };
 
static void __alphatable_init()
{
  unsigned int  x,y;
  if(42==__alphatable[0][0])
  {
    for(x=0;x<256;x++)
      for(y=0;y<256;y++)
        __alphatable[x][y] = min(255,x*y/255);
  }
}
 
static unsigned char __alphatable_value(unsigned char src,unsigned char dst,unsigned char alpha)
{
  unsigned short p = __alphatable[alpha][src] + __alphatable[255-alpha][dst];
  return min(p,255);
}
 

HBITMAP __CreateAlphaBitmap(BITMAPINFO* pbmi,const unsigned char* lpbits,const unsigned int cbbits)
{
  HDC              mdc;
  HBITMAP          hbmp;
  unsigned char*  lpc;
  int              x,y;
 
  mdc = CreateCompatibleDC(0);
  hbmp = CreateDIBSection(mdc,pbmi,DIB_RGB_COLORS,(void**)&lpc,0,0);
  if(lpc)
  {
    __alphatable_init();
    for(y=0;y<pbmi->bmiHeader.biHeight;y++)
    {
      for(x=0;x<pbmi->bmiHeader.biWidth;x++)
      {
        lpc[0] = __alphatable_value(lpbits[0],0,lpbits[3]);
        lpc[1] = __alphatable_value(lpbits[1],0,lpbits[3]);
        lpc[2] = __alphatable_value(lpbits[2],0,lpbits[3]);
        lpc[3] = lpbits[3];
        lpc += 4; lpbits += 4;
      }
    }
  }
  DeleteDC(mdc);
  
  return hbmp;
}
 
void iWndWidget::SetFace(IBitmap* pBmp,HWND hwnd)
{
  if(!hwnd) return;
  
  unsigned long    exstyle = GetWindowLong(hwnd,GWL_EXSTYLE);
  BITMAPINFO*      pbmp;
  unsigned char*  lp;
  unsigned int    cb;
 
  if(pBmp && (S_OK==pBmp->GetBitmapDirect(&pbmp,&lp,&cb)) && (32==pbmp->bmiHeader.biBitCount))
  {
    RECT&            rcw = GetWndPos();
    BLENDFUNCTION    blend = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
    HDC              mdc;
    HDC              hdc = 0;
    SIZE            size = { pbmp->bmiHeader.biWidth, pbmp->bmiHeader.biHeight };
    POINT            pdst = { rcw.left,rcw.top };
    POINT            psrc = { 0,0 };
    HGDIOBJ          obmp;
    HBITMAP          hbmp;
 
    SetWindowLong(hwnd,GWL_EXSTYLE,exstyle|WS_EX_LAYERED);
 
    hbmp = __CreateAlphaBitmap(pbmp,lp,cb);
    mdc = CreateCompatibleDC(hdc);
    obmp = SelectObject(mdc,hbmp);
    UpdateLayeredWindow(hwnd,hdc,&pdst,&size,mdc,&psrc,(COLORREF)0,&blend,ULW_ALPHA);
 
    SelectObject(mdc,obmp);
    DeleteDC(mdc);
    DeleteObject(hbmp);
 
    SetWindowPos(hwnd,0,pdst.x,pdst.y,size.cx,size.cy,
      SWP_NOZORDER|SWP_FRAMECHANGED|SWP_NOSENDCHANGING|SWP_NOACTIVATE);
  }
  else
  {
    SetWindowLong(hwnd,GWL_EXSTYLE,exstyle&~WS_EX_LAYERED);
    SetWindowPos(hwnd,0,0,0,0,0,
      SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_FRAMECHANGED|SWP_NOSENDCHANGING|SWP_NOACTIVATE);
  }
  
 
}
Regards.
  Permalink  
v2
Comments
SAKryukov at 1-Apr-11 22:55pm
   
There is a little problem with this. Is you click on fully transparent region of such window inside window bounds, it will not activate underlying window but will be processed by a window of this application; in other words, it will look as non-rectangular, but when you touch it with mouse, it well behave like rectangular, am I right?
--SA
mbue at 2-Apr-11 5:43am
   
Layered windows working like windows with region. The part of the window that is fully transparant is not processed by any window message (paint, mouse events and so on). If you make the whole window alpha plane full transparent this works like ShowWindow(SW_HIDE) - you only can kill the app to quit.
SAKryukov at 2-Apr-11 16:34pm
   
Very interesting. I want to play a bit with this techniques to understand it better. Thank you very much for this sample. Event is there any problems, it certainly deserves my 5.
--SA
mbue at 3-Apr-11 5:08am
   
see my last comment. regards.
me4dt at 2-Apr-11 18:27pm
   
Thanks mbue for your kind reply. I'll try your code and see what it can accomplish. Seems you did not use the TRANSPARENT bit, so areas with alpha value zero will be transparent. Am I correct?
 
Can you explain your code a little more so I may have a better understanding? Cause I thought when alpha value is zero, the pixel is invisible. Then how the shadow is shown? Also, I thought TRANSPARENT bit does not mean the pixel is really transparent (invisible), it only means to ignore messages. Correct me if I am wrong. I am really fuzzy on this.
 
Best regards.
 
me4dt
mbue at 3-Apr-11 5:08am
   
There are some important values i have set to constants:
 

lpc[0] = __alphatable_value(lpbits[0],0/*color of the back plane*/,lpbits[3]);
lpc[1] = __alphatable_value(lpbits[1],0/*color of the back plane*/,lpbits[3]);
lpc[2] = __alphatable_value(lpbits[2],0/*color of the back plane*/,lpbits[3]);

 
color of the back plane is in this example RGB(0,0,0).
you can combine any other bitmap with your originally bitmap.
black and your alpha==0 is fully transparent. every back color is click transparent but visible.
 
the other constant is:
 

BLENDFUNCTION blend = { AC_SRC_OVER, 0, 255/*blend alpha*/, AC_SRC_ALPHA };

 
blend alpha value tells the system how to merge the window surface with the existing (windows) background.
0==fully transparent 255==only the bitmap transparency. the surface is only click transparent on the fully transparent plane.
ive spent a lot of time to understand whats windows doing with all the combining values. its not easy to check out what kind of combination you need to get the right effect.
 
if you want to get a click transparent shadow you have to create a blurred grayscale bitmap and combine it with the original (color of the back plane, see above).
 
Good luck, regards.
SAKryukov at 13-Apr-11 9:24am
   
Could you please take a look at this question:
http://www.codeproject.com/Questions/181196/Windos-Form-Opacity-control-without-change-the-opa.aspx
 
I guess this technique can help with OP problem...
--SA
mbue at 13-Apr-11 10:39am
   
As far as i know the transparency of the window affects all the children. You cannot make a window transparent for about 50% and the children for 80%. That wont work - the is no support from any windows function. If you want to do so, you have to paint all the controls by yourself into a bitmap and set it to the layered window. There never comes a paint message. To invalidate any part of your window means to repaint all into the bitmap again and set it to the layered window (see my statment above).
 
Summary:
1) you can make a windows transparent with all children with the same alpha.
2) you can make a window transparent with different alpha values - you have to paint all content of it by yourself into a bitmap with alpha-plane.
3) if you want a alpha transparent window that is click transparent region you have to create an underlying window with alpha-plane that is ws_ex_transparent.
4) there is no way to make windows controls as child of another window transparent with another alpha value than the parent.
 
Regards.
SAKryukov at 13-Apr-11 11:00am
   
Thank you very much. I knew what you said in two first sentences. I was asking what bitmaps can do with layered window. You clarified it all.
--SA
Rate this: bad
good
Please Sign up or sign in to vote.

Solution 1

It looks like it is impossible.
The real problem is that the window region should be a sharp, not fuzzy subset of the windows rectangular area. This is the limitation of the area. The shadow is by definition is a part of the other window, not part of the windows of your application. When you click at the shadow, you supposed to activate the window underneath. But you cannot affect other windows (unless you're injecting some code into them... well, does not look realistic.
 
Well, suppose you can sacrifice this part of functionality — you agree to make the shadow actually a part of your windows at the edges. But in this case you need to show different picture at the shadow area, depending on the colors on the windows underneath. It means that you need modulation of transparency of the window: semi-transparent at the edge and not-transparent in the main area. To best of my knowledge, this effect it not available in the Windows API. Only uniform transparency factor is available (and rendering is somewhat problematic, it's recommended to avoid windows transparency).
 
So far, I was talking about Windows API before Windows 7 (XP and older). For this system, you can adjust color and transparency of the borders — see http://www.microsoft.com/enable/training/windowsvista/borders.aspx[^]. This might allow for some effects resembling shadow cast on underlying windows. The problem is: I never heard the border can be of custom shape. Perhaps I'm not well familiar with Windows 7 specific API.
 
It looks like we're close but not there yet. You can do any thinkable semi-transparent trick inside a window (using alpha channel of colors and brushes used for rendering), but at to the window it self— Anyway, I will be amazed if somebody points out solution. I think it does not exist.
 
—SA
  Permalink  
Comments
me4dt at 2-Apr-11 18:09pm
   
At first I thought the transparent bit and alpha feature of layered window could help me on creating a click-through shadow. Then I couldn't figure out a way to do this. I was wondering if there is a trick to get it done. Oh well ...

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

  Print Answers RSS
0 OriginalGriff 587
1 Sergey Alexandrovich Kryukov 479
2 Maciej Los 305
3 Mathew Soji 195
4 BillWoodruff 170
0 OriginalGriff 7,356
1 Sergey Alexandrovich Kryukov 6,777
2 DamithSL 5,461
3 Manas Bhardwaj 4,916
4 Maciej Los 4,475


Advertise | Privacy | Mobile
Web02 | 2.8.1411023.1 | Last Updated 5 Apr 2011
Copyright © CodeProject, 1999-2014
All Rights Reserved. Terms of Service
Layout: fixed | fluid

CodeProject, 503-250 Ferrand Drive Toronto Ontario, M3C 3G8 Canada +1 416-849-8900 x 100