Jump to content

Getting started with a desktop app


Recommended Posts


I am a C++ programmer, have been for a long long time. I have spent the last few years working with direct3d and opengl, and recently I decided to work on an app which is similar to a dock, (not the same functionaltiy, but an app which has no apparent window, who's shape changes upon mouseover) as a challange to myself, and a new direction.

However, I am a little lost as to where to start with this. I know GDI+ a little, and the basics of the Windows API. But I am not sure how to get that look the dock requiers (no visible window, just the transparent png files painted as though they are sat upon the desktop).

I can do dynamically changing shapes based upon the mouse, it's just this sat on the desktop without a window thing I am not sure about.

Could anyone give me some pointers, or a link to advice which could help me with this? I Would appreciate any help.

Link to post

Thanks for the reply.

I have used layered windows before, but I found that my png's which featured transparency of some sort didn't work(for example a bar png was semi-transparent, to appear like a glass bar, and while the layered window would remove the part of the window which was not touched at all by the image being drawn, the png itself was completely opaque unless I changed the transparency of the layered window). In other words, the layered window didn;t seem to support the png's transparency, but a general overall transparency set for the layered window.

This is the bit I am frustrated with, so I wantd to ask for other options on creating these windows which support png transparency while also allowing shaped windows.

I'll figure it out, I guess.

Link to post

The alpha-blended bitmap you feed to UpdateLayeredWindow() [uLW], needs to have pre-multiplied alpha-levels.

I use this class for layered windows:

#ifndef CLAYEREDWINDOWIMPL_HPP_2302939426539436939393

#define CLAYEREDWINDOWIMPL_HPP_2302939426539436939393

#if _WIN32_WINNT < 0x500

#error "CLayeredWindowImpl requires at least _WIN32_WINNT to be 0x500 (Windows 2000 or higher)"


#include "stdafx.h"

#include "resource.h"

//#ifdef USE_GDIPLUS

#include <gdiplus.h>

using namespace Gdiplus;


template<typename T> class CLayeredWindowImpl : public CWindowImpl<CLayeredWindowImpl >





BOOL IsLayered()const


ATLASSERT( ::IsWindow(m_hWnd) );

LONG lWinLong = GetWindowLong(GWL_EXSTYLE);

return ( (lWinLong & WS_EX_LAYERED) != 0 ) ? TRUE: FALSE;


BOOL EnsureWindowIsLayered()


ATLASSERT( ::IsWindow(m_hWnd) );


return IsLayered();


BOOL SetAlpha(BYTE bAlpha)




blend.BlendOp = AC_SRC_OVER;

blend.BlendFlags = 0;

blend.AlphaFormat = 0;

blend.SourceConstantAlpha = bAlpha;

return ::UpdateLayeredWindow(m_hWnd, NULL, NULL, NULL, NULL, NULL,

NULL, &blend, ULW_ALPHA);


BYTE GetAlpha()const



BYTE bAlpha = 0;


return bAlpha;


BOOL SetHDC(HDC hdcSrc, POINT *pptSrcPos, COLORREF crKey, BLENDFUNCTION* pBlendFunction, DWORD dwFlags, POINT *pptNewPos = NULL, SIZE *pNewSize=NULL)



CWindowDC screenDC(NULL);

return ::UpdateLayeredWindow(m_hWnd,screenDC,pptNewPos,pNewSize,hdcSrc,pptSrcPos, crKey,pBlendFunction,dwFlags);


BOOL SetBitmap(HBITMAP hBitmap, BOOL bAlpha,POINT& ptNewPos, SIZE& newSize)


return SetBitmap(hBitmap,bAlpha,&ptNewPos,&newSize);


BOOL SetBitmap(HBITMAP hBitmap, BOOL bAlpha=255,POINT *pptNewPos = NULL, SIZE *pNewSize=NULL)



CWindowDC screenDC( NULL );

CDC dc;


HBITMAP oldBitmapSelectedInDC = dc.SelectBitmap(hBitmap);

POINT ptSourcePosition = {0,0};

BLENDFUNCTION blendFunction = {0};

blendFunction.BlendOp = AC_SRC_OVER;

blendFunction.BlendFlags = 0;

blendFunction.SourceConstantAlpha = bAlpha;

blendFunction.AlphaFormat = AC_SRC_ALPHA;

COLORREF crKey = RGB(255,0,255); // dummy colourkey

BOOL ret = SetHDC(dc,&ptSourcePosition,crKey,&blendFunction,2,pptNewPos, pNewSize);

// clean up trash


return ret;


//#ifdef USE_GDIPLUS

BOOL SetBitmap(Bitmap* bmp, BOOL bAlpha,POINT& ptNewPos, SIZE& newSize)


return SetBitmap(bmp,bAlpha,&ptNewPos,&newSize);


BOOL SetBitmap(Bitmap& bmp, BOOL bAlpha,POINT& ptNewPos, SIZE& newSize)


return SetBitmap(bmp,bAlpha,&ptNewPos,&newSize);


BOOL SetBitmap(Bitmap* bmp, BOOL bAlpha=255,POINT *pptNewPos = NULL, SIZE *pNewSize=NULL)



return FALSE;

return SetBitmap(*bmp,bAlpha,pptNewPos,pNewSize);


BOOL SetBitmap(Bitmap& bmp, BOOL bAlpha=255,POINT *pptNewPos = NULL, SIZE *pNewSize=NULL)


CBitmap hBmp;


return SetBitmap(hBmp,bAlpha,pptNewPos,pNewSize);




#endif//_WIN32_WINNT < 0x500


Link to post

Andreas, is there a tutorial where you learnt this stuff? Or did you figure it out alone from the msdn docs? All the good tutorials are for delhpi and sometimes VB, I guess C++ programmers are too busy with games.

I have to use UpdateLayeredWindow? I have been using SetLayeredWindowAttributes, that's not enough to be able to use the png's alpha? As I say, I can see through the png fine to items underneath the png inside my window, but cannot see through the png to the desktop below it.

I tried something like your code, but I cannot get it to work, though that is most likely my mistake, and I'll struggle on with it.

Link to post

Layered Windows are a bit strange to the end-user (developer). Those special windows with the WS_EX_LAYERED flag have actually two flavors to end-users:

- per-pixel transparency (like PNG files)

- per window transparency (like fading in a whole window).

A per-pixel transparency window is actually just an alpha-blended bitmap, which cannot host any child-windows [~controls], but will receive normal window events. Those windows need to be updated with the UpdateLayeredWindow() API always, and won't use the WM_PAINT model.

Per window-transparency windows are regular windows, they can have child-controls, can and need to handle WM_PAINT messages, etc. They only thing different to the end-user is that the whole window can be set transparent to a certain degree.

To understand this division, and why one and the same Window Style (WS_EX_LAYERED) and API set is used for this functionality, we need to look at how this behaviour is implemented inside windows, or better we need to make a good guess.

Since W2k, Windows supports alpha-blending thru the AlphaBlend() API. This function basically draws a pre-multiplied alpha bitmap onto a canvas.

A layered window is actually simply using this function to handle its transparency. What happens when you have a layered window is the following:

- the windowmanager let the invalidated area update be updated by the regular windows (WM_PAINT) to a temporary buffer.

- the buffer isn't outputted onto the screen yet.

- ALL layered windows, which are stored internally as HBITMAPS, are drawn UPON the temporary buffer using the AlphaBlend() API.

- finally, the screen is really refreshed to the monitor.

All layered windows are stored as HBITMAPS, regardless of their flavour. If you use UpdateLayeredWindow() to set a bitmap, you basically just replace the internally stored HBITMAP with a new one.

If you use SetLayeredWindowAttributes(), you let the windowmanager update the internally stored HBITMAP: first, the windowmanager let the window update the invalidates part with the WM_PAINT message. However, the drawing operation doesn't go directly to the screen, but is delegated to the internally stored HBITMAP. Next, the windowmanager simply uses the internally stored HBITMAP with AlphaBlend() with the specified alpha-level to update it onto the screen.

(this guessed implementation shows why layered windows are so insanely slow on windows, especially when using DirectX:

- there is an extra drawing step involved in the process,

- for each update, also all windows behind a layered window needs to be updated, since the temporary buffer is overwritten with the layered window,

- DirectX cannot draw directly to the 'screen' anymore, but it needs to let it's output be adjusted by the overlaid layered windows).

Link to post

Andreas, thanks for the input.

I have my code working to some degree, I can load a png into memory and draw it, not problem.

But I also want to change the image, that is stretch it like a dock stretches, and I was using GDI+ like so when answering WM_PAINT prompts to get my images altered as I wanted them:

   case WM_PAINT:

HDC hdc = BeginPaint(hWnd, &ps);

OnPaint(hdc); //bunch of gdi functions to create desired image, stretch it without scaling

EndPaint(hWnd, &ps);

now, I understand we don't use WM_PAINT to update image, so how would you draw the image using gdi+ and then get it into the layeredwindow? Would I draw to a hdc using gdi, then store that hdc as a bitmap, and use that when preparing to UpdateLayeredWindow?

I'll keep struggling with it.

Link to post
...Would I draw to a hdc using gdi, then store that hdc as a bitmap, and use that when preparing to UpdateLayeredWindow?

Exactly. You would create a memory Bitmap object with GDI+, create a Graphics object around it, do your drawing, dispose the Graphics object, extract the HBITMAP from the Bitmap and feed UpdateLayeredWindow with it. Its more performant to keep the Bitmap object between draws; if in doubt, do an Erase with the Graphics object...

Link to post
  • 3 years later...

Hi there !

I am very interested in a directX solution to this problem.

I was very impressed with the knowledge around here.

would you know of a place where I can gather more information on how to create a directX object that is semi-tansparent and a click-thru ?

Thank you so much !

Link to post
why don't you use wpf? it's way more easier to have transparent windows that support alpha-blended png images...

Thanks for your answer !

:) guess because I never heard of it...

Would you know if it'd let me create a surface on the desktop that is a click-thru, meaning semi transparent and passes windows messages on to the underlying windows ?

Link to post

Please sign in to comment

You will be able to leave a comment after signing in

Sign In Now
  • Create New...