WINDOWS程序内部运行原理
API(Application programming interface) 应用程序编程的接口
MSG(message) 消息结构体
操作系统将每一个事件包装成一个称为消息MSG的结构体传递给应用程序
MSG的结构定义如下:(windows user interface : platform sdk )
Typedef struct tagMSG{
HWND hwnd; 窗口的句柄 句柄为资源的标识,按类型分为HICON \HCURSOR \HWND \HINSTANCE
UINT message; 无符号整形具体的消息; 用宏来表示数值WM开头的为宏WM_*
WPARAM wParam; 整型. 关于消息的附加信息. WM_CHAR消息字符的代码ASCII;
LPARAM lParam; ;整型. 关于消息的附加信息. PARAM=PARAMETER参数,参量
DWORD time; ;WORD16位的整数DWORD=Double WORD32位整数.指定消息的投递时间.
POINT pt; 当消息被投递的时候光标太屏幕上的坐标;
}MSG,*PMSG;
POINT为一个结构体定义了点x坐标y坐标
Typedef struct tagPOINT{
LONG x;
LONG y;
} POINT,*PPOINT; 结束时间
消息:消息本身,特定的消息响应
WINMAN函数
入口点函数类似于C的MAN函数
int WINAPI WinMan(
HINSTANCE hInstance, //handle to cerrent instance 实例(资源)的句柄,当前运行的句柄;
HINSTANCE hPrevinstance, //handle to previous instance 先前实例的句柄,可能为空,兄弟的实例句柄
win32下这个实例总是为空(win98、2000等);
LPSTR lpCndLine, //command line LP->LONG POINTER长指针,ETRING字符串,指向字符
串的指针;类似于CHAR * 命令行参数
int nCmdSbow //show state 显示的状态,比如窗口的大小全屏
); //这个分号在具体的编程过程中是不要的,需要删除掉。
DOS下的MAIN函数可以接收2个参数:ARJc、ARJv. ARJc用来接受、存放命令行参数的个数,ARJv指针数组用来存放命令行参数,同样的在windows程序当中他也可以接收命令行的参数.
WINAPI :Calling convention for system functions.
窗口的创建。创建一个完整的窗口需要经过下面四个操作步骤:
l 设计一个窗口类;
l 注册窗口类;
l 创建窗口;
l 显示及更新窗口;
1、设计窗口。设计一个窗口就是设计一个窗口类,他是一个结构体
WNDCLASS
Typedef struct _WNDCLASS{ //MSDN--WNDCLASS
UINIT style; style //(Class Styles=CS)指定一个类的类型,这里是窗口类的类型;OR(|),与(&),取反(~),
赋值:wndclass.style=CS_HREDRAW | CS_VREDRAW (水平和垂直重画)
WNDPROC lpfnWndProc; 窗口过程。Lp=long pointer.fn=functionProc= procedure用来接收一个函数指针。
回掉函数(lpfnWndProc: Pointer to the window procedure. You must use the
CallWindowProc[回调window进程] function to call the window procedure. For more
information, see WindowProc.)。这里我们会把一个窗口名赋给他(函数名相当于一个
函数的指针),即在设计的时候就确定了一个回调函数,这里给他赋了WinSunProc
这个函数,当然WinSunProc函数具体内容是什么需要程序员自己去编写。
int cbClsExtra; windows程序会为每一个类管理一个内部数据结构。类附加内存,通常情况下设为零.(=0)
类额外的一个数据。(附加字节数)
int cbWndExtra; windows程序会为每一个窗口管理一个内部数据结构。窗口附加内存,通常情况下也设
置为零。以上两个分配额外的内存,通常我们不需要所以设置为零。(=0)
窗口类额外的一个数据。通常赋值为零表示我们不需要额外的内存,但是如果我们需要则额外的内存空间会自己变为零。这里设置为零就是=0,不同于其他的设置为NULL,因为这里是整数。
HANDLE hInstance; 代表我们当前程序的实例号。操作系统分配,直接通过WinMain的形参传递过来。
代表了我们当前应用程序的实例号,我们在设计窗口类的时候需要知道他是代表那
个应用程序实例的。从bInstance获得这个程序。
HICON hIcon; 图标的句柄。用LoadIcon这个函数来赋值 hIcon=LoadIcon(……)
HCURSOR hCursor; 光标句柄。用LoadCursor这个函数来赋值hCursor=LoadCursor(……)
HBRUSH hbrBackground; 画刷的句柄,用的是GetStockObject()这么一个函数
LPCTSTR lpszMenuName; LP=long point(32位),CT=constant常量,STR=string.用来设定菜单的名字;
可以直接设置为空NULL,如:lpszMenuNam=NULL;
(如果这个类型不认识可以用data type 这个来查看不是SDK)
LPCTSTR lpszClassName; 设置一个类的名字(注册窗口的时候会用到),窗口设计完成之后需要给窗口取一
个名字。
}WNDCLASS,*PWNDCLASS;
这个函数是系统定义好了格式,我们只需要拿过来用,直接对参数进行赋值。
WindowProc 回调函数,窗口过程函数
LRESULT CALLBACK WindowProc( //CALLBACK:窗口过程函数前边定义的时候加了一个CALLBACK
#define CALLBACK _stdcall
CALLBACK就是一个类型的定义
LRESULT就是一个长整型,返回一个结果码。
HWND hwnd, // handle to window
UINT uMsg, // message identifier
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
);
DefWindowProc回调函数,窗口过程函数
LRESULT DefWindowProc(
HWND hWnd, // handle to window
UINT Msg, // message identifier
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
);
_stdcall和_cdecl这是两种调用的约定,_stdcall标准调用约定,_cdecl为c语言的调用约定。标准调用约定也是PASCAL调用约定,dephi就是pascal调用约定。_stdcall和_cdecl在参数的传递顺序和堆栈的清除这两个方面有差异。Vc++默认的调用约定选项是_cdecl.需要时要经行定义。也可以通过Project -> Project Settings ->C/C++ ->Calling convention:中选择_stdcall这种方式来设定。
LoadIcon
HICON LoadIcon(
HINSTANCE hInstance, // handle to application instance 应用程序实例的一个句柄。当标准的图标加载的
时候这个参数用空(NULL),
LPCTSTR lpIconName // name string or resource identifier当第一个参数取值为NULL时第二个参数可以选择
);
如:LoadIcon(NULL,IDI_ERROR) // ID=identifier
LoadCursor
HCURSOR LoadCursor(
HINSTANCE hInstance, // handle to application instance 应用程序实例的一个句柄,如果想用一个标准的光标
这个参数需要设置为NULL
LPCTSTR lpCursorName // name or resource identifier 同样当前一个参数设置为NULL是这个可以选择微
软提供的光标函数。
);
GetStockObject() 获取一个笔、画刷、调色板、的句柄。
HGDIOBJ GetStockObject(
int fnObject // stock object type
);
*=(HBRUSH) GetStockObject(WHITE_BRUSH); // (HBRUSH) 这里是一个强制转换。因为GetStockObject返回的是一个GetStockObject的类型,而hbrBackground定义的为HBRUSH的类型,C++语言是一个强类型语言,对函数的类型要求的很严。强制类型转换必须要有可比性,即两个类型可以转换,这种转换在编译的时候不会报错但是在执行的时候会出现错误。
2、注册。窗口设置完之后需要对其进行注册(向操作系统注册),RegisterClass()窗口的注册函数
RegisterClass
ATOM RegisterClass(
CONST WNDCLASS *lpWndClass // class data 窗口类结构体的指针直接用定义的窗口类结构体的变量加上取
地址符&
);
3、创建一个窗口。
首先需要定义一个句柄(HWND),利用这个句柄的变量保存我们新创建的窗口的标识。然后利用CreateWindow函数来进行窗口的创建。
HWND hwnd;
Hwnd=CreateWindow(……);
CreateWindow
HWND CreateWindow(
LPCTSTR lpClassName, // registered class name 注