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