Windows程序运行原理(总结)

时间:2022-12-23 21:37:28

写这个博客的目的仅仅是为自己编程学习过程中作一些总结,时不时来回顾,里面也有没搞明白的,希望在今后积累够后,回来看看能够豁然开朗


1、消息及消息队列:操作系统是将感知到的事件传递给应用程序。

操作系统给出了消息结构体MSG:  和哪一个窗口相关,消息本身是什么,消息的附加参数是什么,消息发生投递的时间是什么,消息投递时当前光标的位置

typedef struct tagMSG {       
    	HWND   hwnd;      
    	UINT   message; //用一个整数标示一个消息,定义了宏用来表示数字,如按键消息,鼠标左键下按 WM_LBUTTONDOWN这个宏来表示数字就比较好记忆,
    	WPARAM wParam;  //变量类型整数,指示消息的附加信息,具体的按键信息:如键盘按键的ASCIA码,获取具体字符
    	LPARAM lParam;  <span style="font-family: Arial, Helvetica, sans-serif;">//变量类型整数,指示消息的附加信息</span>
    	DWORD  time;   //32位整数,doubleWord
    	POINT  pt;     // 当信息别投递时,当前光标的位置,
} MSG; 

句柄(HANDLE),资源的标示,包括图标(HICON)、光标(HCurSOR)、窗口(HWND)、应用程序实例句柄(HINSTANCE)等

即给各种资源一个标示号,操作系统方便管理。

如HWND,是一个窗口句柄,操作系统通过这个句柄可以管理这个窗口的内容。操作系统是用句柄去索引的内存当中的资源。


2、每一个应用程序,操作系统都会为其建立一个消息队列,先进先出的缓冲区

3、Windows程序的入口函数

int WINAPI WinMain(
  HINSTANCE hInstance,      // handle to current instance   应用程序实例句柄,代表
  HINSTANCE hPrevInstance,  // handle to previous instance
  LPSTR lpCmdLine,          // command line       LP STR 指向字符串的指针        
  int nCmdShow              // show state
);

4、窗口创建

      a、设计一个窗口类;

      b、注册窗口类;

      c、创建窗口;

      d、显示及更新窗口



#include "stdafx.h"
#include <Windows.h>
#include <stdio.h>
#pragma(lib, "MSVCRTD.lib");


LRESULT CALLBACK WinSunProc(HWND hwnd,      //窗口句柄
	UINT wMsg,       //message identifier
	WPARAM wParam,   // first message parameter
	LPARAM lParam);   //second message parameter



int WINAPI WinMain(HINSTANCE hInstance, //应用程序实例句柄
				   HINSTANCE hPrevInstance, //先前应用程序的句柄
				   LPSTR lpCmdLine,        //
				   int nCmdShow)
{
	//设计一个窗口类
	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;
	wndcls.lpfnWndProc = WinSunProc;
	
	
	//代码在VC6中没问题. 因为它的代码没有按可编译为UNICODE版本的方式写,而VS2005之后版本默认是UNICODE编码的.所以所有使用到字串的地方都会出错.
	//方法:修改VS2005之后版本的设置:选择你的项目->属性->常规->设置为不使用UNICODE,发现设置为多字节字符集也可以。发现用VS2005打开VC6的源代码,转换后是使用的多字节字符集。
	// 在VS2008,vs2010中,项目->属性->常规->字符集:改为“使用多字节字符集”即可
	//error C2440: “=”: 无法从“const char [11]”转换为“LPCWSTR”类问题
	
	wndcls.lpszClassName = "tranning";   //wndClass.lpszClassName =L"DIRECTX11BookWindowClass";即在字符串的前面添加一个大写L。这样可以实现将字符串转换为宽字符集。
	wndcls.lpszMenuName = NULL;
	wndcls.style = CS_HREDRAW | CS_VREDRAW;

	//注册窗口类
	RegisterClass(&wndcls);
	
	//创建一个窗口

	HWND hwnd;   //创建一个句柄,代表这窗口标识符 // DWORD dwStyle 窗口类型
	hwnd = CreateWindow("tranning", "仿生机器人实验室",WS_OVERLAPPEDWINDOW,
							0, 0, 600, 400, NULL, NULL, hInstance, NULL);
	//显示窗口
	ShowWindow(hwnd,SW_SHOWNORMAL);
	UpdateWindow(hwnd);

	//消息响应函数
	MSG msg;
	while (GetMessage(&msg,NULL,0,0))     //第二个参数句柄设置为空,希望获取所有函数的消息
	{
		TranslateMessage(&msg);    //消息转换,如将WM_KEYDOWN和WM_KEYUP转换成一个char 消息,并且投递到消息队列当中
		DispatchMessage(&msg);     //将收到的消息传递到窗口的回调函数,在窗口过程函数当中处理,理解为将消息送给操作系统再由操作系统去调用回调函数
	}
	return 0;
}

//窗口过程函数
//回调函数,
//CALLBACK 是标准调用约定_stdcall
LRESULT CALLBACK WinSunProc(HWND hwnd,      //窗口句柄
							UINT wMsg,       //message identifier
							WPARAM wParam,   // first message parameter
							LPARAM lParam)   //second message parameter
{
	switch(wMsg)
	{
	case WM_CHAR:
		char szChar[20];
		sprintf(szChar,"char is %d", wParam);
		break;
	case WM_LBUTTONDOWN:
		MessageBox(hwnd,"mouse clicked", "fangsheng",0);
		HDC hdc;            //device contacts , 提供这个接口,可以不用理会外设驱动怎么回事
		hdc = GetDC(hwnd);

		TextOut(hdc, 0, 50, "Windows程序设计基础", strlen("Windows程序设计基础"));
		ReleaseDC(hwnd,hdc);
		break;
	case WM_PAINT:    //窗口重绘函数
		HDC hdc1;
		PAINTSTRUCT ps;
		hdc1 = BeginPaint(hwnd,&ps);
		TextOut(hdc1, 0, 0, "程序设计基础", strlen("程序设计基础"));
		EndPaint(hwnd, &ps);
		break;
	case WM_CLOSE:
		if(IDYES == MessageBox(hwnd, "是否真的结束?","Windows程序设计基础",0))
		{
			DestroyWindow(hwnd);              //销毁窗口
		}
		break;
	case WM_DESTROY:
		PostQuitMessage(0);        // 投递一个WM_QUIT的消息到线程的消息队列当中,并且立即返回    终止消息发送,式消息循环终止,从而实现退出程序
		break;
	default:
		return DefWindowProc(hwnd,wMsg,wParam,lParam);   //其它消息由操作系统默认处理
	}
	return 0;
}

运行时遇到问题:

1、//error C2440: “=”: 无法从“const char [11]”转换为“LPCWSTR”类问题代码在VC6中没问题. 因为它的代码没有按可编译为UNICODE版本的方式写,而VS2005之后版本默认是UNICODE编码的.所以所有使用到字串的地方都会出错.

//方法:修改VS2005之后版本的设置:选择你的项目->属性->常规->设置为不使用UNICODE,发现设置为多字节字符集也可以。发现用VS2005打开VC6的源代码,转换后是使用的多字节字符集。
// 在VS2008,vs2010中,项目->属性->常规->字符集:改为“使用多字节字符集”即可

2、MSVCRTD.lib(crtexe.obj) : error LNK2019: 无法解析的外部符号 _main,该符号在函数 ___tmainCRTStartup 中被引用

在项目属性-连接器-系统- 子系统 , 将:   /subsytem:console     改为/ subsystem:windows 至于为什么这么改,我就不是太清楚,

一开始在vs2010建立工程是默认控制台工程,我将里头main函数直接删除,并且输入以上代码,就出现这个问题。


_stdcall 与 cdcall 的区别
调用约定,一种是标准调用约定,一种是C语言的调用约定

定义的参数传递的顺序,还有堆栈清除有些差异

除了可变参数API 函数调用,其他都是_stdcall

VC++ 默认是cdcall,,在vc++调用_stdcall  API函数时必须在声明函数时,加入_stdcall标示