您的位置:首页 > 编程语言 > C语言/C++

孙鑫VC++深入详解(1):windows程序内部运行机制

2014-02-17 16:56 375 查看
1、SDK:Software Development Kit,软件开发包

GUI:Graphical User Interface,图形用户接口

GDI:Graphical Derice Interface,图形设备接口

2、句柄用来标识各种资源和对象。

HANDLE:句柄

HWND:窗口句柄

HMENU:菜单句柄

HINSTANCE:应用程序实例句柄

HICON:图标句柄

HCURSOR:光标句柄

HGDIOBJ:GDI对象(字体、画笔、画刷、调色板...)句柄

HBRUSH:画刷句柄

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

typedef struct tagMSG {
				HWND        hwnd;//消息所属窗口的句柄
				UINT        message;//消息值,eg:WM_CHAR
				WPARAM      wParam;//附加信息,eg:'a'
				LPARAM      lParam;//附加信息
				DWORD       time;//投递到消息队列中时间
				POINT       pt;//鼠标当前位置
    } MSG, *PMSG;

4、每一个Windows应用程序开始执行后,系统都会为该进程创建一个消息队列,这个消息队列用来存放该程序创建的窗口的消息。

5、__stdcall与__cdecl是两种不同的函数调用约定,定义了函数参数入栈的顺序、由调用函数还是被调用函数将参数弹出栈、产生函数修饰名的方法规则。

__stdcall又称标准调用约定或pascal调用约定,Win32 API和回调函数遵循此调用约定,故表示的宏有WINAPI和CALLBACK。

__cdecl又称C调用约定,VC++默认遵循此约定,故函数声明中不必再声明为__cdecl。

6、Win32窗口程序创建步骤:1、定义WinMain()函数

2、创建一个窗口

3、进行消息循环

4、编写窗口过程函数

7、WinMain()函数是Windows应用程序的入口函数,其参数由系统传递,第一个参数为当前应用程序实例句柄,第二个参数已弃用,第三个参数为命令行参数,第四个参数指定程序的窗口如何显示,如最大化显示、最小化显示、隐藏等。 函数原型:

int WINAPI WinMain(HINSTANCE hInstance,
	           HINSTANCE hPrevInstance,
	           LPSTR lpCmdLine,
		   int nCmdShow)


8、创建一个窗口的步骤:1、设计窗口类

2、注册窗口类

3、创建窗口

4、显示及更新窗口

1、设计窗口类:窗口的特征是由WNDCLASS结构体来定义的,如下

typedef struct tagWNDCLASSW {
    UINT        style;         //窗口类的样式
    WNDPROC     lpfnWndProc;   //函数指针,指向窗口过程函数
    int         cbClsExtra;    //类附加内存
    int         cbWndExtra;    //窗口附加内存,一般为0
    HINSTANCE   hInstance;     //包含窗口过程的程序的应用程序实例句柄
    HICON       hIcon;         //窗口的图标句柄,NULL则为默认图标
    HCURSOR     hCursor;       //窗口的光标句柄
    HBRUSH      hbrBackground; //窗口的背景画刷句柄
    LPCWSTR     lpszMenuName;  //菜单资源的名称
    LPCWSTR     lpszClassName; //窗口类的名称
} WNDCLASSW, *PWNDCLASSW;

窗口类的样式:水平重绘:CS_HREDRAW;垂直重绘:CS_VREDRAW;无关闭按钮:CS_NOCLOSE;在窗口中双击鼠标时向窗口发送鼠标双击消息:CS_DBLCLKS......使窗口具有多个样式:style = CS_HREDRAW | CS_VREDRAW | CS_NOCLOSE;去掉窗口可能存在的某个样式:style & =~CS_NOCLOSE; 或

style = style & ~CS_NOCLOSE;

窗口过程函数是一个回调函数。

类附加内存和窗口附加内存一般设为0。

包含窗口过程的程序的应用程序实例句柄一般为当前应用程序实例句柄(WinMain函数的第一个参数)。

LoadIcon()函数可以用来加载一个图标资源,返回系统分配给图标的句柄。函数原型:

HICON LoadIcon(HINSTANCE hInstance, LPCTSTR lpIconName);
第一个参数为当前应用程序实例句柄,AfxGetInstanceHandle()函数可以获得当前应用程序实例句柄,如果要加载的是系统标准图标则为NULL

第二个参数为图标资源名称或图标资源标识符字符串,如果要加载的不是系统标准图标则应先把图标添加到工程的资源目录,再利用MAKEINTRESOURCE宏将指定的图标资源ID转换为图标资源标识符字符串,如MAKEINTRESOURCE(IDI_ICON1)

LoadCursor()函数可以用来加载一个光标资源,返回系统分配给光标的句柄。函数原型:

HCURSOR LoadCursor(HINSTANCE hInstance, LPCTSTR lpCursorName);
第一个参数为当前应用程序实例句柄,AfxGetInstanceHandle()函数可以获得当前应用程序实例句柄。如果要加载的是系统标准光标则为NULL

第二个参数为光标资源名称或光标资源标识符字符串,如果要加载的不是系统标准光标则应先把光标添加到工程的资源目录,再利用MAKEINTRESOURCE宏将指定的光标资源ID转换为光标资源标识符字符串,如MAKEINTRESOURCE(IDI_ICUR1)

LoadIcon()和LoadCursor()已被Loadlmage()函数替代。

GetStockObject()函数可以获得系统的标准画刷、画笔、字体、调色板等GDI对象的句柄,返回类型为HGDIOBJ,使用时需要进行类型转换。函数原型:

HGDIOBJ GetStockObject(int i);

参数为要获取的对象的类型,如获取系统透明画刷:

CBrush *pBrush = CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));//获得透明画刷
CGdiObject::FromHandle()、CWnd::FromHandle()可以由对象句柄获得对象指针。

lpszMenuName用来指定窗口菜单资源的名称,如果使用菜单的ID号则需要用MAKEINTRESOURCE宏来进行转换,要注意的是菜单不是一个窗口。为NULL则窗口无菜单。

2、注册窗口类:RegisterClass()函数用来注册窗口类,参数为要注册的窗口类的WNDCLASS结构体。函数原型:

ATOM WINAPI RegisterClass(const WNDCLASS *lpWndClass);

3、创建窗口:CreateWindow()函数创建一个重叠式窗口、弹出式窗口或子窗口,函数执行成功返回创建的窗口的句柄,否则返回NULL。函数原型:

HWND WINAPI CreateWindow(
            LPCTSTR lpClassName,   //窗口类的名称
            LPCTSTR lpWindowName,  //窗口的名称(在窗口的标题栏上显示)
            DWORD dwStyle,         //窗口的样式,即窗口风格
            int x,                 //窗口左上角x坐标
            int y,                 //窗口左上角y坐标
            int nWidth,            //窗口的宽度
            int nHeight,           //窗口的高度
            HWND hWndParent,       //父窗口句柄
            HMENU hMenu,           //窗口菜单的句柄
            HINSTANCE hInstance,   //窗口所属的应用程序实例句柄
            LPVOID lpParam         //作为WM_CREATE消息的附加参数lParam传入的数据指针,多数情况为NULL,若为多文档界面的窗口则必须指向CLIENTCREATESTRUCT结构体
);

要注意区分WNDCLASS中的style成员与CreateWindow()函数的dwStyle参数的区别,第一个是指窗口类的样式,基于该窗口类创建的窗口都具有这些样式,后者指某个具体窗口的样式,即窗口风格,如WS_CAPTION为窗口具有标题栏、WS_MINIMIZEBOX为窗口具有最小化按钮等、WS_VISIBLE为窗口初始可见、WS_OVERLAPPEDWINDOW为多种样式的组合、WS_POPUP为去除一切控件和Windows GUI内容。

CreateWindowEx()函数创建一个具有扩展风格的重叠式窗口、弹出式窗口或子窗口,其第一个参数指定扩展风格,如指定窗口不能移动、指定窗口有一个带阴影的边界等,其余参数与CreateWindow()相同。

4、显示及更新窗口:调用函数ShowWindow()来显示窗口,调用函数UpdateWindow()来刷新窗口。调用完ShowWindow后应紧接着调用UpdateWindow来刷新窗口。函数原型:

BOOL WINAPI ShowWindow(
        HWND hWnd,      //窗口的句柄
        int nCmdShow    //显示状态
);
nCmdShow取值, SW_SHOWNORMAL:激活并显示窗口。如果窗口处于最小化或最大化,Windows还原为其原始大小和位置。程序在第一次显示窗口的时候应指定此标志。

SW_SHOW:在窗口原来的位置以原来的尺寸激活和显示窗口。

SW_HIDE:隐藏窗口并激活其它窗口。

SW_SHOWMAXIMIZED:激活窗口并最大化显示。

SW_SHOWMINIMIZED:激活窗口并最小化显示。

SW_MINIMIZE:最小化窗口并激活顶层窗口

BOOL UpdateWindow(_In_  HWND hWnd);

调用UpdateWindow()函数会产生WM_PAINT消息,通知应用程序绘制窗口。

CloseWindow()为最小化窗口。

DestroyWindow()为销毁当前线程创建的窗口,若要关闭其他线程创建的窗口,可以向该窗口发送WM_CLOSE消息,若窗口过程未在WM_CLOSE的处理中取消关闭操作,则DefWindowProc会默认调用DestroyWindow(彼时自然是在窗口的创建线程上)。

9、GetMessage()函数用来从消息队列中取消息,如果消息队列中无消息就会一直等下去(这是与PeekMessage不同的地方)。

GetMessage函数接收到除WM_QUIT外的消息均返回非0值,而对于WM_QUIT消息则返回0,出错返回-1。

BOOL WINAPI GetMessage(
            LPMSG lpMsg,
            HWND hWnd,
            UINT wMsgFilterMin,
            UINT wMsgFilterMax
);
lpMsg用来保存取出的消息结构体

hWnd指定取出属于哪一个窗口的消息,NULL则为接收属于调用线程的所有窗口的消息

wMsgFileterMin指定要获取的消息的最小值,如果wMsgFileterMin和wMsgFilterMax都设为0则为接收所有消息

wMsgFilterMax指定要获取的消息的最大值

通常我们编写的消息循环代码如下:

/********进行消息循环********/
	MSG msg;//保存取出的消息
	int Ret;

	while((Ret = GetMessage(&msg, NULL, 0, 0)) != 0)//从消息队列中取消息
	{
		if(Ret == -1)
		{
			return -1;
		}
		else
		{
			TranslateMessage(&msg);//转化虚拟键消息
			DispatchMessage(&msg);//分派消息到窗口过程
		}
	}
TranslateMessage()函数将虚拟键消息转化为字符消息,再将字符消息投递到消息队列中

DispatchMessage()函数分派消息到窗口过程(由操作系统调用窗口过程对消息进行处理)

10、MSDN中窗口过程的声明形式:

LRESULT CALLBACK WindowProc(
        HWND hwnd,           //消息所属窗口的句柄
        UINT uMsg,           //消息代码
        WPARAM wParam,       //消息附加参数
        LPARAM lParam        //消息附加参数
);

窗口过程函数的名字可以随便取,但函数定义的形式必须和上述声明一致。窗口过程的内部为一个switch/case 语句用来确定处理那些消息及处理动作。

窗口过程的声明形式可以在MSDN中的WNDCLASS结构中找到。

11、一个完整的Windows窗口程序的示例:

#include "windows.h"
#include "tchar.h"

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

int WINAPI WinMain(HINSTANCE hInstance,
				   HINSTANCE hPrevInstance,
				   LPSTR lpCmdLine,
				   int nCmdShow)
{
	/************创建一个窗口************/
	//设计窗口类
	WNDCLASS wndcls;
	wndcls.style = CS_HREDRAW | CS_VREDRAW;
	wndcls.lpfnWndProc = WindowProc;
	wndcls.cbClsExtra = 0;
	wndcls.cbWndExtra = 0;
	wndcls.hInstance = hInstance;
	wndcls.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	wndcls.hCursor = LoadCursor(NULL, IDC_CROSS);
	wndcls.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
	wndcls.lpszMenuName = NULL;
	wndcls.lpszClassName = _T("window2013");

	//注册窗口类
	RegisterClass(&wndcls);

	//创建窗口
	HWND hwnd;
	hwnd = CreateWindow(_T("window2013"), _T("测试窗口"), WS_OVERLAPPEDWINDOW,
		   0, 0, 600, 400, NULL, NULL, hInstance, NULL);

	//显示和更新窗口
	ShowWindow(hwnd, SW_SHOWNORMAL);
	UpdateWindow(hwnd);

	/********进行消息循环********/
	MSG msg;
	int Ret;

	while((Ret = GetMessage(&msg, NULL, 0, 0)) != 0)
	{
		if(Ret == -1)
		{
			return -1;
		}
		else
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
	}

	return 0;
}

/********编写窗口过程函数********/
LRESULT CALLBACK WindowProc(HWND hwnd,
							UINT uMsg,
							WPARAM wParam,
							LPARAM lParam)
{
	switch(uMsg)
	{
	case WM_PAINT://窗口重绘消息
		HDC Hdc;
		PAINTSTRUCT paint;
		Hdc = BeginPaint(hwnd, &paint);
		TextOut(Hdc, 0, 100, _T("文字"), _tcslen(_T("文字")));
		EndPaint(hwnd, &paint);
		break;
	case WM_LBUTTONDOWN://鼠标左键按下消息
		HDC hdc;
		hdc = GetDC(hwnd);
		SetBkMode(hdc, TRANSPARENT);
		SetTextColor(hdc, RGB(0,0,255));
		TextOut(hdc, 0, 50, _T("鼠标左键按下"), _tcslen(_T("鼠标左键按下")));//输出文字
		ReleaseDC(hwnd, hdc);
		break;
	case WM_CHAR://字符消息 
		TCHAR buffer[20];
		swprintf(buffer, _T("char code is %d"), wParam);
		MessageBox(hwnd, buffer, _T("对话框"), 0);
		break;
	case WM_CLOSE://点击关闭窗口产生的消息
		if(IDYES == MessageBox(hwnd, _T("确定退出?"), _T("对话框"), MB_YESNO))
			DestroyWindow(hwnd);
		break;
	case WM_DESTROY://销毁窗口消息
		PostQuitMessage(0);
		break;
	default://其它消息则调用默认窗口过程函数
		return DefWindowProc(hwnd,uMsg,wParam,lParam);
	}

	return 0;
}
12、 1、WM_PAINT:当窗口从无到有、改变尺寸、最小化后再恢复、被其他窗口遮挡后再显示时,窗口的客户区都会无效,系统会 发送此消息,通知应用程序重新绘制窗口(窗口改变尺寸是否重绘窗口还取决于WNDCLASS结构体中style成员)。以下为其它情况下系统向应用程序发送的消息:

WM_KEYDOWN:按键按下消息。

WM_KEYUP:按键弹开消息。

WM_CHAR:字符按键消息。

WM_MOUSEMOVE:鼠标移动消息。

WM_CLOSE:点击默认关闭按钮产生的消息。

WM_DESTROY:DestroyWindow()函数在销毁窗口后发送的消息。

WM_QUIT:PostQuitMessage()函数产生的消息。

2、BeginPaint()函数用于获得窗口的DC,只用于响应WM_PAINT消息的代码块中,其它地方应使用GetDC()函数。返回HDC类型,即窗口DC的句柄。函数原型:

HDC BeginPaint(HWND hwnd, LPPAINTSTRUCT lpPaint);
第一个参数为窗口句柄,第二个参数为PAINTSTRUCT类型的指针,用来接收绘制信息。

完成DC图形操作后应调用EndPaint()函数释放DC资源。函数原型:

BOOL EndPaint(HWND hWnd, const PAINTSTRUCT *lpPaint);
TextOut()函数用于在指定DC上的指定坐标处绘制文字。函数原型:

BOOL TextOut(
  _In_  HDC hdc,          //窗口DC
  _In_  int nXStart,      //开始位置X坐标
  _In_  int nYStart,      //开始位置Y坐标
  _In_  LPCTSTR lpString, //文字
  _In_  int cchString     //文字长度
);
3、GetDC()函数用于获得窗口的DC,返回HDC类型,即窗口DC的句柄。函数原型:

HDC GetDC(_In_  HWND hWnd);
完成DC图形操作后应调用ReleaseDC()函数释放DC资源。函数原型:

int ReleaseDC(_In_  HWND hWnd, _In_  HDC hDC);
SetBkMode()函数用来设置指定设备环境的背景是否透明,第二个参数为TRANSPARENT为透明,OPAQUE为非透明,eg:

//int SetBkMode(HDC hdc, int iBkMode);
SetBkMode(hdc, TRANSPARENT);

SetBkColor()函数用来设置指定设备环境的背景颜色,GetBkColor()用来获得设备环境的背景颜色。eg:

//COLORREF SetBkColor(HDC hdc,COLORREF crColor);
SetBkColor(hdc, RGB(255,0,0));//设置设备环境(HDC)的背景颜色为红色
SetBkColor(hdc, 0x0000FF);//设置设备环境(HDC)的背景颜色为红色
SetTextColor()函数用来设置指定设备环境的字体颜色,GetTextColor()用来获得设备环境的字体颜色。eg:

//COLORREF SetTextColor(HDC hdc,COLORREF crColor);
SetTextColor(hdc, RGB(0,0,255));//设置设备环境(HDC)的字体颜色为蓝色                


4、sprintf()/swprintf():格式化数据到一个字符串buffer中。eg:

//int sprintf(char *buffer, const char *format [,argument]...);
swprintf(buffer, _T("char code is %d"), wParam);
MessageBox()函数用来弹出一个消息框,返回值为用户在消息框上的选择(IDOK、IDCANCEL、IDYES等)。函数原型:

int WINAPI MessageBox(
  _In_opt_  HWND hWnd,         //父窗口句柄,可为NULL
  _In_opt_  LPCTSTR lpText,    //消息框上显示的内容
  _In_opt_  LPCTSTR lpCaption, //消息框标题,NULL则为Error
  _In_      UINT uType         //消息框内容,如MB_OK:带一个确认按钮,MB_ICONWARNING:带一个叹号图标等
);
5、DestroyWindow()函数销毁指定窗口并向窗口发送WM_DESTROY消息。函数原型:

BOOL WINAPI DestroyWindow(HWND hWnd);
6、PostQuitMessage()函数提出终止申请,向窗口发送WM_QUIT消息,一般用于响应WM_DESTROY消息中。函数参数用来指定退出码,函数原型:

VOID WINAPI PostQuitMessage(_In_  int nExitCode);
7、DefWindowProc()函数为调用默认的窗口过程来处理窗口消息。函数原型:

LRESULT WINAPI DefWindowProc(
  _In_  HWND hWnd,     //窗口句柄
  _In_  UINT Msg,      //消息代码
  _In_  WPARAM wParam, //消息附加参数
  _In_  LPARAM lParam  //消息附加参数
);
12、常用匈牙利表示法

a:数组

b:布尔值

c:字符

rgb:保存RGB颜色值的长整型

fn:函数

h:句柄

i:整形

m_:类的数据成员

p:指针

13、常用Windows数据结构

typedef unsigned long       DWORD;
	typedef unsigned int        UINT;
	typedef unsigned short      WORD;
	typedef unsigned char       BYTE;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: