1 /** DGui project file.
2 
3 Copyright: Trogu Antonio Davide 2011-2013
4 
5 License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0).
6 
7 Authors: Trogu Antonio Davide
8 */
9 
10 /* Windows 2000/XP/Vista/7 Compatibility Module */
11 
12 module dgui.core.wincomp;
13 
14 import dgui.core.utils;
15 import dgui.core.winapi;
16 import dgui.core.charset;
17 import dgui.core.exception;
18 
19 private const WIN_NOT_SUPPORTED_MSG = "This function cannot be used on Windows 2000/XP";
20 
21 enum
22 {
23 	BPPF_ERASE = 0x0001,
24 }
25 
26 align(1) struct BP_PAINTPARAMS
27 {
28   DWORD cbSize;
29   DWORD dwFlags;
30   RECT* prcExclude;
31   BLENDFUNCTION* pBlendFunction;
32 }
33 
34 private alias HANDLE HPAINTBUFFER;
35 private alias uint BP_BUFFERFORMAT; //It's a enum but we need only one value from it, make it an alias of type uint.
36 
37 private alias extern(Windows) HPAINTBUFFER function(HDC, RECT*, BP_BUFFERFORMAT, BP_PAINTPARAMS*, HDC*) BeginBufferedPaintProc;
38 private alias extern(Windows) HRESULT function(HPAINTBUFFER, RGBQUAD**, int*) GetBufferedPaintBitsProc;
39 private alias extern(Windows) HRESULT function(HPAINTBUFFER, BOOL) EndBufferedPaintProc;
40 
41 private BeginBufferedPaintProc beginBufferedPaint;
42 private GetBufferedPaintBitsProc getBufferedPaintBits;
43 private EndBufferedPaintProc endBufferedPaint;
44 
45 private void initBitmapInfo(ref BITMAPINFO bi, SIZE sz)
46 {
47 	bi.bmiHeader.biSize = BITMAPINFOHEADER.sizeof;
48 	bi.bmiHeader.biPlanes = 1;
49 	bi.bmiHeader.biCompression = 0; //BI_RGB;
50 	bi.bmiHeader.biWidth = sz.cx;
51 	bi.bmiHeader.biHeight = sz.cy;
52 	bi.bmiHeader.biBitCount = 32;
53 }
54 
55 private HBITMAP create32BitHBITMAP(HDC hdc, SIZE sz)
56 {
57 	BITMAPINFO bi;
58 	initBitmapInfo(bi, sz);
59 
60 	return CreateDIBSection(hdc, &bi, DIB_RGB_COLORS, null, null, 0);
61 }
62 
63 bool hasAlpha(ARGB* pArgb, SIZE szIco, int cxRow)
64 {
65     ulong cxDelta = cxRow - szIco.cx;
66 
67     for(ulong y = szIco.cy; y; --y)
68     {
69         for(ulong x = szIco.cx; x; --x)
70         {
71             if(*pArgb++ & 0xFF000000)
72             {
73                 return true;
74             }
75         }
76 
77         pArgb += cxDelta;
78     }
79 
80     return false;
81 }
82 
83 private void convertToPARGB32(HDC hdc, ARGB* pArgb, HBITMAP hBmpMask, SIZE sz, int cxRow)
84 {
85 	BITMAPINFO bi;
86 	initBitmapInfo(bi, sz);
87 
88 	ubyte[] pBits = new ubyte[bi.bmiHeader.biWidth * 4 * bi.bmiHeader.biHeight];
89 	GetDIBits(hdc, hBmpMask, 0, bi.bmiHeader.biHeight, pBits.ptr, &bi, DIB_RGB_COLORS);
90 
91 	ulong cxDelta = cxRow - bi.bmiHeader.biWidth;
92 	ARGB *pArgbMask = cast(ARGB*)pBits.ptr;
93 
94 	for(ulong y = bi.bmiHeader.biHeight; y; --y)
95 	{
96 		for(ulong x = bi.bmiHeader.biWidth; x; --x)
97 		{
98 			if(*pArgbMask++)
99 			{
100 				// transparent pixel
101 				*pArgb++ = 0;
102 			}
103 			else
104 			{
105 				// opaque pixel
106 				*pArgb++ |= 0xFF000000;
107 			}
108 		}
109 
110 		pArgb += cxDelta;
111 	}
112 }
113 
114 private void convertBufferToPARGB32(HPAINTBUFFER hPaintBuffer, HDC hdc, HICON hIcon, SIZE szIco)
115 {
116 	int cxRow;
117 	RGBQUAD* pRgbQuad;
118 
119 	getBufferedPaintBits(hPaintBuffer, &pRgbQuad, &cxRow);
120 	ARGB* pArgb = cast(ARGB*)pRgbQuad;
121 
122 	if(!hasAlpha(pArgb, szIco, cxRow))
123 	{
124 		ICONINFO ii;
125 		GetIconInfo(hIcon, &ii);
126 
127 		if(ii.hbmMask)
128 		{
129 			convertToPARGB32(hdc, pArgb, ii.hbmMask, szIco, cxRow);
130 		}
131 
132 		DeleteObject(ii.hbmColor);
133 		DeleteObject(ii.hbmMask);
134 	}
135 }
136 
137 public HBITMAP iconToBitmapPARGB32(HICON hIcon)
138 {
139 	static HMODULE hUxTheme;
140 	WindowsVersion ver = getWindowsVersion();
141 
142 	SIZE szIco;
143 	szIco.cx = GetSystemMetrics(SM_CXSMICON);
144 	szIco.cy = GetSystemMetrics(SM_CYSMICON);
145 
146 	RECT rIco;
147 	rIco.left = 0;
148 	rIco.top = 0;
149 	rIco.right = szIco.cx;
150 	rIco.bottom = szIco.cy;
151 
152 	if(ver > WindowsVersion.windowsXP) //Is Vista or 7
153 	{
154 		if(!hUxTheme)
155 		{
156 			hUxTheme = getModuleHandle("UxTheme.dll");
157 
158 			beginBufferedPaint = cast(BeginBufferedPaintProc)GetProcAddress(hUxTheme, "BeginBufferedPaint");
159 			getBufferedPaintBits = cast(GetBufferedPaintBitsProc)GetProcAddress(hUxTheme, "GetBufferedPaintBits");
160 			endBufferedPaint = cast(EndBufferedPaintProc)GetProcAddress(hUxTheme, "EndBufferedPaint");
161 		}
162 
163 		HDC hdc = CreateCompatibleDC(null);
164 		HBITMAP hBitmap = create32BitHBITMAP(hdc, szIco);
165 		HBITMAP hOldBitmap = SelectObject(hdc, hBitmap);
166 
167 		BLENDFUNCTION bf;
168 		bf.BlendOp = 0; // AC_SRC_OVER
169 		bf.SourceConstantAlpha = 255;
170 		bf.AlphaFormat = 1; // AC_SRC_ALPHA
171 
172 		BP_PAINTPARAMS pp;
173 		pp.cbSize = BP_PAINTPARAMS.sizeof;
174 		pp.dwFlags = BPPF_ERASE;
175 		pp.pBlendFunction = &bf;
176 
177 		HDC hdcBuffer;
178 		HPAINTBUFFER hPaintBuffer = beginBufferedPaint(hdc, &rIco, 1 /*BPBF_DIB*/, &pp, &hdcBuffer);
179 		DrawIconEx(hdcBuffer, 0, 0, hIcon, szIco.cx, szIco.cy, 0, null, DI_NORMAL);
180 		convertBufferToPARGB32(hPaintBuffer, hdc, hIcon, szIco);
181 		endBufferedPaint(hPaintBuffer, true);
182 
183 		SelectObject(hdc, hOldBitmap);
184 		DeleteDC(hdc);
185 
186 		return hBitmap;
187 	}
188 
189 	throwException!(WindowsNotSupportedException)("Not supported in 2000/XP");
190 	return null;
191 }