2011年10月

windows程序设计之DIB操作

主要介绍下与设备无关的位图DIB(Device Independent Bitmap)
位图的基本格式
1.文件头
typedef struct tagBITMAPFILEHEADER {
WORD bfType;//bmp图类型为'BM'或者0X4D42
DWORD bfSize;//整个文件大小
WORD bfReserved1;//0
WORD bfReserved2;//0
DWORD bfOffBits;//DIB像素数据偏移
} BITMAPFILEHEADER
2.信息头
typedef struct tagBITMAPINFOHEADER{
DWORD biSize;//结构体大小 = 40
LONG biWidth;//文件宽度(像素)
LONG biHeight;//文件高度(像素)
WORD biPlanes;//1
WORD biBitCount;//每像素位数(1,4,8,16,24,32)
DWORD biCompression;//压缩方式
DWORD biSizeImage;//实际位图数据占用的字节数
LONG biXPelsPerMeter;//X方向分辨率
LONG biYPelsPerMeter;//Y方向分辨率
DWORD biClrUsed;//使用的颜色数
DWORD biClrImportant;//重要颜色数
} BITMAPINFOHEADER, FAR *LPBITMAPINFOHEADER, *PBITMAPINFOHEADER;
biBitCount字段
$ 1(2色DIB)
$ 4(16色DIB)
$ 8(256色DIB)
$ 24(全色DIB)

3.RGB色彩表(不一定有)
对于像素位(biBitCount字段)是1,4,和8时,BITMAPINFOHEADER后面跟着的是色彩表。
typedef struct tagRGBQUAD {
BYTE rgbBlue;//蓝色
BYTE rgbGreen;//绿色
BYTE rgbRed;//红色
BYTE rgbReserved;//保留,0
} RGBQUAD;

每个像素点都是一个RGB,三种色彩组成颜色。要注意的就是里面的元素顺序是BGR。

4.位图像素位
这里才是图像数据的真实存放处,可以在这里读取图像的数据进行操作。每个像素点都是由RGB数组构成。要注意的是,在DIB中,图像的底行是文件的第一行,图像的顶行是文件的最后一行。但是对于同一行来说,还是从左到右存放数据的。windows程序设计上是这样说的:从下到上DIB的原点是位图图像的左下角,它是图像的第一行的第一个像素。从上到下DIB的原点也是位图图像的左下角,但是这种情况下,左下角是位图数据的最后一行的第一个像素。
DIB中的行数是BITMAPINFOHEADER结构中的biHeight字段,每一行的像素是该结构中biWidth字段,每一行从左边开始,向右数,每个像素位数由bcBitCount确定。
每行的长度必须是4的倍数。
RowLength = 4 * ((bmch.bcWidth * bmch.bcBitCount + 31) / 32)计算;

总的像素位数据大小 = RowLength *bmch.biHeight计算。
下面是对DIB文件的读写:

/****************************************************************************
*函数名称: ReadBmp()
*函数参数: const char *bmpName 写入bmp格式文件的名称及路径
***************************************************************************/
bool ReadBmp(const char *strFile)
{
BITMAPFILEHEADER bitHead;
BITMAPINFOHEADER bitInfoHead;
FILE* pfile;

pfile = fopen(strFile,"rb");//打开文件

if(pfile!=NULL)
{
printf("file bkwood.bmp open success.n");
//读取位图文件头信息
fread(&bitHead,1,sizeof(BITMAPFILEHEADER),pfile);
//fseek(pfile,2,SEEK_CUR); // "BM"
if(bitHead.bfType != 0x4d42)
{
printf("file is not .bmp file!");
return false;
}
//读取位图信息头信息
fread(&bitInfoHead,1,sizeof(BITMAPINFOHEADER),pfile);
}
tagRGBQUAD *pRgb ;
int width = bitInfoHead.biWidth;
int height = bitInfoHead.biHeight;
//分配内存空间把源图存入内存
int l_width = 4 * ((width* bitInfoHead.biBitCount+31) /32);//计算位图的实际宽度并确保它为32的倍数
BYTE *pColorData=(BYTE *)malloc(height*l_width);
memset(pColorData,0,height*l_width);
long nData = height*l_width;

//把位图数据信息读到数组里
fread(pColorData,1,nData,pfile);
fclose(pfile);
return true;
}

/****************************************************************************
*函数名称: saveBmp()

unsigned char *imgBuf 待存盘的位图数据
int width, 以像素为单位待存盘的位图宽
int height, 以像素为单位待存盘的位图高
int biBitCount, 每个像素占的位数
RGBQUAD *pColorTable 颜色表指针
*函数返回值:0为失败 1为成功
*函数描述:给定写入bmp文件的名称和路径 要写入图像的位图数据,宽,高,写进文件中
*
***************************************************************************/
bool saveBmp(const char* bmpName,unsigned char *imgBuf,int width,int height,int biBitCount,RGBQUAD *pColorTable)
{
if(!imgBuf)//imgBuf 待存盘的位图数据
return 0;

int colorTablesize = 0;
if(biBitCount == 8)
colorTablesize =1024;

int lineByte = (width * biBitCount/8+3)/4*4; //行的长度。以字节为单位的每行长度始终是4的倍数

FILE *fp = fopen(bmpName,"wb");
if(fp == 0) return 0;

BITMAPFILEHEADER fileHead; //文件头
fileHead.bfType= 0x4d42; //确保是bmp图像:"BM"
fileHead.bfSize = sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER) + colorTablesize + lineByte *height; //图像大小
fileHead.bfReserved1 = 0;
fileHead.bfReserved2 = 0;
fileHead.bfOffBits = 54 +colorTablesize;

fwrite(&fileHead,sizeof(BITMAPFILEHEADER),1,fp); //写图像文件头

BITMAPINFOHEADER head; //信息头
head.biBitCount = biBitCount; //每像素的位数
head.biClrImportant = 0;
head.biClrUsed = 0;
head.biCompression = 0;
head.biHeight = height; //图像高度
head.biPlanes =1;
head.biSize = 40;
head.biSizeImage = lineByte *height; //图像字节数
head.biWidth = width; //图像高度
head.biXPelsPerMeter = 0;
head.biYPelsPerMeter = 0;

fwrite(&head,sizeof(BITMAPINFOHEADER),1,fp); //写图像文件信息头

if(biBitCount == 8) //如果是8bits,写入色彩表
fwrite(pColorTable,sizeof(RGBQUAD),256,fp);

fwrite(imgBuf,height * lineByte,1,fp); //写图像的数据内容
fclose(fp);
return 1;
}

程序的装载和链接

      今天跑去计算机学院上OS课的时候了解了下程序的装载和链接,虽然很理论,但还是决定记下来,再加些自己的理解。
回来第一件想弄清楚的就是逻辑地址,虚拟地址和物理地址。我去网上查了一下,在http://bbs.chinaunix.net/thread-2083672-1-1.html看到了解释,我觉得解释的很好,就copy下了((*^__^*) )

- 阅读剩余部分 -

汇编基础知识

最近感觉自己学的到了一个瓶颈,学的不知道有多少是记住的,总是感觉自己要学的东西有那么多,时间又太少。专业课也越来越多,花在编程上的时间就少了,但是这毕竟是我的兴趣爱好,所以我不想放弃。昨晚突然有个想法,以后写博客的频率加快,尽管这样博客的质量也就下降了很多,但是我还是觉得博客就是来记录我成长的地方,我该把我的学到的,哪怕是点点滴滴都记录下来,呵呵,不知道能坚持多久。

- 阅读剩余部分 -

【转载】梦断计院--一个计算机学院学生大学学习生活的回顾与反省

【转载】一位学计算机的大学生的历程,真实反映了现在很多大学生的现状,我觉得很不错。就给他家分享了,原文出处已经不清楚了。

与我心有戚戚焉,取其精华吧。有些观点确实不错,另外一些显得有些偏激。

正文:

昨天想了整整一宿,最后写下下面这些对于大学学习生活的回顾与反思。觉得作为一个“过来人”很有必要将一些问题说给未来将要毕业的同学,希望能够吸取
我的教训,少走些弯路。同时以此为鉴,今后努力的改正、提升自己。(没兴趣听我白话者可直接跳读到第六部分总结)
大学生活马上就要结束了,这里不禁感叹时光飞逝,物是人非……
记得刚刚踏入大学校门的时候,心中踌躇满志,虽然那时甚至不知道C语言是什么东西,但是仍然对于自己四年后的形象充满了无限的憧憬:
雄厚的基础知识,良好的学术能力,很高的技术才华,未来之科学栋梁等等……
而如今的状况却是:为了得到一个可以糊口的IT民工职位抓破头皮,郁闷与苦恼中为得到一个工作机会而暗自庆幸,至于什么专心学术,什么科学栋梁,似乎距
离自己越来越遥远。
直到此刻,我仍然不认为自己的大学是完全堕落的,我也不认为自己读的书是无用的,我更不赞成自己没有学习计算机科学的资质,那么问题
究竟出现在什么地方?我想这里有很多原因,绝大部分是自己的,但绝对不能忽视环境的因素。
1. 基础知识薄弱
在我东奔西走找工作的时候,才真正的体会到自己原来喜欢炫耀的基础知识是多么的薄弱,而他们又是那么的重要。我曾经在面试时因为说不清进程间的通信机制
而当场被无情的BS,也因为对于自己基础能力不自信而放弃一家很牛逼的公司研发部提供的笔试机会。
先要谈及计院的一大问题。其实在这里真正对于计算机感兴趣,并且肯于专心研究,搞学术的学生真的是凤毛麟角。大环境是普遍是网游成风,腐败猖獗。 真正
的没有几个人肯安下心来读书,即使那几个老老实实听课的 “ 好学生 ” 也只不过是为了一个高高的 GPA ,一个可以在家长同学面前显摆的奖学金证
书。而真正希望学东西,做学问的人太少了。在我找工作的过程中,手中握着一摞奖学金证书,后来被证明绝对是废纸,任凭你怎么吹嘘自己的成绩,没有单位会
真的拿来仔细的看上一看。
回归正题,什么才是真正的基础扎实?我的理解是不仅要牢牢的掌握大学课本中关于计算机核心课程的理论知识,而且还要适当的进行深入。对于该方向非常重要
的思想、名词、技术都要有良好的把握。比如可以随手写出快速排序、哈希查找等经典的常用算法,熟记线程与进程的概念、他们的差别,并且能够解释清楚诸如
僵尸进程之类的问题。会 Linux 的不仅仅是就会几条 shell 命令,或者干脆就会装个系统。用 C++ 的不仅仅要会语法(估计这是绝大多数
毕业生对于 C++ 的理解程度),起码要了解一些常用的标准库,知道什么是 STL ,了解些基本的 OO 思维方法。学过网络的最起码要用过
socket ,了解数据库的不能仅仅就会写几个 SQL 语句,背两条范式等等。
说到这里不禁有点激动,前几天在一个 IT 论坛上看到一个关于大学读书无用论的帖子。说读书无用的人这些基础知识掌握的恐怕也不怎么样,连基础的东西
都没弄明白怎么好意思说自己读过书?没读过书怎么他妈的好意思说读书没用?!其实不是读书无用,是肯安心读书的人太少,而书读的足够的人更少。
倘若没有这些基础,仅仅会用这个工具,那个框架,充其量也不过是个 IT 民工,今后的发展必定受到制约,选择只有三条: 1. 做一辈子 IT 民
工 2. 将大学中欠下来的债补上 3. 改行
这里我不想说太多,话归正题。如果要我重新的去选择,我一定在学习每一门课程的同时尽量的找到相关的资料,扩展每一个话题。同时,将一些最常用的思想,
技术,方法记录下来,并且苦练到可以熟练应用的地步,并且时常的加以回顾。真正基础雄厚的人就应该是可以将常用的基础性知识熟记成诵的人,提到一个基本
的名词或者话题能够将其来龙去脉解释清楚的人。
2. 学风不正,腐败猖獗
这里的学风不正,腐败成风。我想一方面要怪罪于我们自己,对于前途不负责任,将大好的宝贵时光都用在了网游、泡妞、喝酒等事情上;另一方面计院的领导以
及老师就真的没责任了吗?
如今的老师大都想着自己的小项目能赚多少钱,如今的领导多数考虑自己负责的这一块不要出问题而影响到头上的乌纱帽。“一切为了学生”,表面看起来冠冕堂
皇,实则是句屁话。老师根本没时间备课(或者没水平备课),上课照本宣科的念幻灯片,考试之前为了保证及格率不忘帮大家“画画范围”。记得大学一年级的
计算机导论课,一个老头足足的念了一个学期的幻灯,内容就是C语言,数字逻辑,离散数学课程的前1/3……内容巨枯燥,而且朗读水平超级差劲。也难怪很
多人从一开始就认为进入计院如同进入火坑。大学四年学下来不知道计算机专业的学完了究竟能做什么。到了毕业时刻,领导开始担心就业率了,早就内外成患、
以涣散堕落为风的计算机学院有岂能在短时间里奋发起来?这个时候开始埋怨大家这个不是,那个不对,仿佛一切问题都是学生的,我想问问你们早干什么来的?
之前的那么多时间不好好的调教你的学生,为什么这个时候才想起来教育?
在这样的学习环境下,除了主动的自学,多多的上网搜集信息、泡图书馆,还能有什么选择呢?但说回来,我没完全的做到。最终问题还出在自己,不够坚定,有
时会随着大环境一起堕落,一起enjoy美好的大学生活……
3. 实践薄弱,人才位置错放
看着自己简历中可怜的实践经验,面对人才市场上实践经验黄金般的价格,自己不禁暗自悔恨……
很多人都在用理论扎实来搪塞自己实践方面的低能,我想这个借口根本站不住脚。首先,计算机这个学科的性质就决定了没有实践,理论几乎没法理解的扎实透
彻。就好比熟记骑自行车手册的人可能根本不会骑车一样。 我们不排除有未来的图灵、 Knuth 一类的大牛,只要即使不写什么重要的代码,理论也是巨
牛无比。但是大多数学过数据结构与算法的人来说,能用 C 写个 Dijkstra 最短路算法就算不错了,你要给他个什么城市公交线路选择问题,他保
准晕菜,当场崩溃(这样例子我见多了)。
其实我们的同学中真的有些非常的出色,只不过是放错了位置。(尤其是女生,我觉得大多数都不适合去编程)倘若不是在计院,可能他们已经凭借着自己出色的
能力在该方向上开始崭露头角了。我不只听到一个人抱怨自己不适合编程,一些人是纯粹的为自己腐败找借口。这些人往往自己都不知道计算机究竟在学什么,估
计换个环境也还是一个逼样。有些人我感觉绝对是高考造成的资源严重错放,他们在感性理解方面确实非常的出色,自己也非常的上进,换专业绝对是非常好的选
择。但是大一大二的时候,我们的老师,我们的领导又他妈在干啥呢?一些必要的引导总是你们的职责吧,干麻叫这些同学走过了大学四年才意识到自己不适合学
计算机?
总之,种种因素,大多数同学四年没编过几行代码,课设不过草草了事(据说某些老师甚至推荐同学去校外找人代做毕设),所以毕业时,之前做过的东西根本不
敢往简历里写,因为根本没有啥技术含量,都他妈copy的。
4. 项目反思
在我向面试官夸夸其谈自己的所谓有技术含量的项目经验时,不住的冒虚汗,甚至还被一个考官当场揭穿并遭到无情的BS。现在想想,更加悔恨不已……
我也曾经意识到实践的问题。自己也曾经雄心勃勃的要写有技术含量的代码。我大学里自己写过两个自认为是比较有技术含量的项目。不过两个项目最终皆因打不
完的补丁,层出不穷的新bug,臃肿而杂乱的代码,以及自己对于继续开发与维护失去信心与兴趣等原因而最终搁浅失败。
究其原因,我总结如下:
首先是自己太浮躁。我觉得这个问题在当今的毕业生人群中以及IT行业里是普遍存在的。刚刚会编程就开始yy自己能写出多牛逼的程序,做多牛逼的软件。事
实证明,任何牛逼的软件都不是一下子就那么牛逼的,必须要循序渐进的展开。当时,刚刚背熟了C++的语法,就萌生了要写一个牛逼系统证明自己的想法。其
实这个想法本没有错,错就错在我没有进行必要的积累,而且缺乏对于系统模块逐步开发并测试的耐心。在网上下了点别人的设计经验,自己就开始照猫画虎的写
代码。其结果可想而知,调试了n久代码才能勉强的运行,而且及其不稳定。整个项目乱成一团,打一个补丁又出两个bug那种。
这个时候其实应该吸取经验,对于代码进行重写,系统进行改进,甚至有必要重新设计。而我又开始浮躁了,觉得这个算不了什么,吸取教训,再写个更有技术含
量的牛逼程序一定成功。于是竟然无厘头的放弃了那一堆研究了将近一个月的代码,开始了新的项目设计。这个项目的结果更加的可笑,我最终甚至都没有完整的
运行整个程序,无论我怎么调试,程序到一半的时候都会莫名其妙的崩溃,而杂乱的设计与垃圾代码使得我想赶紧将这些破玩意放入回收站。这时我一方面感觉自
己也没啥能力写软件,估计再写也就是九流货色,没啥发展;另一方面开始责怪学校,为什么没有一丁点编程的氛围,这样也不至于我孤军奋战。我还傻了吧唧的
郁闷了好一阵子,之后做了一个我虽然不后悔,但是却觉的是很愚蠢的决定—加入考G大军,并全职学习一年的英语。
其实现在想想那时真是愚蠢的很,明知道做软件一次成功是不可能的,还偏偏犯这种错误。为什么呢?答案就是当时太急功近利了,以为自己多牛逼,写个程序不
费事。但实际遇到困难的时候,有没有耐心与毅力去解决,甚至感觉之前的工作是在浪费时间。虽然现在想想可笑,但是此刻很多人(可能我也在内)还在犯着同
样的错误。
总之急功近利很容易导致莫名的失败感,并且会为自己的失败(其实这个不能叫失败)找各种借口,然后在借口的安慰下完全的放纵自己。这一点也体现在了我考
G的过程中。
5. 借口==障碍
当时的挫败感使得我对于计算机学院这个机构完全的失去了信息,眼看就是最最关键的大三了,这将决定我的出路,我该如何是好?
这个时候我是这样想的,如果考研的话,恐怕会从一个火坑跳到另外一个。从而可能会与许多和我一样迷茫的同学一样继续两年打酱油的生活。因为种种yy以及
对于自己不准确的定位,导致我想到了考GT出国。于是花了1000多块钱报了个新东方,成天夹着厚厚的红宝石去图书馆……现在来看,我不后悔当初的决
定,因为我确实在这个过程中学到了好多,也认识了很多朋友。而且我觉得,如果当时是因为害怕而没有去尝试的话,自己会在悔恨中渡过前半生。但是我觉得当
时的考G绝对是泡沫,它让我产生了种种幻觉,以为自己因为考G水平就高了不少。这个泡沫膨胀了半年多,最后以一个失败的分数为标志迅速的破灭。(就好像
金融危机一样)
其实,如果这个时候,我意识到前面问题的严重性,最差也应该把握住考G这个机会。然而,我又一次没有做到。回顾整个考G的过程,我在不断的为自己找借
口。我埋怨背单词太苦,于是经常为自己开小差(游游泳,看看杂书、电影等)。我做题受到打击时,埋怨周围没有人跟我一起准备。我还以考G为借口,糊弄自
己的专业课,糊弄自己的课设,糊弄自己的前程!我还经常的受到打击,而每当被天书般的GRE习题打击之后,总是自己傻了吧唧的郁闷,而没有用心的去总
结,去努力的提升自己。我因此浪费了不少时间。虽然,在此期间我从没有放纵过自己,每天都尽可能的坚持呆着图书馆或自习室里,但是对于本身英语基础就很
薄弱的我来说,面对这样大的挑战,如此糟糕的状态又怎么能成功呢?
最后的结果可想而知,我用了一年的时间专门学习英语,虽然英文水平有了一些进步,但是与巨额的开销,以及自己辛苦的付出绝对不成比例。现在我的GRE单
词也忘的差不多了,不知道这个曾经的美丽留学梦会不会随着我的科学梦一起从此破灭呢……
6. 总结
上面说了好多,此刻心情很激动,思维好杂乱,现在要平静一下,整理一下。
上大学首要任务:明白自己是来干什么的,走出这里的时候自己要收获什么,自己希望会变成什么样子。
每个人都必须要有明确的目标,除非你想过四年打酱油的生活。
这一点我做到了,虽然做的不好,走了弯路,但是我没有白白荒废四年的时间。
要有扎实的学科基础,不要将自己局限在得一个高分的狭小范围内,仅仅看到眼前的荣誉无疑是目光短浅的表现。要注意学习的扩展性,要努力的去理解并掌握本
专业常用的的核心思想与技术,并达到熟记于胸的程度。
发现自己的优势,选择适合自己的出路。不要仅仅看中程序员的高薪水,做最适合自己的方向才是最最重要的。
学过理论要注重实践,可以自己做一些力所能及的小东西,有意从事计算机方向的同学需要:
熟练掌握一门程序设计语言,一个开发工具,一个系统平台,一种编程思想。自己动手做一些有一定技术含量的项目。
最好是能够利用好假期的时间,出去实习。因为这种经历将是毕业时卖身的有力筹码。
切忌浮躁、急功近利,假如以你的实力可以通过5年的时间成为一个领域的高手,如果自己期望缩短到3年的时间甚至更短,最终很可能要用8年的时间甚至永远
都做不到。
对于自己的目标和已经决定的选择,要执著的追求,直到在其中获得了你满意的成果。
做事情不为自己找借口,借口==失败。
最后环境的因素,我们希望它会变得越来越好。但是继续这样也没有关系,只有对自己充满信心,相信自己,坚持自己的理想,无论在多垃圾的环境中都会取得自
己满意的成绩。

windows程序设计之GDI简介

最近在做一个有关激光笔的小项目,和学长们一起做的。里面还有硬件成份,现在因为才开始做,我主要做软件上面的东西,当然技术含量是很少的抓狂···诶,学了一年左右了,水平还是没很大长进刚刚C入门,SDK也只能说勉强算是入门了吧。项目里面有一部分是要绘制出来鼠标的移动轨迹的,我就去重新看了下GDI,发现自己以前没写过这些东西,印象就是不深刻啊,于是就温习了下。重新看了下<>和<>,ctrl+c和ctrl+v出来下面个实验品,然后做了些笔记,我还是记得学长讲得那句话:博客就是用来记录自己成长的地方。无论有什么学到的,都可以写上来,无论含量高不高,总能在自己以后有一天需要的时候想起来,并且找到,这大概和老师说的好记性不如让笔头差不多吧.

下面是自己一些简单的总结:

windows GDI绘图
Graphics Device Interface:图形设备接口
GDI是GraphicsDeviceInterface的缩写,含义是图形设备接口,它的主要任务是负责系统与绘图程序之间的信息交换,处理所有Windows程序的图形输出。
在Windows操作系统下,绝大多数具备图形界面的应用程序都离不开GDI,我们利用GDI所提供的众多函数就可以方便的在屏幕、打印机及其它输出设备上输出图形,文本等操作。GDI的出现使程序员无需要关心硬件设备及设备驱动,就可以将应用程序的输出转化为硬件设备上的输出,实现了程序开发者与硬件设备的隔离,大大方便了开发工作。

1.资源使用
// 初始的颜色
BYTE bRed = 0;
BYTE bGreen = 0;
BYTE bBlue = 0;
// 笔的颜色 正黑
COLORREF cPen = RGB(bRed, bGreen, bBlue);
//画笔的设置
HPEN CreatePen(
__in int fnPenStyle,
__in int nWidth,
__in COLORREF crColor
);
HPEN hpen;
hpen = CreatePen(PS_SOLID, 10, cPen); //画笔基本属性

//画刷的设置
HBRUSH hbrush;
COLORREF cBrush = RGB(233, GetGValue(cPen),255);
hbrush = CreateSolidBrush(cBrush);
// 释放资源
DeleteObject(hpen);
DeleteObject(hbrush);

2.获取DC。获取了DC就相当于获取了绘画的资格。
HDC hDC = GetDC(hWnd);//参数是NULL时获取的是整个显示器的DC,若是句柄就是指定窗口的DC。

3.将DC设置成对象目标句柄。将图形对象选入DC中,这样DC中原有的类型图形对象就会被新的对象替换。
SelectObject(hDC, hpen);
SelectObject(hDC, hbrush);
这样绘画的时候就可以改变默认的DC属性。

4.绘画区域的变化
GetClientRect(hWnd, &rect);这里获取的是客户区域的大小,是以客户区左上角为坐标原点进行创建的。因此比如在处理WM_MOUSEMOVE等鼠标消息的时候,传进来的lParam参数中包含的坐标也是相对于客户端的。要想转化成屏幕坐标可以用下面的方法:
//转换窗口有效区为屏幕座标
POINT point;
point.x = 0, point.y = 0;
ClientToScreen(hWnd,&point);
你要是想把光标限制在客户区内,可以这样:
//将光标限定在窗口有效区内
rect.top = point.y;
rect.left = point.x;
rect.bottom += rect.top;
rect.right += rect.left;
ClipCursor(&rect); //rect一定要是屏幕座标
下面是获取屏幕坐标的函数
POINT pt;
GetCursorPos(&pt);
这里获取的坐标就是相对屏幕左上角的坐标。若是要转化成客户区坐标可以用
ScreenToClient(hWnd,&point);

5.绘制线条
移到指定的点

下面是我修改的一个绘制鼠标轨迹的小程序

#define MAXGUIDESEGMENTS 1000
#define MyAlloc(dwSize) HeapAlloc(GetProcessHeap(),0,dwSize)
#define MyFree(lpMem) HeapFree(GetProcessHeap(),0,lpMem);

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
BOOL GetGuideLine(HWND hWnd, LPPOINT *lpPoint, LPDWORD lpdwNumPts);

LONG clsCur;

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT ("LineDemo") ;
HWND hwnd ;
MSG msg ;
WNDCLASS wndclass ;

wndclass.style = CS_HREDRAW | CS_VREDRAW ;
wndclass.lpfnWndProc = WndProc ;
wndclass.cbClsExtra = 0 ;
wndclass.cbWndExtra = 0 ;
wndclass.hInstance = hInstance ;
wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
wndclass.lpszMenuName = NULL ;
wndclass.lpszClassName = szAppName ;

if (!RegisterClass (&wndclass))
{
MessageBox (NULL, TEXT ("Program requires Windows NT!"),
szAppName, MB_ICONERROR) ;
return 0 ;
}

hwnd = CreateWindow (szAppName, TEXT ("Line Demonstration"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL) ;

ShowWindow (hwnd, iCmdShow) ;
UpdateWindow (hwnd) ;

while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
return msg.wParam ;
}

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hDC = NULL ;
static LPPOINT lpRed = NULL;
static DWORD dwRed = 0;
switch (message)
{
case WM_CREATE:
hDC = GetDC(hwnd);
break;

case WM_LBUTTONDOWN:
//取得窗口有效区
RECT rect;
GetClientRect(hwnd,&rect);

//转换窗口有效区为屏幕座标
POINT point;
point.x = 0, point.y = 0;
ClientToScreen(hwnd,&point);
rect.top = point.y;
rect.left = point.x;
rect.bottom += rect.top;
rect.right += rect.left;

ClipCursor(&rect); //rect一定要是屏幕座标

if (!clsCur) {
clsCur = GetClassLong(hwnd,GCL_HCURSOR); //取当前窗口的光标
}
SetClassLong(hwnd,GCL_HCURSOR,NULL); //设置当前窗口的光标为NULL
SetCursor(LoadCursor(NULL, IDC_CROSS)); //设置当前光标为十字形

GetGuideLine(hwnd, &lpRed, &dwRed);

break;
case WM_DESTROY:
if (lpRed)
MyFree(lpRed);
PostQuitMessage (0) ;
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}

BOOL GetGuideLine(HWND hWnd, LPPOINT *lpPoint, LPDWORD lpdwNumPts)
{
MSG msg;
HDC hDC = GetDC(hWnd);
BOOL bFirstTime = TRUE;
DWORD dwPos = 0;
RECT rect;
static HPEN hpen;

hpen = CreatePen(PS_SOLID,3, RGB(0,255,0));
SelectObject(hDC,hpen);

GetClientRect(hWnd, &rect);
// 为点数组分配空间
*lpPoint = (LPPOINT)MyAlloc(MAXGUIDESEGMENTS * sizeof(POINT));
SetCapture(hWnd); // 设置鼠标捕获器
// 将客户区填充为白色
GetClientRect(hWnd, &rect);
PatBlt(hDC, 0, 0, rect.right, rect.bottom, WHITENESS);

while(1)
{
// 过滤所有鼠标消息
WaitMessage();
if (PeekMessage(&msg,NULL,WM_MOUSEFIRST,WM_MOUSELAST,PM_REMOVE))
{
// 判断是否在客户区中
if ((LOWORD(msg.lParam) < rect.right) && (HIWORD(msg.lParam) <
rect.bottom))
{
// 是否第一次收到消息
if (bFirstTime)
{
bFirstTime = FALSE;
// 如果是第一次将笔的起点移动到鼠标点击的位置
MoveToEx(hDC, LOWORD(msg.lParam), HIWORD(msg.lParam),
NULL);
}
// 是否达到了最大点数
if (dwPos < MAXGUIDESEGMENTS)
{
// 鼠标的移动会产生鼠标消息,每收到一次消息保存一个点
(*lpPoint)[dwPos].x = LOWORD(msg.lParam);
(*lpPoint)[dwPos].y = HIWORD(msg.lParam);
// 绘制到鼠标所在的点
LineTo(hDC, (*lpPoint)[dwPos].x, (*lpPoint)
[dwPos].y);
dwPos++;
}
}
}
if (msg.message == WM_RBUTTONDOWN)
{
ClipCursor(NULL);
SetClassLong(hWnd,GCL_HCURSOR, clsCur);
SetCursor((HCURSOR)clsCur);
break;
}
else
continue;
}

*lpdwNumPts = dwPos;
ReleaseDC(hWnd, hDC);
ReleaseCapture();
DeleteDC( hDC );

return TRUE;
}

最近的时间越来越紧啊···专业课越来越难,自己课余学计算机的时间也越来越少,真是后后悔自己没去计算机专业额,不过事在人为,努力就好!昨天看到一句比较好的话:一个优秀的程序员:勤奋+执着!我看着很有感触,有时觉得自己花那么多时间面对代码,是否值得···不过我想有付出就会有回报的!!