将HBITMAP绘制到分层窗口上。 怎么了?

大家好,今天好,

我的最终目标是在屏幕上绘制一个包含alpha的PNG文件 – 这意味着不能进入自己的窗口,而只是在桌面上的某处。 将PNG加载到HBITMAP中的部分现在可以工作(以不同的方式进行testing),但是我无法设法将其绘制为包括alpha。

据我所知,最好的办法是使用alyered窗口。 所以我花了很多时间来重做一些例子和小教程。

下面的代码编译没有问题,并没有提示任何消息(这意味着showError(“#”)函数永远不会被调用)。

然而屏幕上没有任何可见的东西 :/

对不起,它是这么长…希望有人希望至less看看它..

LRESULT CALLBACK WndProc(HWND hWindow, UINT msg, WPARAM wParam, LPARAM lParam); int main(HINSTANCE hInstance) { WNDCLASSEX WndClass; char sClassName[] = "mainClass"; WndClass.cbSize = sizeof(WNDCLASSEX); WndClass.style = NULL; WndClass.lpfnWndProc = WndProc;//WndProc; WndClass.cbClsExtra = 0; WndClass.cbWndExtra = 0; WndClass.hInstance = hInstance; WndClass.hIcon = NULL; WndClass.hCursor = LoadCursor(NULL, IDC_ARROW); WndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); WndClass.lpszMenuName = NULL; WndClass.lpszClassName = sClassName; WndClass.hIconSm = LoadIcon(NULL, IDI_APPLICATION); if (RegisterClassEx(&WndClass) == 0) showError("-1"); HWND screen = CreateWindowEx(WS_EX_LAYERED,//WS_EX_LEFT "mainClass", "UpdateLayeredWind", WS_DISABLED | WS_VISIBLE, 200,200,260,260, NULL /*eventuelly, GM window*/, NULL, hInstance, NULL); if (screen == NULL) showError("0"); HBITMAP img = LoadImageResource("D://ThreadDraw/ThreadDraw-test/ThreadDraw/test.png"); if (img == NULL) showError("1"); BLENDFUNCTION blend = {0}; blend.AlphaFormat = AC_SRC_ALPHA; blend.SourceConstantAlpha = 155; POINT ptPos = {200,300}; SIZE sizeWnd = {260,260}; POINT ptPos2 = {200,300}; ShowWindow(screen, SW_SHOW); while (1) { PAINTSTRUCT ps; HDC hdc; BITMAP bitmap; HDC hdcMem; HGDIOBJ oldBitmap; hdc = BeginPaint(screen, &ps); hdcMem = CreateCompatibleDC(hdc); oldBitmap = SelectObject(hdcMem, img); GetObject(img, sizeof(bitmap), &bitmap); if (SetLayout(hdc,LAYOUT_RTL) == GDI_ERROR) showError("5"); if (!BitBlt(hdc, 0, 0, 64, 64, hdcMem, 0, 0, SRCCOPY)) showError("4"); if (!UpdateLayeredWindow(screen,hdcMem,&ptPos,&sizeWnd,hdc,&ptPos2,RGB(255,255,255),&blend,ULW_ALPHA))//ULW_OPAQUE)) showError("2"); EndPaint(screen, &ps); SelectObject(hdcMem, oldBitmap); DeleteDC(hdcMem); Sleep(10); } return 0; } LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) { switch(Message) { case WM_CLOSE: DestroyWindow(hwnd); break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hwnd, Message, wParam, lParam); } return 0; } 

顺便说一下,如果我在UpdateLayeredWindow中使用ULW_OPAQUE而不是ULW_ALPHA,那么就会出现一个正确大小的黑色窗口,所以认为这个问题必须与PAINTSTRUKT或BitBlt函数最小有关。然而,我尝试了很多方法,没有任何改变。

希望有人能帮忙。 提前非常感谢!

这大多是错误的。 你的代码应该:

  • 使用CreateWindowEx创建分层窗口。
  • 使用UpdateLayeredWindow将位图附加到它。
  • ShowWindow显示窗口。 Windows将负责绘制分层窗口,因此您不需要处理WM_PAINT或调用BeginPaint
  • 输入一个消息循环。

就是这样。

如果您使用的是Visual Studio,请创建一个新的Win32项目,它将为您创建一个带有消息循环的新项目。

更新

这是一个示例程序,它创建一个透明的分层窗口。 它需要一个函数来加载一个PNG作为一个透明的位图。 它没有错误检查。

 int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { LPCTSTR szWindowClass = _T("TransparentClass"); // Register class WNDCLASSEX wcex = {0}; wcex.cbSize = sizeof(WNDCLASSEX); wcex.lpfnWndProc = DefWindowProc; wcex.hInstance = hInstance; wcex.lpszClassName = szWindowClass; RegisterClassEx(&wcex); HWND hWnd = CreateWindowEx(WS_EX_LAYERED, szWindowClass, 0, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL); int width; int height; HBITMAP hbmp = LoadPng(L"sample.png", &width, &height); HDC hdcScreen = GetDC(0); HDC hdc = CreateCompatibleDC(hdcScreen); ReleaseDC(0, hdcScreen); HBITMAP hbmpold = (HBITMAP)SelectObject(hdc, hbmp); POINT dcOffset = {0, 0}; SIZE size = {width, height}; BLENDFUNCTION bf; bf.BlendOp = AC_SRC_OVER; bf.BlendFlags = 0; bf.SourceConstantAlpha = 255; bf.AlphaFormat = AC_SRC_ALPHA; UpdateLayeredWindow(hWnd, 0, 0, &size, hdc, &dcOffset, 0, &bf, ULW_ALPHA); SelectObject(hdc, hbmpold); DeleteDC(hdc); DeleteObject(hbmp); ShowWindow(hWnd, SW_SHOW); MSG msg; // Main message loop: while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return (int)msg.wParam; } 

另一个更新

这里有一些代码预先乘alpha,红色,绿色和蓝色值。 它假定splash_image指向大小为width*height 32bpp ARGB数据。

 LPBYTE bits = (LPBYTE)splash_image; int size = width * height; for (int pixel = 0; pixel != size; ++pixel) { bits[0] = bits[0] * bits[3] / 255; bits[1] = bits[1] * bits[3] / 255; bits[2] = bits[2] * bits[3] / 255; bits += 4; }