原址:http://www.codeproject.com/Questions/182071/GDI-font-rendering-and-layered-windows
使用GDI+绘制字体并使用UpdateLayeredWindow更新窗口时,半透明问题,解决方案是将alpha设置为254
// Create as a console application project // + Unicode charset // + Precompiled headers off // + make sure to add linker input: gdiplus.lib #ifndef _WIN32_WINNT // Allow use of features specific to Windows XP or later. #define _WIN32_WINNT 0x0501 // Change this to the appropriate value to target other versions of Windows. #endif // Standard and GDI+ stuffstuff #include <stdio.h> #include <tchar.h> #include <windows.h> #include <iostream> #include <cassert> #include <Gdiplus.h> using namespace Gdiplus; GdiplusStartupInput g_oGdiPlusStartupInput; ULONG_PTR g_pGdiPlusToken = NULL; #pragma comment(lib, "gdiplus.lib") // #*#*#*#*#*#*#*#*# LINES TO CHANGE ---------->---------->----------> Color g_oTextColor( 255, 240, 0, 0 ); // Simply change Color to ( 254, 240, 0, 0 ) [to add slight transparency] and everything will work! #define USE_LAYERED_WINDOW // or just comment this line out [to use a regular window], and everything will work! // Forward declarations void RegWndClass(); LRESULT CALLBACK WndProc( HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam ); void CreateWindows(); void Draw(); void MsgLoop(); // Other Globals ATOM g_iWndClass = 0; HWND g_hWndGdiPlus = NULL; HWND g_hWndGdi = NULL; const wchar_t* g_pWndClass = L"TST"; int g_iWidth = 200; int g_iHeight = 200; // Main entry-point int _tmain( int argc, _TCHAR* argv[] ) { GdiplusStartup( &g_pGdiPlusToken, &g_oGdiPlusStartupInput, NULL ); RegWndClass(); CreateWindows(); Draw(); MsgLoop(); ::UnregisterClass( g_pWndClass, NULL ); ::Sleep( 500 ); GdiplusShutdown( g_pGdiPlusToken ); return 0; } // _tmain void CreateWindows() { #ifdef USE_LAYERED_WINDOW // The key trick is to create a window with style WS_EX_LAYERED, but WITHOUT any subsequent calls to SetLayeredWindowAttributes() // This gives us a magic window that must be updated with UpdateLayeredWindow() ( and it does NOT recieve any WM_PAINT messages ) // as brilliantly described in: http://alexkr.com/source-code/50/layered-windows-and-updatelayeredwindow/ g_hWndGdiPlus = ::CreateWindowEx( WS_EX_LAYERED, g_pWndClass, L"", WS_POPUP | WS_VISIBLE, 1000, 200, g_iWidth, g_iHeight, NULL, NULL, NULL, NULL ); #else g_hWndGdiPlus = ::CreateWindowEx( 0, g_pWndClass, L"", WS_OVERLAPPEDWINDOW | WS_POPUP | WS_VISIBLE, 1000, 200, g_iWidth, g_iHeight, NULL, NULL, NULL, NULL ); #endif //g_hWndGdi = ::CreateWindowEx( WS_EX_LAYERED, g_pWndClass, L"", WS_POPUP | WS_VISIBLE, 720, 500, 200, 200, NULL, NULL, NULL, NULL ); } // CreateWindows void Draw() { // Init GDI+ surface HDC hOff = ::CreateCompatibleDC( NULL ); Bitmap oDaBigOne( g_iWidth, g_iHeight, PixelFormat32bppARGB ); HBITMAP hBMit = NULL; Color oCol( 0, 0, 0, 0 ); oDaBigOne.GetHBITMAP( oCol, &hBMit ); HGDIOBJ hSave = ::SelectObject( hOff, hBMit ); #ifdef USE_LAYERED_WINDOW Graphics oGraph( hOff ); #else Graphics oGraph( g_hWndGdiPlus ); #endif oGraph.Clear( Color( 255, 55, 155, 255 ) ); // Draw text oGraph.SetTextRenderingHint( TextRenderingHintAntiAliasGridFit ); oGraph.SetTextContrast( 0xffffffff ); oGraph.SetCompositingMode( CompositingModeSourceOver ); oGraph.SetCompositingQuality( CompositingQualityHighQuality ); oGraph.SetPixelOffsetMode( PixelOffsetModeHighQuality ); const FontFamily oFamily( L"Tahoma", NULL ); #if 1 // Use bold Font oF600( &oFamily, 6.00, FontStyle::FontStyleBold, Unit::UnitPixel ); Font oF800( &oFamily, 8.00, FontStyle::FontStyleBold, Unit::UnitPixel ); Font oF848( &oFamily, 8.48, FontStyle::FontStyleBold, Unit::UnitPixel ); Font oF849( &oFamily, 8.49, FontStyle::FontStyleBold, Unit::UnitPixel ); Font oF1200( &oFamily, 12.00, FontStyle::FontStyleBold, Unit::UnitPixel ); Font oF1500( &oFamily, 15.00, FontStyle::FontStyleBold, Unit::UnitPixel ); Font oF1648( &oFamily, 16.48, FontStyle::FontStyleBold, Unit::UnitPixel ); Font oF1649( &oFamily, 16.49, FontStyle::FontStyleBold, Unit::UnitPixel ); #else // Use regular Font oF600( &oFamily, 6.00, FontStyle::FontStyleRegular, Unit::UnitPixel ); Font oF800( &oFamily, 8.00, FontStyle::FontStyleRegular, Unit::UnitPixel ); Font oF848( &oFamily, 8.48, FontStyle::FontStyleRegular, Unit::UnitPixel ); Font oF849( &oFamily, 8.49, FontStyle::FontStyleRegular, Unit::UnitPixel ); Font oF1200( &oFamily, 12.00, FontStyle::FontStyleRegular, Unit::UnitPixel ); Font oF1500( &oFamily, 15.00, FontStyle::FontStyleRegular, Unit::UnitPixel ); Font oF1648( &oFamily, 16.48, FontStyle::FontStyleRegular, Unit::UnitPixel ); Font oF1649( &oFamily, 16.49, FontStyle::FontStyleRegular, Unit::UnitPixel ); #endif assert( oF600.GetLastStatus() == Ok ); // Make sure font is OK SolidBrush oBrush( g_oTextColor ); double dy = 1.0; oGraph.DrawString( L"Size 6.00", -1, &oF600, PointF( 30.0, dy += 18.0 ), &oBrush ); oGraph.DrawString( L"Size 8.00", -1, &oF800, PointF( 30.0, dy += 18.0 ), &oBrush ); oGraph.DrawString( L"Size 8.48", -1, &oF848, PointF( 30.0, dy += 18.0 ), &oBrush ); oGraph.DrawString( L"Size 8.49", -1, &oF849, PointF( 30.0, dy += 18.0 ), &oBrush ); oGraph.DrawString( L"Size 12.00", -1, &oF1200, PointF( 30.0, dy += 18.0 ), &oBrush ); oGraph.DrawString( L"Size 15.00", -1, &oF1500, PointF( 30.0, dy += 18.0 ), &oBrush ); oGraph.DrawString( L"Size 16.48", -1, &oF1648, PointF( 30.0, dy += 18.0 ), &oBrush ); oGraph.DrawString( L"Size 16.49", -1, &oF1649, PointF( 30.0, dy += 18.0 ), &oBrush ); #ifndef USE_LAYERED_WINDOW return; #endif // Do da layered window magic stuff BLENDFUNCTION oBF = { 0 }; oBF.BlendOp = AC_SRC_OVER; oBF.BlendFlags = 0; oBF.SourceConstantAlpha = 255; oBF.AlphaFormat = AC_SRC_ALPHA; SIZE oSize = { 0 }; oSize.cx = g_iWidth; oSize.cy = g_iHeight; POINT oPTZero = { 0 }; RECT oRect = { 0 }; ::GetWindowRect( g_hWndGdiPlus, &oRect ); POINT oPTWnd = { 0 }; oPTWnd.x = oRect.left; oPTWnd.y = oRect.top; //HDC hDC = oGraph.GetHDC(); BOOL bOK = ::UpdateLayeredWindow( g_hWndGdiPlus, NULL, //HDC hdcDst, &oPTWnd, // POINT &oPtNull, &oSize, // SIZE *psize, hOff, // HDC hdcSrc, &oPTZero, // POINT *pptSrc, RGB(255,255,255), // COLORREF crKey, &oBF, // BLENDFUNCTION *pblend, ULW_ALPHA // DWORD dwFlags ); } // Draw void MsgLoop() { ::SetTimer( g_hWndGdiPlus, 0, 19999, NULL ); // Self-destruct timer MSG msg = { 0 }; while ( ::GetMessage( &msg, NULL, 0, 0 ) ) { ::TranslateMessage(&msg); ::DispatchMessage(&msg); } } // MsgLoop void RegWndClass() { WNDCLASSEX wcex = { 0 }; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; wcex.lpfnWndProc = WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 8; // 8 bytes, to allow for 64-bit architecture wcex.hInstance = NULL; // CHECK wcex.hIcon = NULL; wcex.hCursor = ::LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)NULL_BRUSH; // CHECK wcex.lpszMenuName = NULL; wcex.lpszClassName = g_pWndClass; wcex.hIconSm = NULL; g_iWndClass = ::RegisterClassEx(&wcex); } // RegWndClass LRESULT CALLBACK WndProc( HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam ) { switch( uiMsg ) { case WM_TIMER: { std::wstring s; std::wcout << L"Let´s quit" ; ::PostQuitMessage( 0 ); return 0; } case WM_PAINT: Draw(); break; default: { return DefWindowProc( hWnd, uiMsg, wParam, lParam ); } } return DefWindowProc( hWnd, uiMsg, wParam, lParam ); } // WndProc