SDK02- 窗口创建

本文详细介绍了使用SDK在C++中创建窗口的步骤,包括设计注册窗口类、创建窗口实例、显示和更新窗口、理解消息循环和消息队列的工作原理,以及处理鼠标和键盘消息。特别强调了窗口过程函数在响应消息中的关键角色。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

窗口创建的六要素:

  1. 设计注册窗口类
  2. 创建窗口实例
  3. 显示窗口
  4. 更新窗口
  5. 消息循环
  6. 窗口过程函数

设计注册窗口类

typedef struct _WNDCLASS { 
    UINT       style; //风格
    WNDPROC    lpfnWndProc; //函数过程
    int        cbClsExtra; //默认为0
    int        cbWndExtra; //默认为0
    HINSTANCE  hInstance; //实例句柄
    HICON      hIcon; //图标
    HCURSOR    hCursor; //光标
    HBRUSH     hbrBackground; //背景
    LPCTSTR    lpszMenuName; 
    LPCTSTR    lpszClassName; 
} WNDCLASS, *PWNDCLASS; 
#include <Windows.h>

void ShowError();
LRESULT CALLBACK WndProc
(
	HWND hwnd,      // handle to window
	UINT uMsg,      // message identifier
	WPARAM wParam,  // first message parameter
	LPARAM lParam   // second message parameter
)
{
	return 1;
}

int WINAPI WinMain(
	HINSTANCE hInstance,      // handle to current instance
	HINSTANCE hPrevInstance,  // handle to previous instance
	LPSTR lpCmdLine,          // command line
	int nCmdShow              // show state
)
{
	//设计注册窗口类函数

	WNDCLASS wc = { };
	wc.style = CS_VREDRAW | CS_HREDRAW;//默认,当尺寸修改时,通知函数
	wc.lpfnWndProc = WndProc;//窗口过程函数
	wc.cbClsExtra = 0;//默认给0
	wc.cbWndExtra = 0;//默认给0
	wc.hInstance = hInstance;//实例句柄
	wc.hIcon = NULL;//图标
	wc.hCursor = NULL;//光标
	wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);//背景色
	wc.lpszMenuName = NULL;//菜单
	wc.lpszClassName = "窗口";//窗口类名

	if (!RegisterClass(&wc))
	{
		MessageBox(NULL, "注册窗口失败", "提示", MB_OK);
	}
	if (!RegisterClass(&wc))
	{
		
		DWORD nRet = GetLastError();
		ShowError();
	
	}

	return 0;
}

void ShowError()
{
	LPVOID lpMsgBuf;
	FormatMessage(
		FORMAT_MESSAGE_ALLOCATE_BUFFER |
		FORMAT_MESSAGE_FROM_SYSTEM |
		FORMAT_MESSAGE_IGNORE_INSERTS,
		NULL,
		GetLastError(),
		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
		(LPTSTR)&lpMsgBuf,
		0,
		NULL
	);
	// Process any inserts in lpMsgBuf.
	// ...
	// Display the string.
	MessageBox(NULL, (LPCTSTR)lpMsgBuf, "Error", MB_OK | MB_ICONINFORMATION);
	// Free the buffer.
	LocalFree(lpMsgBuf);

}


总结:风格、标志用位运算存储

创建窗口实例

HWND CreateWindow(
  LPCTSTR lpClassName,  // registered class name
  LPCTSTR lpWindowName, // window name
  DWORD dwStyle,        // window style
  int x,                // horizontal position of window
  int y,                // vertical position of window
  int nWidth,           // window width
  int nHeight,          // window height
  HWND hWndParent,      // handle to parent or owner window
  HMENU hMenu,          // menu handle or child identifier
  HINSTANCE hInstance,  // handle to application instance
  LPVOID lpParam        // window-creation data
);

#include <Windows.h>

void ShowError();
LRESULT CALLBACK WndProc
(
	HWND hwnd,      // handle to window
	UINT uMsg,      // message identifier
	WPARAM wParam,  // first message parameter
	LPARAM lParam   // second message parameter
)
{
	return 1;
}

int WINAPI WinMain(
	HINSTANCE hInstance,      // handle to current instance
	HINSTANCE hPrevInstance,  // handle to previous instance
	LPSTR lpCmdLine,          // command line
	int nCmdShow              // show state
)
{
	//设计注册窗口类函数

	WNDCLASS wc = { };
	wc.style = CS_VREDRAW | CS_HREDRAW;//默认,当尺寸修改时,通知函数
	wc.lpfnWndProc = WndProc;//窗口过程函数
	wc.cbClsExtra = 0;//默认给0
	wc.cbWndExtra = 0;//默认给0
	wc.hInstance = hInstance;//实例句柄
	wc.hIcon = NULL;//图标
	wc.hCursor = NULL;//光标
	wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);//背景色
	wc.lpszMenuName = NULL;//菜单
	wc.lpszClassName = "窗口";//窗口类名

	if (!RegisterClass(&wc))
	{
		MessageBox(NULL, "注册窗口失败", "提示", MB_OK);
	}
	/*if (!RegisterClass(&wc))
	{

		DWORD nRet = GetLastError();
		ShowError();

	}*/

	//2、创建窗口实例
	HWND hWnd = CreateWindow("窗口",  // 窗口类类名
		"第一个窗口", // 窗口标题
		WS_OVERLAPPEDWINDOW,//重叠窗口、带标题、系统菜单
		CW_USEDEFAULT,//默认位置
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		NULL,//父窗口
		NULL,//菜单
		hInstance,//实例句柄
		NULL //消息参数
	);
	if (hWnd == NULL)
	{
		ShowError();
		return 0;
	}

	return 0;
}

void ShowError()
{
	LPVOID lpMsgBuf;
	FormatMessage(
		FORMAT_MESSAGE_ALLOCATE_BUFFER |
		FORMAT_MESSAGE_FROM_SYSTEM |
		FORMAT_MESSAGE_IGNORE_INSERTS,
		NULL,
		GetLastError(),
		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
		(LPTSTR)&lpMsgBuf,
		0,
		NULL
	);
	// Process any inserts in lpMsgBuf.
	// ...
	// Display the string.
	MessageBox(NULL, (LPCTSTR)lpMsgBuf, "Error", MB_OK | MB_ICONINFORMATION);
	// Free the buffer.
	LocalFree(lpMsgBuf);

}

显示窗口

BOOL ShowWindow(  HWND hWnd,     // handle to window
  int nCmdShow   // show state);

更新窗口

BOOL UpdateWindow(  HWND hWnd   // handle to window);

消息循环

消息和消息队列

1、消息

在Windows中,不仅用户程序可以调用系统的API函数,反过来,系统也会调用用户程序,这个调用是通过消息来进行的。将响应的事件包装成一个消息,投递到应用程序的消息队列中,然后应用程序从消息队列中取出消息并进行响应。这个处理的过程就是操作系统调用程序中一个专门负责处理消息的函数,这个函数就称为窗口过程函数。

BOOL GetMessage( 
  LPMSG lpMsg,         // message information
  HWND hWnd,           // handle to window
  UINT wMsgFilterMin,  // first message  UINT wMsgFilterMax   // last message);

消息是由MSG结构体来表示的

typedef struct tagMSG {
  HWND   hwnd;  //标识窗口
  UINT   message; //消息的标识符 例如:WM_KEYDOWN
  WPARAM wParam; 
  LPARAM lParam; 
  DWORD  time; 
  POINT  pt; 
} MSG, *PMSG; 

wParam和lParam 用于指定消息的附加消息。
time 和 pt表示消息投递到消息队列中的时间和鼠标的当前位置。

2、消息队列

当一个Windows程序执行时,系统都会为该程序创建一个消息队列,这个消息队列用来存放该程序创建窗口的消息。Windows将产生的消息依次放到消息队列中,应用程序通过一个消息循环不断地从消息队列中取出消息,并进行响应。

3、进队消息和不进队消息

进队消息将由系统放入应用程序的消息队列中,由应用程序取出并发送。不进队的消息在系统调用窗口过程时直接发送给窗口。不管是进队消息还是不进队消息,最终都由系统调用窗口过程函数对消息队列进行处理。

LRESULT DefWindowProc(  HWND hWnd,      // handle to window
  UINT Msg,       // message identifier
  WPARAM wParam,  // first message parameter
  LPARAM lParam   // second message parameter);


LRESULT DispatchMessage(  CONST MSG *lpmsg   // message information);
VOID PostQuitMessage(  int nExitCode   // exit code);

窗口过程函数

LRESULT CALLBACK WindowProc(  HWND hwnd,      // handle to window
  UINT uMsg,      // message identifier
  WPARAM wParam,  // first message parameter
  LPARAM lParam   // second message parameter);

WM_DESTROY消息是在窗口被销毁时发送的。 在窗口从屏幕上删除后,它被发送到正在被销毁的窗口的窗口过程。
此消息首先发送到被销毁的窗口,然后发送到被销毁的子窗口(如果有的话)。 在处理消息期间,可以假定所有子窗口仍然存在。

LRESULT CALLBACK WndProc
(
	HWND hwnd,      // handle to window
	UINT uMsg,      // message identifier
	WPARAM wParam,  // first message parameter
	LPARAM lParam   // second message parameter
)
{
	switch (uMsg)
	{
	case WM_DESTROY: //销毁窗口的消息
		PostQuitMessage(0);//退出消息循环
		break;
	default:
		break;
	}
	return DefWindowProc(hwnd,uMsg,wParam,lParam);
}

实例总代码:

#include <Windows.h>

void ShowError();
LRESULT CALLBACK WndProc
(
	HWND hwnd,      // handle to window
	UINT uMsg,      // message identifier
	WPARAM wParam,  // first message parameter
	LPARAM lParam   // second message parameter
)
{
	switch (uMsg)
	{
	case WM_DESTROY: //销毁窗口的消息
		PostQuitMessage(0);//退出消息循环
		break;
	default:
		break;
	}
	return DefWindowProc(hwnd,uMsg,wParam,lParam);
}

int WINAPI WinMain(
	HINSTANCE hInstance,      // handle to current instance
	HINSTANCE hPrevInstance,  // handle to previous instance
	LPSTR lpCmdLine,          // command line
	int nCmdShow              // show state
)
{
	//设计注册窗口类函数

	WNDCLASS wc = { };
	wc.style = CS_VREDRAW | CS_HREDRAW;//默认,当尺寸修改时,通知函数
	wc.lpfnWndProc = WndProc;//窗口过程函数
	wc.cbClsExtra = 0;//默认给0
	wc.cbWndExtra = 0;//默认给0
	wc.hInstance = hInstance;//实例句柄
	wc.hIcon = NULL;//图标
	wc.hCursor = NULL;//光标
	wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);//背景色
	wc.lpszMenuName = NULL;//菜单
	wc.lpszClassName = "窗口";//窗口类名

	if (!RegisterClass(&wc))
	{
		MessageBox(NULL, "注册窗口失败", "提示", MB_OK);
	}
	/*if (!RegisterClass(&wc))
	{

		DWORD nRet = GetLastError();
		ShowError();

	}*/

	//2、创建窗口实例
	HWND hWnd = CreateWindow("窗口",  // 窗口类类名
		"第一个窗口", // 窗口标题
		WS_OVERLAPPEDWINDOW,//重叠窗口、带标题、系统菜单  WS_VISIBLE显示窗口
		CW_USEDEFAULT,//默认位置
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		NULL,//父窗口
		NULL,//菜单
		hInstance,//实例句柄
		NULL //消息参数
	);
	if (hWnd == NULL)
	{
		ShowError();
		return 0;
	}

	//显示窗口
	ShowWindow(hWnd, SW_SHOW);

	//更新窗口

	UpdateWindow(hWnd ); //立即绘制

	//消息循环
	MSG msg = {};
	while (GetMessage(&msg, NULL, 0, 0))
	{
		DispatchMessage(&msg);
	}
		
	return 0;
}

void ShowError()
{
	LPVOID lpMsgBuf;
	FormatMessage(
		FORMAT_MESSAGE_ALLOCATE_BUFFER |
		FORMAT_MESSAGE_FROM_SYSTEM |
		FORMAT_MESSAGE_IGNORE_INSERTS,
		NULL,
		GetLastError(),
		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
		(LPTSTR)&lpMsgBuf,
		0,
		NULL
	);
	// Process any inserts in lpMsgBuf.
	// ...
	// Display the string.
	MessageBox(NULL, (LPCTSTR)lpMsgBuf, "Error", MB_OK | MB_ICONINFORMATION);
	// Free the buffer.
	LocalFree(lpMsgBuf);

}

窗口销毁

LRESULT CALLBACK WndProc
(
	HWND hwnd,      // handle to window
	UINT uMsg,      // message identifier
	WPARAM wParam,  // first message parameter
	LPARAM lParam   // second message parameter
)
{
	switch (uMsg)
	{
	case WM_DESTROY: //销毁窗口的消息
		PostQuitMessage(0);//退出消息循环
		return 0;
	case WM_CLOSE:
		int Ret = MessageBox(hwnd, "是否确认退出", "提示", MB_YESNO);
		switch (Ret)
		{
		case IDYES:
			DestroyWindow(hwnd);
			break;
		case IDNO:
			break;
		}
		return 0;
	}
	return DefWindowProc(hwnd,uMsg,wParam,lParam);
}

鼠标消息

当用户按下鼠标左键而光标位于窗口的客户端区域时,WM_LBUTTONDOWN消息被发布。 如果鼠标未被捕获,则消息将被发送到光标下方的窗口。 否则,消息将被发送到捕获鼠标的窗口。

xPos = GET_X_LPARAM(lParam); 
yPos = GET_Y_LPARAM(lParam); 
WORD nX = LOWORD(lParam);
WORD nY = HIWORD(lParam);

键盘消息:

当按下非系统键时,WM_KEYDOWN消息被发送到带有键盘焦点的窗口。 非系统键是指未按下ALT键时按下的键。

LRESULT CALLBACK WindowProc(
  HWND hwnd,       // handle to window
  UINT uMsg,       // WM_KEYDOWN
  WPARAM wParam,   // virtual-key code
  LPARAM lParam    // key data
);

只能显示大写字母,使用WM_CHAR可转化大写
当WM_KEYDOWN消息被TranslateMessage函数翻译时,WM_CHAR消息被发送到带有键盘焦点的窗口。 WM_CHAR消息包含被按下的键的字符代码。

BOOL TranslateMessage(  
CONST MSG *lpMsg   // message information
);

TranslateMessage(&msg);
实列代码

HINSTANCE hinst; 
HWND hwndMain; 
 
int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, 
    LPSTR lpszCmdLine, int nCmdShow) 
{ 
    MSG msg;
    BOOL bRet; 
    WNDCLASS wc; 
    UNREFERENCED_PARAMETER(lpszCmdLine); 
 
    // Register the window class for the main window. 
 
    if (!hPrevInstance) 
    { 
        wc.style = 0; 
        wc.lpfnWndProc = (WNDPROC) WndProc; 
        wc.cbClsExtra = 0; 
        wc.cbWndExtra = 0; 
        wc.hInstance = hInstance; 
        wc.hIcon = LoadIcon((HINSTANCE) NULL, 
            IDI_APPLICATION); 
        wc.hCursor = LoadCursor((HINSTANCE) NULL, 
            IDC_ARROW); 
        wc.hbrBackground = GetStockObject(WHITE_BRUSH); 
        wc.lpszMenuName =  "MainMenu"; 
        wc.lpszClassName = "MainWndClass"; 
 
        if (!RegisterClass(&wc)) 
            return FALSE; 
    } 
 
    hinst = hInstance;  // save instance handle 
 
    // Create the main window. 
 
    hwndMain = CreateWindow("MainWndClass", "Sample", 
        WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 
        CW_USEDEFAULT, CW_USEDEFAULT, (HWND) NULL, 
        (HMENU) NULL, hinst, (LPVOID) NULL); 
 
    // If the main window cannot be created, terminate 
    // the application. 
 
    if (!hwndMain) 
        return FALSE; 
 
    // Show the window and paint its contents. 
 
    ShowWindow(hwndMain, nCmdShow); 
    UpdateWindow(hwndMain); 
 
    // Start the message loop. 
 
    while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
    { 
        if (bRet == -1)
        {
            // handle the error and possibly exit
        }
        else
        {
            TranslateMessage(&msg); 
            DispatchMessage(&msg); 
        }
    } 
 
    // Return the exit code to the system. 
 
    return msg.wParam; 
} 

总代码:

#include <Windows.h>

void ShowError();
LRESULT CALLBACK WndProc
(
	HWND hwnd,      // handle to window
	UINT uMsg,      // message identifier
	WPARAM wParam,  // first message parameter
	LPARAM lParam   // second message parameter
)
{
	switch (uMsg)
	{
	case WM_CHAR:
	{
		char szBuff[MAXBYTE] = {};
		wsprintf(szBuff, "虚拟码:%d 字符:%c ", wParam, wParam);
		MessageBox(hwnd, szBuff, "WM_CHAR", MB_OK);
		return 0;
	}
	/*case WM_KEYDOWN:
	{
		char szBuff[MAXBYTE] = {};
		wsprintf(szBuff, "虚拟码:%d 字符:%c ", wParam, wParam);
		MessageBox(hwnd, szBuff, "WM_KEYDOWN", MB_OK);
		return 0;
	}*/
	case WM_LBUTTONDOWN:
	{
		WORD nX = LOWORD(lParam);
		WORD nY = HIWORD(lParam);
		char szBuff[MAXBYTE] = {};
		wsprintf(szBuff, "x:%d y:%d ", nX, nY);
		MessageBox(hwnd, szBuff, "鼠标坐标", MB_OK);
		return 0;

	}
		
	case WM_DESTROY: //销毁窗口的消息
	{
		PostQuitMessage(0);//退出消息循环
		return 0;
	}
	case WM_CLOSE:
	{
		int Ret = MessageBox(hwnd, "是否确认退出", "提示", MB_YESNO);
		switch (Ret)
		{
		case IDYES:
		{
			DestroyWindow(hwnd);
			break;
		}
		case IDNO:
		{
			break;
		}
			
		}
		return 0;
	}
	}
	return DefWindowProc(hwnd,uMsg,wParam,lParam);
}

int WINAPI WinMain(
	HINSTANCE hInstance,      // handle to current instance
	HINSTANCE hPrevInstance,  // handle to previous instance
	LPSTR lpCmdLine,          // command line
	int nCmdShow              // show state
)
{
	//设计注册窗口类函数

	WNDCLASS wc = { };
	wc.style = CS_VREDRAW | CS_HREDRAW;//默认,当尺寸修改时,通知函数
	wc.lpfnWndProc = WndProc;//窗口过程函数
	wc.cbClsExtra = 0;//默认给0
	wc.cbWndExtra = 0;//默认给0
	wc.hInstance = hInstance;//实例句柄
	wc.hIcon = NULL;//图标
	wc.hCursor = NULL;//光标
	wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);//背景色
	wc.lpszMenuName = NULL;//菜单
	wc.lpszClassName = "窗口";//窗口类名

	if (!RegisterClass(&wc))
	{
		MessageBox(NULL, "注册窗口失败", "提示", MB_OK);
	}
	/*if (!RegisterClass(&wc))
	{

		DWORD nRet = GetLastError();
		ShowError();

	}*/

	//2、创建窗口实例
	HWND hWnd = CreateWindow("窗口",  // 窗口类类名
		"第一个窗口", // 窗口标题
		WS_OVERLAPPEDWINDOW,//重叠窗口、带标题、系统菜单  WS_VISIBLE显示窗口
		CW_USEDEFAULT,//默认位置
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		NULL,//父窗口
		NULL,//菜单
		hInstance,//实例句柄
		NULL //消息参数
	);
	if (hWnd == NULL)
	{
		ShowError();
		return 0;
	}

	//显示窗口
	ShowWindow(hWnd, SW_SHOW);

	//更新窗口

	UpdateWindow(hWnd ); //立即绘制

	//消息循环
	MSG msg = {};
	while (GetMessage(&msg, NULL, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
		
	return 0;
}

void ShowError()
{
	LPVOID lpMsgBuf;
	FormatMessage(
		FORMAT_MESSAGE_ALLOCATE_BUFFER |
		FORMAT_MESSAGE_FROM_SYSTEM |
		FORMAT_MESSAGE_IGNORE_INSERTS,
		NULL,
		GetLastError(),
		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
		(LPTSTR)&lpMsgBuf,
		0,
		NULL
	);
	// Process any inserts in lpMsgBuf.
	// ...
	// Display the string.
	MessageBox(NULL, (LPCTSTR)lpMsgBuf, "Error", MB_OK | MB_ICONINFORMATION);
	// Free the buffer.
	LocalFree(lpMsgBuf);

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

黑桃鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值