白手起家Win32SDK应用程序.docx
- 文档编号:23300280
- 上传时间:2023-05-16
- 格式:DOCX
- 页数:54
- 大小:137.99KB
白手起家Win32SDK应用程序.docx
《白手起家Win32SDK应用程序.docx》由会员分享,可在线阅读,更多相关《白手起家Win32SDK应用程序.docx(54页珍藏版)》请在冰豆网上搜索。
白手起家Win32SDK应用程序
白手起家Win32SDK应用程序
第一篇预备知识
1说在前面
由于VC6及MFC的特点,我们许多人从标准C++学习到VC6MFC应用程序的编程学习的过度会有一个很大的夸跃,从而感到非常的吃力。
究其原因之一:
MFC类库设计虽然精巧,但我们在使用MFC设计程序时,会发现MFC到处是API函数的影子。
MFC并没有象Delphi的VCL类库,VB的控件库一样封装得让人几乎完全不用知道还有Win32API函数及其操作原理,所以要想利用VC6的MFC编程,我认为就一定要先学习如何直接用Win32API函数来编程。
对API编程中的一些关键的概念和原理要有一定认识,这样才会有一个比较平滑的过渡。
以上就是我写这个系列的初衷。
2我假设你已有的知识:
这里我假设你已经掌握了如下的知识,如果你在如下方面知识有点不太清楚,那要去补一补罗,否则你看到相关的内容时会有麻烦的。
下面说是我对你知识的假设:
2.1Windows系统的文件、文件夹、路径的概念
2.2C语言的基本知识(基本以等级考试二级C语言为准,还要有所扩充)
2.2.1指针的概念。
2.2.2函数指针概念。
2.2.3各种自定义类型(最重要的是struct类型)的概念。
2.2.4要知道函数的各种参数传递形式(值、地址、引用传递)。
2.2.5typedef及其应用。
2.2.6#include及其应用。
2.2.7十进制、二进制、十六进制。
2.2.8按位与、或、非运算的实质。
2.2.9宏定义概念、使用及意义。
(每个人总是学完了C或C++语法后才会开始用VC6进行Windows编程学习的。
但是你的基础又是如何呢?
这是一个关键。
因此我对你的C知识做了具体的假设。
)
2.3会安装VC6.0并安装到一台机上
2.4VC6编译界面的各组成部分及基本操作(至少会用VC6写控制台程序)。
2.5VC6调试中至少要会设置断点哦。
(呵呵!
我的要求不过份吧!
)
3还必须预备的知识:
以上知识是你看本系列的前提,不过我还要给你预备一下我们再这个阶段学习中会遇到的新东西。
3.1你将会接触到的Win32API函数库:
以前的DOS下或Windows的控制台程序下,你要在显示器上输出文字,要用printf(),或cout的函数对象来完。
但如果你要显示一个图形或图象或为你的程序设计一个图形化的操作界面等等的,那可就惨了,一切都要你自已完成。
复杂得很了!
(唉!
谁叫DOS是字符界面的操作系统呢!
)
现在好了,在Windows下编程你可就轻松得多了。
因为Windows操作系统都为我们准备好了,它提供给我们多达数千个函数(啊!
我要昏倒了。
这么多的函数要学。
),我们通过这些函数来操作Windows系统提供给我们的各种功能。
比如我要在桌面上创建并显示一个窗口。
就只要调用几个相关的被称为API的函数,让Windows来帮助我们完成这些事。
我们是通过这些函数与Windows系统交互的,所以这些函数被称作Win32应用程序接口函数,简称Win32API函数。
请不用害怕哟!
其实,这么多的函数我们不必都马上一一学过,只要掌握了不多的具有代表性的函数的使用方法,并知道大体API函数都提供了哪些功能就可以了。
以后要用时再去查。
Window拥有现成的各种各样的系统功能,供我们的程序调用。
那么又是通过什么方式来调用这些系统功能呢?
原来,Window还现成提供一个接口,好让我们的程序来使用这些系统功能,这个结口就是Win32API函数了(注:
API是应用程序接口的英文缩写)。
Win32API函数是我们的应用程序与Windows系统交互的唯一途径。
我并不打算这时就介绍任何一个具体的API函数。
你现在只要知道你又要接触一个函数库了——被称为Win32API的函数库,如同你以前所学的C/C++函数库。
哈哈,这真是太好了,我们不用再象DOS一样,自已来完成程序界面的绘制了。
我们现在又增加一个全新的函数库,只要调用几个相关API函数,剩下的一切由Windows来完成就可以啦!
(当然还有很多其它功能。
)
3.2 “新”的数据类型:
学完C、C++之后,我们就可以开始进入VC6的Windows编程学习了。
但是在接下来的学习中我们会发现在Windows编程中有许多“新”的数据类型。
看下面:
BOOL、BYTE、INT、UINT、WORD、DWORD、FLOAT、CHAR、LPSTR、HINSTANCE、HWND、HMENU、HICON等等。
你看这些大写的数据类型,你以前有见过吗?
还有很多哦!
我们以后的学习过程中还会见到的。
(呵呵!
你可要有思想准备了!
)
这真是让我们初学者迷惑呀!
难道VC6中对C/C++的基本数据类型又有重大的扩充了吗?
其实不用害怕,只是用新瓶装旧酒而已了。
在VC6的windef.h头文件中已有这些定义:
typedefint BOOL;
typedefunsignedchar BYTE;
typedefint INT;
typedefunsignedint UINT;
typedefunsignedshort WORD;
typedefunsignedlong DWORD;
typedeffloat FLOAT;
在winnt.h中有
TypedeflongLONG;
TypedefcharCHAR;
typedefCHAR*LPSTR,*PSTR;
你看其中(粗体字)CHAR只不过是char的别名而已,也就是说它们是等价的。
只要你包含了相关的头文件,然后你就可以这样申明一个变量:
INTi; //等同于inti;
CHARa; //等同于chara;
LPSTRpa; //等同于char*pa;
明白了吗?
我想你一定会问:
为什么要这样转义呢?
我们直接用int、unsighedint、char等等不就行了吗?
我一句两句也说不清,你只要知道,微软这样做一定是要道理的。
哦!
还有这些HINSTANCE、HWND、HMENU、HICON我没说呢!
今后你还会见到许多这样以H为开头的数据类型,下面就让我在下一节的“句柄”概念中说给你听。
3.3“句柄”概念
由windows系统创建出来的或加载的对象(如应用程序进程、线程、窗口、菜单、图标、光标等等的对象),windows系统都会分配给它们一个唯一的标识值,作为这些对象的标志,称之为句柄。
我们程序中对这些对象的操作其实就是对其句柄的操作。
请记住,句柄就是这些对象的“代号”了。
在编程序中,我们需要用相应的句柄变量来保存这些句柄值,那么用什么类型的句柄变量呢?
就是我们前面提到过的HINSTANCE、HWND。
像其它变量一样(如:
inta;)申明句柄变量,如下:
HINSTANCE hst; //hst变量可以保存某个应用程序实例(即一个进程)的句柄。
HWND hwFirst; //hwFrist变量可以保存某个窗体句柄。
HMENUhMenu; //hMenu变量可以保存某个菜单句柄。
HICONhIcon; //hIcon变量可以保存某个图标句柄。
具体的使用让我以后再慢慢与你道来啦。
那么这些类型的实质又是什么?
目前,它们都只是一个int类型(小语:
我听说微软也许以后会改变它的类型)。
不过不管怎样,你现在只要把HINSTANCE、HWND、HMENU、HICON当做是一个独立的数据类型就可以了。
3.4消息标识
Windows系统是一个基于消息的系统。
这样的机制导致我们的程序与以往DOS下的程序流程会有很大的不同。
(这可是很考我们的智慧喽!
)
从软件使用者角度看一个Win32窗口程序运行的过程:
1)我们运行一个应用程序,程序创建并显示一个我们想要的程序窗口。
2)当我们对窗口进行操作时(如单击、双击、右击、按下键盘、最大化、最小化、关闭窗口等等),程序会完成特定的操作,如:
单击最大化、最小化按钮时,窗口会最大化、最小化操作;对窗口中菜单项的选取时,会完成该菜单的相应功能。
从程序员的角度看一个Win32窗口程序运行的过程:
1)我们运行一个应用程序,程序中我们通过Win32API函数创建并显示一个我们想要的程序窗口。
(由我们的程序来调用函数实现)
2)当我们对窗口进行操作时(如单击、双击、右击、按下键盘、最大化、最小化、关闭窗口等等),窗口会自动产生一系列相应的消息(这是由操作系统实现的)。
3)具体地讲:
当我们改变窗口大小时,会产生WM_SIZE消息;单击关闭按钮关闭窗口时,会产生WM_CLOSE消息;选取某一菜单项时,会产生WM_COMMAND消息;按下键盘时,会产生WM_CHAR、WM_KEYDOWN、WM_KEYUP消息;单击鼠标左键时,会产生WM_LBUTTONUP、WM_LBUTTONDOWN消息等等。
啊,很多很多,我也不必全部罗列出来了。
(我说过了,这些都是由操作系统实现的)
4)windows系统会将这些消息排入我们窗口所在线程的消息队列中(你会明白线程是什么吗?
)(也由Window操作系统实现),这样我们的程序才有机会获取并处理这些产生的消息。
5)我们的程序可以通过Window操作系统提供的API函数来获取这些消息及相关的信息。
然后通过我们学过的条件判断语句来判断是什么消息及其相关的操作信息并可编写相应的程序代码,从而实现对窗口操作的不同反应。
(由我们的程序来实现)
看上述的过程描述,你可能要有点的抽象思维能力了。
你现在只要有对程序流程有如上的大体认知就可以了。
慢慢地我会将上述流程变成确实的程序代码噢!
(等等,还是有个问题:
这些WM_CLOSE、WM_COMMAND、WM_CHAR、WM_KEYDOWN、WM_KEYUP、WM_LBUTTONUP、WM_LBUTTONDOWN等等的以WM_开头的消息到底又是什么东西呢?
)
看VC6的头文件winuser.h中的片段:
……
#defineWM_CLOSE 0x0010
……
#defineWM_LBUTTONDOWN 0x0201
#defineWM_LBUTTONUP 0x0202
#defineWM_LBUTTONDBLCLK 0x0203
#defineWM_RBUTTONDOWN 0x0204
……
#defineWM_KEYDOWN 0x0100
#defineWM_KEYUP 0x0101
#defineWM_CHAR 0x0102
……
#defineWM_INITDIALOG 0x0110
#defineWM_COMMAND 0x0111
#defineWM_SYSCOMMAND 0x0112
……
哦!
这些WM_开头的所谓的消息只不过是一系列16进制整型数值的符号常量而已。
每一个不同的整型数值代表着一个窗口某一操作的标识,因此我们将这些数值或者说以WM_开头的符号常量称之为消息了。
也就说,我们在窗口中作各种不同的操作,Windows系统会产生各种相应的数值。
我们就是通过条件语句比较这些数值来判断我们在窗口中所做的操作的。
3.5资源标识
(你看我没完没了地介绍一个个概念,觉得烦不烦?
不用你说,我自已也有点烦了。
唉!
不过这些似乎是必要的,所以我不得不坚持下去。
不过,还好,剩下的不多了。
)
那么VC6中资源是什么一种概念呢?
我们的程序中可能要用到各种图标(*.ico文件)、各种形状的鼠标(*.cur文件)、各种图像(*.bmp/*.gif等等)、各种声音(*.wav等)、各种菜单……,这些就是我们这里所说的资源了。
每一个要用到资源,我们都要给它分配一个编号或名称,作为这个资源的标识。
之后我们的程序只是通过这个编号或名称来访问这些资源了。
所以这些编号或名称我们称之为资源标识。
好了,现在你也只要有了一个大体的映象就可以了,具体的形式和应用让我慢慢再与你说了。
(各位可以提出你的疑问,白云小飞一定会尽力回复的。
)
啊!
终于结束冗长的概念解说了,看到这里,请先回顾一下我们前面讲的东西。
然后嘛——我们可以开工啦!
。
第二篇创建Win32工程和主函数
1 要编写一个程序,我们就要首先用VC6应用程序向导创建一个工程,下面我将给你创建一个空工程(也就是没有任何源文件及代码的工程)
1.1 =>文件->新建…->”工程”标签->位置:
”D:
\”(你可以设置你想要创建的位置)->工程名:
MyApp(你可以自己指定其它名)->选择”创建新的工作空间”->确定->一个空工程->完成
1.2 我们发现,它在D:
\下生成了一个MyApp文件夹。
并在MyApp文件夹下生成了几个文件,如下:
MyApp.dsp
MyApp.dsw
MyApp.ncb
MyApp.opt
其中,MyApp.dsp是项目文件和MyApp.dsw是工作区文件,它们是不能删除。
项目文件的作用:
生成一个EXE或DLL程序的所有相关源文件、有头文件的位置信息都记录在MyApp.dsp项目文件中。
工作区文件的作用:
如果一个复杂的软件工程可能是由多个EXE和多个DLL程序组成,这样每个项目文件的位置信息又记录在MyApp.dsw工作区文件中。
当然,我们的这个工程只有一个EXE程序,所以只有一个项目,这个项目文件MyApp.dsp也同样要记录在MyApp.dsw中了。
MyApp.ncb和MyApp.opt虽删除后会自动生成,但是还是请不要这样做哦!
以后我还会说它们的作用。
我们下次要编辑源程序时,只要打开工作区文件MyApp.dsw就可。
2 =>文件->新建…->”文件”标签->选”添加到工程”->选”MyApp”->文件名:
MyAppMain->”位置”默认->确定
2.2 可以看到,在D:
\MyApp文件夹下生成了MyAppMain.cpp源文件。
3在MyAppMain.cpp文件中输入一个主函数
3.1代码如下:
#include
#include
intWINAPIWinMain(HINSTANCEhinstance,
HINSTANCEhprevinstance,
LPSTRlpcmdline,
intncmdshow)
{
//将会在这里输入主函数的代码
return0;
}
3.2包含必要的头文件:
首先你只要包含下面两个头文件就可,因为它们已经包含了绝大多数的MyApp应用程序必要的头文件。
#include
#include
3.3主函数名:
函数头定义的书写格式很有趣:
intWINAPIWinMain(HINSTANCEhinstance,
HINSTANCEhprevinstance,
LPSTRlpcmdline,
intncmdshow)
写成四行,其实没什么,只不过写在一行里太长了,如下:
intWINAPIWinMain(HINSTANCEhinstance,HINSTANCEhprevinstance, LPSTRlpcmdline, intncmdshow)
并且写成上面的四行反而可读性更强,所以以后你会经常看到这样书写的。
WinMain函数相当于Dos下的main函数,Windows应用程序的主函数不用main而是用WinMain。
一个程序必有并只能有一个WinMain函数。
这个主函数可以写在本工程中的任何一个.cpp文件中。
3.4参数:
hinstance:
类型是HINSTANCE,这种类型就是前面我们可是提到过的应用程序句柄啦。
hinstance的值就是你的当前应用程序进程的句柄。
你的程序每次运行,它的hinstance值是不会一样的。
不过我们并不关心hinstance的值是多少。
我们只要知道hinstance里的值就是代表本应用程序进程的句柄值就可以了。
我们等一会儿就会用到它了,请看好哦!
hprevinstance:
现在已经不用了。
我们可以完全不理它。
lpcmdline:
这是一个命令行参数。
与main(intargc,char**argv)中的命令行参数相似。
由于与本题无关,我们也不可完全不理它,对此不再进一步讨论下去。
至于它的数据类型LPSTR,我在前面已经说明了,它其实就是char*类型。
ncmdshow:
一个整型值。
启动过程中被传递给应用程序,带有如何打开应用程序主窗口的信息。
这样,程序的使用者有了一点点的控制应用程序如何启动的能力了。
作为一个程序员,如果想忽略它也可以,想使用它也行。
哦,那我们这里也先忽略它了。
3.5返回值:
是一个int值,当我们的程序正常结束退出时,一定要返回一个0值。
所以我们的WinMain函数体内最后有return0;了
3.6函数名前的WINAPI是什么?
最后还有一个要说明的——就是WINAPI。
这是什么呢?
在VC6的Windef.h头文件中是如下定义的:
#defineWINAPI __stdcall
也就是WINAPI等于__stdcall了。
你知道吗,凡是提供给Windows操作系统调用的函数都得是__stdcall调用的。
WinMain主函数当然是由Windows系统调用的,因此定义WinMain前要用__stdcall(即WINAPI)修饰。
(你会明白函数调用方式的具体含义吗?
不知道也没关系,现在只要记得WINAPI要放在WinMain前就行了。
)
另外说明一点,int与WINAPI哪个在前哪个在后都是可以的。
好了,我们现在对主函数定义处的各个部分有了必要的了解。
你可以休息一会儿,然后回顾一下我们前面操作的过程:
想想我们在本篇中做了哪些事?
生成了哪些文件?
这些文件是什么作用的?
主函数定义的各个部分是什么作用?
如果你已经对上面所做的感到比较清晰,那太好了,Comeon!
我们继续吧!
第三篇增加一个回调函数
1请再创建一个函数。
LRESULTCALLBACKWinProc(HWNDhwnd,
UINTmsg,
WPARAMwparam,
LPARAMlparam)
{
//这里可以输入响应消息的代码
return0;
}
此函数人称回调函数也称自定义窗口过程函数。
但其实它与我们一般函数无异,你千万不要把这个函数想得太复杂了啊!
记住,函数名WinProc及各参数变量名是可以由你来指定,但是参数类型、个数、顺序、及返回值类型是不能改变的。
那么,这个函数是干什么的啊?
它是一个用来与某窗口关联的函数。
当我们在窗口上的每一个操作,都会调用这个函数。
这在个函数里,我们可以写上代码来完成我们在窗口上操作的相应功能。
先来看参数部分:
UINTmsg:
UINT类型不是我们在前面也见过吗?
就是unsignedint类型了。
每次程序运行时用户在窗口上操作所产生的消息都会通过msg传递进来。
msg里保存的值就是我们对窗口操作时产生的消息值(即WM_CLOSE、WM_CHAR、WM_COMMAND、……的值)。
HWINDhwnd:
哦!
这是我在第一篇中讲过的一个窗口句柄类型的变量。
我们可以通过传入的hwnd的值知道msg中的消息对应的是哪一个窗口。
WPARAMwparam,LPARAMlparam:
wparam和lparam这两个参数变量的类型分别是WPARAM和LPARAM。
呵呵,我不是说过,你还会见到许多“新”的数据类型的吗?
你可要有心理准备噢。
在windef.h中有定义:
typedefUINTWPARAM; //看,WPARAM其实就是unsignedint。
typedefLONGLPARAM; //看,LPARAM其实就是long类型
typedefLONGLRESULT; //LRESULT与LPARAM一样也是长整型long
返回值:
类型为LRESULT,看windef.h中的定义可以知道是一个长整型long现在你大体知道这些就行了。
至于更进一步的认识,让我们先放到一边去吧!
CALLBACK:
这又是什么呢?
在windef.h中的定义如下:
#defineCALLBACK __stdcall
#defineWINAPI __stdcall
哦!
它与WINAPI是一样的,也是__stdcall了,这个WinProc函数是提供给操作系统调用的。
我说过操作系统调用的函数都得在前加__stdcall。
(那为什么不直接用__stdcall呢?
)
呵呵,这至少可以增加代码的可读性及易改性。
我猜也许你还会继续下一个疑问:
那我又如何具体地使用这个函数呢?
慢慢来,现在你只要输入到你的.cpp文件中就可以了。
到此为止,我们的MyAppMain.cpp文件代码如下:
//BeginMyAppMain.cpp
#include
#include
LRESULTCALLBACKWinProc(HWNDhwnd,
UINTmsg,
WPARAMwparam,
LPARAMlparam)
{
//这里可以输入响应消息的代码
return0;
}
intWINAPIWinMain(HINSTANCEhinstance,
HINSTANCEhprevinstance,
LPSTRlpcmdline,
intncmdshow)
{
//将会在这里输入主函数的代
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 白手起家 Win32SDK 应用程序