-
C
语言究竟能干什么
序言
鉴于现在已经大三了,很多同学
很迷茫,自己学的东西到底能做什么,将来自己到底能干什么?我不想看着同学迷茫
的面
孔,
特别是几个好兄弟,
有几个想学习编程,
但又苦苦找不到门路的兄弟,
所以想写点东西,
希望对大家又点略微的帮助,
以尽兄弟我的
微薄之力。
很多同学学了
C
语言之后,可能难免会有所感叹:这就是
C<
/p>
语言!总是感觉
C
语言竟然能写出
Windows
、
Linux
?为
了解除同学们
的疑惑,
也愿为同学们指点编程之道吧。我写的这些东西采用
C
语言,计
划通过编程实例来讲解
C
编程的一些知识,
让大家对
C
能又更深一层的理解和认识。当然,大家不要
指望看了这些之后会写出一个操作系统来,但是我想,如果你认真看了
的话,写
一个类似与
QQ
的聊
天程序应该不难。
本来书是假期
里照顾妈妈时写的,原想是
1
、不让自己
的水平停滞不前,温故知新
(两个月
的假期是很
长的)
2.
帮助一些
同学,解决编程上的困惑
<
/p>
3.
希望妈妈快
点康复
< br>
4.
让母亲和家
里人知道自己
一直都很努力,我
是好样的
C
p>
语言的基本语法我是不打算再提了,很多
C
语言编程的书,就是将一些基本的数据类型、数据结构、语法,然后就
是一些数值
计算的实例,大多数都是雷同的,难免有抄袭之嫌,而且页没有多少
实用价值。
本书以实用实例作为编
程指导,指引大家编写真正实用的程序。了解到大家对黑客程序、病毒、窗口类程序比较感兴
趣,
因此我就拿这些实例进行讲解。
基于大家基本都用
p>
Windows XP SP3
,
我也就在
这个系统上把程序调试成功后再给
大家讲解。编程环境,我还是喜欢
V
isual
C++ 6.0
本书计划从四个大的方面来讲,这四个方面是:窗口类、文件
操作类、网络类、数据库类。
都是时下流行的编程必备技术,
也是软件开发者,必须掌握的技术。中间以实例讲解,逐步学习,相信大家看完后
会有很
大的提高的。
< br>但现在母亲已
经能够不在了,所以第三点,就
改为原母亲
在天之灵得到慰藉,早日放下烦恼,不用惦记
我们。
第一章
窗口类程序的编写
这一章就先来讲解下窗口类程序的编写。因为现在程序没有界面,就像人没有脸面一样,而且好的界面更
能吸引人。
从基本的界面开始,
相信能给大家指明出一条路的,
使大家很容易地掌握窗口序的编写。
其实界面设计利用
VC 6.0
的
MFC
,很容易地制作出来。这里从底层开始写代码来写界面程序,使大家知道一些底层的东西,为以后学习打下好的
基础,相信您学了这些,再用
VC
的
MFC
会得心应手的。
1.1
用
C
写的第一个一个窗口程序
作为编程的开始,我们还是以一个
Hello
World
来开始我们的学习之旅。代码如下:
#include
void
main()
{
}
这是一个再简单不过的
C
程序了,
只要有点
C
语言的知识就能够懂的,
不过这里估计还有些人,
到现在还不知道
#include
中的头文件
p>
stdio.h
到底是什么东西,我就来说下了,
< br>stdio.h
是一个文本文件,存在于磁盘上的,已
V
C
为例
它的位置如下图:
printf(
也许你听说过
printf
()函数是在
stdio.h
中预定义的,但是
你见过其定义的形式没有,没有且看下图
< br>其定义形式,就如图中所示,也许你并不懂前面那些东西是什么,不用担心,以后我会慢慢解释给大家的。 函数是先定义才能使
用的,所以
stdio.h
中定义
printf
函数,我我们在引用了
stdio.h
头文件后就可以在程序中调用
pr
intf
函数了。
上面是在命令行中显示一个“
Hello World!
”
,
没什么意思,下面我写一个窗口程序,显
示个
Hello World!
#include
void main()
{
}
编译运行后如下图:
MessageBox(NULL,
我的第一个窗口程序
< br>
弹出的是一个对话框,上面有
Hello
World
,还有一个标题和一个“确定”按钮。
当然你会说这对话框也算个窗口吗?这里肯定的告诉你:是的,对话框是窗口程序的一个子集。你可 能还会这样问,这样一个简
单的窗口有啥用呢,其实这样的窗口非常有用,我们在操作计
算机的时候,会出现一些警告或提示的对话框,都是基本是这种方
法写出来的。就算是这
个很简单,学习本来不就是有易向难,有浅显深奥去的过程吗。
整个效果几乎就是靠一个函数
MessageBox
的功劳。
这里也先不介绍这个函数了,说些其他的。
其实用
C
编写一些恶程序,就是把编程环境中所提供的
一些函数熟悉了基本就可以了。用
VC
来写成序,其中的头文件
有很多,
定义了很多
Windows API
函数
、
数据
结构、
宏,
可以让我们大家运用,
通过
它们,
我们可以快速开发出使用的程序。
这些
< br>Windows
API
在微软的
MSDN
上查,上面有很多说明,部分还有代码示例。不会是可以输入函数名,查找相
关信息,建议大家用英文版的
Library
,因为其内容比中
文版的全面,英语不好的同学呢,就先看中文了
中文
MSDN:/library/zh-cn/
英文
MSDN:/library/en-us/
到这里,我们就完成第一个有界面程序的编写,你感觉写有界
面的程序难吗?显然不难。
下面看一个向锋和波波感兴趣的程序:九九乘法
采用命令行形式
#include
“
stdio.h
”
< br>
int i=0,j=0;
for(i=1;i<10;i++)
好的,
这一节就这样吧,大家先各自了解下微软的
MSDN
,对以后的
学习会有很大的帮助的。
1.2
上
一节中,我们用
MessageBox
函数轻松地实现了一个对
话框窗口,可能你会说,那仅仅是个没有用的对话框而已,是的,只是
我们继续。今天来
编写一个真正的窗口程序。
下面就该罗嗦一段了,由于大家以
前并没有写过什么窗口程序,写的都是命令行下的,我们知道在命令行下的程序都有一个主函
第一个真正的窗口程序
for(j=1;j
printf(
“
%d*%d=%d
t
”
,j,i,j*i);
prin
tf(
“
n
”
);
和那个
javascript
效
果都是一样的,所以语言只要学好一样,其他的就很容易旁通的,学习就捡一种学好,不要贪多。
对话框而已。
我之所以以一个对话框为例呢,
是因为我只是想让你知道写一个有界面的程序并不是件难办的事。
明白
了这一点后,
数
< br>main
,这个函数也就是程序的入口函数。我们现在用
VC 6.0
来写,而且要写窗口类程序,
VC 6.0
给我们提供了一个专门用作
窗口类程序的入口函数
WinMain()
这个函数原型是这样的
int WINAPI WinMain(
HINSTANCE
hIns
tance,
HINSTANCE
hPrevIns
tance,
LPSTRlpCmdLine,
int nCmdShow
);
大家是不是感
觉这个函数挺复杂
的,有这么几
个参数,而像
main
好
像就没有参数。其
实
main
是有参数
,这
个向
锋和小四是知
道了的。但是<
/p>
main
函数的参数是可以省略的
,而<
/p>
WinMain
是不可以省的。这里也要
对
VC 6.0
的编
译模
式改下
看下图
依次
是“
工
程”→“设置”→“连接”,在“
工程选项”里把
console
改为
windows
就可以了。
如果认真学了汇编
,
或是手写命令
编译连接过
C
程序,
就会知道这是干什么的。
Console
是控制台的意思,以前
我们
用
mian
函数写的
程序
都是以控制台
模式连接的,所以很少会有界面<
/p>
的。现在我们要写有界面的程序
,所以要选
Windows
(窗口)模式了。
我们写入以下
代码,并按照上面说的方法去做
< br>,看看结果
#include
int WINAPI
WinMain(HINSTANCE hIns
tance,
{
}
<
/p>
MessageBox(NULL,
创建的窗口程序
return 0;
HINSTANCE
hPreInstance,
LPSTR lpCmdLin
e,
int nShowCmd)
结果如下图
:
与第一节中的
这段代码代码比较下
#include
“
windows
.h
”
void main()
{
}
M
essageBox(NULL,
我的第一个窗口程序
两者比较下
,
后者多
了个
cmd
窗口。
可见用
main
写的并没有完全脱离命令行呀
。
所以以后我们写
窗口程序就用
winmain
p>
了。
好了,转过来
,我们来看看
WinMain()
函数,其中有
4
个参数
先看下解释(
看不明白得先看完):
hIns
tance
:应用程序当前事
例的句
柄。
hPrelnstanc
e
:应用程序
的先事例
的句柄。对
p>
于同一个程
序打开两次
,出现两个
窗口第一次
打开的窗口
就是先前
实例
的窗口。对于
一个
32<
/p>
的位程序,该参数总
为
NULL
。
lpCmdLine
:指向应
用程序命令行的空字符串的指
针,不包括函数名。获
得整个命
令行,参看
GetCommandLine
。
nCmdShow
:
指
明窗口如何显示(是隐藏还是显
示,有没有最大化按钮之类的
)
。取值可以参
考
MSDN
这里我相信有
一个词大家好应该比较陌生,句<
/p>
柄
(HANDLE)
是吧。下面我就来简
单的说下
句柄其实就
是
Windows
系统中一个东西的唯一标识。就是系统中有很
多运行的程序或者资源之类的,为了更好的
管理
使用,
Windows
系统给它们每人一
个<
/p>
ID
一样。懂
得网页制作的人应该知道网
页中
各个元素的
ID
吧
,网页的
ID
如
果重
复话可
能出现错误。
那么系统的句柄
会不会有相同的
,那是肯定不
会有的了,就和
p>
我们的学号一样
,系统自动分
配每
一个模块的句
柄,是不会相同的了。
对于句柄大家
可以先这样理解着,不
用一下子
搞懂得。以后学着学着就明白了
。
估计大家对那
几个参数的类型
改犯迷糊了吧
。其实那几个类型,并不是什
么新类型,都是
p>
Windows
开发人员为了
自己
和他人编程方
便,同过基本的
C
语言语法定义一种
新的结构体,或者是共同体,
再者就
是枚举类型。我知道结构
体、
共同体和枚举
类型,很多老师是没有讲到的,
因为在书的后边,很多教
C
的,又
是很垃圾的老师,所以不会讲那
么快
的。其
实结构体这些
数据类型,就
是
通过我们常用的
字符、整型、
浮点等
数据类型
构造一个比较复
杂的类型而已
,举
个例子,就是
我们知道
C
没有一个数据类型可以描
述一个人吧,那么我构造一个
< br>是不是很方便我们编程呢。我们
可以
这样构造一个
struct People
{
} <
/p>
我们这样定义
以后就可以在我们以后的程序中
利用这个数据类型了,
People
zhangsan;
把
zhangsan
的身高
172
放到
中
。这样可以方便完成很多工作。
所以结构体是很简单的,还有其
他的复杂数据类型也是很简单
的,
都是有常用的<
/p>
简单的类型来结合到一起构造一
个复杂的而已。这
和
JAVA
定
义类是很相似的
,
java
定义个人类,
不是
可以这样的
public class People
{
}
看起来
都差不多,而
且用法也很相像
。唯一的差别其
< br>实就是类可以
有方法,而结构
体是没有的(经
过特殊处理也
是可
以的,这里不
< br>用考虑)。
public
int age;
public s
tring sex;
public height;
……
int
age;//
年
龄
char sex[2];//
性别
int height;//
身高
……
<
/p>
上面是为了让
大家了解下复杂数据类型的定义
,罗嗦了一大堆。下面来看
下
WinMain
中
第一个参数的类型
HINSTANCE
这个只是个结构体而已,实际上
和
HANDLE<
/p>
这个类型差不多
,但是有一点差别,而
H
ANDLE
是这样
typedef PVOID HANDLE
;
定义的,
PVOID
是什么呢,
p>
我们来看下
typedef void *PVOID;
说明
PVOID
是一个指针,
初始指向空(
void
)。因此可以知道句柄也是个指针而
已。看着这么复杂原来也只是指针。
这些都可以在微软的
p>
msdn
上查得到的,而且很详细的
那个第二个
LPSTR
根据字面上的
意思就知道是字符
串类型了。查一查果然是。
大家一定要利
用好
msdn
,
很有用的。
本节就到此结
束了,主要是说明了一个
WinMain
函数和
结构体
的事情,东西也不算太多,大家应该能接受
得了吧。下<
/p>
节就来点复杂
点深点的东西,希望大家做好心
理准备。
1.3
在来啰嗦
之前,希望大家能够
做好准备,这一节
知识有点多,内容有
点长。但愿大家能够
一口气读完,
如果
一口
气读不完,那
就换口气接着读
。
上节
中我们
用
MessageBox()
就
实现了一个真正的窗口。
MessageBox()
中的原型<
/p>
如下:
Int
MessageBox(HWND hWnd,
LPCTSTR lp
Text,
LPCTSTR lpCaption,
UINT
uType);
窗口程序的编
写
参数解释
hWnd
所属对话框所属窗口的句
柄,如果是
NULL
,则此对话框不属
于任何一个
窗口。
lpText
对话框窗口的
显示内容。
lpCaption
对话框窗口的标题。
uType
对话框的
样式和动作(像是确定按钮
,还
是取消按钮就是设置这里的)
关于这个函数
的细节可以看这里
/en-
us/library/ms645505(VS.85).aspx
到此为
止
,你也算是会了窗口程序
的编写,但只是一个
开始,不过这已经
很好,可能会让你感
觉到了
C
的
魅
力,也可能会<
/p>
稍微解点
C
语言能干什么的疑惑。在开始
写
代码之前,我有必要把细节和
原理先说明下。
Windows
下一个窗口创建的过程
有以下几个步骤:
1.
程序创建一个
窗口,首先要向
Wind
ows
系统注册一个窗口类
wndclassex
,其实就是定义一个变量,变量的
类
型
是
WNDCLASSEX(
结
构
体
)
。
该
结
构
体
的
p>
定
义
与
介
绍
看
这
里
(
/en-us
/library/ms63357
7(VS.85).aspx)
,
typedef struct {
UINT
cbSize;
UINT style;
WNDPROC lpfnWndProc;
int cbClsExtra;
int
cbWndExtra;
HINSTANCE hInstance;
HICON hIcon;
HCURSOR
hCursor;
HBRUSH hbrBackground;
LPCTSTR lpszMenuName;
LPCTSTR lpszClassName;
HICON
hIconSm;
} WNDCLASSEX, *PWNDCLASSEX;
成员介绍
cbSize
值为
sizeof(WNDCLASSEX),
在调用
G
etClassInfoEx
前必须要先设置它值。
style
窗口类的样式,它的值可以是
窗口样式值的任意组合。
可以有以下的
值
lpfnWndProc
指向窗口
处理函数(回调
函数)。处理窗
口事件
,像单击
鼠标会怎样,右
击鼠标会怎样,
都
是由此函数控
制的。
cbClsExtra
为窗口类的
额外信息做记录,
系统初始化为
0
。<
/p>
cbWndExtra
记录窗口实例
的额外
信息,
系统初始为
0.
如果程序使用
WNDCLASSEX
注册一个从
资源文件
里
创建的对话框
,则此参数必
须设置为
DLGWINDOWEXTRA
hIcon
窗口类的
图标,为资源句柄,如果设
置
为
NULL
,系统将为窗口提供一个
默
认的图标。
hCursor
p>
窗口类的鼠标样式,为鼠标样
式资源的句柄,如果设置
为
NULL
,
系统提供一个
默认的鼠标样式
。
hbrBackground
窗口类的背景刷,为背景刷句<
/p>
柄,也可以为系统颜色值,如
果颜色值已给出,则必须转化
为
以下的
HBRUSH
的值
?
COLOR_ACTIVEBORDER
?
COLOR_ACTIVECAPTION
?
COLOR_APPWORKSPACE
?
COLOR_BACKGROUND
?
COLOR_BTNFACE
?
COLOR_BTNSHADOW
?
COLOR_BTNTEXT
?
COLOR_CAPTIONTEXT
?
COLOR_GRAYTEXT
?
COLOR_HIGHLIGHT
?
COLOR_HIGHLIGHTTEXT
?
COLOR_INACTIVEBORDER
?
COLOR_INACTIVECAPTION
?
COLOR_MENU
?
COLOR_MENUTEXT
?
COLOR_SCROLLBAR
?
COLOR_WINDOW
?
COLOR_WINDOWFRAME
?
COLOR_WINDOWTEXT
lps
zMenuName
指向一个
以
NULL
结尾的字符床,同目录资源
的名字一样
。如果使用整
型
id
表示菜
单,可
p>
以用
MAKEINTRESOURCE
定义
一个宏
。如果它的值为
NULL,
那么
该类创建的
窗口将都没有默认的菜单。
lps
zClassName
窗口类的名字,字符串类型。
hIconSm
小图标
的句柄,在任务栏显示的图标,
可以和上面的那个一样。
< br>
定义一
个
< br>WNDCLASSEX
类型变
量后,在给变量成员初始化
后,
我们就可以用
Register
WindowEx(&wndclassex)
来注册这个窗口
类了。
这个注册过程
,就和我们平常创建一个项目一
样,都要先注册才能创建
。
2.
创建窗口
这一步很简单
,就是利用
CreateWindowEx()
函数
来创建就是了。
CreateWin
dowEx
函数的原型如下
:
HWND CreateWindowEx(
DWORD
dwExStyle
,
LPCTSTR
lpClassName
,
LPCTSTR
lpWindowName
,
DWORD
dwStyle
,
int
x
,
int
y
,
int
nWidth
,
int
nHeight
,
HWND
hWndParent
,
HMENU
hMenu
,
HINSTANCE
hInstance
,
LPVOID
lpParam
);
参数说明
dw
ExStyle
:指定窗口的扩展
风格。该参数可以是下列值:
p>
WS_EX_ACCEPTFILES
:指定以该风格创建
的窗口接受一个拖拽文件。
<
/p>
WS_EX_APPWINDOW
:
当窗
口可见时,将一个顶层窗
口放置到任务条上。
WS_EX_CLIENTEDGE
:指定窗口有一
个
带阴影的边界。
WS_EX_CONTEXTHELP
:在窗口的标题条包含一个问
号标志。
p>
WS_EX_CONTROLPARENT
:允许
< br>用户使用
Tab
键在窗口的子窗口间搜索。
WS_EX_DLGMODALFRAME
:创建
一个
带双边的窗口;该窗口可以
在
dwStyle
< br>中指定
WS_CAPTION
风格来创建一个
标题栏。
WS_EX_LEFT
:
窗口具有左对齐属性,这是缺省
设置的。
WS_EX_LEFTSCROLLBAR
:
如
果外壳语言是如
Hebrew
p>
,
Arabic
,
或其他支
持
reading order
alignment
的语言,则
标题条(如果存在)则在客
户
区
的左部分。若是其他语言,在
该风
格被忽略并且不作
为错误处理。
WS
_EX_LTRREADING
:窗口文本以
LEFT
到
RIGHT
(自左向右)属性的顺序显示。这
是缺
省设置的。
WS_
EX_MDICHILD
:创建一
个
M
D
子窗口。
WS_EX_NOPATARENTNOTIFY
:指明以这个风格创建的窗口
在被创建和销毁时不向父
窗口发
送
WM_PARENTNOTFY
消息。
WS_EX_OVERLAPPED
:
WS_E
X_CLIENTEDGEWS_EX_WINDOWEDGE
的组合。
WS_EX_PALE
TTEWINDOW
:
WS_EX_WINDOWEDGE,
WS_EX_TOOLWINDOW
和
WS_WX_TOPMOST
风格的组合
WS_EX_RIGH
T:
窗口具有普通
的右对齐属性,这依赖于窗口类
。
WS_EX_RIGHTSCROLLBAR<
/p>
:垂直滚动条在窗口的右边界。
这是缺省设置的。
WS_EX_RTLREADING
:如果外壳语言是
如
Hebrew
,<
/p>
Arabic
,
或其他支持读顺序对齐<
/p>
(
reading
order
alignment
)的语言,则窗口文本是一自
左向右)
RIGHT
到
LEFT<
/p>
顺序的读
出顺序。
WS_EX_STATICEDGE
:为不接受用户
输入的
项创建一个
3
一维边界风格
WS_
EX_TOOLWIDOW
:
创建工具窗口,即窗口是一个游<
/p>
动的工具条。
WS_EX_TOPMO
ST
:指明以该风
格创建的窗口应放置在所有非最
高层窗口的上面并且停留在
其
L
,即使窗
口未被激活。
使用函数
S
etWindowPos
来设置和移
去这个风格。
WS_EX_TRANSPARENT
:指定以
这个风格创建的窗口在窗口下的
同属窗口已重画时,
该窗
口才可以重画
。
由于其下
的同属富日已被重画,该窗口是
透明的。
IpClassName
:
窗口类
的名字。
lpW
indow
Name
:
p>
指向一个指定窗口名的空结束
的字符串指针。其实就是窗口
的名字。
dwStyle
:
指定创建窗口的风格。
该参数可以是下列窗口风格的
p>
组合再加上说明部分的控制风格
。
x
:
窗口的横坐
标。
y
:
窗口的
竖坐
标。
nWidth
:
窗口
的宽度。
nHeight
:
窗口
的高度。
hMenu
:菜
单句柄,或依据窗口风格指明
一个子窗口标识。
hlnstance
:与窗口相关联的模块事例的
句柄。
lpParam
:
指向一个值的指
针,该值传递给窗口
WM_CREATE
消息
请调用
GetLastError
函数。
3.
显示窗口
显示窗口就是
更简单的事情了。
p>
连个函数轻松
搞定,第一个函数就是
Sho
wWindow
(),原型如下:
BOOL ShowWindow(
HWND
hWnd
,//
当前的窗口句柄
int
nCmdShow //
可见状态
);
返回值
:如果函数成功,返回值为新窗口的句柄
:如果函数失败,返回值为
< br>NULL
。若想
获得更多错误信息
,
因为
CreateWindowEx
函数创建的窗口是在内存中的,并没有显示到显示器上,用
ShowWindow()
函数,设
定窗口的可见状态,并把数据从内存中移动到显卡上,
以便显示。
第二个函数就是
UpdateWindow()
;
函数原型
:
BOOL
UpdateWindow(HWND hWnd);
描述
:
这个
UpdateWindow
函数通
过发送重绘消息
WM_PAINT
给目标窗体来更新目标
窗体客户区的无效
区域。如果那
个窗体的无效区域没有,就
不发
送重绘消息
WM_PAINT
了
。注意了,这个
API
函数
是直
接发送消息
WM_PAINT
给目标窗
体的,没有进入过消息队列。
函数
参数:
hWnd
一个要更新的窗体的句
柄
函数
返回值:
如果函数
调用成功,返回值为非零值。
如果函数调用
不成功,返回值为零。
经过这三步后
,一个窗口就实现了,
就创建了
出来,难不,也真够难的,
Windows
想的正周到,
把创
建过程的每一
< br>个细节都给想到了,每毫秒可能
发生的事情都想到了,难
怪
Windows
那么
贵,还不开源。
也
算是人间的产
< br>品嘛,费的心血可真不
少呀。说难其实也不难
,创建一个
窗口程序也就
三步:一注册
,二创建,
三显示。很容
易就
ok
了。这
T
他妈容易了吧。
原来就是这些的,我想我已经说的挺明白的了,如果你有什么疑惑,可以给我发邮件(<
/p>
cangsanbujin@
)
下面我们就按照上面所说的来编程实现一个窗口:
#include
//
回调函数
LRESULT WINAPI WinProc(HWND hWnd,UINT
Msg,WPARAM wParam,LPARAM lParam)
{
switch(Msg)//
处理消息过程,什么是消
息,下节再讲
{
case
WM_DESTROY://
响应鼠标单击关闭按钮事件
PostQuitMessage(0);//
退出消息队列,至于什么是消息队列,下节说
return 0;//
退出函数
}
return
DefWindowProc(hWnd,Msg,wParam,lParam);
}
//
主函数
int WINAPI WinMain(HINSTANCE
hInstance,HINSTANCE hPrevInstance,LPSTR
lpCmdLine,int nShowCmd)
{
char *cName =
WNDCLASSEX wc;
HWND hWnd;
MSG Msg;
xtra = 0;
xtra = 0;
= sizeof(WNDCLASSEX);
kground = (HBRUSH)GetStockObject(WH
ITE_BRUSH);//
通过函数来设置一个白色的背景,
这里大家设置
为
NULL
看看,会很有
趣的
r = NULL;//
不设置
= NULL;//
不设置
m = NULL;//
不设置
nce = hInstance;//
当前程序的句柄,
hI
nstance
是有系统给传递的
dProc =
WinProc;//
窗口处理过程的回调函数。
assName
=(LPSTR)cName;//
窗口类的名字。
nuName =
NULL;//
目录名,不设置
= CS_HREDRAW | CS_VREDRAW;
RegisterClassEx(&wc);//
在
系统中注册
hWnd =
CreateWindowEx(WS_EX_CLIENTEDGE,cName,
我
的窗口我喜欢
200,100,600,40
0,NULL,NULL,hInstance,NULL);//
创建窗口,窗口标题
为
我的窗口我喜欢
if(hWnd == NULL)
{//
容错处理
MessageBox(NULL,
return 0;
}
ShowWindow(hWnd,nS
howCmd);//
显示窗口
UpdateWindow(hWnd);
//<
/p>
下面是对消息的循环处理,大家先不必管这些,下节课我会细说的
{
Tr
anslateMessage(&Msg);//
翻译消息
DispatchMessage(&Msg);//
分派消息
}
return e;
}
编译运行后,可以看到一个白色背景的窗口出来了。如下图
while(GetMessage(&Msg,NULL,0,0))
p>
哎,这一节,篇幅可是真有点长的,看完估计得换几口气吧,但是只要你看到了这些,你的水
平就立马上了一个档次。
想你看完后也许会头昏脑胀的,
没有再
看下去的信心的,
但是估计当你把我的代码复制到
VC
中编译运行后,
看到一个
可爱的窗口时,肯定又
会重新点燃你心中学习的热情吧,因为你已经看到了成功,看到了成就,一种成就感犹然自心
中生,自信也提起来了,这比什么都好,人嘛就得对自己充满信心的。所以大家要发扬持之以恒的精神,坚持 和我一
起把这段苦闷的入门过程给走完,那么编程就不再是痛苦,而是一种乐趣。其实写
这些程序很多东西都不用去记的想
WNDCLASSEX
结构的
成员及成员作用,这些都不用去死记,只要知道有这么个东西,到时时再查就可以了,编程用到的
函数、结构体那么多,谁想记呀。这一节已经留下了些问题,在下节介绍的,大家如果有余力的话,可以
先查下资料
的。
1.4
鼠标指针特效
大家在都玩过网络游戏吧,里面的
界面都是很吸引人的,好的界面的确能给人以美的感受。而里面的鼠标并不是我们
平常见
到的箭头了,而是独具匠心的。网游我就只玩过魔域,所以就以魔域为例,魔域中的鼠标是这样的
们就来实现让鼠标到程序窗口上就变为我们想要的图案。
在写代码之前,我们还是先来看下先驱知识,这里要说的就是上节说资源了,当时大家看了可能并不知道什么 是
资源,这里就详细说一下。
大家知
道
Windows
程序都有图标,鼠标有光标,窗口上有图片、
按钮、文字等等,这些都是程序的部分,这样就
是程序的资源。程序没有进入内存运行的
时候,我们就叫它可执行文件吧,在磁盘保存的时候,并不只是保存了程序
运行的代码部
分(即
cpu
指令部分),还有一些图片、字符、按钮、图标并
不是在代码段的。可执行文件的大致机构
如下图
。今天我
一个可执行文件是很复杂的
,这里就简单的画这么一个难看的图,知道资源所在的大概位置,能理解程序的执行
部分
和知道程序的图标是从哪来的就可以了。
今天我们只是修改鼠
标的指针,
所以用到的资源,
只有鼠标的光标资源而已。
资源的源文件是以
rc
为扩展名的脚
本文件(仍然是
C
语言格式的,很简单),有资
源编译器
编译成以
res
为扩展名的二进制资源文件,最后用连
接器,把
re
s
文件和
obj
文件连接到一起就成了
我们的程序
exe
文件了,现在知道了程序编译后要连接了吧。
光标的
图片格式有两中
cur
和
ani
的。这个文件我在魔域的图片库里面找到了就复制到,当前项目
目录下。下面来定义下资
源文件
//
written by xhk 2009.3.1
#include
#define
资源文件要用到的图文件
CUR
0x1000
//
定义资源的
ID
,为整型
id
CUR
CURSOR
//
用到的光标图案
写完后,在命令提示符下进入目录,
然后用
编译,输入
rc
命令,回车
我们查看下项目目录下多了个
的文件,就是编译生成的二进制
资源件。
接下来就该编写代码了,
来应用这个资源文件,建立
myOwnCursor.c
文件,
其实代码和上节所写代码很相似的,
只是稍微加以修改而已。
#include
#define CUR 0x1000
//
回调函数
//
预定义光标的
id
LRESULT WINAPI
WinProc(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM
lParam)
{
switch(Msg)//<
/p>
处理消息过程,什么是消息,下节再讲
{
case
WM_DESTROY://
响应鼠标单击关闭按钮事件
PostQuitMessage(0);//
退出消息队列,至于什么是消息队列,下节说
return 0;//
退出函数
}
return
DefWindowProc(hWnd,Msg,wParam,lParam);
}
//
主函数
int WINAPI WinMain(HINSTANCE
hInstance,HINSTANCE hPrevInstance,LPSTR
lpCmdLine,int nShowCmd)
{
char *cName =
WNDCLASSEX wc;
HWND hWnd;
MSG Msg;
xtra = 0;
xtra = 0;
= sizeof(WNDCLASSEX);
kground
=
(HB
RUSH)GetStockObject(WHITE_BRUSH);//
通过函数
来设置一个白色的背景,这里大家
设置为
NULL
看看,会很有趣的
r = LoadCursor(hInstance,MAKEINTRESOURC
E(CUR));//
这里改了,来载入光标资源
= NULL;//
不设置
m =
NULL;//
不设置
nce = hInstance;//
当前程序的句柄,
hI
nstance
是有系统给传递的
dProc =
WinProc;//
窗口处理过程的回调函数。
assName
=(LPSTR)cName;//
窗口类的名字。
nuName =
NULL;//
目录名,不设置
= CS_HREDRAW | CS_VREDRAW;
RegisterCla
ssEx(&wc);//
在系统中注册
hWnd = CreateWindowEx(W
S_EX_CLIENTEDGE,cName,
我的窗口我喜欢
200,100,600,400,NULL,NULL,hIns
tance,NULL);//
创建窗口,窗口标题为
我的窗口我喜欢
if(hWnd ==
NULL)
{//
容错处理
MessageBox(NULL,
return 0;
}
ShowWind
ow(hWnd,nShowCmd);//
显示窗口
UpdateWindow(hWnd);
//
下面是对消息的循环处理,大家先不必管这些,下
节课我会细说的
while(GetMessage(&Msg,NULL,0,0))
{
TranslateMessa
ge(&Msg);//
翻译消息
DispatchMessage(&Msg);//
分派消息
}
return e;
}
用
vc
编
译生成
,
把
和
放到同一个文件夹下,然后在命令行
下
进入它们所在的目录
,输入命令:
linke
/subsystem:windows
把两个文件连接成
.
运行后界面如下
;
看到了
吧,
当鼠标移入窗口的时候,
光标就变成了那个手型图案了,<
/p>
这和魔域的是一样的。
到现在想想一个
特效
又咋地,不还是一句一句代码写出来的,而特效和普通程序往往只有数据代码不同而
已。网络游戏的界面很好看,也
只不过是资源文件用的比较多而已,而且计算量很大,所
以网游总是很占内存的,因为图片、声音文件都很大,而且
变换比较多、快,就比较占用
资源了。
其实再好的程序,只要有了思路,就能写出来,而且
写出来也难的,是不是,今天大家应该会有点收获了,都会
设计个性的鼠标光标了,比起
以前学习
C
的东西,应该有一种层次感了吧。这些东西都比较接
近系统了,所以学了之
后,你对
Windows
系统也会有很深的了解的。如果各位看官看到本节还有兴趣继续看下去,那么这对小人就是一种支
持,小人在此谢过了;如果看官觉得看这些没有半点收获,那么请看官不要再勉强自己看下去了
,免得浪费看官大人
的宝贵时间,那是小人所承担不起的。
<
/p>
总之了,要想写好程序,就得多练,编译连接过程中很容易发现错误的所在,那么这时你解
决一个错误你就提高
一次,解决的错误越多越快,你就学的越多越快。终于后来你会发现
,你太难找到错误了,那么恭喜你,你已经升级
为大虾了,已经完全脱离了菜菜级了。希
望大家继续努力!
1.5
在窗口上写上“
Hello
World
”
这一节我们乘胜追击,来继续深入学习下,学习窗口处理时间的东东。
也许你以前听说过,
windo
ws
系统是消息驱动的,
可是可能根本就不知道什么消息,
p>
更不知道什么消息驱动了。
其实什么是消息呢,说白了就是我们点鼠
标击键盘而程序发生反应,消息是一种数据,就是我们点鼠标击键盘后,系
统把我们的操
作封装到数据中,然后发送给程序,让程序对我们点鼠标击键盘的动作做出反应,当然程序也可以置之
不理。
Window
s
可是一个多任务的系统,而且同时可能产生很多的击键动作,那么同时可能能会有很多
消息,
windows
系统为了更好的管理维护这些消息,就把
这些消息加入消息队列中,消息队列其实就是消息的集合。
学
过
VB
的人知道,
VB
中的程序是事件驱动的,因为一般都是发生时,调用相应的事件处理函数,所以整个处理
过程都好像是事件引发的一样。这里的事件就是指我们击键的动作等。
学过
JAVA
的人知道,
JAVA
中有事件适配器,来捕获相应的事件,并交给相应的处理方法进行处理。<
/p>
其实三种语言的处理过程也都是大同小异,只不过
JAVA
和
VB
把这些处理
过程给封装了,
VB
尤其封装的更厉害,
所以编程者不必考虑和知道这中间的细节问题,
仍然可以编写出实用的程序,
但正是由于细节的原因,
用
VB
的开发的
程序并不能高效地处理问题。
而
C
语言本身就是面向过程的语言,所以这一过程可
以用
C
语言更好地表现出来,这也是我用
C
而不用
C++
的原
因之一。
通过前几节的学习,
我们知道了,
在窗口程序中都有一个处理窗口的函数,
其实所
有的消息将会得到怎样的处理,
都是此函数安排的。现在大家再回去看看那个程序代码和
注释,相信应该能明白些了吧。
系统产生的消息是不断的,但
是中间是有间隔的,程序要想知道有没有自己的消息,得不停地去问系统,问系统
当前有
没有属于自己的消息,这就需要一个循环来实现了。
下面先看下前两节种用到的消息循环代码:
while(GetMessage(&Msg,NULL,0,0))
{
TranslateMessa
ge(&Msg);//
翻译消息
DispatchMessage(&Msg);//
分派消息
}
Windows
为消息定
义一种新的数据类型
MSG
,用于保存消息的相关信息。在
p>
windows
中
GetMessage<
/p>
函数从消息队
列种取得消息,填写好
MS
G
结构并返回,如果获取的消息是
WM_QUIT
消息,则退出循环。
TranslateMess
age
将
MSG
结构传给
Windows
进行一些键盘消息的转换,当有键盘按下或者放开时,
Windows
产生
WM_KEYDOWN<
/p>
和
WM_KEYUP
或
< br>WM_SYSKEYDOWN
和
WM_SYSKEYUP
消息
(像
WM_KEYDOWN
这些都是微软定义的一些宏,
是什么
意思,看
字面意思就可以知道了),但是这些消息的参数种包含的是按键的扫描码(暂时不用理会),转换成常用的
ASCII
码要经过查表,很不方便,
Tra
nslatMessage
遇到键盘消息则将扫描码转换成
AS
CII
码并在消息队列种插入
WM_CHAR
< br>或
WM_SYSCHAR
消息,参数就是转换好的
ASCII
码,如此一来,要处理键盘消息的话只要是处理
WM_CHAR
消息
就好了。菊与刀非键盘消息<
/p>
TranslateMessage
则不做处理。
最后,由
DispatchMessage
将消息发送到窗口对应的窗口过程去处理。窗口过程返回后
Dispat
chMessage
函数才
返回,然后开始新一轮的消息循环。
想想我们这节的目的是为了在洁白的窗口种写下“
Hello
World
”,那么我们怎么来留下我们的笔迹呢?窗口我们<
/p>
是能做出来了,那么怎么在上面写东西呢,等等,在上面写东西的前提是不是窗口做出来之
后,当初我是这么想的,
后来看到
别人的代码才知道原来可以在窗口绘制的过程就绘制“
Hello world
”了。
Windows
有时真是个细心的家伙,
把窗口创建到显示的一瞬间又给划分了很多小的过程。在绘制窗口时,
< br>Windows
会产生
WM_PAINT
消息,那么我们在得
到这个个消息的时候,来留下我们的笔迹,岂不就是下手最
早的时刻。其实
Windows
在屏幕上输出文字和图像是一样
的,都是在屏幕上画,和我们在纸上画图和写字是一样的,都是用笔来画的,只不过用的
笔不一样而已,如果牵强用
一支笔去做所有的工作,效果并不会理想的。
Windows
的笔也是这样的,不过这些笔是函数而已,画图和画文字的函<
/p>
数不一样而已。
下面就接着上节修改的
代码继续修改,必要的注释和改变的地方我会标明的
#include
#define CUR 0x1000
HDC hDC;//HDC
是指设备上下文(暂时不用管,只
要能这样用就可以了)的句柄
//PAINTSTRUCT<
/p>
要绘制的信息,
详情请登陆
/en-
us/library/dd162768(VS.85).aspx
//
了解下就可以了,没什么重要的东西
PAINTSTRUCT paint;
RECT rect
;//RECT
用来存储窗口信息的结构,只要是窗口的坐标、宽度和高度。
//
回调函数
LRESULT WINAPI WinProc(HWND hWnd,UINT
Msg,WPARAM wParam,LPARAM lParam)
{
switch(Msg)//
处理消息过程,什么是消
息,下节再讲
{
case WM_PAINT:
//BginPaint
做些绘画的开始工作,填充
PAINSTURCT
结构,返回设备上下文(暂时不用理解)句柄
hDC=BeginPaint(hWnd,&paint);
//GetClientRect
用
来获取窗口所在客户区的位置大小信息
GetClientRect(hWnd,&rect);
//DrawText
就是
Windo
ws
用来“画字”的笔了,
DT_*
之
类是指文字的样式,看字面意思也能看懂的
//
有多少样式呢,可以查看这里
/en-
us/library/
//
本例
中是单线、水平居中和竖直居中。
DrawText(hDC,
//
预定义光标的
id
//EndPaint
就是做些收尾的工作了。
EndPaint(hWnd,&paint);
break;
case
WM_DESTROY://
响应鼠标单击关闭按钮事件
PostQuitMessage(0);//
退出消息队列,至于什么是消息队列,下节说
return 0;//
退出函数
}
return
DefWindowProc(hWnd,Msg,wParam,lParam);
}
//
主函数
int WINAPI WinMain(HINSTANCE
hInstance,HINSTANCE hPrevInstance,LPSTR
lpCmdLine,int nShowCmd)
{
char *cName =
WNDCLASSEX wc;
HWND hWnd;
MSG Msg;
xtra = 0;
xtra = 0;
= sizeof(WNDCLASSEX);
kground
=
(HB
RUSH)GetStockObject(WHITE_BRUSH);//
通过函数
来设置一个白色的背景,这里大家
设置为
NULL
看看,会很有趣的
r = LoadCu
rsor(hInstance,MAKEINTRESOURCE(CUR));//
这里改了,来载入光标资源
=
NULL;//
不设置
m
= NULL;//
不设置
nce = hInstance;//
当前程序的句柄,
hI
nstance
是有系统给传递的
dProc =
WinProc;//
窗口处理过程的回调函数。
assName
=(LPSTR)cName;//
窗口类的名字。
nuName =
NULL;//
目录名,不设置
= CS_HREDRAW | CS_VREDRAW;
RegisterCla
ssEx(&wc);//
在系统中注册
hWnd = CreateWindowEx(W
S_EX_CLIENTEDGE,cName,
我的窗口我喜欢
200,100,600,400,NULL,NULL,hIns
tance,NULL);//
创建窗口,窗口标题为
我的窗口我喜欢
if(hWnd ==
NULL)
{//
容错处理
MessageBox(NULL,
return 0;
}
ShowWind
ow(hWnd,nShowCmd);//
显示窗口
UpdateWindow(hWnd);
//
下面是对消息的循环处理,大家先不必管这些,下
节课我会细说的
while(GetMessage(&Msg,NULL,0,0))
{
TranslateMessa
ge(&Msg);//
翻译消息
DispatchMessage(&Msg);//
分派消息
}
return e;
}
最终运行结果:
其实就
是比原来的多了三个变量和几句代码,多的我也标出来了,而且都说明,那些简单的函数,大家可以自己
查下,很简单的,我就不再为一些简单的函数来打字了,这样也可以锻炼大家的动手能力。
编译连接后,大家看看预期的结果出现了吧,洁白的窗口上留下了我
们的字迹。建议学过
VB
或
JAVA<
/p>
的读者,可
以联系起来想一想,把
C
p>
的处理消息过程给理解下,理解下消息的结构和概念,熟悉西
Win
dows
的消息机制,这样就
可以为以后编写优质的软件打下坚
实的基础。此言不虚的,像金山词霸的屏幕取词功能就是对
Windows
消息巧妙的运
用;键盘记录器(木马)也是利用了截获
Windows
消息,而记录我们的按键行为,从而盗取信息的。大家好好理解下
p>
本节内容,自己动手写点东西,查些其他的事件信息,改进下程序,多熟练下,为后面的学习
做一点铺垫。
1.6
让窗口响应鼠标的事件
为了让大家能够多熟悉下
事件和消息的概念,本节再以一个小的例子看下鼠标事件的应用。鼠标的事件有
单击、右
击、双击和滚动轮的,我们这里先让鼠标响应两种事件:单击和右击。我们在实现在窗口上单击时弹出一个
上面
有“你击了左键”的对话框,右击时弹
出一个上面有“你击了右键”的对话框。代码仍用上节的,只在窗口处理
过程的,消息处
理语句(
switch
)中加入一下代码:
case
WM_LBUTTONUP://
鼠标左键松开时
MessageBox(hWnd
,
你击了左键
提示
break;
case
WM_RBUTTONUP://
鼠标右键松开时
Mes
sageBox(hWnd,
你击了右键
提示
break;
编译运行,单击左键如下图
当然,至于是弹出对话框还是干别的什么,你可以自己添加代码的。不管怎样,我想通过这个例
子,你应该理解
了程序是怎么处理鼠标的单击和右击了吧,应该对消息驱动有了更好一点
理解吧。自己多写写代码,多查查资料成就
很快的。就在写这个实例的时候,因为
VC
6.0
的
MF
C
中定义的消息和
API
中的不太一样
,一时忘了
API
中鼠标事件的
宏是怎
么写的,我查了
MSDN
、百度和谷歌,竟然没有查出来(真是
岂有此理),最后,我就只有自己解决了,硬是在
winuser.h
< br>的头文件中找到鼠标事件消息的宏定义的。真个过程中有一种山穷水尽疑无路,柳暗花明又一村的感觉,< /p>
就在我快要放弃的时候,想起来了用基本的方法,直接查看头文件的定义,真可谓天才,然
是最笨的方法了。不过这
样也好,一下子看了很多消息的宏定义。大家学习一定要自己多
查多练习,相信聪明的你一定会轻松解决遇到的问题
的。想我这么笨的人,都学会了用<
/p>
C
写
Windows
程序,又何况聪明的你呢。
1.7
单击鼠标来改变窗口的位置
目的还是为了大家进一步熟悉
Windows
的窗口实现消息的
机制,也使大家了解多一点的
Windows API
函数,
从而利于日后的实际编程。平常我们都是用鼠标拖着窗口来改变窗口的,今天我们来点新
鲜的,通过单击鼠标来使窗
口改变位置。
从前面的知识中,我们知道,窗口的初始位置是在
CreateWindow
函数中设定的,
Windows
既然可以让用
户通过鼠
标拖来改变窗口位置,那么肯定就有函数是专门用来改变窗口位置的。是的,的
确有这样的函数,常用的有两个,它
们是
SetWindowP
os
和
MoveWindow
。两个函
数的详细情况如下:
SetWindowPos
函数功能
:该函数改变一个子窗口,弹出
式窗口式顶层窗口的尺寸,位置
和
Z
序。子窗口,弹
出式窗口,
及顶层窗口根
据它们在屏幕上出现的顺序排序
、
顶层窗口设置的级别最高,
并
且被设
置为
Z
序的第
一个窗口。
函数原型
:
BOOL
SetWindowPos
(
HWN
hWnd
,
HWND
hWndlnsertAfter,int X
,
int
Y,int cx
,
int
cy,U
NIT
.
Flags
);
参数:
hWnd:
窗口句柄。
hWndlnsertAfter
:
在
z
序中的
位于被置位的窗口前的窗口句柄
。该参数必须
为一个窗口句柄,
或下列值
之一:
HWND_BOTTOM
:将窗口置
于
Z
序的底
部。如果参
数
hWnd
标识
了一个顶层窗口,则窗口失去顶级位
置,并且被置
在其他窗口的底部。
HWND_NOTOPMOST
:将窗口置于所
有
非顶层窗口之上(即在所有顶层
窗口之后)。如果窗口已经是
非
顶层窗口则
该标志不起作用。
HWND_TOP:
将窗口置
于
Z
序的顶部。
HWND_TOPMOST:
p>
将窗口置于所有非顶
层窗口之上。即使窗口未被激活
窗口也将保持顶级位置。
查看该参
数的使用方法,请看说明部分。
x
:
以客户坐标指定窗口新
位置的左边界。
Y
:以客
户坐标指定窗口新
位置的顶边界。
cx:
以像素指定
< br>窗口的新的宽度。
cy
:以像
素指定窗口的新的高度。
uFlags:
窗口尺
寸和定位的标志。该参数可以是
下列值的组合:
SWP_ASNCWINDOWPOS
:如果调用进程不拥有窗
口,系统会向拥有窗口的线程发
出需求。这就防止
调用
线程在其
他线程处理需求的时候发生死锁
。
SWP_DEFERERA
SE
:防止产
生
WM_SYNCPAI
NT
消息。
SWP_DRAWFRAME
:在窗
口周围画一个
边框(定义在窗口类描述中)。
SWP_FRAMECHANGE
D
:给窗口发送
WM_NCCALCSIZE
< br>消息,即使窗口尺
寸没有改变也会发送该消
息。如果未指
定这个标志,只有在改变了窗口
尺寸时才发送
< br>WM_NCCALCSIZE
。
SWP_HIDEWINDOW;
隐藏窗口。
SWP_NOACTIVATE
:不
激活窗口
。如果未设置标志,则窗口被激活,并被设
置到其他最
高级窗口或非
最高级组的顶
部(根据参数
hWndlnsertAfter
设置)。
p>
SWP_NOCOPYBITS
:清除客户区的所有
内容。如果未设置
该标志,客户区的
有效内容被保存并
且在窗
口尺寸更新和
重定位后拷贝回客户区。
< br>
SWP_NOMOVE<
/p>
:维持当前位置(
忽略
X
和
Y
参数)。
SWP_NOOWNERZORD
ER
:不改
变
z
序中
的所有者窗口的位置。
SWP_NOREDRAW:
不重画
改变的内容。如
果设置了这个标志,则不发生任
何重画动作。适
用于客户区
和非客户区(包括标题栏和滚动条)
和
任何由于窗回移动而露出的父窗
口的所有部分。
如果
设置了
这个标志,
应用程序必须
明确地
使窗口无效并区重画窗口
的任何部分和父窗口需要重画的
部分。
SWP
_NOREPOSITION
;与
SWP_NOOWNERZO
RDER
标志相
同。
SWP_NOSENDCHANG
ING
:防止窗口接
收
WM_WIND
OWPOSCHANGING
消息
。
SWP_NOSIZE
:维持当
前尺寸(忽略
cx
和
Cy
参数)。
SWP_NOZORDER
:维持
当前
Z
序(忽
略
hWndlnsertAfter
参
数)。
SWP_SHOWWINDOW
:显示窗口。
返回值:如果函数成
功,返回值为非零;如果函数失败,返回值为零。若想获得更多错误消息,请调用
GetLas
tError
函
数。
备注:
如
果设置了
SWP_SHOWWINDOW
和
SWP_HIDEWIND
OW
标志,
则窗口不能被移动和改变大
小。如果使
< br>用
SetWindowLoog
改变
了窗口的某些数据,则必须调
用函数
SetWindowP
os
来作真正的改
变。
使用下列的组<
/p>
合标志:
SWP_NOMOVEISWP_NOSIZEISWP
_FRAMECHANGED
。
有两种方
法将窗口设为最顶层窗口:
一种
是将参数
hWndlnsertAfter
设
置为
HWND_TOPMOST
并确保
没有设
置
SWP_NOZO
RDER
标志;另一种是设置窗口在
Z
序中的位置以使其在其他存在
的窗口之上。当一
个窗口被置为<
/p>
最顶层窗口时,属于它的所有窗
口均为最顶
层窗口,而它的所有
者的
z
序并不改
变。
如
果
HWND_TOPMOST
和
HWND_NOTOPMOST
标志均未指
定
,
即应用程序要求窗口在激活的同时改
变其在
< br>Z
序中的位置时,在参
数
hWn
dinsertAfter
中指定的值只有
在下列条件中才使用
:
在<
/p>
hWndlnsertAfter
参数中没有设
< br>定
HWND_NOTOPMOST
和
HWND_TOPMOST
标志。
由
hWn
d
参数标
识的窗口不是激活窗口。
如果未将
一个非激活窗口设定到
z
序的顶
端,应
用程序不能激活该窗口。应用
程序可以无任何限制地改
变被激活
窗口
在
Z
序中的位置,或激
活一个窗口并将其移到最高级
窗口的顶部或非最高级窗口的顶
部。
如果一个
顶层窗口被重定位到
z
序的底部
(
HWND_BOTTOM
)或在任何非最高序的
窗口之后,该窗口
就不再是最顶
层窗口。当一个最顶层窗口被置为
非最顶级,则它的所有者窗口和所
p>
属者窗口均为非最顶层窗
口。
一个非最
顶端窗口可以拥有一个最顶端窗
口,但反之则不可以
。任何属于
顶层窗口的窗
口(例如一个对
话框)本身就
被置为顶层窗口,以确保所有被
属窗口都在它们的所有者之上。
如果应用
< br>程序不在前台,但应该位于前台
,就应调用
SetFor
egroundWindow
函数
来设置。
Windows
CE
:如果这是一个
可见的顶层窗口,并且未指
定
SWP_NOACTIVATE<
/p>
标志,则这个函数将激
活窗口、如果
这是
当前的激活窗口,并且指定
了
SWP_NOACTIVATE<
/p>
或
SWP_HIDEWINDOW
标志,
则激
活另外一个可
见的顶层窗口。
当在这个
函数中的
nFlags
参数里指定了
S
WP_FRAMECHANGED
标志时,
WindowsCE
重画窗口的整
个非客户区,
这可能
p>
会改变客户区的大小。
这也是重新计算
客户
区的唯一途径,
也是通过调
用
Setw
indowLong
函数改变窗口
风格后通常使用的方法。
p>
SetWi
ndowPos
将使
WM_WINDOWPOSCHANGED
消息向窗口发送,在这个
消息中传递的标志与传递
给函数的相同
。这个函数不传递其他消息。
MoveWindow
函数功能
:该函数改变指定窗口的位置和
尺寸。
对于顶层窗口,位置和尺
寸是相对于屏幕的左上角的:
对于子窗
口,
位置和尺寸是相对于父窗口客户
区的左上角坐标的。
函数原型
:
BOOL
MoveWindow
(
HWND hWnd,int
y,int nWidth,int nHeight,BOOL
BRePaint
);
参数:
hWnd
:窗口句柄。
x
:指定
窗口的新位置的左
边界。
Y
:指定窗口的新位置的顶
部边界。
nWidth
:指定窗口的新的宽度
。
nHaigh
t
:指定
窗口的新的高度。
bRepaint:
确定
窗口是否被刷新。如果该参数
为
TRUE
,窗口接收一个
WM_PAINT
消息;
如果参数为
FALSE
,不发生任
何刷新动作。它适
用于客户区,非客
户区(包括标题栏和
滚动条),及由于移动子窗口而
露出的父窗口
的区域。如果参数为
FALSE
,应用程序就
必须明确地使窗口无效或重画
该窗口和需
要刷新的
父窗口。
返回值:如果函数成
功,返回值为非
零;如果函数失败,返回值为零。若想获得更多错误信息,请调用
GetLas
tError
函
数。
备注:如
果
bRepaint
为
TRUE
,系统在窗口移动后立即给窗
口过程发送
WM
_PAINT
消息(即由
MoveWindow
函数调用
UPdateWindow
函数)。如果
p>
bRepaint
为
FALSE
,系统将
WM_PAINT
消息放在该
窗口的消息队
列中。消息循环只有在派遣完消
息
队列中的其他消息时才派
遣
WM_PAINT
< br>消息。
MoveWindow
给窗口发送
WM_WfNOWPOSCHANGING
,
WM_WINDOWPOSCHANGED
,
WM_MOVE
,
WM_SIZE
和<
/p>
WM_NCCALCSIZE
消息
。
p>
以上的东西,都是从
msdn
上翻译
过来的,把它们翻译过来,是在有故意添文字之嫌。看了函数说明就
好的多了吧
,我们只把上节中的
代码稍
加修改即可
,我这里给出我的代码
,大家可以借鉴下(我觉得知
道这
两个函数怎么
用,真是没什么要的说的了):
#include
#define CUR 0x1000
HDC hDC;//HDC
是指设备上下文(暂时不用
管,只要能这样用就可以了)的
句柄
//PAINTSTRUCT
要绘制的信息
//
详情请登陆
/en
-us
/library/dd162768(VS.85).aspx
p>
//
了解下就可以了,没什
么重要的东西<
/p>
PAINTSTRUCT paint;
RECT rect;//RECT
用来存储窗口信息的结构,
只
要是窗口的坐标、宽度和高度。
//
预定义光标的
id
//
自定
义函数
MoveLeft,
使窗口向左移
动
5
像素
,
此函数中
调用
MoveWindow
函
数
int MoveLeft(HWND hWnd)
{
G
et
WindowRect(hWnd,&rect);//
获
取窗
口的信息
M
oveWindow(hWnd,-5,,,,TRUE);
r
eturn 1;
}
//
自
定义函数
MoveRight
,是窗口向右移动
5
像素,此函数中调
用
Set
WindowPos
函数(换个口味)
int MoveRight(HWND hWnd)
{
G
etWindowRect(hW
nd,&rect);//
获
取窗口的信息
S
etWindowPos(
hWnd,HWND_NOTOPMOST,
+5,,
,
,
SWP_NOZORDER);
r
eturn 1;
}
//
回调函数
LRESULT WINAPI WinProc(HWND hWnd,UINT
Msg,WPARAM wParam,LPARAM lParam)
{
p>
switch(Ms
g)//
处理消息过程
,
什么是消息,下节再讲
{
c
ase WM_PAINT:
柄
的
//<
/p>
有多少样式呢,可以查
看这里
/en
-us/library/
//
本例中是单线、水平居
中和竖直居中。
DrawText(hDC,
//EndPaint
< br>就是做些收尾
的工作了。
EndPaint(hWnd,&paint);
hDC=BeginPaint(hWnd,&paint);
//GetClientRect
用来获取窗口所在客户区
的
位置大小信息
GetClientRect(hWnd,&rect);
/
/DrawText
就是
Windows
用来“画字”的笔了,
DT_*
之类是指文字的样
式,看字面意思也能看懂
//BginPaint
做些绘画
的开始工作,填充
PAINSTURCT
结构,返回设备上下文(暂时不用理解)句
break;
c
ase WM_LBUTTONUP://
< br>鼠标左键松
开时
MoveLeft(hWnd);
break;
c
ase WM_RBUTTONUP://
< br>鼠标右键松
开时
MoveRight(hWnd);
break;
case WM_DESTROY
://
响应鼠标单击关闭按钮事
件
p>
Pos
tQuitMessage(0);//
退出消息
队列,至于什么是消息队列,
下节说
return
0;//
退出函数
}
return
DefWindowProc(hWnd,Msg,wParam
,lParam);
}
//
主函数
int WINAPI WinMain(HINSTANCE
hIns
tance,HINSTANCE hPrevInstance,LPSTR
lpCmdLine,int
nShowCmd)
{
char *cName =
yWindow
WNDCLASSEX wc;
HWND hWnd;
MSG Msg;
xtra = 0;
xtra = 0;
=
sizeof(WNDCLASSEX);
kground = (HBRU
SH)GetStockObject(WHITE_BRUSH);//
通过函数来设
置
一个白色的
背景,这里大
家设置为<
/p>
NULL
看看,会很
有趣的
r = LoadCursor(hIns
< br>tance,MAKEINTRESOURCE(CUR));//
这里改了
p>
,来载入光标资源
=
NULL;//
不设置
m
=
NULL;//
不设置
tance = hIns
tance
;//
当前程序的句柄,
hIns
ta
nce
是有系
统给传递的
dProc =
WinProc;//
窗口处理过程的回调函数。
zClassName =(LPSTR)cName;//<
/p>
窗
口类的名字。
zMenuName =
NULL;//
目
录名,不设置
= CS_HREDRAW | CS_VREDRAW;
Regis
terClassEx(
&wc);//
在系统中注册
hWnd = CreateWi
ndowEx(WS_EX_CLIENTEDGE,cName,
我的窗口我喜
欢
200,100,600,400
,NULL,NULL,hIns
tance,NULL);//
创建窗口,窗口标题为
我的窗口
我喜
欢
if(hWnd == NULL)
{//
容错处理
MessageBox(NULL,
an
Error
return 0;
}
p>
ShowWindow(h
Wnd,nShowCmd);//
p>
显示窗口
UpdateWindow(hWnd);
p>
//
下面是对消息
的循环处理,大家先不必
管这些
,下节课我会细说的
w
hile(GetMessage(&Msg,NULL,0,0)
)
{
TranslateMessage(&Msg);//
p>
翻译
消息
Dis
patchMessage(&Msg);//
分派消息
}
return e;
}
这个结果,不能用静态的图
片来说明
什么,大家自己编译连
接后,击鼠标试试,看能出现预期
的效果
不,
我这里就不贴
图出来了,贴静态的没啥意思,
贴动态
的,有点不想整,我也懒
,哈。
经过这几次折腾,如果大家真的每一次都手写了
,相信其中的那关键的且相同的那部分代码应该是非常熟悉了,
到此就我们就该升级了,
就行高一层次的修炼,后面两节,我准备给大家说些资源的深入细节,还有再在写几个完全
实用的小程序和几个恶作剧程序,不知大家意下如何。
1.8
资源的初步深入
前面已经说了资源的基本概念,
不过
只是做了和很简单的介绍,
这次我们来点狠的,
深入的。
前面我虽然也
用了资源,不过只是鼠标光标的,回忆下我们的程序,是
那么的简陋。我们早就想把它给装点下了吧,不用着急,学
完了这节后,你就可以成为一
个雕刻师了,想让你的窗口咋样基本都可以了(需要练习了,呵呵)。
以当前
我这个
Word
编辑窗口为例,可以看到一个窗口有很多项的,
而我们之前的串口跟这个相比,真可谓
小巫见大巫。前面的程序连最起码的菜单栏都没有
,真是惭愧呀。
在
Vb
做界面,简直就跟画图是一样一样的,
Java
中可
以在编程时,一个一个组件往窗体对象(
JFrame
)上
p>
画(也许有
IDE
可以手画的),
VC
中呢,也可以画,但是注意的细节明显比
V
B
要多。其实手画的过程,只是程序帮
了我们,帮我们写了资源
文件。这和用网页设计工具是一样的,我们只顾点鼠标,代码则是网页设计工具生成的了。
同样,
其他编程也是这样,
这样的好处是:
< br>一可以让初学者很容易进入状态
,
二是可以加快开发,
可以少写
n
拖
代码。
坏处是:不懂得底层机制,很多人写了
n
久的程序,也只能是比葫芦画瓢,写的程序界面还是自己学习时候的那种样
式,
界面单调死板,开发不出个性界面的。鉴于工具带来的负面影响,我才给大家从基本说起,虽然我们是用
VC
6.0
的环境,但是我还是手写资源来教
大家定义资源文件,并不利用
VC
中
I
DE
工具。如果大家资源文件写的很熟练的话,
再用
VC
中的
IDE
工具,不
用去看多余的书,自然一看就知道是怎么回事,到时用起来就是得心应手。说实在话,如果
不理解
Windows
的一些处理机制,上去直接去学习
p>
VC
,我敢肯定学一段时间后,大部分人会头昏脑胀,事倍功半,虽
有收获,然仍是皮毛,有放弃之想。好了废话不多说了,言归正传。
如上图,是我这节要实现的效果,上面有菜单栏,其中点击“查看”可以菜单子菜单项,弹出的有禁用的菜
单、分割线和灰化的菜单项。还有一个我自己做的图标(
xhk
字样的,左上角)。单击标题栏上的图标可以弹出系统
菜单,在有的程
序,在窗口中击鼠标右键,就可以弹出“快捷菜单”,这些菜单都属于弹出式菜单。
<
/p>
菜单中的菜单项有好几种,
从资源定义的角度来看,
分割用的横线也是一个菜单项。
除横线外其他菜单项可
以供用户选择,也可以设置为“禁止”或“灰化”状态暂时停用,如果上图的。
p>
快捷键,
这个不用说了,
大家都知道是做什
么用的。
菜单项显示的字符都是在资源文件中定义,
至于如何来
响应按键则要在消息处理函数中添写代码了,
本节先不讨论怎样
获取这些消息和处理这些消息,
这写留到下节中完成,
本节先常
用资源的定义格式说下,先完成界面上的东东。
1.
菜单资源的定义
在资源脚本文件菜单中的定义格式是这样的:
菜单
BEGIN
END
也可以这样定义:
菜单
{
}
“菜单
ID MENU [DISC
ARDABLE]
”可以用来制定菜单的
ID
< br>值和内存属性,菜单
ID
可以是
16
位(二进制
菜单项的定义
ID MENU [DISCARDABLE]
菜单项的定义
ID MENU
[DISCARDABLE]
位)的整数,也可以是字符串。但是如果
ID
位字符串的话,在程序中引用的时候就要用字符串指针代替菜
单
ID
值,显然这样不太方便,所以在我们经常用整
数来做菜单的
ID
值。
MENU
关键词后面的
DISCARDABLE
是菜单
的内存属性,表示菜单在不再使用的时候可以暂时从内存中释放以节省内存,是个可选属性。菜单
项的定义必须在
BEGIN
和
END
关键词之内,这两个关键词也可以用
{
< br>和
}
来代替。
菜单项目的定义方法有三类:
1.
常用的
MENUITEM
菜单文字
,
命令
ID
[,
选项列表
]
2.
分割线
MENUITEM SEPARATOR
3.
下级菜单
和菜单定义的方式一样
POPUP
菜单文字
[,
选项列表
]
BEGIN
END
下面对这三类加以说明
Item-
definitions
第一类:
菜单文字——显示在菜单项中的字符串。像上图中的“被禁用的菜单项”和“被灰化的菜单项”。
命令
ID
——不同菜单项的
标识。
当菜单被选中的时候,
Windows
< br>会向窗口过程发送
WM_COMMAND
消息,
消息的参数就是
这个命令
ID
< br>。这个可以分辨用户选中了哪个菜单项,如果想让两个菜单项具有相同的功能,可以设置为相同的
ID
。
选项列表——用来形容菜单项的各种属性,它可以是下列选项:
CHECHKED
——表示打上选定标识。
GRAYED
——表示菜单项是灰化的。
INACTIVE
——表示菜单项是禁用的。
MENUBRREAK
或
< br>MENUBARBREAK
——表示将这个菜单项和以后的那个列到新的列中。<
/p>
第二类:
菜单项之间的分割线,没什么好说的了。
第三类:
弹出式菜单,前文有解释,这里说下它的选项:
GREAYED
——灰化。
INACTIV
——禁用。
HELP
——表示本项和以后的菜单项是右对齐的,像上图中的“帮助”
菜单。
2.
快捷键的定义
快捷键定义是很简单的,格式如下:
快捷键
BEGIN
END
BEGIN
和
END
仍然可以用
{
和
}
替换。
键名——表示加速键对应的按键,可以有
3
中
定义方式:
“
^
p>
字母”:表示
Ctrl
键加上字母键。
p>
“字母”:表示字母,这时类型必须指明
VIRTKEY
。
数值:表示
ASCII
码,这时类型必须为
ASCII
键名
,
命令
I
D[,
类型
][,
选项
]
ID
ACCELERATORS
命令
ID
—
—按下快捷键后,
Windows
就向程序发送此命令
ID
。
类型——用来
指定键的定义方式,可以是
VIRTKEY
和
< br>ASCII
,分别用来表示“键名”字段定义的是虚拟键还是
ASCII
码。
选项——可以使
Alt,Control
或
Shift
中的单个或多个,如果指定多个,则中间用逗号隔开,表示快捷键是按键加上
这些控制键的组合键。
说了这么多,考验我们的
时候终于到了,下面我们就来写程序了。
兵马未动,粮草先行
,我们先来把界面定义好,定义一个
的资源文件,内容如下:<
/p>
/************** Written By
XHK 2009.3.3*************/
#include
#define
ICO_MAIN
0X1000
#define
IDM_MAIN
0X2000
#define
IDA_MAIN
0X2000
#define
IDM_OPEN
0X4101
#define
IDM_INACTIVE
#define
IDM_GRAYED
0X4202
#define IDM_HELP
0X4301
/********The ico file of the
window***********/
ICO_MAIN ICON
//
“打开”菜单项
0X4201
//
“被禁用的菜单项”
//
图标
//
菜单
//
快捷键
//
“灰化的菜单项”
//
“帮助”菜单项
/*********************************************
/
/**Next is the definition of the
Menus**********/
IDM_MAIN menu
discardable
{
popup
{
menuitem
打开
(&O)tCtrl+Alt+O
}
popup
p>
查看
(&V)
文件
(&F)
}
{
menuitem
被禁用的菜单项<
/p>
menuitem
s
eparator
menuitem
被灰化的菜单项<
/p>
}
popup
{
帮助
(&H)
menuitem
帮助主题
(&H)tF1
}
//
下面定义快捷建
IDA_MAIN accelerators
{
}
把我们用到的资源
ico
文件
也和此文件放到同一目录下,然后用资源编译器
把
编译成
下面该出兵了,
程序代码,采用最精简的:
/***********MyMenu.c Written By
XHK 2009.3.3************/
#include
#define
ICO_MAIN
0X1000
#define
IDM_MAIN
0X2000
#define
IDA_MIAN
0X2000
//
回调函数
LRESULT WINAPI WinProc(HWND hWnd,UINT
Msg,WPARAM wParam,LPARAM lParam)
//
图标
//
菜单
//
快捷键
VK_F1,IDM_HELP,VIRTKEY
//F1
//Ctrl+Alt+O
-
-
-
-
-
-
-
-
-
上一篇:英文版实习评语
下一篇:和谐作文之英语作文在和谐社会中