IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 一、Window程序运行的内部机制 -> 正文阅读

[C++知识库]一、Window程序运行的内部机制


1、API与SDK

  • API
    Windows操作系统提供了各种各样的函数,以方便我们开发Windows应用程序。这些函数是Windows操作系统提供给应用程序编程的接口(Application Programming Interface)API

  • SDK
    那么什么是SDK呢?SDK实际上是开发所需资源的一个集合。
    假如我们要开发呼叫中心,在购买语音卡的同时,厂商就会提供语音卡的SDK开发包,以方便我们对语音卡的编程操作,这个开发包通常会包含语音卡的API函数库、帮助文档、使用手册、辅助工具等资源。


2、窗口与句柄

一个应用程序窗口通常都包含标题栏、菜单栏、系统菜单、最小化框、最大化框、可调边框,有的还有滚动条。
在这里插入图片描述
在 Windows 应用程序中,窗口是通过窗口句柄(HWND)来标识的。我们要对某个窗口进行操作,首先就要得到这个窗口的句柄。

句柄(HANDLE)是 Windows 程序中一个重要的概念,使用也非常频繁。

句柄包括如下:

  • 窗口句柄(HWND)
  • 图标句柄(HICON)
  • 光标句柄(HCURSOR)
  • 刷句柄(HBRUSH)

3、消息与消息队列

Windows 程序设计是一种完全不同于传统的 DOS 方式的程序设计方法。它是一种事件驱动方式的程序设计模式,主要是基于消息的。例如,当用户在窗口中画图的时候,按下鼠标左键,此时,操作系统会感知到这一事件,于是将这个事件包装成一个消息,投递到应用程序的消息队列中,然后应用程序从消息队列中取出消息并进行响应。在这个处理过程中,操作系统也会给应用程序“发送消息”。所谓“发送消息”,实际上是操作系统调用程序中一个专门负责处理消息的函数,这个函数称为窗口过程。

3.1 消息

在 Windows 程序中,消息是由 MSG 结构体来表示的。

typedef struct tagMSG {
    HWND        hwnd;       //表示消息所属的窗口
    UINT        message;    //指定了消息的标识符
    WPARAM      wParam;     //指定消息的附加信息
    LPARAM      lParam;     //指定消息的附加信息
    DWORD       time;       //投递到消息队列中的时间
    POINT       pt;         //鼠标的当前位置
#ifdef _MAC
    DWORD       lPrivate;
#endif
} MSG, *PMSG, NEAR *NPMSG, FAR *LPMSG;

3.2 消息队列

每一个 Windows 应用程序开始执行后,系统都会为该程序创建一个消息队列,这个消息队列用来存放该程序创建的窗口的消息。Windows 将产生的消息依次放到消息队列中,而应用程序则通过一个消息循环不断地从消息队列中取出消息,并进行响应。这种消息机制,就是 Windows程序运行的机制。

3.3 进队消息和不进队消息

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

4、WinMain函数

WinMain 是 Windows程序的入口点函数,与 DOS 程序的入口点函数 main 的作用相同,当 WinMain 函数结束或返回时,Windows 应用程序结束。

一个完整的Win32程序实现步骤:

  1. WinMain函数的定义
  2. 创建一个窗口
  3. 进行消息循环
  4. 编写窗口过程函数

4.1 WinMain函数的定义

int WINAPI WinMain(
 HINSTANCE hInstance,      // handle to current instance
 HINSTANCE hPrevInstance,  // handle to previous instance
 LPSTR lpCmdLine,          // command line
 int nCmdShow              // show state
);

4.2 窗口的创建

创建一个完整的窗口,需要经过下面几个操作步骤:

  1. 设计一个窗口类;
  2. 注册窗口类;
  3. 创建窗口;
  4. 显示及更新窗口。

4.2.1 设计一个窗口类

typedef struct _WNDCLASS { 
 UINT style; 
 WNDPROC lpfnWndProc; 
 int cbClsExtra; 
 int cbWndExtra; 
 HANDLE hInstance; 
 HICON hIcon; 
 HCURSOR hCursor; 
 HBRUSH hbrBackground; 
 LPCTSTR lpszMenuName; 
 LPCTSTR lpszClassName; 
} WNDCLASS; 

4.2.2 注册窗口类

ATOM RegisterClass(CONST WNDCLASS *lpWndClass);

4.2.3 创建窗口

HWND CreateWindow(
 LPCTSTR lpClassName, 		// pointer to registered class name
 LPCTSTR lpWindowName, 		// pointer to 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, 				// handle to menu or child-window identifier
 HANDLE hInstance, 			// handle to application instance
 LPVOID lpParam 			// pointer to window-creation data
);

4.2.4 显示及更新窗口

(1)显示窗口

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

(2)更新窗口

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

4.3 消息循环

在创建窗口、显示窗口、更新窗口后,我们需要编写一个消息循环,不断地从消息队列中取出消息,并进行响应。要从消息队列中取出消息,我们需要调用 GetMessage()函数,该函数的原型声明如下:

BOOL GetMessage(
LPMSG lpMsg, 			// address of structure with message
HWND hWnd, 				// handle of window
UINT wMsgFilterMin, 	// first message
UINT wMsgFilterMax 		// last message
);
//通常我们编写的消息循环代码如下:
MSG msg;
while(GetMessage(&msg,NULL,0,0))
{
 TranslateMessage(&msg);  //用于将虚拟键消息转换为字符消息
 DispatchMessage(&msg);   //分派一个消息到窗口过程
}

Windows应用程序的消息处理机制
在这里插入图片描述

  1. 操作系统接收到应用程序的窗口消息,将消息投递到该应用程序的消息队列中。
  2. 应用程序在消息循环中调用 GetMessage 函数从消息队列中取出一条一条的消息。取出消息后,应用程序可以对消息进行一些预处理,例如,放弃对某些消息的响应,或者调用 TranslateMessage 产生新的消息。
  3. 应用程序调用 DispatchMessage,将消息回传给操作系统。消息是由 MSG 结构体对象来表示的,其中就包含了接收消息的窗口的句柄。因此,DispatchMessage 函数总能进行正确的传递。
  4. 系统利用 WNDCLASS 结构体的 lpfnWndProc 成员保存的窗口过程函数的指针调用窗口过程,对消息进行处理(即“系统给应用程序发送了消息”)。
    以上就是 Windows 应用程序的消息处理过程。

4.4 编写窗口过程函数

在完成上述步骤后,剩下的工作就是编写一个窗口过程函数,用于处理发送给窗口的消息。一个 Windows 应用程序的主要代码部分就集中在窗口过程函数中。在 MSDN 中可以查到窗口过程函数的声明形式,如下所示:

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

5、动手写第一个Windows程序

在这里插入图片描述
在这里插入图片描述
修改项目属性
在这里插入图片描述

#include <windows.h>
#include <stdio.h>
LRESULT CALLBACK WinSunProc(
	HWND hwnd, // handle to window
	UINT uMsg, // message identifier
	WPARAM wParam, // first message parameter
	LPARAM lParam // second message parameter
);
int WINAPI WinMain(
	HINSTANCE hInstance, // handle to current instance
	HINSTANCE hPrevInstance, // handle to previous instance
	LPSTR lpCmdLine, // command line
	int nCmdShow // show state
)
{
	//设计一个窗口类
	WNDCLASS wndcls;
	wndcls.cbClsExtra = 0;
	wndcls.cbWndExtra = 0;
	wndcls.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
	wndcls.hCursor = LoadCursor(NULL, IDC_CROSS);
	wndcls.hIcon = LoadIcon(NULL, IDI_ERROR);
	wndcls.hInstance = hInstance; //应用程序实例句柄由 WinMain 函数传进来
	wndcls.lpfnWndProc = WinSunProc;
	wndcls.lpszClassName = "sunxin2006";
	wndcls.lpszMenuName = NULL;
	wndcls.style = CS_HREDRAW | CS_VREDRAW;
	RegisterClass(&wndcls);
	//创建窗口,定义一个变量用来保存成功创建窗口后返回的句柄
	HWND hwnd;
	hwnd = CreateWindow("sunxin2006", "http://www.sunxin.org",
		WS_OVERLAPPEDWINDOW, 0, 0, 600, 400, NULL, NULL, hInstance, NULL);
	//显示及刷新窗口
	ShowWindow(hwnd, SW_SHOWNORMAL);
	UpdateWindow(hwnd);
	//定义消息结构体,开始消息循环
	MSG msg;
	BOOL bRet;
	while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0)
	{
		if (bRet == -1) {
			return -1;
		}
		else {
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
	}
	return msg.wParam;
}
//编写窗口过程函数
LRESULT CALLBACK WinSunProc(
	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 szChar[20];
		sprintf_s(szChar, "char code is %d", wParam);
		MessageBox(hwnd, szChar, "char", 0);
		break;
	case WM_LBUTTONDOWN:
		MessageBox(hwnd, "mouse clicked", "message", 0);
		HDC hdc;
		hdc = GetDC(hwnd); //不能在响应 WM_PAINT 消息时调用
		TextOut(hdc, 0, 50, "程序员之家", strlen("程序员之家"));
		//ReleaseDC(hwnd,hdc);
		break;
	case WM_PAINT:
		HDC hDC;
		PAINTSTRUCT ps;
		hDC = BeginPaint(hwnd, &ps); //BeginPaint 只能在响应 WM_PAINT 消息时调用
		TextOut(hDC, 0, 0, "http://www.sunxin.org", strlen("http://www.sunxin.org"));
		EndPaint(hwnd, &ps);
		break;
	case WM_CLOSE:
		if (IDYES == MessageBox(hwnd, "是否真的结束?", "message", MB_YESNO))
		{
			DestroyWindow(hwnd);
		}
		break;
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	default:
		return DefWindowProc(hwnd, uMsg, wParam, lParam);
	}
	return 0;
}

6、小结

创建一个 Win32 应用程序的步骤。

  1. 编写 WinMain 函数,可以在 MSDN 上查找并复制。
  2. 设计窗口类(WNDCLASS)。
  3. 注册窗口类。
  4. 创建窗口。
  5. 显示并更新窗口。
  6. 编写消息循环。
  7. 编写窗口过程函数。窗口过程函数的语法,可通过 MSDN 查看 WNDCLASS 的lpfnWndProc 成员变量,在这个成员的解释中可查到。
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-05-12 16:18:51  更:2022-05-12 16:19:09 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 19:10:39-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码