窗口产生过程,句柄原理,消息队列,回调函数,窗口关闭与应用程序退出的工作关系,使用VC++的若干小技巧,stdcall与Lessonecl调用规范的比较,初学者常犯错误及注意事项。以下是应用程序与操作系统之间的关系。

1.Windows API与Win32 SDK

操作系统提供了各种方便开发Windows应用程序的编程接口,所的函数都在Windows.h头文件中声明。Win32 SDK(Software Development Kit): 即Windows 32位平台下的软件开发包,包括API函数,帮助文档,微软提供的一些辅助开发工具。

2.窗口与句柄

窗口是是屏幕上一块矩形区域,是Windows应用程序与用户进行交互的接口。窗口分为客户区和非客户区。在Windows应用程序中,窗口是通过窗口句柄(HWND)来标识的,要对某个窗口进行操作,首先就要得到这个窗口的句柄。其它各种资源(窗口,图标,光标等),系统在创建这些资源时会为它们分配内在,并返回标识这些资源的标识号,即句柄。-->光标句柄(HCURSOR),图标句柄(HICON)。

3.消息与队列

Windows程序设计是一种基于消息的事件驱动方式的程序设计模式。

windows程序是一种完全不同于传统的DOS操作系统的程序设计方法。它是一种时间驱动方式的程序设计模式,主要是基于消息的。例如用户在窗口中画图的时候,按下鼠标左键,此时,操作系统会感知到这件事件,于是将这个小时包装成一个消息,投递到应用程序的消息队列中,然后应用程序从消息队列中取出消息并进行响应。在这个过程中,操作系统也会给应用程序“发送消息”。所谓的“发送消息”,实际上是操作系统调用程序中一个专门负责处理消息的函数,这个函数称为窗口过程。

消息:在Windows中由结构体MSG来表示,

typedef struct tagMSG{
HWND hwnd;//消息所属的窗口句柄
UINT message;//消息本身标识符,由一数值表示,系统对消息定//义为WM_XXX宏(WM为Windows Message缩写)
WPARAM wParam; //随消息的不同附加信息也不同
LPARAM lParam; //消息的附加参数
DWORD time; //消息投递的时间
POINT pt; //鼠标当前位置
}

消息队列:每当一个Windows应用程序创建后,系统都会为该程序创建一个消息队列,这个消息队列用来存放该程序一的窗口的消息,消息产生后被投递到消息队列中,应用程序通过一个消息循环不断的消息队列中取出消息进行响应。响应过程由系统向应用程序发送消息,实际就是调用应用程序的消息处理函数。

4.创建一个完整的win32程序的主要步骤

  1. WinMain函数的定义
  2. 创建一个窗口      创建一个完整的窗口的四个步骤SDK,1设计窗口类,2注册窗口类,3创建窗口,4显示窗口
  3. 进行消息循环
  4. 编写窗口过程函数

回调函数的实现机制:

  (1)      定义一个回调函数

  (2)      提供函数实现的一方在初始化的时候,将回调函数的函数指针注册给调用者

  (3)      当特定的事件或条件发和的时候,调用使用函数指针调用回调函数对事件进行处理

    针对Windows的消息处理机制,窗口过程函数被调用的过程如下:

    1. 在设计窗口类的时候,将窗口赛程函数的地址赋值给lpfnWndProc成员变量

    2. 调用RegisterClass(&wndclass)注册窗口类,那么系统就有了我们所编写的窗口过程函数的地址

    3. 当应用程序接收到某一窗口的消息,调用DispatchMessage(&msg)将消息加值给系统。系统则利用先前注册窗口类时得到函数指针,调用窗口过程函数对消息进行处理。
HICON LoadIcon(HINSTANCE hInstance, LPCTSTR lpIconName);
//加载窗图标,返回系统分配给该图标的句柄, LPCTSTR被定义为CONST CHAR *(指向常量的字符指针),图标的ID是一个常数,要使用MAKEINTRESOUCE宏把资源ID标识转换为需要的LPCTSTR类型

  (4)  sprintf格式化字符,其头文件为stdio。h,在MFC中格式化字符用CString。Forma

  (5)  GetDC()与ReleaseDC()要成对使用,否则会内存泄漏。同样,BeginPaint()与EndPaint(),这两个Parint只能在影响WM_PAINT消息中调用。

  (6)  GetStockObject()得到画笔、画刷、字体、调色板的句柄,使用时必须用类型转换。如:hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH )//创建空画刷

  (7)什么时候用NULL,什么时候用0。答,对指针赋值时用NULL,对变量赋值

时用0。

  (8)什么是野指针?答:将指针指向的变量的内存释放后,此指针即变成野指针!

如何避免野指针?答:将此指针指向NULL即可。p=NULL;

备注:

  1. MFC中生成的C++源文件中都有StdAfx.h,此文件包含了常用的AFX函数的声明,其中有afxwin.h,此文件包含了CRECT,CPOING,CWnd等许多类及其方法的应用。
  2. project->setting->debug可以加入命令行参数。
  3. 在SDK中要加入“windows.h"和”stdio.h"因为LoadCursor,MessageBox等函数的声明在这个文件中。
  4. 创建一个完整的窗口的四个步骤:设计窗口类,注册窗口类,创建窗口,显示窗口。
  5. 函数名可以代表函数代码的首地址,即可以作为函数指针。
  6. atof将字符串转化成float,atoi将字符串装化成int型。
  7. 所有从CWnd类派生的类都有m_hWnd句柄。
  8. 变量的生命周期:可以认为出了包含它的大括号,这个变量的生命周期就结束了。所以全局变量的声明应该在大括号的外面,但是用new声明的变量和用static声明的变量除外。

产生窗口的程序如下:

#include <stdio.h>
#include <windows.h>
#include <stdexcept>
using namespace std; //回调函数原型声明,返回长整形的结果码,CALLBACK是表示stdcall调用
LRESULT CALLBACK WinProc(
HWND hwnd, // handle to window
UINT uMsg, // message identifier
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
); //(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
){
//(2)
//一.设计一个窗口类,类似填空题,使用窗口结构体
WNDCLASS wnd;
wnd.cbClsExtra = ; //类的额外内存
wnd.cbWndExtra = ; //窗口的额外内存
wnd.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH);//创建一个空画刷填充背景
//加载游标,如果是加载标准游标,则第一个实例标识设置为空
wnd.hCursor = LoadCursor(NULL, IDC_CROSS);
wnd.hIcon = LoadIcon(NULL, IDI_ERROR);
wnd.hInstance = hInstance;//实例句柄赋值为程序启动系统分配的句柄值
wnd.lpfnWndProc = WinProc;//消息响应函数
wnd.lpszClassName = "gaojun";//窗口类的名子,在注册时会使用到
wnd.lpszMenuName = NULL;//默认为NULL没有标题栏
wnd.style = CS_HREDRAW | CS_VREDRAW;//定义为水平和垂直重画
//二.注册窗口类
RegisterClass(&wnd);
//三.根据定制的窗口类创建窗口
HWND hwnd;//保存创建窗口后的生成窗口句柄用于显示
//如果是多文档程序,则最后一个参数lParam必须指向一个CLIENTCREATESTRUCT结构体
hwnd = CreateWindow("gaojun", "WIN32应用程序", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, , , NULL, NULL, hInstance, NULL);
//四.显示窗口
ShowWindow(hwnd, SW_SHOWDEFAULT);
//五.更新窗口
UpdateWindow(hwnd); //(3).消息循环
MSG msg;//消息结构体
//如果消息出错,返回值是-1,当GetMessage从消息队列中取到是WM_QUIT消息时,返回值是0
//也可以使用PeekMessage函数从消息队列中取出消息
BOOL bSet;
while((bSet = GetMessage(&msg, NULL, , )) != ){
if (- == bSet)
{
return -;
}
else{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return ;//程序结束,返回0
} //消息循环中对不同的消息各类进行不同的响应
LRESULT CALLBACK WinProc(
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[];
sprintf(szChar, "char is %d;", wParam);//格式化操作,stdio.h
MessageBox(hwnd, szChar, "gaojun", );//输出操作windows.h中
break;
case WM_LBUTTONDOWN://鼠标左键按下消息
MessageBox(hwnd, "this is click event!", "点击", );
HDC hdc;
hdc = GetDC(hwnd);//获取设备上下文句柄,用来输出文字
//在x=0,y=50(像素)的地方输出文字
TextOut(hdc, , , "响应WM_LBUTTONDONW消息!",
strlen("响应WM_LBUTTONDONW消息!"));
ReleaseDC(hwnd, hdc);//在使用完DC后一定要注意释放
break;
case WM_PAINT://窗口重给时报消息响应
HDC hDc;
PAINTSTRUCT ps;
hDc = BeginPaint(hwnd, &ps);
TextOut(hDc, , , "这是一个Paint事件!", strlen("这是一个Paint事件!"));
EndPaint(hwnd, &ps);
break;
case WM_CLOSE://关闭消息
if (IDYES == MessageBox(hwnd, "确定要关闭当前窗口?", "提示", MB_YESNO))
{
DestroyWindow(hwnd);//销毁窗口
}
break;
case WM_DESTROY:
PostQuitMessage();//在响应消息后,投递一个退出的消息使用程序安全退出
break;
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);//调用缺省的消息处理过程函数
}
return ;
}

C++学习笔记1(Windows程序运行原理及程序编写流程)的更多相关文章

  1. Java基础知识强化之多线程笔记05:Java程序运行原理 和 JVM的启动是多线程的吗

    1. Java程序运行原理:     Java 命令会启动Java 虚拟机,启动 JVM,等于启动了一个应用程序,也就是启动了一个进程.该进程会自动启动一个 “主线程” ,然后主线程去调用某个类的 m ...

  2. Android:日常学习笔记(2)——分析第一个Android应用程序

    Android:日常学习笔记(2)——分析第一个Android应用程序 Android项目结构 整体目录结构分析 说明: 除了APP目录外,其他目录都是自动生成的.APP目录的下的内容才是我们的工作重 ...

  3. ZooKeeper学习笔记(二)——内部原理

    zookeeper学习笔记(二)--内部原理 1. zookeeper的节点的类型 总的来说可以分为持久型和短暂型,主要区别如下: 持久:客户端与服务器端断开连接的以后,创建的节点不会被删除: 持久化 ...

  4. Android(java)学习笔记160:Framework运行环境之 Android进程产生过程

    1.前面Android(java)学习笔记159提到Dalvik虚拟机启动初始化过程,就下来就是启动zygote进程: zygote进程是所有APK应用进程的父进程:每当执行一个Android应用程序 ...

  5. Android(java)学习笔记103:Framework运行环境之 Android进程产生过程

    1. 前面Android(java)学习笔记159提到Dalvik虚拟机启动初始化过程,就下来就是启动zygote进程: zygote进程是所有APK应用进程的父进程:每当执行一个Android应用程 ...

  6. 第二章--Win32程序运行原理 (部分概念及代码讲解)

    学习<Windows程序设计>记录 概念贴士: 1. 每个进程都有赋予它自己的私有地址空间.当进程内的线程运行时,该线程仅仅能够访问属于它的进程的内存,而属于其他进程的内存被屏蔽了起来,不 ...

  7. Netty 学习笔记(1)通信原理

    前言 本文主要从 select 和 epoll 系统调用入手,来打开 Netty 的大门,从认识 Netty 的基础原理 —— I/O 多路复用模型开始.   Netty 的通信原理 Netty 底层 ...

  8. Android学习笔记(二十一)——实战:程序数据共享

    //此系列博文是<第一行Android代码>的学习笔记,如有错漏,欢迎指正! 我们继续在Database项目的基础上继续开发,通过内容提供器来给它加入外部访问接口.首先将 MyDataba ...

  9. UNP学习笔记2——从一个简单的ECHO程序分析TCP客户/服务器之间的通信

    1 概述 编写一个简单的ECHO(回复)程序来分析TCP客户和服务器之间的通信流程,要求如下: 客户从标准输入读入一行文本,并发送给服务器 服务器从网络输入读取这个文本,并回复给客户 客户从网络输入读 ...

随机推荐

  1. ASP.NET MVC学习笔记(二)登陆验证

    书上的验证时在配置文件中直接声明用户名和密码,想改成从数据验证账号和密码,搞了一下午都没高出来,不断的调试,发现 var table = userInfo.Tables.FirstOrDefault( ...

  2. Exp2 后门原理与实践 20164323段钊阳

    220164323 Exp2 后门原理与实践 (1)例举你能想到的一个后门进入到你系统中的可能方式?在使用盗版软件,盗版系统,甚至游戏外挂时,往往会让我们关闭杀毒软件,.(2)例举你知道的后门如何启动 ...

  3. 【OCP题库-12c】最新CUUG OCP 071考试题库(71题)

    71.(32-18) choose three Which three statements indicate the end of a transaction? (Choose three.) A) ...

  4. JavaScript(汇聚页)

    JavaScript对象 String 对象 RegExp 对象 \W 元字符

  5. js正则包含三位

    var reg = new RegExp("^(?![A-Za-z]+$)(?![A-Z\\d]+$)(?![A-Z_\\W]+$)(?![a-z\\d]+$)(?![a-z_\\W]+$) ...

  6. 详解sizeof与strlen

    一,sizeof是C语言的一种单目运算符,与C语言的其他运算符++,--一样,它并不是函数:sizeof()以字节为单位给出了操作数的大小:sizeof的值是无符号int. strlen是一个函数,只 ...

  7. CVE-2018-15982漏洞复现

    作者:欧根 漏洞信息:CVE-2018-15982 Adobe已发布适用于Windows,macOS,Linux和Chrome OS的Adobe Flash Player安全更新.这些更新解决一个  ...

  8. MongoDB健壮集群——用副本集做分片

    1.    MongoDB分片+副本集 健壮的集群方案 多个配置服务器 多个mongos服务器  每个片都是副本集 正确设置w 架构图 说明: 1.   此实验环境在一台机器上通过不同port和dbp ...

  9. [科普] 借助 everything 扩展教你屏蔽网址或转发网址

    教你屏蔽网址或转发网址 万恶之源 为什么写这篇文章,俺觉得大家应该是有这个需(bai)求(du)的.只是不知道如何操作... 一.屏蔽网址 1.借助系统自带防火墙 (不推荐) Linux 下有 ipt ...

  10. SpringData JPA实现CRUD,分页与多参数排序

    Spring Data 项目的目的是为了简化构建基于 Spring 框架应用的数据访问计数,包括非关系数据库.Map-Reduce 框架.云数据服务等等,SpringData JPA是简化创建 JPA ...