GDI+ Layered Window Render Problem

(I am new on this website so I hope "Windows Programming" is the correct forum for GDI+.)

I am using GDI+ to render an image to a layered window.
It's supposed to be a fully transparent window, and only the image being visible.


Here is the code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#include <windows.h>
#include <objidl.h>
#include <gdiplus.h>
using namespace Gdiplus;
#pragma comment (lib,"Gdiplus.lib")


VOID OnPaint(HWND hWnd, HDC hdc)
{
	Bitmap image(L"example.png");

	// Get dimensions
	int imageWidth = image.GetWidth();
	int imageHeight = image.GetHeight();

	// Make mem DC + mem  bitmap
	HDC drawingDC = CreateCompatibleDC(hdc);
	
	// Create a new bitmap for drawing on it
	HBITMAP newBitmap = CreateCompatibleBitmap(hdc, imageWidth, imageHeight);

	// Select the new bitmap to draw on it and save the old one
	HBITMAP oldBitmap = (HBITMAP)SelectObject(drawingDC, newBitmap);
	
	// Draw image to the newly created DC
	Graphics graphics(drawingDC);
	Point point(0, 0);
	graphics.DrawImage(&image, point);

	// Create a blend function
	BLENDFUNCTION blend = { 0 };
	blend.BlendOp = AC_SRC_OVER;
	blend.SourceConstantAlpha = 255;
	blend.AlphaFormat = AC_SRC_ALPHA;

	// Set window info
	POINT windowPosition = { 0, 0 };
	SIZE windowSize = { imageWidth, imageHeight };
	POINT imagePosition = { 0, 0 };

	// Call UpdateLayeredWindow
	UpdateLayeredWindow(hWnd, hdc, &windowPosition, &windowSize, drawingDC, &imagePosition, 0, &blend, ULW_ALPHA);

	SelectObject(drawingDC, oldBitmap);
	DeleteObject(newBitmap);
	DeleteDC(drawingDC);
	ReleaseDC(NULL, hdc);
}

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, PSTR, INT iCmdShow)
{
	// Initialize GDI+.
	GdiplusStartupInput gdiplusStartupInput;
	ULONG_PTR           gdiplusToken;
	GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);


	HWND                hWnd;
	MSG                 msg;
	WNDCLASS            wndClass;

	wndClass.style = CS_HREDRAW | CS_VREDRAW;
	wndClass.lpfnWndProc = WndProc;
	wndClass.cbClsExtra = 0;
	wndClass.cbWndExtra = 0;
	wndClass.hInstance = hInstance;
	wndClass.hIcon = 0;
	wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
	wndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	wndClass.lpszMenuName = NULL;
	wndClass.lpszClassName = TEXT("Sticker");

	RegisterClass(&wndClass);

	hWnd = CreateWindowEx(
		WS_EX_LAYERED,
		TEXT("Sticker"),   // window class name
		TEXT("Sticker"),  // window caption
		NULL,      // window style
		0,            // initial x position
		0,            // initial y position
		500,            // initial x size
		500,            // initial y size
		NULL,                     // parent window handle
		NULL,                     // window menu handle
		hInstance,                // program instance handle
		NULL);                    // creation parameters

	ShowWindow(hWnd, iCmdShow);

	while (GetMessage(&msg, NULL, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	GdiplusShutdown(gdiplusToken);
	return msg.wParam;
}  // WinMain

LRESULT CALLBACK WndProc(HWND hWnd, UINT message,
	WPARAM wParam, LPARAM lParam)
{
	HDC          hdc;
	PAINTSTRUCT  ps;

	switch (message)
	{
	case WM_CREATE:
		hdc = BeginPaint(hWnd, &ps);
		OnPaint(hWnd, hdc);
		EndPaint(hWnd, &ps);
		return 0;
	case WM_PAINT:
		hdc = BeginPaint(hWnd, &ps);
		OnPaint(hWnd, hdc);
		EndPaint(hWnd, &ps);
		return 0;
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}
} // WndProc 


This almost works the way I want it, but the image is for some reason not fully rendered. Either the window size in the OnPaint function is smaller than the image or the image is for some reason scaled up so it doesn't fit? These are just my guesses, but I couldn't confirm any of them yet.

I tried reading different Microsoft examples for GDI+ but can't seem to understand it well enough yet, and there are so few examples outside of Microsoft to learn from, especially for layered windows, that it is really difficult to understand how layered windows are even supposed to be rendered.

So please help me understand what is wrong in this code and maybe recommend some good tutorials on using GDI+ layered window if you know any
Last edited on
Implementing a double-buffering setup with GDI+ might be what you are looking for.

The app creates an off-screen compatible bitmap surface that you draw to instead of the main screen. Then when all your drawing is done and you want to display it that compatible bitmap is displayed on the main window.

Double buffering eliminates flickering that can occur when you paint every drawing operation to the main screen in real time.

https://stackoverflow.com/questions/2473799/gdi-double-buffering-in-c
Registered users can post here. Sign in or register to post.