238 lines
6.0 KiB
C
238 lines
6.0 KiB
C
#include <ph.h>
|
|
#include <guisup.h>
|
|
#include <uxtheme.h>
|
|
|
|
// code from http://msdn.microsoft.com/en-us/library/bb757020.aspx
|
|
|
|
typedef HPAINTBUFFER (*_BeginBufferedPaint)(
|
|
_In_ HDC hdcTarget,
|
|
_In_ const RECT *prcTarget,
|
|
_In_ BP_BUFFERFORMAT dwFormat,
|
|
_In_ BP_PAINTPARAMS *pPaintParams,
|
|
_Out_ HDC *phdc
|
|
);
|
|
|
|
typedef HRESULT (*_EndBufferedPaint)(
|
|
_In_ HPAINTBUFFER hBufferedPaint,
|
|
_In_ BOOL fUpdateTarget
|
|
);
|
|
|
|
typedef HRESULT (*_GetBufferedPaintBits)(
|
|
_In_ HPAINTBUFFER hBufferedPaint,
|
|
_Out_ RGBQUAD **ppbBuffer,
|
|
_Out_ int *pcxRow
|
|
);
|
|
|
|
static BOOLEAN ImportsInitialized = FALSE;
|
|
static _BeginBufferedPaint BeginBufferedPaint_I = NULL;
|
|
static _EndBufferedPaint EndBufferedPaint_I = NULL;
|
|
static _GetBufferedPaintBits GetBufferedPaintBits_I = NULL;
|
|
|
|
static HBITMAP PhpCreateBitmap32(
|
|
_In_ HDC hdc,
|
|
_In_ ULONG Width,
|
|
_In_ ULONG Height,
|
|
_Outptr_opt_ PVOID *Bits
|
|
)
|
|
{
|
|
BITMAPINFO bitmapInfo;
|
|
|
|
memset(&bitmapInfo, 0, sizeof(BITMAPINFO));
|
|
bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
|
bitmapInfo.bmiHeader.biPlanes = 1;
|
|
bitmapInfo.bmiHeader.biCompression = BI_RGB;
|
|
|
|
bitmapInfo.bmiHeader.biWidth = Width;
|
|
bitmapInfo.bmiHeader.biHeight = Height;
|
|
bitmapInfo.bmiHeader.biBitCount = 32;
|
|
|
|
return CreateDIBSection(hdc, &bitmapInfo, DIB_RGB_COLORS, Bits, NULL, 0);
|
|
}
|
|
|
|
static BOOLEAN PhpHasAlpha(
|
|
_In_ PULONG Argb,
|
|
_In_ ULONG Width,
|
|
_In_ ULONG Height,
|
|
_In_ ULONG RowWidth
|
|
)
|
|
{
|
|
ULONG delta;
|
|
ULONG x;
|
|
ULONG y;
|
|
|
|
delta = RowWidth - Width;
|
|
|
|
for (y = Width; y; y--)
|
|
{
|
|
for (x = Height; x; x--)
|
|
{
|
|
if (*Argb++ & 0xff000000)
|
|
return TRUE;
|
|
}
|
|
|
|
Argb += delta;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static VOID PhpConvertToPArgb32(
|
|
_In_ HDC hdc,
|
|
_Inout_ PULONG Argb,
|
|
_In_ HBITMAP Bitmap,
|
|
_In_ ULONG Width,
|
|
_In_ ULONG Height,
|
|
_In_ ULONG RowWidth
|
|
)
|
|
{
|
|
BITMAPINFO bitmapInfo;
|
|
PVOID bits;
|
|
|
|
memset(&bitmapInfo, 0, sizeof(BITMAPINFO));
|
|
bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
|
bitmapInfo.bmiHeader.biPlanes = 1;
|
|
bitmapInfo.bmiHeader.biCompression = BI_RGB;
|
|
|
|
bitmapInfo.bmiHeader.biWidth = Width;
|
|
bitmapInfo.bmiHeader.biHeight = Height;
|
|
bitmapInfo.bmiHeader.biBitCount = 32;
|
|
|
|
bits = PhAllocate(Width * sizeof(ULONG) * Height);
|
|
|
|
if (GetDIBits(hdc, Bitmap, 0, Height, bits, &bitmapInfo, DIB_RGB_COLORS) == Height)
|
|
{
|
|
PULONG argbMask;
|
|
ULONG delta;
|
|
ULONG x;
|
|
ULONG y;
|
|
|
|
argbMask = (PULONG)bits;
|
|
delta = RowWidth - Width;
|
|
|
|
for (y = Height; y; y--)
|
|
{
|
|
for (x = Width; x; x--)
|
|
{
|
|
if (*argbMask++)
|
|
{
|
|
*Argb++ = 0; // transparent
|
|
}
|
|
else
|
|
{
|
|
*Argb++ |= 0xff000000; // opaque
|
|
}
|
|
}
|
|
|
|
Argb += delta;
|
|
}
|
|
}
|
|
|
|
PhFree(bits);
|
|
}
|
|
|
|
static VOID PhpConvertToPArgb32IfNeeded(
|
|
_In_ HPAINTBUFFER PaintBuffer,
|
|
_In_ HDC hdc,
|
|
_In_ HICON Icon,
|
|
_In_ ULONG Width,
|
|
_In_ ULONG Height
|
|
)
|
|
{
|
|
RGBQUAD *quad;
|
|
ULONG rowWidth;
|
|
|
|
if (SUCCEEDED(GetBufferedPaintBits_I(PaintBuffer, &quad, &rowWidth)))
|
|
{
|
|
PULONG argb = (PULONG)quad;
|
|
|
|
if (!PhpHasAlpha(argb, Width, Height, rowWidth))
|
|
{
|
|
ICONINFO iconInfo;
|
|
|
|
if (GetIconInfo(Icon, &iconInfo))
|
|
{
|
|
if (iconInfo.hbmMask)
|
|
{
|
|
PhpConvertToPArgb32(hdc, argb, iconInfo.hbmMask, Width, Height, rowWidth);
|
|
}
|
|
|
|
DeleteObject(iconInfo.hbmColor);
|
|
DeleteObject(iconInfo.hbmMask);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
HBITMAP PhIconToBitmap(
|
|
_In_ HICON Icon,
|
|
_In_ ULONG Width,
|
|
_In_ ULONG Height
|
|
)
|
|
{
|
|
HBITMAP bitmap;
|
|
RECT iconRectangle;
|
|
HDC screenHdc;
|
|
HDC hdc;
|
|
HBITMAP oldBitmap;
|
|
BLENDFUNCTION blendFunction = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
|
|
BP_PAINTPARAMS paintParams = { sizeof(paintParams) };
|
|
HDC bufferHdc;
|
|
HPAINTBUFFER paintBuffer;
|
|
|
|
iconRectangle.left = 0;
|
|
iconRectangle.top = 0;
|
|
iconRectangle.right = Width;
|
|
iconRectangle.bottom = Height;
|
|
|
|
if (!ImportsInitialized)
|
|
{
|
|
HMODULE uxtheme;
|
|
|
|
uxtheme = GetModuleHandle(L"uxtheme.dll");
|
|
BeginBufferedPaint_I = PhGetProcedureAddress(uxtheme, "BeginBufferedPaint", 0);
|
|
EndBufferedPaint_I = PhGetProcedureAddress(uxtheme, "EndBufferedPaint", 0);
|
|
GetBufferedPaintBits_I = PhGetProcedureAddress(uxtheme, "GetBufferedPaintBits", 0);
|
|
ImportsInitialized = TRUE;
|
|
}
|
|
|
|
if (!BeginBufferedPaint_I || !EndBufferedPaint_I || !GetBufferedPaintBits_I)
|
|
{
|
|
// Probably XP.
|
|
|
|
screenHdc = GetDC(NULL);
|
|
hdc = CreateCompatibleDC(screenHdc);
|
|
bitmap = CreateCompatibleBitmap(screenHdc, Width, Height);
|
|
ReleaseDC(NULL, screenHdc);
|
|
|
|
oldBitmap = SelectObject(hdc, bitmap);
|
|
FillRect(hdc, &iconRectangle, (HBRUSH)(COLOR_WINDOW + 1));
|
|
DrawIconEx(hdc, 0, 0, Icon, Width, Height, 0, NULL, DI_NORMAL);
|
|
SelectObject(hdc, oldBitmap);
|
|
|
|
DeleteDC(hdc);
|
|
|
|
return bitmap;
|
|
}
|
|
|
|
screenHdc = GetDC(NULL);
|
|
hdc = CreateCompatibleDC(screenHdc);
|
|
bitmap = PhpCreateBitmap32(screenHdc, Width, Height, NULL);
|
|
ReleaseDC(NULL, screenHdc);
|
|
oldBitmap = SelectObject(hdc, bitmap);
|
|
|
|
paintParams.dwFlags = BPPF_ERASE;
|
|
paintParams.pBlendFunction = &blendFunction;
|
|
|
|
paintBuffer = BeginBufferedPaint_I(hdc, &iconRectangle, BPBF_DIB, &paintParams, &bufferHdc);
|
|
DrawIconEx(bufferHdc, 0, 0, Icon, Width, Height, 0, NULL, DI_NORMAL);
|
|
// If the icon did not have an alpha channel, we need to convert the buffer to PARGB.
|
|
PhpConvertToPArgb32IfNeeded(paintBuffer, hdc, Icon, Width, Height);
|
|
// This will write the buffer contents to the destination bitmap.
|
|
EndBufferedPaint_I(paintBuffer, TRUE);
|
|
|
|
SelectObject(hdc, oldBitmap);
|
|
DeleteDC(hdc);
|
|
|
|
return bitmap;
|
|
}
|