WinAPI BitBlt flickering

Hello!

It seems this topic has been evaulated quite intensively here, but I can't get it to work anyways. This is a DLL injecting to the main APP via provided SDK. I tried to get memDC, but I still get massive flickering, and after some time (5-15 mins), I am getting completely messed up (resulting in total mess up and app crash: https://prnt.sc/zf1dh8 -> https://prnt.sc/zf0dfz )

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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
#include "pch.h"
#include "ELW.h"
#include "ELWData.h"

int HWND_HEIGHT_CURRENT;

// Constructor
ELW::ELW()
{
	hInst = GetModuleHandle(NULL);
	 thread = CreateThread(0, NULL, ELW::ThreadProc, NULL, NULL, &threadId);
}


// WindowThread - Window Class Registry, Creation and Showing
DWORD WINAPI ELW::ThreadProc(LPVOID lpParam)
{
#pragma region WindowClassRegister
	
	// REGISTER THE WINDOW CLASS
	WNDCLASS wc = {};

	wc.lpfnWndProc = ELW::WindowProc;
	wc.hInstance = hInst;
	wc.lpszClassName = CLASS_NAME;
	wc.hCursor = LoadCursor(NULL, IDC_ARROW);


	RegisterClass(&wc);

#pragma endregion WindowClassRegister

	// CREATE THE WINDOW
#pragma region CreateWindow
	hWnd = CreateWindow(
		CLASS_NAME,					// WINDOW CLASS NAME
		WINDOW_NAME,				// WINDOW NAME
		WS_CAPTION,					// WINDOW STYLES
		CW_USEDEFAULT,				// int X
		CW_USEDEFAULT,				// int Y
		HWND_WIDTH,					// int WIDTH
		HWND_HEIGHTC,				// int HEIGHT
		NULL,						// hWnd PARENT WINDOW
		NULL,						// hMenu MENU
		hInst,						// handle Instance Handle
		NULL);						// Additional appllication data


	if (hWnd == NULL)
		return 0;

#pragma endregion CreateWindow

	// ELEMENTS


	// SHOW THE WINDOW
	ShowWindow(hWnd,SW_SHOWNORMAL);
	SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
	// RUN THE MESSAGE LOOP
	MSG msg = {};
	while (GetMessage(&msg, NULL, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	

}

// WindowProc definition - Window Messages

LRESULT	CALLBACK ELW::WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch (uMsg)
	{
		case WM_DESTROY:
			PostQuitMessage(0);
			break;

		case WM_PAINT:
			{
			ELW::DrawContent(hWnd, hInst, hdc);
			}
			break;

		case WM_CLOSE:
			{
			DestroyWindow(hWnd);
			UnregisterClass(CLASS_NAME, hInst);
			}
			break;

		case WM_SYSCOMMAND:
			{
			if (wParam == SC_CLOSE);
			break;
			}

		case WM_ERASEBKGND:
		{
			break;
		}
	}

	return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

// ELW::DrawContent Content drawing - PaintStruct, hdc = BeginPaint, elements, EndPaint
void ELW::DrawContent(HWND hWnd, HINSTANCE hInst, HDC hdc)
{
	PAINTSTRUCT ps;
	hdc = BeginPaint(hWnd, &ps);
	// Bitmap double buffering
	if (GetDC(hWnd) == NULL)
		ELWmemdc = CreateCompatibleDC(hdc);
	else
		ELWmemdc = GetDC(hWnd);

	// DrawContent 
	const char* defaultFont = "Euroscope";
	int defaultFontSize = 16;
	FillRect(ELWmemdc, &ps.rcPaint, (HBRUSH)(COLOR_GRAYTEXT + 1));
	ELW::AddTextControl(ELWData::Callsign(), 5, 5, 100, 20, CUSTOM_COLOR_GREEN, defaultFontSize, defaultFont, ELWmemdc, 'l');
	ELW::AddTextControl("W", 90, 5, 25, 20, CUSTOM_COLOR_GREEN, defaultFontSize, defaultFont, ELWmemdc, NULL);
	ELW::AddTextControl("Y", 100, 5, 25, 20, CUSTOM_COLOR_LIGHTGRAY, defaultFontSize, defaultFont, ELWmemdc, NULL);
	ELW::AddTextControl(ELWData::RadioCallsign(), 130, 5, 55, 20, CUSTOM_COLOR_GREEN, defaultFontSize, defaultFont, ELWmemdc, 'l');
	ELW::AddTextControl(ELWData::SSR().c_str(), (HWND_WIDTH - 115), 5, 90, 20, CUSTOM_COLOR_WHITE, defaultFontSize, defaultFont, ELWmemdc, 'r');
	ELW::AddTextControl(ELWData::ACTypeWtc().c_str(), 35, NEWLINE, 50, 20, CUSTOM_COLOR_WHITE, defaultFontSize, defaultFont, ELWmemdc, 'l');
	ELW::AddTextControl(ELWData::ASSR().c_str(), (HWND_WIDTH - 75), NEWLINE, 50, 20, CUSTOM_COLOR_YELLOW, defaultFontSize, defaultFont, ELWmemdc, 'r');
	ELW::AddTextControl(ELWData::ADEP().c_str(), 5, 3 * NEWLINE, 40, 20, CUSTOM_COLOR_WHITE, defaultFontSize, defaultFont, ELWmemdc,'l');
	ELW::AddTextControl(ELWData::DEST().c_str(), 47, 3 * NEWLINE, 40, 20, CUSTOM_COLOR_WHITE, defaultFontSize, defaultFont, ELWmemdc, 'l');
	if (ELWData::CheckDestinationIsEP())
	{
		ELW::AddTextControl("(", 92, 3 * NEWLINE, 5, 20, CUSTOM_COLOR_WHITE, defaultFontSize, defaultFont, ELWmemdc, 'l');
		ELW::AddTextControl(ELWData::ALT().c_str(), 101, 3 * NEWLINE, 40, 20, CUSTOM_COLOR_WHITE, defaultFontSize, defaultFont, ELWmemdc, 'l');
		ELW::AddTextControl(")", 138, 3 * NEWLINE, 3, 20, CUSTOM_COLOR_WHITE, defaultFontSize, defaultFont, ELWmemdc, 'l');
		ELW::AddTextControl(ELWData::STAR().c_str(), 160, 3 * NEWLINE, 60, 20, CUSTOM_COLOR_WHITE, defaultFontSize, defaultFont, ELWmemdc, 'l');
		ELW::AddTextControl(ELWData::RWY().c_str(), 235, 3 * NEWLINE, 60, 20, CUSTOM_COLOR_WHITE, defaultFontSize, defaultFont, ELWmemdc, 'l');
	}
	ELW::AddTextControl(ELWData::NextFreq().c_str(), (HWND_WIDTH - 125), 3 * NEWLINE, 100, 20, CUSTOM_COLOR_GREEN, defaultFontSize, defaultFont, ELWmemdc, 'r');
	ELW::AddTextControl(ELWData::FPType().c_str(), 5, 4 * NEWLINE, 5, 20, CUSTOM_COLOR_YELLOW, defaultFontSize, defaultFont, ELWmemdc, 'l');
	ELW::AddTextControl(ELWData::RouteToBePassed().c_str(), 20, 4 * NEWLINE, 400, 20, CUSTOM_COLOR_WHITE, defaultFontSize, defaultFont, ELWmemdc, 'l');
	
	BitBlt(hdc, 0, 0, HWND_WIDTH, HWND_HEIGHT_CURRENT, ELWmemdc, 0, 0, SRCCOPY);
	ReleaseDC(hWnd, ELWmemdc);
	ReleaseDC(hWnd, hdc);
	EndPaint(hWnd, &ps);

};

/*ELW:AddTextControl text - Text to be labeled
xPos - initial horizontal position, yPos - initial vertical position
xSize, ySize - RECT size
rgb - Colour of the text
fontSize, fontName - font styles to be applied,
hdc - current dc, 
align - 'l' for left, 'r' for right, else for center */
void ELW::AddTextControl(const char* text, int xPos, int yPos, int xSize, int ySize, COLORREF rgb, int fontSize, const char* fontName, HDC hdc, char align)
{

	RECT TextRectangle = { xPos, yPos, ( xPos + xSize ) , ( yPos + ySize ) }; // Left, Top, Right, Bottom
	
	
	if (rgb == NULL)
		rgb = RGB(0, 0, 0);
	if (fontSize == NULL)
		fontSize = 10;
	if (fontName == NULL)
		fontName = "Euroscope";


	HFONT hFont = CreateFontA(fontSize, 8, 0, 0, 800, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_OUTLINE_PRECIS, CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, VARIABLE_PITCH, TEXT(fontName));
	SelectObject(hdc, hFont);
	SetBkMode(hdc, TRANSPARENT);
	SetTextColor(hdc, rgb);

	if (align == 'l')
		DrawTextA(hdc, text, strlen((text)), &TextRectangle, DT_LEFT | DT_NOCLIP);
	else if (align == 'r')
		DrawTextA(hdc, text, strlen((text)), &TextRectangle, DT_RIGHT | DT_NOCLIP);
	else
		DrawTextA(hdc, text, strlen((text)), &TextRectangle, DT_CENTER | DT_NOCLIP);
}

/*Force redrawing the window*/
void ELW::UpdateContent()
{
	if (ELWData::CheckIsModeS())
	{
		SetWindowPos(hWnd, NULL, 0, 0, HWND_WIDTH, HWND_HEIGHTS, SWP_NOMOVE | SWP_NOACTIVATE);
		HWND_HEIGHT_CURRENT = HWND_HEIGHTS;
	}
	else
	{
		SetWindowPos(hWnd, NULL, 0, 0, HWND_WIDTH, HWND_HEIGHTC, SWP_NOMOVE | SWP_NOACTIVATE);
		HWND_HEIGHT_CURRENT = HWND_HEIGHTC;
	}
	InvalidateRect(hWnd, NULL, TRUE);
	//RedrawWindow(hWnd, NULL, NULL, RDW_INVALIDATE);
}

// Destructor 
ELW::~ELW()
{
	SendMessage(hWnd, WM_CLOSE, 0, 0);
	WaitForSingleObject(thread, INFINITE);
	CloseHandle(thread);
};


@EDIT: Regarding the messup (as per screenshots), after debugging it crashed with CResourceException. Seems like some leak? This code is heap-allocated.
Last edited on
> thread = CreateThread(0, NULL, ELW::ThreadProc, NULL, NULL, &threadId);
The Win32 GUI API is not thread safe.

How can I create a window if I don't have winmain/dllmain then? Let's say I have a place where constructor (and destructor, if closed) is called from.

I tried to change DWORD WINAPI ELW::ThreadProc(LPVOID lpParam) to int WINAPI ELW::ThreadProcWinApi(HINSTANCE hInst) and call it from the constructor of the class
1
2
3
4
5
6
ELW::ELW()
{
	hInst = GetModuleHandle(NULL);
	// thread = CreateThread(0, NULL, ELW::ThreadProc, NULL, NULL, &threadId);
	ELW::ThreadProcWinApi(hInst);
}

Window opens, but it crashes (does not redraw, hangs, as well as crash once close command is sent called in the destructor:
1
2
3
4
5
6
7
8
9
// Destructor 
ELW::~ELW()
{
	SendMessage(hWnd, WM_CLOSE, 0, 0);
	//WaitForSingleObject(thread, INFINITE);
	//CloseHandle(thread);
	WaitForSingleObject(hInst, INFINITE);
	CloseHandle(hInst);
};


The ELW::UpdateContent() did not change, previously worked properly.
Last edited on
Rearranged some code, found HFONT and HDC leak as well the fact, that I did my double buffer incorrectly.
Last edited on
Registered users can post here. Sign in or register to post.