关键词不能为空

当前您在: 主页 > 英语 >

C语言到底能干什么(用C写QQ)

作者:高考题库网
来源:https://www.bjmy2z.cn/gaokao
2021-03-03 12:40
tags:

-

2021年3月3日发(作者:色度单位)







C


语言究竟能干什么




序言



鉴于现在已经大三了,很多同学 很迷茫,自己学的东西到底能做什么,将来自己到底能干什么?我不想看着同学迷茫


的面 孔,




特别是几个好兄弟,


有几个想学习编程,


但又苦苦找不到门路的兄弟,


所以想写点东西,


希望对大家又点略微的帮助,


以尽兄弟我的 微薄之力。




很多同学学了


C


语言之后,可能难免会有所感叹:这就是


C< /p>


语言!总是感觉


C


语言竟然能写出


Windows



Linux


?为


了解除同学们



的疑惑, 也愿为同学们指点编程之道吧。我写的这些东西采用


C


语言,计 划通过编程实例来讲解


C


编程的一些知识,

让大家对


C


能又更深一层的理解和认识。当然,大家不要 指望看了这些之后会写出一个操作系统来,但是我想,如果你认真看了


的话,写



一个类似与


QQ


的聊 天程序应该不难。





本来书是假期


里照顾妈妈时写的,原想是


1


、不让自己


的水平停滞不前,温故知新


(两个月 的假期是很


长的)



2.


帮助一些


同学,解决编程上的困惑


< /p>


3.


希望妈妈快


点康复

< br>


4.


让母亲和家


里人知道自己 一直都很努力,我


是好样的







C


语言的基本语法我是不打算再提了,很多


C


语言编程的书,就是将一些基本的数据类型、数据结构、语法,然后就


是一些数值



计算的实例,大多数都是雷同的,难免有抄袭之嫌,而且页没有多少 实用价值。




本书以实用实例作为编 程指导,指引大家编写真正实用的程序。了解到大家对黑客程序、病毒、窗口类程序比较感兴

趣,


因此我就拿这些实例进行讲解。


基于大家基本都用


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





中的头文件


stdio.h


到底是什么东西,我就来说下了,

< br>stdio.h


是一个文本文件,存在于磁盘上的,已


V C


为例


它的位置如下图:



printf(





也许你听说过


printf


()函数是在


stdio.h


中预定义的,但是 你见过其定义的形式没有,没有且看下图



< br>其定义形式,就如图中所示,也许你并不懂前面那些东西是什么,不用担心,以后我会慢慢解释给大家的。 函数是先定义才能使


用的,所以


stdio.h


中定义


printf


函数,我我们在引用了

< p>
stdio.h


头文件后就可以在程序中调用


pr intf


函数了。




上面是在命令行中显示一个“


Hello World!



,


没什么意思,下面我写一个窗口程序,显 示个


Hello World!


#include




void main()


{



}


编译运行后如下图:


< p>
MessageBox(NULL,


我的第一个窗口程序

< br>



弹出的是一个对话框,上面有


Hello World


,还有一个标题和一个“确定”按钮。


< p>
当然你会说这对话框也算个窗口吗?这里肯定的告诉你:是的,对话框是窗口程序的一个子集。你可 能还会这样问,这样一个简


单的窗口有啥用呢,其实这样的窗口非常有用,我们在操作计 算机的时候,会出现一些警告或提示的对话框,都是基本是这种方


法写出来的。就算是这 个很简单,学习本来不就是有易向难,有浅显深奥去的过程吗。



整个效果几乎就是靠一个函数


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


的编


译模


式改下



看下图




依次



是“ 工


程”→“设置”→“连接”,在“


工程选项”里把

< p>
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


写的并没有完全脱离命令行呀


< p>
所以以后我们写


窗口程序就用


winmain


了。






好了,转过来


,我们来看看


WinMain()


函数,其中有


4

< p>
个参数



先看下解释(


看不明白得先看完):



hIns


tance


:应用程序当前事 例的句


柄。



hPrelnstanc e


:应用程序


的先事例


的句柄。对


于同一个程


序打开两次


,出现两个


窗口第一次


打开的窗口


就是先前


实例


的窗口。对于


一个


32< /p>


的位程序,该参数总



NULL




lpCmdLine


:指向应


用程序命令行的空字符串的指


针,不包括函数名。获 得整个命


令行,参看


GetCommandLine

< p>



nCmdShow


: 指


明窗口如何显示(是隐藏还是显


示,有没有最大化按钮之类的



。取值可以参


MSDN


这里我相信有


一个词大家好应该比较陌生,句< /p>



(HANDLE)


是吧。下面我就来简 单的说下



句柄其实就



Windows


系统中一个东西的唯一标识。就是系统中有很


多运行的程序或者资源之类的,为了更好的


管理


使用,


Windows


系统给它们每人一


个< /p>


ID


一样。懂


得网页制作的人应该知道网 页中


各个元素的


ID



,网页的


ID



果重


复话可


能出现错误。


那么系统的句柄

< p>
会不会有相同的


,那是肯定不


会有的了,就和


我们的学号一样


,系统自动分


配每


一个模块的句


柄,是不会相同的了。




对于句柄大家


可以先这样理解着,不 用一下子


搞懂得。以后学着学着就明白了




估计大家对那


几个参数的类型 改犯迷糊了吧


。其实那几个类型,并不是什


么新类型,都是


Windows


开发人员为了


自己


和他人编程方


便,同过基本的


C


语言语法定义一种


新的结构体,或者是共同体,


再者就 是枚举类型。我知道结构


体、


共同体和枚举

类型,很多老师是没有讲到的,


因为在书的后边,很多教


C


的,又


是很垃圾的老师,所以不会讲那


么快


的。其


实结构体这些


数据类型,就 是


通过我们常用的


字符、整型、


浮点等 数据类型


构造一个比较复


杂的类型而已


,举


个例子,就是


我们知道


C


没有一个数据类型可以描


述一个人吧,那么我构造一个

< br>是不是很方便我们编程呢。我们


可以


这样构造一个



struct People


{





} < /p>


我们这样定义


以后就可以在我们以后的程序中

利用这个数据类型了,


People


zhangsan;



zhangsan


的身高

< p>
172


放到



< p>
。这样可以方便完成很多工作。


所以结构体是很简单的,还有其

< p>
他的复杂数据类型也是很简单


的,


都是有常用的< /p>


简单的类型来结合到一起构造一


个复杂的而已。这



JAVA



义类是很相似的



java


定义个人类,


不是


可以这样的



public class People


{






}



看起来


都差不多,而


且用法也很相像


。唯一的差别其

< br>实就是类可以


有方法,而结构


体是没有的(经

< p>
过特殊处理也


是可


以的,这里不

< br>用考虑)。




public int age;


public s


tring sex;


public height;


……



int age;//





char sex[2];//


性别



int height;//


身高



……




< /p>


上面是为了让


大家了解下复杂数据类型的定义

,罗嗦了一大堆。下面来看



WinMain



第一个参数的类型


HINSTANCE

< p>
这个只是个结构体而已,实际上



HANDLE< /p>


这个类型差不多


,但是有一点差别,而


H ANDLE


是这样


typedef PVOID HANDLE ;


定义的,


PVOID


是什么呢,


我们来看下


typedef void *PVOID;

< p>
说明


PVOID


是一个指针,

初始指向空(


void


)。因此可以知道句柄也是个指针而 已。看着这么复杂原来也只是指针。



这些都可以在微软的


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(





)
















(


/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


窗口类的鼠标样式,为鼠标样


式资源的句柄,如果设置



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


结尾的字符床,同目录资源


的名字一样


。如果使用整

< p>


id


表示菜


单,可


以用


MAKEINTRESOURCE


定义 一个宏


。如果它的值为


NULL,


那么 该类创建的


窗口将都没有默认的菜单。



lps


zClassName



窗口类的名字,字符串类型。



hIconSm



小图标

< p>
的句柄,在任务栏显示的图标,


可以和上面的那个一样。

< 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


:指定窗口的扩展


风格。该参数可以是下列值:



WS_EX_ACCEPTFILES


:指定以该风格创建


的窗口接受一个拖拽文件。











< /p>


WS_EX_APPWINDOW



当窗 口可见时,将一个顶层窗


口放置到任务条上。



WS_EX_CLIENTEDGE


:指定窗口有一


个 带阴影的边界。



WS_EX_CONTEXTHELP


:在窗口的标题条包含一个问


号标志。



WS_EX_CONTROLPARENT


:允许

< br>用户使用


Tab


键在窗口的子窗口间搜索。






WS_EX_DLGMODALFRAME


:创建


一个 带双边的窗口;该窗口可以



dwStyle

< br>中指定


WS_CAPTION


风格来创建一个

< p>
标题栏。











WS_EX_LEFT

< p>


窗口具有左对齐属性,这是缺省


设置的。



WS_EX_LEFTSCROLLBAR




果外壳语言是如


Hebrew



Arabic



或其他支



reading order

alignment


的语言,则


标题条(如果存在)则在客 户



的左部分。若是其他语言,在


该风 格被忽略并且不作


为错误处理。







WS _EX_LTRREADING


:窗口文本以


LEFT



RIGHT


(自左向右)属性的顺序显示。这 是缺


省设置的。











WS_ EX_MDICHILD


:创建一



M D


子窗口。




WS_EX_NOPATARENTNOTIFY


:指明以这个风格创建的窗口


在被创建和销毁时不向父


窗口发


< p>
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


:


指向一个指定窗口名的空结束


的字符串指针。其实就是窗口


的名字。



dwStyle

:


指定创建窗口的风格。


该参数可以是下列窗口风格的


组合再加上说明部分的控制风格




x


:


窗口的横坐


标。



y


:


窗口的 竖坐


标。



nWidth


:


窗口


的宽度。



nHeight


:


窗口


的高度。



hMenu


:菜

< p>
单句柄,或依据窗口风格指明


一个子窗口标识。



hlnstance


:与窗口相关联的模块事例的


句柄。



lpParam


:


指向一个值的指


针,该值传递给窗口



WM_CREATE


消息


< p>
请调用


GetLastError


函数。





3.


显示窗口



显示窗口就是


更简单的事情了。



连个函数轻松


搞定,第一个函数就是


Sho wWindow


(),原型如下:








BOOL ShowWindow(





HWND


hWnd


,//

< p>
当前的窗口句柄



int


nCmdShow //


可见状态




);


返回值


:如果函数成功,返回值为新窗口的句柄


:如果函数失败,返回值为

< br>NULL


。若想


获得更多错误信息



因为


CreateWindowEx


函数创建的窗口是在内存中的,并没有显示到显示器上,用


ShowWindow()


函数,设


定窗口的可见状态,并把数据从内存中移动到显卡上, 以便显示。




第二个函数就是


UpdateWindow()




函数原型






BOOL UpdateWindow(HWND hWnd);




描述






这个



UpdateWindow


函数通


过发送重绘消息



WM_PAINT


给目标窗体来更新目标

窗体客户区的无效


区域。如果那


个窗体的无效区域没有,就 不发


送重绘消息



WM_PAINT




。注意了,这个



API

< p>
函数


是直


接发送消息



WM_PAINT


给目标窗


体的,没有进入过消息队列。





函数


参数:





hWnd


一个要更新的窗体的句






函数


返回值:





如果函数


调用成功,返回值为非零值。



如果函数调用


不成功,返回值为零。




经过这三步后


,一个窗口就实现了, 就创建了


出来,难不,也真够难的,


Windows

< p>
想的正周到,


把创


建过程的每一

< 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))






哎,这一节,篇幅可是真有点长的,看完估计得换几口气吧,但是只要你看到了这些,你的水 平就立马上了一个档次。


想你看完后也许会头昏脑胀的,


没有再 看下去的信心的,


但是估计当你把我的代码复制到


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


,用于保存消息的相关信息。在


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


码,如此一来,要处理键盘消息的话只要是处理

< p>
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


//

< p>
了解下就可以了,没什么重要的东西



PAINTSTRUCT paint;


RECT rect ;//RECT


用来存储窗口信息的结构,只要是窗口的坐标、宽度和高度。

< p>




//


回调函数



LRESULT WINAPI WinProc(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam)


{


switch(Msg)//


处理消息过程,什么是消 息,下节再讲



{












case WM_PAINT:



//BginPaint


做些绘画的开始工作,填充

< p>
PAINSTURCT


结构,返回设备上下文(暂时不用理解)句柄




hDC=BeginPaint(hWnd,&paint);



//GetClientRect


用 来获取窗口所在客户区的位置大小信息




GetClientRect(hWnd,&rect);



//DrawText


就是


Windo ws


用来“画字”的笔了,


DT_*


之 类是指文字的样式,看字面意思也能看懂的




//


有多少样式呢,可以查看这里


/en- us/library/



//


本例 中是单线、水平居中和竖直居中。




DrawText(hDC,


//


预定义光标的


id







//EndPaint

< p>
就是做些收尾的工作了。




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


的处理消息过程给理解下,理解下消息的结构和概念,熟悉西


Win dows


的消息机制,这样就


可以为以后编写优质的软件打下坚 实的基础。此言不虚的,像金山词霸的屏幕取词功能就是对


Windows


消息巧妙的运


用;键盘记录器(木马)也是利用了截获


Windows


消息,而记录我们的按键行为,从而盗取信息的。大家好好理解下


本节内容,自己动手写点东西,查些其他的事件信息,改进下程序,多熟练下,为后面的学习 做一点铺垫。





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


标识

< p>
了一个顶层窗口,则窗口失去顶级位


置,并且被置


在其他窗口的底部。




< p>
HWND_NOTOPMOST


:将窗口置于所


有 非顶层窗口之上(即在所有顶层


窗口之后)。如果窗口已经是


非 顶层窗口则


该标志不起作用。





HWND_TOP:


将窗口置



Z


序的顶部。





HWND_TOPMOST:


将窗口置于所有非顶


层窗口之上。即使窗口未被激活


窗口也将保持顶级位置。





查看该参


数的使用方法,请看说明部分。





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


设置)。







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

< p>
:维持当


前尺寸(忽略


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


序中的位置,或激

< p>
活一个窗口并将其移到最高级


窗口的顶部或非最高级窗口的顶


部。





如果一个


顶层窗口被重定位到


z


序的底部



HWND_BOTTOM


)或在任何非最高序的


窗口之后,该窗口


就不再是最顶


层窗口。当一个最顶层窗口被置为


非最顶级,则它的所有者窗口和所


属者窗口均为非最顶层窗


口。





一个非最


顶端窗口可以拥有一个最顶端窗


口,但反之则不可以


。任何属于 顶层窗口的窗


口(例如一个对


话框)本身就

被置为顶层窗口,以确保所有被


属窗口都在它们的所有者之上。




如果应用

< br>程序不在前台,但应该位于前台


,就应调用


SetFor egroundWindow


函数


来设置。




Windows


CE


:如果这是一个 可见的顶层窗口,并且未指



SWP_NOACTIVATE< /p>


标志,则这个函数将激


活窗口、如果


这是 当前的激活窗口,并且指定



SWP_NOACTIVATE< /p>



SWP_HIDEWINDOW


标志, 则激


活另外一个可


见的顶层窗口。





当在这个


函数中的


nFlags


参数里指定了


S WP_FRAMECHANGED


标志时,


WindowsCE


重画窗口的整


个非客户区,


这可能


会改变客户区的大小。


这也是重新计算


客户 区的唯一途径,


也是通过调



Setw indowLong


函数改变窗口


风格后通常使用的方法。





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

< p>
消息;


如果参数为


FALSE

,不发生任


何刷新动作。它适


用于客户区,非客

< p>
户区(包括标题栏和


滚动条),及由于移动子窗口而


露出的父窗口


的区域。如果参数为


FALSE


,应用程序就


必须明确地使窗口无效或重画


该窗口和需 要刷新的


父窗口。





返回值:如果函数成


功,返回值为非 零;如果函数失败,返回值为零。若想获得更多错误信息,请调用


GetLas


tError



数。





备注:如



bRepaint



TRUE


,系统在窗口移动后立即给窗


口过程发送


WM _PAINT


消息(即由


MoveWindow


函数调用


UPdateWindow


函数)。如果


bRepaint



FALSE


,系统将


WM_PAINT


消息放在该


窗口的消息队


列中。消息循环只有在派遣完消


息 队列中的其他消息时才派



WM_PAINT

< br>消息。



MoveWindow


给窗口发送


WM_WfNOWPOSCHANGING



WM_WINDOWPOSCHANGED



WM_MOVE



WM_SIZE


和< /p>


WM_NCCALCSIZE


消息




以上的东西,都是从


msdn

< p>
上翻译


过来的,把它们翻译过来,是在有故意添文字之嫌。看了函数说明就


好的多了吧


,我们只把上节中的


代码稍 加修改即可


,我这里给出我的代码


,大家可以借鉴下(我觉得知 道这


两个函数怎么


用,真是没什么要的说的了):



#include



#define CUR 0x1000



HDC hDC;//HDC


是指设备上下文(暂时不用


管,只要能这样用就可以了)的


句柄



//PAINTSTRUCT


要绘制的信息



//


详情请登陆


/en


-us


/library/dd162768(VS.85).aspx


//


了解下就可以了,没什


么重要的东西< /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)


{






switch(Ms


g)//


处理消息过程 ,


什么是消息,下节再讲







{



c


ase WM_PAINT:
















//< /p>


有多少样式呢,可以查


看这里


< p>
/en


-us/library/


//


本例中是单线、水平居


中和竖直居中。



DrawText(hDC,


//EndPaint

< br>就是做些收尾


的工作了。



EndPaint(hWnd,&paint);


hDC=BeginPaint(hWnd,&paint);


//GetClientRect


用来获取窗口所在客户区


的 位置大小信息



GetClientRect(hWnd,&rect);


/ /DrawText


就是


Windows


用来“画字”的笔了,


DT_*


之类是指文字的样

< p>
式,看字面意思也能看懂


//BginPaint


做些绘画


的开始工作,填充


PAINSTURCT


结构,返回设备上下文(暂时不用理解)句





break;



c


ase WM_LBUTTONUP://

< br>鼠标左键松


开时





MoveLeft(hWnd);


break;



c


ase WM_RBUTTONUP://

< br>鼠标右键松


开时





MoveRight(hWnd);


break;






case WM_DESTROY ://


响应鼠标单击关闭按钮事












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));//


这里改了


,来载入光标资源







= 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;






}






ShowWindow(h


Wnd,nShowCmd);//


显示窗口







UpdateWindow(hWnd);







//


下面是对消息


的循环处理,大家先不必 管这些


,下节课我会细说的




w


hile(GetMessage(&Msg,NULL,0,0) )






{










TranslateMessage(&Msg);//


翻译


消息











Dis patchMessage(&Msg);//


分派消息







}






return e;


}



这个结果,不能用静态的图


片来说明 什么,大家自己编译连


接后,击鼠标试试,看能出现预期


的效果 不,


我这里就不贴


图出来了,贴静态的没啥意思,


贴动态


的,有点不想整,我也懒


,哈。




经过这几次折腾,如果大家真的每一次都手写了 ,相信其中的那关键的且相同的那部分代码应该是非常熟悉了,


到此就我们就该升级了, 就行高一层次的修炼,后面两节,我准备给大家说些资源的深入细节,还有再在写几个完全


实用的小程序和几个恶作剧程序,不知大家意下如何。




1.8


资源的初步深入




前面已经说了资源的基本概念,


不过 只是做了和很简单的介绍,


这次我们来点狠的,


深入的。


前面我虽然也


用了资源,不过只是鼠标光标的,回忆下我们的程序,是 那么的简陋。我们早就想把它给装点下了吧,不用着急,学


完了这节后,你就可以成为一 个雕刻师了,想让你的窗口咋样基本都可以了(需要练习了,呵呵)。






以当前 我这个


Word


编辑窗口为例,可以看到一个窗口有很多项的, 而我们之前的串口跟这个相比,真可谓


小巫见大巫。前面的程序连最起码的菜单栏都没有 ,真是惭愧呀。




Vb


做界面,简直就跟画图是一样一样的,


Java


中可 以在编程时,一个一个组件往窗体对象(


JFrame


)上


画(也许有


IDE


可以手画的),


VC


中呢,也可以画,但是注意的细节明显比


V B


要多。其实手画的过程,只是程序帮


了我们,帮我们写了资源 文件。这和用网页设计工具是一样的,我们只顾点鼠标,代码则是网页设计工具生成的了。


同样,


其他编程也是这样,


这样的好处是:

< br>一可以让初学者很容易进入状态



二是可以加快开发,


可以少写


n


拖 代码。


坏处是:不懂得底层机制,很多人写了


n


久的程序,也只能是比葫芦画瓢,写的程序界面还是自己学习时候的那种样


式, 界面单调死板,开发不出个性界面的。鉴于工具带来的负面影响,我才给大家从基本说起,虽然我们是用


VC


6.0


的环境,但是我还是手写资源来教 大家定义资源文件,并不利用


VC



I DE


工具。如果大家资源文件写的很熟练的话,


再用

< p>
VC


中的


IDE


工具,不 用去看多余的书,自然一看就知道是怎么回事,到时用起来就是得心应手。说实在话,如果


不理解


Windows


的一些处理机制,上去直接去学习


VC


,我敢肯定学一段时间后,大部分人会头昏脑胀,事倍功半,虽


有收获,然仍是皮毛,有放弃之想。好了废话不多说了,言归正传。





如上图,是我这节要实现的效果,上面有菜单栏,其中点击“查看”可以菜单子菜单项,弹出的有禁用的菜


单、分割线和灰化的菜单项。还有一个我自己做的图标(


xhk


字样的,左上角)。单击标题栏上的图标可以弹出系统


菜单,在有的程 序,在窗口中击鼠标右键,就可以弹出“快捷菜单”,这些菜单都属于弹出式菜单。


< /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


中 定义方式:








^


字母”:表示


Ctrl


键加上字母键。



“字母”:表示字母,这时类型必须指明


VIRTKEY




数值:表示


ASCII


码,这时类型必须为


ASCII


键名


,


命令


I D[,


类型


][,


选项


]


ID


ACCELERATORS



命令


ID


— —按下快捷键后,


Windows


就向程序发送此命令


ID




类型——用来 指定键的定义方式,可以是


VIRTKEY


< br>ASCII


,分别用来表示“键名”字段定义的是虚拟键还是

ASCII


码。



选项——可以使


Alt,Control



Shift


中的单个或多个,如果指定多个,则中间用逗号隔开,表示快捷键是按键加上

< p>
这些控制键的组合键。



说了这么多,考验我们的 时候终于到了,下面我们就来写程序了。



兵马未动,粮草先行 ,我们先来把界面定义好,定义一个



的资源文件,内容如下:< /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

< p>


//


“打开”菜单项



0X4201


//


“被禁用的菜单项”



//


图标



//


菜单



//


快捷键



//


“灰化的菜单项”



//


“帮助”菜单项



/********************************************* /


/**Next is the definition of the Menus**********/


IDM_MAIN menu


discardable


{









popup


{



menuitem

< p>


打开


(&O)tCtrl+Alt+O

< p>
}



popup



查看


(&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


-


-


-


-


-


-


-


-



本文更新与2021-03-03 12:40,由作者提供,不代表本网站立场,转载请注明出处:https://www.bjmy2z.cn/gaokao/699970.html

C语言到底能干什么(用C写QQ)的相关文章