(孙鑫C++)windows 程序内部运行原理

一.Windows程序内部运行原理

1.关于消息和消息队列
  系统将每个事件都包装成一个称为消息的结构体MSG来传递给应用程序,MSG结构定义如下:
typedef struct tagMsg{
	HWND hwnd;
	UINT message;   //消息种类,以WM_开头的一些消息
	WPARAM wParam;  //这两个是消息的补充
	LPARAM lParam;
	DWORD time;    //消息被投递post的时间
	POINT pt;     //这是一个点数据(结构体,有x、y),记录投递消息时光标cursor的屏幕坐标coordinate
}MSG;
2.windows程序的入口WinMain函数
  int WINAPI WinMain(
  HINSTANCE hInstance,      // handle to current instance  当前运行的实例句柄
  HINSTANCE hPrevInstance,  // handle to previous instance 先前运行的实例句柄
  LPSTR lpCmdLine,          // command line;lp开头(long pointer) 表示指针,str表示字符串;这里是命令行参数
  int nCmdShow              // show state窗口显示状态(最大化、最小化……)
);

(可以在运行里面输入notepad.exe 1.txt传递一个参数)
3.窗口的创建
  	需要经过下面四个操作步骤:
·设计一个窗口类
·注册窗口类
·创建窗口
·显示及更新窗口
1)
typedef struct _WNDCLASS { 
   UINT    	style;   //可以设为CS_HREDRAW,即窗口水平坐标变化时窗口全部重画
   WNDPROC	lpfnWndProc; //回调函数(由系统调用),直接将函数名赋给此参数(即函数指针)
   int     	cbClsExtra;   //为窗口类分配附加内存空间(所有属于这个窗口类的窗口共享)
   int     	cbWndExtra;   //窗口实例附加内存空间
   HANDLE 	hInstance; 
   HICON   	hIcon;    //用LoadIcon赋值
   HCURSOR 	hCursor;  //用LoadCursor
   HBRUSH  	hbrBackground; 
//画刷背景,这里用GetStockObject()获取,它参数是系统带的。如:=(HBRUSH)GetStockObject(BLACK_BRUSH),这里有强制类型转换
   LPCTSTR 	lpszMenuName;   //CT=constant……菜单名
   LPCTSTR 	lpszClassName;    //窗口类名
} WNDCLASS; 

  经常会遇到一类变量,其每一位bit都对应某一种属性(1有0无),系统定义了一些常量(宏定义),只有一位为1,其余为0。若要同时用这几种特性,则用或运算|;要去掉某一特征,用取反~之后再进行与运算&即实现。(or有;and not取消,类似VB)
HICON  LoadIcon(
	HINSTANCE hInstance,   //若加载标准图标则为NULL(系统自带的,如IDI_APPLICATION)
	LPCTSTR lpIconName
);
HGDIOBJ GetStockObject(
  __in  int fnObject
);
2)
然后用RegisterClass(&wndcls)注册窗口类
ATOM RegisterClass(         
 CONST WNDCLASS *lpWndClass
);
3)
再用hwnd=CreateWindow()创建窗口
HWND CreateWindow(
    LPCTSTR lpClassName,  //窗口类名,必须是先前设计的
    LPCTSTR lpWindowName, //窗口名字
    DWORD dwStyle,//窗口样式window styles,如WS_OVERLAPPEDWINDOW,若想去掉最大化按钮(加个&~WS_MAXIMIZEBOX)
    int x,  //窗口初始位置,可设置为CW_USEDEFAULT,这样就忽略y的值了
    int y,
    int nWidth,  //宽度,也可用CW_USEDEFAULT
    int nHeight,
    HWND hWndParent,  //父窗口句柄,没有则为NULL
    HMENU hMenu,  
    HINSTANCE hInstance,    
    LPVOID lpParam   //  作为WM_CREATE消息的参数lParam
);
4)显示窗口ShowWindow
BOOL ShowWindow(   
    HWND hWnd,
    int nCmdShow  //窗口状态,如SW_SHOWMAXIMIZED
);
之后用UpdateWindow(hwnd)刷新窗口,这里可有可无
4.获取消息GetMessage
BOOL GetMessage(      //获取到WM_QUIT消息时,返回值为0;其他为非0值
    LPMSG lpMsg,
    HWND hWnd,   //为NULL时表示属于当前线程的所有消息
    UINT wMsgFilterMin,  //最低的消息值
    UINT wMsgFilterMax   //最高消息值
);
	消息循环:
	while(GetMessage(&msg,NULL,0,0))    
	{
		TranslateMessage(&msg);   //将按键消息(KEYDOWN/KEYUP和对应字符的扫描码)转换成WM_CHAR消息
		DispatchMessage(&msg);    //派送消息,将消息发送给窗口程序
	}
	return 0;
5.窗口程序:
LRESULT CALLBACK WindowProc(          //窗口名可随意取,这里CALLBACK其实就是__stdcall(标准调用格式,宏定义的)
  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(szChar,"char is %d",wParam);  //格式化文本到一个内存区(buffer)
		MessageBox(hwnd,szChar,"weixin",0);
		break;
	case WM_LBUTTONDOWN:
		MessageBox(hwnd,"mouse clicked","weixin",0);
		HDC hdc;
		hdc=GetDC(hwnd);
		TextOut(hdc,0,50,"计算机编程语言培训",strlen("计算机编程语言培训"));
		ReleaseDC(hwnd,hdc);
		break;
	case WM_PAINT:
		HDC hDC;
		PAINTSTRUCT ps;
		hDC=BeginPaint(hwnd,&ps);
		TextOut(hDC,0,0,"维新培训",strlen("维新培训"));
		EndPaint(hwnd,&ps);
		break;
	case WM_CLOSE:
		if(IDYES==MessageBox(hwnd,"是否真的结束?","weixin",MB_YESNO))
		{
			DestroyWindow(hwnd);
		}
		break;
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	default:
		return DefWindowProc(hwnd,uMsg,wParam,lParam);		
	}
	return 0;
}
6.所用其他函数分析:
1)int MessageBox(     
    HWND hWnd,
    LPCTSTR lpText,  //显示的文本(存放到一个字符数组,或直接用“”括起输出字符)
    LPCTSTR lpCaption,  //标题
    UINT uType  // 样式,如MB_OK=0(方便就写0)/MB_OKCANCEL
);
返回值有:IDOK,IDNO,IDYES……
2)画图、输出
先用GetDC:
HDC GetDC(
  __in  HWND hWnd  //窗口句柄,若为NULL则返回整个屏幕的DC(device context设备上下文、环境)
);
再用TextOut输出文本:
BOOL TextOut(
  __in  HDC hdc,
  __in  int nXStart,   //这两者是文本输出的开始坐标
  __in  int nYStart,
  __in  LPCTSTR lpString,  //输出的文本
  __in  int cbString    	//输出的字符个数
);
注意最后要释放DC:用ReleaseDC
int ReleaseDC(
  __in  HWND hWnd, 
  __in  HDC hDC
);
3)WM_PAINT消息(窗口加载、窗口移动时窗口要重绘)
先用	HDC hdc;PAINTSTRUCT ps;
	hdc=BeginPaint(hwnd,&ps) //在重绘时获取DC
HDC BeginPaint(
  __in   HWND hwnd,
  __out  LPPAINTSTRUCT lpPaint    //这里是PAINTSTRUCT变量的指针,如&ps
);
使用(如TextOut(hdc,0,0,"维新培训",strlen("维新培训")))完之后,要用EndPaint释放DC
BOOL EndPaint(
  __in  HWND hWnd,
  __in  const PAINTSTRUCT *lpPaint
);
这里BeginPaint和EndPaint只能用WM_PAINT消息中
4)WM_CLOSE(窗口即将关闭时的消息)
   if(IDYES==MessageBox(hwnd,"是否真的结束?","weixin",MB_YESNO))
   {  
	DestroyWindow(hwnd);
    }
经验:在条件测试的时候,一般把常量(IDYES)写在前面,不容易出错
BOOL DestroyWindow(       //销毁窗口,程序还没退出,它会发送WM_DESTROY消息和WM_NCDESTROY消息
    HWND hWnd
);
5)WM_DESTROY  //窗口销毁
void PostQuitMessage(      //投递一个WM_QUIT消息给这个线程的消息队列
     int nExitCode    //它用来当做WM_QUIT消息的wParam
);
6)其它消息:
default:
	return DefWindowProc(hwnd,uMsg,wParam,lParam);   //默认的窗口程序
7.用VC编写:
1)选择win32 application工程(选择空工程)
2)添加C++源文件
3)包含头文件:#include "windows.h"	#include "stdio.h"
4) 写WinMain函数,可查msdn
   int WINAPI WinMain(     
    HINSTANCE hInstance,
    HINSTANCE hPrevInstance,
    LPSTR lpCmdLine,
    int nCmdShow
);
5)在WinMain函数中设计一个窗口类
{
	WNDCLASS wndcls;
	wndcls.cbClsExtra=0;
	wndcls.cbWndExtra=0;
	wndcls.hbrBackground=(HBRUSH)GetStockObject(BLACK_BRUSH);
	wndcls.hIcon=LoadIcon(NULL,IDI_APPLICATION);
	wndcls.hCursor=LoadCursor(NULL,IDC_ARROW);
	wndcls.hInstance=hInstance;
	wndcls.lpfnWndProc=WinSunProc;
	wndcls.lpszClassName="first";
	wndcls.lpszMenuName=NULL
	wndcls.style=CS_HREDRAW | CS_VREDRAW;
}
6)在WinMain中注册窗口类
	RegisterClass(&wndcls);
7)创建窗口
HWND hwnd;
hwnd=CreateWindow("first","我第一个窗口",WS_OVERLAPPEDWINDOW,USER_DEFAULT,0,0,USER_DEFAULT,NULL,NULL,hInstance,NULL);
8)显示窗口
	ShowWindow(hwnd,SW_SHOWNORMAL);
	UpdateWindow(hwnd);
9)消息循环
	MSG msg;
	while(GetMessage(&msg,NULL,0,0)   //获取到WM_QUIT消息时才退出循环,注意这里是NULL表示接受所有消息
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return 0; //winmain返回0

10)窗口过程
LRESULT CALLBACK WindowProc(           //注意改名WinSunProc,和申明
    HWND hwnd,
    UINT uMsg,
    WPARAM wParam,
    LPARAM lParam
)
{
	switch(uMsg)
	{
	case WM_CHAR:
		break;
	case WM_LBUTTONDOWN:
		break;
	case WM_PAINT:
		break;
	case WM_CLOSE:
		break;
	case WM_DESTROY:
		break;
	default:
		return DefWindowProc(hwnd,uMsg,wParam,lParam);
	}
	return 0;
}
11)编写具体过程:
1.WM_CHAR:
		char szChar[20];
		sprintf(szChar,"asc is %d",wParam);
		MessageBox(hwnd,szChar,"MyFirst",0);		
2.WM_PAINT:
		PAINTSTRUCT ps;
		HDC hdc;
		hdc=BeginPaint(hwnd,&ps);
		TextOut(hdc,0,0,"painting...",strlen("painting..."));
		EndPaint(hwnd,&ps);
		break;
3.WM_CLOSE:
		if(IDYES==MessageBox(hwnd,"exit?","MyFirst",MB_YESNO))
		{
			DestroyWindow(hwnd);
		}
		break;
4.WM_DESTROY:
		PostQuitMessage(0);
		break;
	default:
		return DefWindowProc(hwnd,uMsg,wParam,lParam);
	}
	return 0;

posted @ 2022-11-24 11:28  Expl0it  阅读(13)  评论(0)    收藏  举报  来源