First knowledge of Windows programming

I am a beginner with limited level. I write blog mainly to record my learning track. Refer to msdn for code introduction. If there are errors or omissions, please criticize and correct. Thank you for reading!

1. Basic understanding of Windows programming

The simplest windows programming calls some user state API s in windows, mostly user32 dll GDI32. DLL functions in these two library files.

MFC is a class library to C++ Class encapsulates Windows API And includes an application framework to reduce the workload of developers. The classes included include a large number of Windows handle encapsulation classes and many Windows built-in control and assembly Encapsulation class for. MFC is WIN API Combined with C + +, it is not only a page development system, but also contains many classes. The function of many classes is not an interface class. It does not realize the control of a window object. Some classes are processed inside windows.

2. Understanding process of basic framework

After understanding the basic knowledge of c language, the author tries to read the basic framework code.

Each c language program has its own main function, and the based win32 program has WinMain function as the entry point of the program. The basic code is as follows

int CALLBACK WinMain(  
  _In_ HINSTANCE hInstance,  //handle to the current instance
  _In_ HINSTANCE hPrevInstance,  //handle to the previous instance
  _In_ LPSTR     lpCmdLine,  // command line of the application
  _In_ int       nCmdShow  // control how the window to be shown
);

In winmain, create the struct of WNDCLASSEX, which contains the basic information of a window. The basic code is as follows

WNDCLASSEX wcex;  

wcex.cbSize = sizeof(WNDCLASSEX);  
wcex.style          = CS_HREDRAW | CS_VREDRAW;  
wcex.lpfnWndProc    = WndProc;  
wcex.cbClsExtra     = 0;  
wcex.cbWndExtra     = 0;  
wcex.hInstance      = hInstance;  
wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION));  
wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);  
wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);  
wcex.lpszMenuName   = NULL;  
wcex.lpszClassName  = szWindowClass;  
wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_APPLICATION));

After that, you need to register the window (its meaning is a bit similar to writing function definitions before the main program). The basic code is as follows

if (!RegisterClassEx(&wcex))  
{  
    MessageBox(NULL,  
        _T("Call to RegisterClassEx failed!"),  
        _T("Win32 Guided Tour"),  
        NULL);  

    return 1;  
}

After registering the window, we can create the window. The return value of create window is HWND, handle to the window, which is used to track the window.

static TCHAR szWindowClass[] = _T("win32app");  
static TCHAR szTitle[] = _T("Win32 Guided Tour Application");  

// The parameters to CreateWindow explained:  
// szWindowClass: the name of the application  
// szTitle: the text that appears in the title bar  
// WS_OVERLAPPEDWINDOW: the type of window to create  
// CW_USEDEFAULT, CW_USEDEFAULT: initial position (x, y)  
// 500, 100: initial size (width, length)  
// NULL: the parent of this window  
// NULL: this application does not have a menu bar  
// hInstance: the first parameter from WinMain  
// NULL: not used in this application  
HWND hWnd = CreateWindow(  
    szWindowClass,  
    szTitle,  
    WS_OVERLAPPEDWINDOW,  
    CW_USEDEFAULT, CW_USEDEFAULT,  
    500, 100,  
    NULL,  
    NULL,  
    hInstance,  
    NULL  
);  
if (!hWnd)  
{  
    MessageBox(NULL,  
        _T("Call to CreateWindow failed!"),  
        _T("Win32 Guided Tour"),  
        NULL);  

    return 1;  
}

Then we show this window and let it update

// The parameters to ShowWindow explained:  
// hWnd: the value returned from CreateWindow  
// nCmdShow: the fourth parameter from WinMain  
ShowWindow(hWnd,  
    nCmdShow);  
UpdateWindow(hWnd);

Next, add a message loop to retrieve window related messages from the message queue, and send the received messages to WndProc for processing

window application is a message based programming mode, which uses events to drive programming mode. The so-called message loop is actually a program loop that receives messages from the message queue, retrieves messages, and sends them to WndProc.

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

return (int) msg.wParam;

In addition, we also need a windows procedure function. We are used to calling it WndProc. The basic code is as follows

LRESULT CALLBACK WndProc(  
  _In_ HWND   hwnd,  
  _In_ UINT   uMsg,  
  _In_ WPARAM wParam,  
  _In_ LPARAM lParam  
);

In windows programs, when an event occurs, WinProc is used to handle an event. The pattern inside is similar to a switch. There are multiple case s in it. Different responses are made according to the received messages.

Examples are as follows:

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	switch (message)
	{
	case WM_CREATE:
		// Initialize form
		InitGame(hWnd, wParam, lParam);
		break;
	case WM_KEYDOWN:
		// Keyboard press event
		KeyDown(hWnd, wParam, lParam);
		break;
	case WM_KEYUP:
		// Keyboard release event
		KeyUp(hWnd, wParam, lParam);
		break;
	case WM_MOUSEMOVE:
		// Mouse movement event
		MouseMove(hWnd, wParam, lParam);
		break;
	case WM_LBUTTONDOWN:
		// Left mouse button press event
		LButtonDown(hWnd, wParam, lParam);
		break;
	case WM_LBUTTONUP:
		// Left mouse button release event
		LButtonUp(hWnd, wParam, lParam);
		break;
	case WM_TIMER:
		// timer event 
		if (currentStage != NULL && currentStage->timerOn) TimerUpdate(hWnd, wParam, lParam);
		break;
	case WM_PAINT:
		// mapping
		Paint(hWnd);
		break;
	case WM_DESTROY:
        //sign out
		PostQuitMessage(0);
		break;
	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}
	return 0;
}

3.little  pieces

(1) Double buffer drawing

WM in WndProc encountered by the author in his study_ Paint function, which involves double buffer drawing.

Because in WM_ In paint, when drawing graphics, the program responds quite frequently. Every time OnEraseBKgnd is executed, the image on the original screen must be erased, then filled with background color, and finally redrawn. This will not only cause the problem that the drawing takes too long, but also cause flickering on the screen during the drawing process. Therefore, we thought of drawing the picture into the memory buffer first, and then using BitBlt to copy it to the screen. BitBlt is fast, so it can display the picture on the screen as a whole. The example code is as follows

void Paint(HWND hWnd)
{

	PAINTSTRUCT ps;
	HDC hdc_window = BeginPaint(hWnd, &ps);

	HDC hdc_memBuffer = CreateCompatibleDC(hdc_window);
	HDC hdc_loadBmp = CreateCompatibleDC(hdc_window);

	//Initialize cache
	HBITMAP	blankBmp = CreateCompatibleBitmap(hdc_window, WINDOW_WIDTH, WINDOW_HEIGHT);
	SelectObject(hdc_memBuffer, blankBmp);

	// Draw background to cache
	SelectObject(hdc_loadBmp, bmp_Background);

	BitBlt(hdc_memBuffer, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, hdc_loadBmp, 0, 0, SRCCOPY);
    
    //need to do


    // Finally, draw all the information on the screen
	BitBlt(hdc_window, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, hdc_memBuffer, 0, 0, SRCCOPY);

	// Reclaim memory occupied by resources (very important)
	DeleteObject(blankBmp);
	DeleteDC(hdc_memBuffer);
	DeleteDC(hdc_loadBmp);

	// End drawing
	EndPaint(hWnd, &ps);
}

To be updated

                                            

Keywords: C++ Windows microsoft

Added by davelr459 on Mon, 03 Jan 2022 15:31:12 +0200