栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

一、Window程序运行的内部机制

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

一、Window程序运行的内部机制

文章目录
  • 1、API与SDK
  • 2、窗口与句柄
  • 3、消息与消息队列
    • 3.1 消息
    • 3.2 消息队列
    • 3.3 进队消息和不进队消息
  • 4、WinMain函数
    • 4.1 WinMain函数的定义
    • 4.2 窗口的创建
      • 4.2.1 设计一个窗口类
      • 4.2.2 注册窗口类
      • 4.2.3 创建窗口
      • 4.2.4 显示及更新窗口
    • 4.3 消息循环
    • 4.4 编写窗口过程函数
  • 5、动手写第一个Windows程序
  • 6、小结


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 
#include 
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 成员变量,在这个成员的解释中可查到。
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/873077.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号