第一个:FindWindow根据窗口类名或窗口标题名来获得窗口的句柄,该函数返回窗口的句柄
函数的定义:HWNDWINAPIFindWindow(LPCSTRlpClassName,LPCSTRlpWindowName);
第一个参数填窗口的类名,第二个填窗口的标题名,其实是不需要同时填两个参数的,也就是说,你只要知道窗口的类名或窗口的标题就可以了,没有的那个就用NULL代替。
比如现在有一个窗口名为"无标题.txt-记事本"的记事本程序。那么我就可以用上面的函数获得这个窗口的句柄,那获得了这个窗口的句柄我可以干什么呢?作用可大了,因为很多操作窗口的函数,都需要窗口句柄作参数,如移动、改变窗口大小的MoveWindow函数,在这里举个例子,大家就更能体会到这个FindWindow的用法、用处。
FindWindow例子:已知一个窗口名称,写一个程序关闭该窗口,假设当前电脑正有一个窗口名为"无标题.txt-记事本"的记事本程序运行
1#include
第二个:SendMessage根据窗口句柄发送一个消息给窗口
函数定义:LRESULTSendMessage(HWNDhWnd,UINTMsg,WPARAMwParam,LPARAMIParam);
第一个参数是窗口句柄,第二参数个是消息类型,下面的消息表列举了所有消息,第三,四个参数是消息附带信息,解释依赖于消息类型,比如一个字符消息(WM_CHAR),那么第三个参数就储存有一个字符的ASCII码。
消息机制大家都应该知道吧,Windows是基于消息的系统,鼠标移动键盘按键都会产生消息。
接下来举一个例子,发送一个WM_CHAR消息给窗口,也就是模仿键盘按键,接收消息的窗口依旧以"无标题.txt-记事本"为例:
SendMessage例子:模仿键盘按键
1#include
可行的例子:模仿键盘按键:
1#include
如果这样觉得模仿键盘按键太麻烦的话,那么就用keybd_event这个函数,这个专门用于模仿键盘按键的,关于怎么用,自己百度一搜,就知道了。既然SendMessage能模仿键盘按键的话,那也能模仿鼠标左击,右击。而此时SendMessage函数第三,四个参数的解释就是储存有鼠标左击,右击时的位置。如模仿鼠标右击,想一想,一次鼠标右击有哪几步,分别是鼠标右键按下,鼠标右键松开,如果你按下鼠标右键不松开,那它是不是鼠标右击,不是的,直到你松开鼠标右键,才能算是一次完整的鼠标右击.鼠标右键按下的消息类型是“WM_RBUTTONDOWN”,右键松开的消息是“WM_RBUTTONUP”,那么一次完整的鼠标右击应该是:
1SendMessage(wnd,WM_RBUTTONDOWN,0,0);//鼠标右键按下,第三,四个参数说明了鼠标按下时的位置2Sleep(100);//间隔100毫秒3SendMessage(wnd,WM_RBUTTONUP,0,0);//鼠标右键松开同样,也有一个专门模仿鼠标动作的函数,mouse_event这个函数,可以模仿鼠标的移动,单击,双击等。以后会有专门介绍。
第三个:GetCursorPos获取鼠标当前位置(屏幕)
这个函数在SendMessage函数有介绍,这里仅举一个例子,在界面里不停的输出鼠标当前位置。
1#include
在SendMessage有解释,这里仅举一个例子,鼠标指向哪个窗口,就关闭哪个窗口。
1#include
函数定义:BOOLMoveWindow(HWNDhWnd,intX,intY,intnWidth,intnHeight,BOOLbRepaint);hWnd是要改变大小的窗口的句柄,x,y相对于屏幕的坐标,窗口左上角的位置与之相对应,nWidth和nHeight是窗口新的宽高,bRepaint指定窗口是否重画。这里依旧以"无标题.txt-记事本"为例子,改变这个窗口大小,并把窗口移到左上角去。
1#include
函数定义BOOLShowWinow(HWNDhWnd,intnCmdShow);SW_HIDE:隐藏窗口并激活其他窗口。第一个参数hWnd指明了窗口句柄,第二个参数指明了窗口的状态,现在给出第二个参数常用取值范围:SW_MAXIMIZE:最大化指定的窗口。SW_MINIMIZE:最小化指定的窗口并且激活在Z序中的下一个顶层窗口。SW_RESTORE:激活并显示窗口。如果窗口最小化或最大化,则系统将窗口恢复到原来的尺寸和位置。在恢复最小化窗口时,应用程序应该指定这个标志。SW_SHOW:在窗口原来的位置以原来的尺寸激活和显示窗口。ShowWindow例子:程序运行后,在桌面上隐藏一个指定的窗口,并在4秒后再将其显示
1#include
函数定义:BOOLSetCursorPos(intx,inty);
这个函数的两个参数我想大家应该知道是什么意思吧,屏幕的坐标点。
直接看例子:
1#include
如何复制一个文件,比如,我要把E盘的abb.txt的文本文件复制到d盘的zhengyong.txt,则调用语句
1CopyFile("e:\\abb.txt","d:\\zhengyong.txt",FALSE);第三个参数有以下说明:如果设为TRUE(非零),那么一旦目标文件已经存在,则函数调用会失败。否则目标文件会被覆盖掉。
第九个DeleteFile删除一个文件
如何删除一个文件,语句:DeleteFile("e\\abb.txt");既是删除如果目标为隐藏或只读,则无用。
第十个CreateDirectory创建一个文件夹(目录)
假如E盘下什么文件也没有CreateDirectory("e:\\aaa\\bbb",NULL);这样是错的,不能同时建两个文件,除非E盘下已经有了个aaa文件夹了。这样是对的CreateDirectory("e:\\aaa",NULL);
第十一个:GetClientRect获得窗口大小
看例子:
1#include
第十二个:GetCWindowRect获得窗口大小(相对屏幕)
例子:
1#include
第十三个FindFirstFile寻找文件以及获得文件的信息
这里举一个例子吧,列举E盘第一目录下的所有文件,包括文件夹,结合FindNextFile
1#include
当然通过控制通配符,也可以寻找特定类型的文件,比如我只要找文本文件,那么就是这个语句FindFirstFile("e:\\*.txt",&fd);就行了,关键看你自己灵活运用。
前面说过fd里存储有文件的信息,那怎么根据fd里面的成员判断这个文件的属性,文件是否隐藏,是不是文件夹。
fd里的dwFileAttributes存储有文件的信息,如判断是否为文件夹,只要把这个变量和FILE_ATTRIBUTE_DIRECTORY进行按位与运算,如果为1的话,表明为文夹件,如if(fd.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY==1)printf("%s是文件夹\n",fd.cFileName);
其它判断也是一样,现在给出文件的属性(常用几个):FILE_ATTRIBUTE_HIDDEN(隐藏)
FILE_ATTRIBUTE_READONLY(只读)FILE_ATTRIBUTE_SYSTEM(系统)
第十四个FindNextFile寻找文件
参照FindFirstFile函数的例子!
第十五个MoveFile移动文件
如把一个盘里的文本移到另一个盘里去:MoveFile("e:\\a.txt","d:\\abc.txt");即可,意思把e盘下的a.txt移到d盘下去,并改名为abc.txt
第十六个GetClassName根据窗口句柄获得窗口类名
函数定义:intGetClassName(HWNDhWnd,LPTSTRIpClassName,intnMaxCount);
这种函数不需要再解释了吧,前面有太多类似的例子。
第十七个SetFileAttributes设置文件属性
函数定义:BOOLSetFileAttributes(LPCTSTRlpFileName,DWORDdwFileAttributes);
这个函数的第二个参数dwFileAttributes和前面讲过的WIN32_FIND_DATA结构里的dwFileAttributes成员相对应。假设E盘第一目录下有一个文本文件a.txt的正常文件,我要把它设为只读和隐藏那要如何做呢?在前面介绍过WIN32_FIND_DATA结构里dwFileAttributes成员的几个常用属性,根据这个我们知道隐藏是FILE_ATTRIBUTE_HIDDEN,只读是FILE_ATTRIBUTE_READONLY。
那么把E盘下文本文件的属性设为隐藏和只读的语句就是:
SetFileAttributes("e:\\a.txt",FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_READONLY);
(说明:这个函数同样也能设置文件夹属性)
虽然这个语句可以达到要求,但不建议用,因为会覆盖掉文件的原来属性,也就是说如果这个文件之前有系统属性(系统文件)的话,那么这个语句一旦执行后,文件就只有隐藏和只读属性了。
比如一个文件原先就有隐藏属性,依旧以a.txt为例子,那么我把它设为只读,是不是这个语句就可以呢?
SetFileAttributes("e:\\a.txt",FILE_ATTRIBUTE_READONLY);这样的话,虽然文件有只读属性了,但隐藏属性却没有了。
那要如何在不覆盖掉原来的属性下,把文件设为只读呢,其实说了这么多的废话,总结起来就一句话:如何增加一个文件的属性!
前提是要获得这个文件的原有属性:获得文件的属性,在FindFirstFile函数讲过。好吧!直接看例子:
假设e盘的a.txt文件属性为隐藏,给它增加只读属性:
1#include
(补习一下,懂的人直接跳过)
我想懂这里的按位或、按位与或者按位异或运算的人应该知道该如何去掉一个文件的属性。其实一个文件信息都是以二进制代码说明的。
比如一个八位二进制码:10000010,这里的每一位是不是只有0和1取值,不是0,就是1,正好符合一个文件属性的有无,如这个文件是隐藏的吗?只有是和不是,这样我们规定把这八位二进制码的第一位用于确定文件是否具有隐藏属性,如果为1那便是隐藏,无则没有,以此类推第二位就代表文件的只读,第三位系统。。。但要如何判断呢,或者把某一位的值改变呢,用按位运算就可以,00000010,我要把第2位的值设为0,其它位上的值保持不变,用按位异或运算即可,与00000010进行按位异或运算,但这里并不是与它本身进行运算,不管任何八位二进制数的值是多少只要与00000010进行按位异或运算,那第二位都会变成0,而其它的位保持不变。这样为了方便,我们就把00000010进行宏定义,方便记忆,这个二进制数的十进制为2。宏定义#defineFILE_ATTRIBUTE_READONLY2
明白了这个我们就来清除一个文件的一种属性吧!
清除一个文件的隐藏属性,假设a.txt为隐藏文件:
1#include
第十八个ShellExecute运行一个程序函数定义:ShellExecute(HWNDhwnd,LPCSTRlpOperation,LPCSTRlpFile,LPCSTRlpParameters,LPCSTRlpDirectory,INTnShowCmd);第一个参数hwnd是父窗口的句柄,可以为NULL,第二个参数lpOperation表示行为,第三个参数lpFile是程序的路径名,第四个参数lpParameters是给所打开程序的参数,可以为NULL,第五个参数lpDirectory可以为NULL,第六个参数nShowCmd跟ShowWindow函数的第二个参数一样,作用也一样,如果打开的程序有窗口的话,这个参数就指明了窗口如何显示.例如打开一个记事本:
1ShellExecute(NULL,"open","NOTEPAD.EXE",NULL,NULL,SW_SHOWNORMAL);而且这个函数还可以指定程序打开一个属于程序本身类型的文件,假如e盘有一个a.txt文件;我调用函数运行记事本程序并打开这个文本文件.
1ShellExecute(NULL,"open","NOTEPAD.EXE","e:\\a.txt",NULL,SW_SHOWNORMAL);这里由于记事本程序属于系统本身自带的程序,所以没有绝对路径.这个函数还可以打开一个网站:
1WinExce("NOTEPAD.EXEe:\\a.txt",SW_SHOWNORMAL);
第十九个PlaySound播放一个WAV文件
函数定义:BOOLPlaySound(LPCSTRpszSound,HMODULEhmod,DWORDfdwSound);
第一个参数是WAV文件的路径名,第二个参数如果不是播放MFC里以资源ID命名的文件,则可以为空,第三个参数,指明了以何种方式播放文件。注意这个函数只能播放100K以下的WAV文件。
假如E盘有个a.wav文件,下面这个例子播放这个文件:
1#include
第二十个GetModuleFileName根据模块导入表获程序的完整路径
函数定义:DWORDGetModuleFileName(HMODULEhModule,LPTSTRlpFilename,DWORDnSize);
关于第一个参数,将在以后的动态链接库里会有介绍,这里我们只要获得程序本身的路径,那么第一个参数可以为空。
第二个参数用以存储路径,nSize指明字符数组大小。
这个举个例子,运行后,把自身程序移动到e盘下,并改名为a.exe;
1#include
//补习懂的人直接跳过
之前API函数的例子,都是针对DOS编程的,严格来说是在windows下的仿DOS(cmd)进行编程,编写控制台应用程序大家都知道,主函数是main,那针对windows编程的主函数也是main吗?不是的,windows下的主函数(入口函数)是WinMain。在定义main主函数的时候,可以给它带两个参数,也可以不带。而WinMain函数就不能这样了,它有固定的格式,它必须带四个参数。
现给出WinMain函数的固定格式:
intWINAPIWinMain(HINSTANCEhInstance,HINSTANCEhPrevInstance,instanceLPSTRlpCmdLine,intnCmdShow)
大家如果有兴趣可以通过其它渠道了解一下各参数的意思,现在我们只需要知道WinMain函数就是这样定义的,不理解也没关系。
知道了这个我们就来编一个WINDOWS程序吧!
因为我们是针对windows编程,所以要建一个Win32Application工程,步骤是点击文件,然后选择新建,在弹出的对话框里选择工程,再选中Win32Application接着在右边的工程名称下填工程名称,名字随便取。之后点确定。接着又弹出了一个对话框,这里为了方便,我们选择“一个简单的Win32程序”,点完成。接着双击WinMain弹出代码编辑窗口,做完这个我们就可以打代码了。
简单的例子如下:
1#include"stdafx.h"23intAPIENTRYWinMain(HINSTANCEhInstance,4HINSTANCEhPrevInstance,5LPSTRlpCmdLine,6intnCmdShow)7{89while(1)1011Sleep(100);12return0;13}怎么样够简单吧,是不是觉得奇怪,怎么没有窗口,因为窗口要自己创建,不像控制台程序,只要一运行便会有窗口。虽然没有窗口,但你创建了一个进程,打开任务管理器,可以找到你所创建的那个进程,其实也没什么奇怪的,像WINDOWS本身的一些系统服务,也是只有进程,没有窗口的像spoolsv.exe,svchost.exe。
那要如何创建一个窗口呢?要创建一个窗口,就必须要向系统提供窗口的信息,如你要创建的窗口名字叫什么,窗口图标是什么,窗口大小,窗口背景色等,不然,系统怎么给你创建窗口呢?所以为了方便,VC就定义了一个结构,专门用存储窗口信息。
现给出这个结构的定义。
1typedefstruct_WNDCLASS{2UINTstyle;//描述类风格3WNDPROClpfnWndProc;//窗口处理函数4intcbClsExtra;//表示窗口类结构之后分配的额外的字节数。系统将该值初始化为05intcbWndExtra;//表示窗口实例之后分配的额外的字节数。系统将该值初始化为06HINSTANCEhInstance;//应用程序实例句柄由WinMain函数传进来7HICONhIcon;//窗口图标句柄8HCURSORhCursor;//窗口光标句柄9HBRUSHhbrBackground;//画刷句柄10LPCTSTRlpszMenuName;//窗口菜单名11LPCTSTRlpszClassName;//窗口类名12}WNDCLASS,*PWNDCLASS;好了,如果我们已经把窗口信息填好了,那我们要怎样把这个信息告诉系统呢,也就是把要创建窗口的信息传给系统。这里我们调用RegisterClass函数就能实现这个功能。注册完窗口,我们就要创建窗口,用CreateWindow函数就能实现,不要问为什么注册窗口后直接显示不就行了,还要搞什么创建窗口。这我也不知道,反正你只要记住这格式就行了,硬式规定的,你想创建一个窗口,就必须按这些步骤来。
好了,窗口创建了,我们就要调用ShowWindow函数显示窗口,然后用UpdateWindow函数刷新一下,确保窗口能立即显示。
以下详细实现代码:
窗口过程(消息)处理函数,那这个函数是怎样定义的呢,像WinMain一样,它也有固定的格式。
窗口过程处理函数的格式:LRESULTCALLBACKWinSunProc(HWNDwnd,UINTuMsg,WPARAMwParam,LPARAMlParam)
下面的这个是一个窗口创建的完整例子:
MSG类型解释:
结构定义:
如在窗口过程函数中处理窗口关闭WM_CLOSE消息:if(uMsg==WM_CLOSE)PostQuitMessage(0);这样只要一关闭窗口,它的进程也会结束。
接下来解释一下CreateWindow函数参数的意思,函数定义
1HWNDCreateWindow(LPCTSTRlpClassName,//窗口类名,应与WNDCLASS结构里的成员lpszClassName一致2LPCTSTRlpWindowName,,//窗口标题名3DWORDdwStyle,//窗口的风格,取值参见表Style45intx,6inty,//x,y表示所创建窗口左上角位置7intnWidth,8intnHeight,//nWidth,nHeight表示窗口的宽高9HWNDhWndParent,//父窗口句柄,如果不是子窗口,这里取值为NULL10HMENUhMenu,//菜单句柄,没菜单的话,取NULL值11HANDLEhlnstance,//对应着WinMain函数的第一个参数12LPVOIDlpParam);//NULL表Style:(参考:百度)
第二十二个GetMessage获取窗口消息
参照CreateWindow函数例子,以后的例子可能是在控制台下,也可能是Win32Application,大家以后根据主函数判断该建什么工程。
第二十三个RegisterClass注册窗口类,参照CreateWindow
第二十四个UpdateWindow参照CreateWindow
第二十五个DispatchMessage参照CreateWindow
第二十六个LoadCursorFromFile从磁盘加载一个光标文件,函数返回该光标句柄
假设e盘下有一个名为a.cur的光标文件。
1HCURSORcursor//定义一个光标句柄,用于存放LoadCursorFromFile函数返回的光标句柄23cursor=LoadCursorFromFile("e:\\a.cur");获得了光标句柄有什么用呢?看一下窗口类WNDCLASS里的hCursor成员,这个成员也是一个光标句柄,明白了吧!
第二十七个CreateSolidBrush创建一个画刷,函数返回画刷句柄
1HBRUSHhbr=CreateSolidBrush(RGB(12,172,59));//三个数字分别表明RGB的颜色值,RGB根据三种颜色值返回一个COLORREF类型的值
第二十八个LoadImage装载位图、图标、光标函数
函数定义:HANDLELoadImage(HINSTANCEhinst,LPCTSTRlpszName,UINTuType,intcxDesired,intCyDesired,UINTfuLoad)
这里我们只要这个函数的几个简单功能:从磁盘加载位图,从磁盘加载图标,从磁盘加载光标。所以第一个参数hinst我们不用管它,直接填NULL就行,第二个参数lpszName是图片文件所在路径名,第三个参数uType指明要加载的是什么类型的图片,
是位图(填IMAGE_BITMAP),还是光标(填IMAGE_CURSOR),还是图标(填IMAGE_ICON)。第四个cxDesired和第五个参数CyDesired,指定要加载的图片的宽高(可以放大光标,或者缩小),如果加载的是位图的话,则两个参数必须为0,第六个参数fuLoad表示以何种方式加载文件,这里我们是从磁盘加载文件,所以填LR_LOADFROMFILE;
好了,假设e盘下有一个c.cur和i.ico文件。例子:设置窗口图标和光标,还有背景色
1//编写窗口过程函数2LRESULTCALLBACKWinSunProc(3HWNDhwnd,//handletowindow4UINTuMsg,//messageidentifier5WPARAMwParam,//firstmessageparameter6LPARAMlParam//secondmessageparameter7)8{9switch(uMsg)10{11caseWM_CHAR://字符消息12charszChar[20];13sprintf(szChar,"charcodeis%c",wParam);14MessageBox(hwnd,szChar,"char",0);15break;16caseWM_LBUTTONDOWN://鼠标左键按下消息17MessageBox(hwnd,"mouseclicked","message",0);18break;19caseWM_CLOSE:20if(IDYES==MessageBox(hwnd,"是否真的结束?","message",MB_YESNO))21{22DestroyWindow(hwnd);//销毁窗口,并发送WM_DESTROY消息给自身窗口23}24break;25caseWM_DESTROY:26PostQuitMessage(0);27break;28default:29returnDefWindowProc(hwnd,uMsg,wParam,lParam);30}31return0;32}
第二十九个GetDC根据窗口句柄获取设备上下文(DC)返回DC句柄
得到了一个窗口的设备上下文,就可以进行画图操作了,像画圆,画正方形,显示图片等函数都是要设备上下文(DC)句柄做参数的。
1HDCdc//定义一个DC句柄23HWNDwnd=FindWindow(NULL,"无标题.txt-记事本");//获取窗口句柄45dc=GetDC(wnd)//获取这个窗口的设备上下文
第三十个Rectnagle在窗口中画一个矩形
以"无标题.txt-记事本"窗口为例,在这个窗口简单的画一个矩形
1#include
第三十个CreateToolhelp32Snapshot给当前进程拍一个照
1HANDLEhProcessSnap=::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);23//记住这种格式就行了,返回的句柄,存储有进程信息,可以用Process32Firs函数找出来。
第三十一个Process32First根据CreateToolhelp32Snapshot函数返回的句柄获取进程信息
结合Process32Next函数使用,有点像文件寻找函数。
看完整例子:显示系统进程名,以及进程ID号
第三十二个OpenProcess根据进程ID号获得进程句柄,句柄通过函数返回
函数定义:HANDLEOpenProcess(DWORDdwDesiredAccess,BOOLbInheritHandle,DWORDdwProcessId);
第一个参数不要管它,填PROCESS_ALL_ACCESS,第二个参数也一样,填FALSE,那最后一个参数就是进程ID号。
第三十三个TerminateProcess结束一个进程(需进程句柄做参数)
该函数只有两个参数,第一个是进程句柄,第二个填0就行了。
现在给个例子:假设当前有一个进程名为abc.exe的进程正在运行,编一个程序结束它。
第三十四个CreatePen创建一个画笔(返回画笔句柄)
函数定义:BOOLCreatePen(intnPenStyle,intnWidth,COLORREFcrColor);
第一个参数,表示是什么类型的线,取值有以下:
如创建一个画笔:HPENpen=CreatePen(PS_SOLID,3,RGB(255,78,99));
PS_SOLID画笔画出的是实线PS_DASH画笔画出的是虚线(nWidth必须是1)PS_DOT画笔画出的是点线(nWidth必须是1)PS_DASHDOT画笔画出的是点划线(nWidth必须是1)PS_DASHDOTDOT画笔画出的是点-点-划线(nWidth必须是1)第二个参数是画笔的宽度,第三个参数是画笔的颜色,COLORREF类型可以RGB来获得如RGB(233,128,88);分别是红绿蓝。
第三十五个CreateSolidBrush创建一个画刷
只有一个COLORREF类型的参数
HBRUSHbrush=CreateSolidBrush(RGB(22,182,111));
第三十六个SelectObject把GDI对象选入相应的DC中
像画笔(句柄HPEN),画刷(HBURSH),位图(HBITMAP)等都是GID对象。因为画图函数,如画圆,画矩形,画直线,它们所画出图形,默认属性都是不变的,如线的宽度。那么想要改变画出来时线的宽度,比如我想画出来的图形它的线条宽度为5(像素),那么就要创建一个宽度为5的画笔,然后再通过SelectObject函数,给这个画笔选入,就可以了.
接下举个例子:SelectObject应用
第三十七个ReadProcessMemory根据进程句柄读取相应的一段内存(读其它进程里的内存)
函数定义:BOOLReadProcessMemory(HANDLEhProcess,PVOIDpvAddressRemote,PVOIDpvBufferLocal,DWORDdwSize,
PDWORDpdwNumBytesRead);总共四个参数
第一个参数hProcess是远程进程句柄,被读取者。第二个pvAddressRemote是远程进程中内存地址。从具体何处读取
pvBufferLocal是本地进程中内存地址.函数将读取的内容写入此处,dwSize是要读取的字节数。要读取多少
pdwNumBytesRead是实际读取的内容(函数执行后,实际读了多少字节,将存储在该变量里)
远程进程的内存地址是什么意思呢,比如我现在定义一个变量a,inta;就是了,大家知道int型是占四个字节的,也就是说如果a变量所占的内存起始地址是0x1234,那么变量a就占用0x1234,0x1235,0x1236,0x1237这四个字节,这四个字节的内容决定了a变量的值。
好了知道了这个,我们就来举个例子,读取另一个进程里一个变量的值:需设计两个程序,一个用于读(Read)一个用于被读(BeRead);
那么要如何获得另一个进程中一个变量的地址呢这里我们用一个简单的方法,让另一个进程自己去获取,然后输出地址值。
被读的程序代码如下:假设该进程名为:BeRead.exe
1#include
读取的程序代码如下:
1#include
第三十八个WriteProcessMemory根据进程句柄写入相应的一段内存(写入其它进程里的内存)
这个函数里的参数跟ReadProcessMemory函数参数意思一样,只不过一个是写,一个是读。
下面直接举个例子,形式跟读内存函数的例子一样。
被写的程序代码如下:假设该进程名为:BeWrite.exe
1#include
第三十九个CreateThread创建一个线程(多线程)
线程是什么意思呢,代码是由线程来执行的,一个程序默认只有一个线程(主线程),打个比方,线程就好比一个人,而不同功能的代码或函数就好是一件件不同的事情,如洗碗,洗衣服,擦地。一个人要把这几种事情做完,可以有好几种方案,第一种就是,洗完碗,就去洗衣服,衣服洗完了,再去擦地。第二种就是:洗一分钟碗,再去洗一分钟衣服,再去擦一分钟,然后又去洗一分钟衣服.......直到做完。好了,现在你可以再创造一个人帮你做事,创造这个人后,你就叫他洗衣服,而你就洗碗,这样两件事就可以同时被做了。而这里的创造一个人指的就是CreateThread函数。
函数定义:HANDLECreateThread(LPSECURITY_ATTRIBUTESlpThreadAttributes,DWORDdwStackSize,LPTHREAD_START_ROUTINElpStartAddress,LPVOIDlpParameter,DWORDdwCreationFlags,LPDWORDlpThreadId);
该函数有六个参数,第一个参数不用管它,填NULL,第二个参数dwStackSize用于新线程的初始堆栈大小,默认为0,第三个lpStartAddress填函数名(指标),但这个函数必须是这种固定格式的DWORD_stdcallThreadProc(LPVOIDlpParameter),新的线程将会执行这个函数里面的代码,直到函数结束,线程死亡。第四个lpParameter是一自定义参数,用户可以通过这个参数,传递需要的类型,这个参数与线程函数的参数相对应。第五个dwCreationFlags填0表示立即执行,如果是CREATE_SUSPENDED表示挂起,直到用ResumeThread函数唤醒。第六个lpThreadId填NULL就行了。
现举个例子,两个线程同时每隔一秒输出一个数字,也就是一秒会有两数字输出。
1#include
第四十个GetCurrentProcessId获得当前进程ID
1DWORDcurrentPID;2currentPID=::GetCurrentProcessId();//返回进程ID号3cout< 第四十一个CreateCompatibleDC创建一个兼容的内存设备上下文(DC) 简单的来说,就是复制一个模一样的DC。就把窗口看成一幅幅图画,窗口有大有小,里面的内容也不一样(颜色值),每个像素点的颜色值可能不一样,所以就用设备上下文来描述每个窗口的信息,对于DC具体是怎样描述设备上下文的,我们暂时还不需要知道,只要了解这个概念就行了。这个窗口信息,获得一个窗口设备上下文,就用GetDC函数就行了,如HDChDC=GetDC(hWnd);而CreateCompatibleDC的作用是根据一个设备上下文,再创建一个兼容的设备上下文,如HDCmDC=CreateCompatibleDC(hDC)。这样mDC里的信息就跟hDC里的一样,那这有什么用呢?这个将会在后面的BitBltl输出一个位图(合并两个DC)函数里会用到。 第四十二个GetObject获取一个对象信息(如位图,图标,光标) 函数定义:intGetObject(HGDIOBJhgdiobj,intcbBuffer,LPVOIDlpvObject); 第一个参数hgdiobj是对象句柄,第二个参数cbBuffer是待写入lpvObject指针指向缓存区数据大小,第三个参数lpvObject是一个指针,指向一个缓存区。 这里举一个获取位图的信息,获取位图的大小,假设E盘下有一个aa.bmp的位图文件,输出位图的宽高 1#include 第四十三个BitBlt在窗口输出一个位图 其实倒不如说这个BitBlt函数是拷贝一个设备上下文(DC),或者合并两个窗口,再延伸一下,合并两个图片?也并无不可,往大了说,窗口难道不是图片吗?用截屏软件,把窗口截成图片,这样窗口便成了图片。可能有点瞎说,大家还是按照标准来吧,反正,你只要掌握这个函数就行了,而且这个概念也不会有什么影响,那就足够了。 BitBlt的作用跟把两幅图片合在一起一样,合并两幅图片。可能两幅图片大小不一样也可以合并,但合并DC就不行了,必须两个信息一样的DC才可以合并,那要如何确保两个DC一样呢?这就要用到CreateCompatibleDC函数了。 函数定义:BOOLBitBlt(HDChdcDest,intnXDest,intnYDest,intnWidth,intnHeight,HDChdcSrc,intnXSrc,intnYSrc,DWORDdwRop); 第一个参数hdcDest是原DC句柄,被覆盖的DC,nXdest,nYDest,nWidth,nHeight这四个参数,指明了一个矩形,覆盖原DC哪块区域。 第六个参数hdcSrc是覆盖的DC句柄,nXSrc,nYSrc参数指明从哪里开始覆盖。(覆盖DC的左上角),第九个参数dwPop表示以何种方式覆盖。因为这里我们只要输出一个位图,所以用SRCCOPY,直接覆盖。 好了,直接举个例子,在窗口输出一副图片,假设e盘下有一个aa.bmp的位图。为了方便,我们直接在记事本窗口输出位图,先运行一个窗口名为"无标题.txt-记事本"记事本窗口程序。 1#include 第四十四个GetWindowText根据窗口句柄获得窗口标题名 函数定义:intGetWindowText(HWNDhWnd,LPTSTRlpString,intnMaxCount); 第一个参数hWnd是要获取窗口标题名的窗口句柄,第二个lpString是个字符串,窗口标题名,将会存储在这里面,第三个参数nMaxCount指明了第二个参数字符数组的大小。 下面结合GetCursorPos和WindowFromPoint举个例子,鼠标指向哪个窗口,就在界面显示那窗口的标题名 1#include 第四十五个SetWindowText根据窗口句柄设置窗口标题名 这个函数有两个参数,一个是窗口句柄,一个是标题名,这里就不需要解释了吧,直接看例子,设置一个窗口标题名,依旧以 "无标题.txt-记事本"为例。 1#include 第四十六个GetCurrentProcess获得当前线程句柄 没有参数,直接调用即可,该函数返回线程句柄 第四十七个OpenProcessToken获得一个进程的访问令牌句柄 函数定义:BOOLOpenProcessToken(HANDLEProcessHandle,DWORDDesiredAccess,PHANDLETokenHandle) 第一个参数ProcessHandle待获取的进程句柄,第二个参数DesiredAccess操作类型,填TOKEN_ADJUST_PRIVILEGES就行了, 第三个TokenHandle是访问令牌句柄的指针,该参数接收句柄。 如获得本进程的访问令牌句柄:HANDLEhToken; OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES,&hToken); 第四十八个AdjustTokenPrivileges调整一个进程的访问令牌信息(权限) 函数定义:BOOLAdjustTokenPrivileges(HANDLETokenHandle,BOOLDisableAllPrivileges,PTOKEN_PRIVILEGESNewState,DWORDBufferLength,PTOKEN_PRIVILEGESPreviousState,PDWORDReturnLength) 第一个参数TokenHandle是令牌句柄,第二个是禁用所有权限标志,后面填FALSE就行了。第三个NewState是待刷进令牌句柄的PTOKEN_PRIVILEGES结构信息指针,第四个BufferLength指明TOKEN_PRIVILEGES结构大小,第五,六个参数填NULL就行了。 那么结束上面两个函数,提升一个进程权限制,让它能够结束系统进程的代码就是: 1HANDLEhToken;2OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES,&hToken);3TOKEN_PRIVILEGEStp;4LookupPrivilegeValue(NULL,SE_DEBUG_NAME,&tp.Privileges[0].Luid);5tp.PrivilegeCount=1;//tp里其它一些属性设置6tp.Privileges[0].Attributes=SE_PRIVILEGE_ENABLED;7AdjustTokenPrivileges(hToken,FALSE,&tp,sizeof(TOKEN_PRIVILEGES),NULL,NULL);只上把上面的代码,加入结束普通进程例子的前面,那么就能结束系统进程了。 第四十九个LoadLibrary加载动态链接库,返回动态链接库模块句柄 该函数只有一个参数,那就是动态链接库的名称,如user32.dll,函数返回HMOUDLE类型的模块句柄,获得了一个动态链接库的模块句柄,就可以调用GetProcAddress函数获得模块里面的函数地址,从而调用动态链接库里的函数。 第五十个GetProcAddress根据模块句柄获取相应的函数地址 提到GetProcAddress函数,不得不讲一下怎么设计一个动态链接库,这里我们就以自己设计动态链接库作为GetProcAddress函数的例子。 动态链接库里的函数相对于头文件的函数有什么优势呢?更节省内存,相对于比较常用的函数而已。如果在一个程序里,调用一个头文件里的函数的话,那不管如何,函数的代码就会被复制一份到当前程序里,所以,当有十几个程序调用同一个函数的时候,这个函数在内存中所占用的空间,就会有十几份,分别在各自调用的进程内存空间里,而动态链接库的函数,只在内存中有一份空间(公用空间)如果哪个程序要用到这个函数的话,只要给这个函数的地址,进程就可以跑到这个空间执行函数,那么如何获取函数地址呢,用GetProcAddress函数就行了。 下面我们就自己设计一个动态链接库,点“文件->新建->工程",然后选中“Win32Dynamic-LinkLibrary”,再在右边给工程取一个名,点确定。接着弹出了一个对话框,询问希望创建什么类型,我们选择第二个“一个简单的DLL工程”,点完成->确定.然后单击右边的“+”号,很小的一个,接着下面会出现一个Globals的"+"号,单击该加号,然后再双击DllMain函数,进入代码编辑区,在这里编写代码,这里已经有了一些代码了,编译器自动生成的。那个DllMain函数,便是动态链接库的主函数。在程序进程加载动态链接的时候,进程会自动调用DllMain函数,也就是说会自动执行DllMain函数里的代码,也就是说,如果哪程序执行了这个语句“LoadLibrar("user32.dll")",那么执行这个语句的进程,便会自动执行user32.dll里的DllMain函数。如果是主线程加载动态库的话,那么该DllMain函数里的代码会被执行两次,分别是加载的时候执行一次,调用FreeLibrary函数释放或程序结束自动释放动态链接库的时候执行一次,至于是什么原因导致DllMain函数被调用,DllMain函数的第二个参数ul_reason_for_call说明了原因,它有四个取值,代表了四个原因。分别是: DLL_PROCESS_ATTACH(进程加载),DLL_THREAD_ATTACH(线程加载) DLL_THREAD_DETACH(线程释放),DLL_PROCESS_DETACH(进程释放) 因为这里我们只要设计一个动态链接函数,所以便不用管DllMain函数,DllMain函数将会在介绍CreateRemoteThread(创建一个远程线程)函数的时候讲到,所以我们只要在DllMain函数外定义一个函数就行了。 动态链接里的代码: 1#include"stdafx.h"23BOOLAPIENTRYDllMain(HANDLEhModule,4DWORDul_reason_for_call,5LPVOIDlpReserved6)7{8returnTRUE;9}10extern"C"__declspec(dllexport)intAdd(inta,intb)11{12returna+b;13}点编译执行,然后就会弹出一个调试对话框,直接点取消,接着便生成了动态链接库DLL,然后到你的工程里把后缀名为dll的文件找到, 位置在MyProject\"你的工程名"\Debug下。接着把这个文件复制到要调用的工程下,或者直接复制C:\windows\system32目录下。 假设这个文件名为"sss.dll",那么要调用里面的Add函数便是如下代码: 1HMODULEhmod=::LoadLibrary("sss.dll");//获取sss.dll的模块,加载sss.dll动态链接库2typedefint(*pAdd)(inta,intb);//定义一个对应的函数型,以便识别3pAddadd=(pAdd)GetProcAddress(hmod,"Add");//获取hmod模块里的Add函数地址4inta=add(3,5);//调用模块里的Add函数 第五十一个SetWindowsHookEx安装一个钩子 WINDOWS是基于消息的系统,鼠标移动,单击,键盘按键,窗口关闭等都会产生相应的消息,那么钩子是什么意思呢,它可以监控一个消息,比如在一个窗口里单击了一下,首先获得这个消息的,不是应用程序,而是系统,系统获取这个消息后,就去查看这个消息是在哪个窗口产生的,找到窗口后,再把消息投递到相应程序里的消息队列里,这之间有一个传递过程,那么钩子的作用就是在消息到达应用程序之前截获它,钩子可以关联一个函数(钩子处理函数),也就是说,如果对一个进程安装了一个钩子,进程再接收到相应在消息之前,会先去执行钩子所关联的函数, 先来看一下这个函数定义: HHOOKWINAPISetWindowsHookEx(intidHook,HOOKPROClpfn,HINSTANCEhmod,DWORDdwThreadId) 第一个参数idHook指明要安装的钩子类型,如WH_KEYBOARD(键盘钩子),WH_MOUSE(鼠标钩子),第二个参数是钩子处理函数的地址,该函数必须是这种固定的格式:LRESULTWINAPIHookProc(intnCode,WPARAMwParam,LPARAMlParam) 第三个参数hmod是钩子函数所在模块的句柄,第四个参数dwThreadId是线程ID,待监视消息的ID,如果为0,则为全局钩子,监视所有消息 好,接下来我们举一个例子,钩子类型为WH_KEYBOARD,全局钩子。截获键盘按键消息,并扔掉该消息,让键盘失灵。 由于是装的是全局钩子,所以钩子处理函数必须放在动态链接库里。那么我们就设计一个动态链接库吧。 现给出动态链接库的所有代码:(KeyDll.dll) 1#include"stdafx.h"2#include 再新建一个工程,调用用动态链接库里的函数,代码如下: 1#include 1LRESULTCALLBACKHookKey(intnCode,WPARAMwParam,LPARAMlParam)2{3charsz[25];4sprintf(sz,"%c",wParam);//这个函数头文件#include 第五十二个SHGetFileInfo获取一个文件的各项信息(文件关联图标,属性等)函数定义:DWORDSHGetFileInfo(LPCSTRpszPath,DWORDdwFileAttributes,SHFILEINFOAFAR*psfi,UINTcbFileInfo,UINTuFlags);pszPath是文件的路径,dwFileAttributes一般取0,如果想要获取文件夹信息的话,则取值为FILE_ATTRIBUTE_DIRECTORY,psfi是一个SHFILEINFO结构的指针,该结构存储文件信息,定义如下: 1typedefstruct_SHFILEINFOA2{3HICONhIcon;//文件关联图标句柄4intiIcon;//系统图标列表索引5DWORDdwAttributes;//文件的属性6CHARszDisplayName[MAX_PATH];//文件的路径名7CHARszTypeName[80];//文件的类型名,如是bmp文件,还是执行文件exe,或者其它8}SHFILEINFO;第四个参数cbFileInfo指明SHFILEINFO结构的大小,填sizoef(SHFILEINFO);最后一个参数uFlags指定获取文件的什么信息,可选取值如下:(对应着SHFILEINFO里的成员) 1SHGFI_ICON;//获得图标2SHGFI_DISPLAYNAME;//获得显示名3SHGFI_TYPENAME;//获得类型名4SHGFI_USEFILEATTRIBUTES;//获得属性5SHGFI_LARGEICON;//获得大图标6SHGFI_SMALLICON;//获得小图标7SHGFI_PIDL;//pszPath是一个标识符比如,我只要获取文件图标,那么参数填SHGFI_LARGEICON就行了。如果又想获取文件关联的图标,又想获取文件类型名,那么就是SHGFI_LARGEICON|SHGFI_TYPENAME;函数例子: 1SHFILEINFOsfi;2SHGetFileInfo("e:\\aa.bmp",0,&sfi,sizeof(sfi),3SHGFI_ICON|SHGFI_LARGEICON|SHGFI_USEFILEATTRIBUTES|SHGFI_TYPENAME);接着可以用DrawIcon函数画出文件关联图标:该函数定义:BOOLDrawIcon(HDChDC,intX,intY,HICONhlcon); 第五十三个RegCreateKeyEx在注册表里创建一个子键,或获取一个子键的句柄 在这里我们先来了解一下注册表的基本概念,打开运行对话框,输入regedit,然后回车,便打开了注册表编辑器,首先映入眼前的,便是五个根键HKEY_CLASSES_ROOTHKEY_CURRENT_USERHKEY_LOCAL_MACHINEHKEY_USERHKEY_CURRENT_CONFIG 了解了上面这些东西,接着就来了解下RegCreateKeyEx函数的各个参数吧,先来看一下函数定义: 1LONGRegCreateKeyEx(23HKEYhKey,//根键句柄,指明要在哪个根键下创建子键,填根键名既可4LPCSTRlpSubKey,//子键名,包含完整路径名5DWORDReserved,.//一般取06LPSTRlpClass,//一般取NULL7DWORDdwOptions,//创建子键时的选项,可选值REG_OPTION_NON_VOLATILE,REG_OPTION_VOLATILE,这里取0既可8REGSAMsamDesired,//打开方式,填KEY_ALL_ACCESS,在任何情况都行。9LPSECURITY_ATTRIBUTESlpSecurityAttributes,//指定继承性,还是取010PHKEYphkResult,//子键对应句柄,待创建或打开的子键句柄将存储在该句柄里11LPDWORDlpdwDisposition//打开还是创建子键,对应REG_CREATED_NEW_KEY和REG_OPENED_EXISTING_KEY12);在这里举一个例子,以便我们能更好的理解该函数。 在HKEY_CURRENT_CONFIG根键下的Software主键里创建一个名为MySelf的子键。 1#include 函数定义: 1LONGRegSetValueEx(2HKEYhKey,//子键句柄3LPCTSTRlpValueName,//键值名称,如果提供的子键下没有该名称,则创建4DWORDReserved,//保留,填05DWORDdwType,//键值类型,6CONSTBYTE*lpData,//键值的数据7DWORDcbData//键值的数据的大小8);接着我们以增加开机自启动为例,来看一下函数是如何创建一个键值的,我们知道,像程序添加开机自启动一般都在 HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run下添加一个键值,键值类型为二进制(REG_SZ),而键值的数据就为要自启动程序的路径。 假设e盘下有一个AutoRun.exe的应用程序,让电脑开机时自动运行它。 1#include 第五十五个RegDeleteValue根据子键句柄删除其下的一个键值 这里直接举一个例子,删除RegSetValueEx函数创建的键值 1#include 第五十六个RegQueryValueEx根据子键句柄获取一个键值数据,类型。 1LONGRegQueryValueEx(2HKEYhKey,//根键句柄3LPCWSTRlpValueName,//键值名称4LPDWORDlpReserved,//预留,填05LPDWORDlpType,//接收键值类型6LPBYTElpData,//接收键值数据7LPDWORDlpcbData//接收数据的大小8);例子,获取RegSetValueEx函数创建的键值的类型,数据 1intmain()2{3charData[52];4DWORDSize,Type;5HKEYhroot;//子键句柄6DWORDdwDisposition;7RegCreateKeyEx(HKEY_LOCAL_MACHINE,"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run",0,8NULL,0,KEY_ALL_ACCESS,NULL,&hroot,&dwDisposition);//获取根键句柄9RegQueryValueEx(hroot,"AutoRun",0,&Type,(BYTE*)Data,&Size);//获取AutoRun的信息10printf("键值名称:AutoRun");11switch(Type)12{13caseREG_SZ:printf("键值类型:REG_SZ");break;14caseREG_BINARY:printf("键值类型:REG_BINARY");break;15caseREG_DWORD:printf("键值类型:REG_DWORD");break;16caseREG_MULTI_SZ:printf("键值类型:REG_MULTI_SZ");break;17caseREG_EXPAND_SZ:printf("键值类型:REG_EXPAND");break;18}19printf("键值数据:%s%d\n",Data,Size);20return0;21} 第五十七个RegEnumValue根据子键句柄返回对应索引的键值信息(名称,数据,类型,子键下第一个键值索引为0,以此类推,函数成功执行返回ERROR_SUCCESS) 1LONGRegEnumValue(2HKEYhKey,//子键句柄3DWORDdwIndex,//键值索引4LPWSTRlpValueName,//接收键值名称,字符数组5LPDWORDlpcbValueName,//指明数组大小6LPDWORDlpReserved,//预留,07LPDWORDlpType,//键值类型,填NULL,不获取8LPBYTElpData,//键值数据,填NULL,不获取9LPDWORDlpcbData//接收数据的大小,如果键值数据那项参数为NULL,则该项也为NULL10);例子:输出Run下的所有键值名 1#include 第五十八个ExitWindowsEx关机,重启,注销计算机函数 这个函数只有两个参数,后一个参数为系统预留,填0就可以了,而第一个参数则,指明关机,还是重启,或注销,可选值如下: EWX_LOGOFF//注销EWX_REBOOT//重启NT系统中需SE_SHUTDOWN_NAME特权EWX_SHUTDOWN//关机,需权限。 例子:关闭计算机,由于需要SE_SHUTDOWN_NAME权限,所以我们得先提升权限,代码如下: 1#include 第五十九个VirtualAllocEx在其它的进程中分配内存空间 第六十个CreateRemoteThread创建一个远程线程(在其它进程中创建线程) 1HANDLEWINAPI2CreateRemoteThread(HANDLEhProcess,//进程句柄,函数将在这个进程句柄关联的进程创建线程34LPSECURITY_ATTRIBUTESlpThreadAttributes,56DWORDdwStackSize,7LPTHREAD_START_ROUTINElpStartAddress,8LPVOIDlpParameter,9DWORDdwCreationFlags,10LPDWORDlpThreadId11);这个函数比CreateThread函数多了一个参数,就是这个函数的第一个hProcess(函数在该进程里创建线程),后面的六个参数跟第三十九个函数CreateThread的六个参数一样,这里就不再解释了。 例子:远程线程注入 远程线程注入: 假设动态链接库为“ReCode.dll”它的代码如下: 1#include 注入线程的代码: 第六十一个GetWindowThreadProcessId根据窗口句柄获得对应进程ID号,和线程ID号 函数只有两个参数,第一个参数是窗口句柄,第二个参数是一个DOWRD类型的指针,函数返回线程ID 如: 1DWORDThreadId,ProcessId;2ThreadId=GetWindowThreadProcessId(wnd,&ProcessId); 第六十二个EnumWindows枚举当前正运行的所有主窗口,不包括子窗口 调用这个函数,还必须定义一个回调函数,它的格式是这样的:BOOLCALLBACKlpEnumFunc(HWNDwnd,LPARAMlParam); EnumWindows函数有两个参数,第一个就是回调函数的地址,另一个是自定义参数,对应着回调函数的第二个参数。 每枚举一次窗口,这个回调函数就会被执行一次,而获得的窗口句柄,就会传递给回调函数,对应着回调函数的第一个参数。直到枚举完所有窗口。而在回调用函数里,返回真表示继续枚举,返回假则停止枚举。 例子:枚举窗口 1#include 第六十三个MessageBox弹出一个消息提示框 1intMessageBox(2HWNDhWnd,//指明消息框是属于哪个窗口的,可以为NULL3LPCSTRlpText,//消息提示具体内容4LPCSTRlpCaption,//提示框窗口标题5UINTuType);//指明提示框类型,按钮,图标这里只说下uType的常用可选值:按钮:MB_ABORTRETRYIGNORE终止重试忽略MB_OK确定MB_OKCANCEL确定取消MB_RETRYCANCEL重试取消MB_YESNO是否MB_YESNOCANCEL是否取消图标:MB_ICONWARNING感叹号MB_ICONINFORMATION提示iMB_ICONQUESTION问号MB_ICONSTOP红X号按钮和图标可以结合用,如: 1MessageBox(NULL,"该内存不能访问","出错",MB_OK|MB_ICONSTOP);系统模式:MB_SYSTEMMODAL 函数的返回值确定用户选择了哪个按钮,正面给各按钮的定义:IDABORT“放弃”按钮IDCANCEL“取消”按钮IDIGNORE“忽略”按钮IDNO“否”按钮IDOK确定IDRETRY重试IDYES是判断返回值是否与其相等即可。 第六十四个GetForegroundWindow获得当前激活的窗口句柄 函数没参数,调用即返回最前窗口句柄 这里举一个例子:每当切换窗口的时候弹出一个消息提示框 1#include 第六十五个GetTopWindow根据窗口句柄获得其下第一子窗口句柄(如果有) 用过MFC的人都知道,在对话编辑区,如果要为控件排序的话,就按CTRL+D显示出每个控件的顺序,如下图: 而GetTopWindow函数获取的就是控件顺序为1的窗口句柄。 例子:改变一个主窗口下的第一子窗口的显示内容(前提得它有),这里就以上面那个abc对话框为例: 1#include 第六十六个GetNextWindow根据子窗口句柄获得下一个或上一个同级的窗口句柄(返回NULL,函数执行失败) 函数有两个参数,第一个是子窗口句柄,第二个参数指明寻找上一个,还是一下个窗口句柄,值:GW_HWNONEXT(下一个),GW_HWNDPREV(上一个)。比如子窗口句柄在主窗口的顺序为3,那么获取的是顺序为2或顺序为3的窗口句柄(具体取决于第二个参数),函数返回获得的窗口句柄.这样GetNextWindow结合GetTopWindow函数就可以遍历一个主窗口里的所有子窗口了。 例子:遍历一个窗口里的所有子窗口,以上面的abc窗口为例 1#include 1BOOLInvalidateRect(2HWNDhWnd,//要刷新窗口的句柄3CONSTRECT*lpRect,//刷新的范围4BOOLbErase//重画为TRUE56);例子:在SetTimer函数里会举例 例子:在用w,a,s,d键控制一个矩形移动的同时,一个相同的矩形自动移动。 第六十九个RegisterHotKey注册一个热键 1BOOLRegisterHotKey(2HWNDhWnd,3intid,4UINTfsModifiers,5UINTvk);第一个参数hWnd表明热键消息(HOT_KEY)发送给哪个窗口,为NULL表明直接把消息投递给调用这个函数进程的消息队列。 第二个参数可以自定取值,取值范围0xC000-0xFFFF,这个参数是为了程序能同时拥有多个热键而存在。 例子:按下ctrl+alt+x热键,弹出消息提示框,询问是否要退出。 1//#include"stdafx.h"新建空工程,不需要该头文件2#include 第七十个StretchBlt在窗口输出一个位图 这个函数比BitBlt多了两个参数,那就是源目标DC的宽高,像BitBlt函数,只有目标DC的宽高。 有了这两个参数的加入,StretchBlt函数功能就比BitBlt函数强大了许多,它可以缩小或放大图片,可以把一张图片上的任意矩形区域覆盖到另一张图片上的任意区域。 函数语句:StretchBlt(hdc,0,0,bmInfo.bmWidth,bmInfo.bmHeight,memDC,0,0,50,50,SRCCOPY); 具体用法参考BitBlt函数。 第七十一个TextOut根据设备DC在窗口输出文字 函数定义: 1BOOLTextOut(HDChdc,//设备DC2intnXStart,//窗口x坐标3intnYStart,//窗口y坐标,字符串左上角是将是x,y4LPCTSTRlpString,//字符串5intcbString//字符串中字符的个数6);例子:在窗口输出文字,为了方便,这里依旧在"无标题.txt-记事本",窗口里输出文字 1#include 第七十二个DrawText根据设备DC在窗口的一个矩形区输出文字。 1intDrawTextW(2HDChDC,//设备DC3LPCWSTRlpString,//字符串4intnCount,//字符串的个数5LPRECTlpRect,//指明一个矩形区6UINTuFormat);//输出格式uFormat的常用取值 值说明DT_BOTTOM将正文调整到矩形底部。此值必须和DT_SINGLELINE组合。DT_CENTER使正文在矩形中水平居中。DT_VCENTER使正文在矩形中垂直居中。DT_END_ELLIPSIS对于显示的文本,如果结束的字符串的范围不在矩形内,它会被截断并以省略号标识。如果一个字母不是在字符串的末尾处超出了矩形范围,它不会被截断并以省略号标识。字符串不会被修改,除非指定了DT_MODIFYSTRING标志。T_WORD_ELLIPSIS,DT_PATH_ELLIPSIS和DT_END_ELLIPSIS不能和此参数一起使用DT_LEFT正文左对齐。T_RIGHT正文右对齐。DT_RTLREADING当选择进设备环境的字体是希伯来文或阿拉伯文字体时,为双向正文安排从右到左的阅读顺序都是从左到右的。DT_TOP正文顶端对齐(仅对单行)。DT_WORDBREAK断开字。当一行中的字符将会延伸到由lpRect指定的矩形的边框时,此行自动地在字之间断开。一个回车一换行也能使行折断。DT_WORD_ELLIPSIS截短不符合矩形的正文,并增加省略号。 第七十三个GetLogicalDriveStrings获取系统分区信息 1DWORDGetLogicalDriveStrings(2DWORDnBufferLength,//指明lpBuffer参数大小3LPSTRlpBuffer//分区信息将会存储在这个参数,格式是“分区NULL分区NULL分区NULLNULL”两个NULL结尾4//假设当前电脑有C,D,E分区,那字符串的存储格式是"C:\\\0D:\\\0E:\\\0\0";('\\'转义字符\)5);例子:枚举当前磁盘所有分区 1#include 第七十四个GetDiskFreeSpaceEx获取一个分区(盘符)的信息(已用空间,总大小,可用空间) 这个函数必须用ULARGE_INTEGER联合类型来存储磁盘使用信息。因为要获取磁盘的已用空间,总大小,可用空间,所以我们必须定义三个ULARGE_INTEGER类型变量来存储这三个信息。而具体信息就存储在ULARGE_INTEGER类型的QuadPart成员变量(该成员占八位字节) 如获取C盘的信息:ULARGE_INTEGERdwAvailable,dwFree,dwTotal; GetDiskFreeSpaceEx("c:\\",&dwAvailable,&dwTotal,&dwFree);//获取分区信息 下面结合GetLogicalDriveStrings举个例子:获取当前磁盘所有分区信息并输出 1#include 第七十五个WritePrivateProfileString修改或创建一个INI文件里的数据 INI文件的内容一般由节名,键名,键值组成,先来看一下INI文件的结构,打开一个INI文件,我们可能会看到以下内容 //////////////////////////////////////////////////////////////////////////////////// [gmy_p]exist_p=0linux_p= [boot]a20=0a21=0 /////////////////////////////////////////////////////////////////////////////////// 上面的内容中[gmy_p]和[boot]便是INI文件的节名,节名包含键名,和键值。一个INI文件可以有多个节名. 那么哪些是键名,那些是键值呢,在“=”左边的是键名,而在右边的就是键值,键值可以为NULL。 好了,看一下WritePrivateProfileString的函数的定义: 1BOOLWritePrivateProfileString(2LPCWSTRlpAppName,//节名3LPCWSTRlpKeyName,//键名4LPCWSTRlpString,//修改的数据5LPCWSTRlpFileName//INI文件名6);如果要修改键值,那么要提供哪些信息呢,首先,必须要知道INI文件的路径(lpFileName),要修改的键值是在哪个节名下(lpAppName),以及具体是哪个键名(lpKeyName),还有修改的键值数据(lpString). 比如我要把之前INI文件里节名为gmy_p下的键名exist_p的键值改为100(假设这个文件的路径为d:\gho.ini). 那么就是语句:WritePrivateProfileString("gmy_p","exist_p","100","d:\\gho.ini"); WritePrivateProfileString函数功能不止于此,当函数提供的INI文件名,节名,键名不存在时,那么函数就会创建他们。这样,我们就可以用这个函数创建一个INI文件,或在一个INI文件里创建一个节名,或在一个节名下创建一个键名。 第七十六个GetPrivateProfileString获取一个INI文件里的数据 1DWORDGetPrivateProfileStringW(2LPCWSTRlpAppName,//节名3LPCWSTRlpKeyName,//键名4LPCWSTRlpDefault,//默认值,填0既可5LPWSTRlpReturnedString,//接收数据的缓存区(字符串)6DWORDnSize,//指明缓存区的大小7LPCWSTRlpFileName//INI文件名8);例子获取一个键值:假设D盘下有一个名为Info.ini文件,它的内容如下: //////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// 例子:枚举ZhengYong节名下的所有键名: 1#include GetPrivateProfileString(NULL,NULL,0,Data,252,"d:\\Info.ini"); 大家可以用这个函数编一个读取INI文件内容的程序,以便更好的掌握这个函数。记得把接收数据的缓存区设置大一点。 第七十七个GetSystemMetrics获得特定窗口的高宽度 该函数只有一个参数,常用取值如下: SM_CXSCREEN屏幕宽度 SM_CYSCREEN屏幕高度 SM_CXFULLSCREEN窗口客户区宽度 SM_CYFULLSCREEN窗口客户区高度 SM_CYMENU菜单栏高度 SM_CYCAPTION//标题栏高度 SM_CXBORDER窗口边框宽度 SM_CYBORDER窗口边框高度 例子:获取屏幕分辨率(桌面宽高度) 1#include 第七十八个SetWindowPos设置一个窗口的大小和它的Z序 窗口的Z序是什么意思呢?用过MFC的人应该都清楚,在对话框编辑区按CTRL+D就会显示出每个控件的顺序。如下图: 设置控件的顺序有什么用呢,大家看到上面两个控件有什么特别的吗?对了,两个控件正好有一部分重叠,这时候问题就来了,重叠的部分显示的是那个窗口呢,或者说是以什么来确定显示哪个窗口,我想大家也应该猜到了,是以控件的顺序来确定的。顺序较大的会被显示。这个程序运行如下图如示: 明白窗口的Z序了,我们就来看一下这个函数的参数及其意思。 1BOOLSetWindowPos(2HWNDhWnd,//要设置的窗口句柄3HWNDhWndInsertAfter,4intX,5intY,//X,Y指明窗口左上角的位置6intcx,//窗口宽度7intcy,//窗口高度8UINTuFlags);第二个参数hWndInsertAfter的常用取值: HWND_BOTTOM:将窗口置于Z序的底部.HWND_NOTOPMOST:如果窗口在Z序顶部,则取消顶部位置,如果不是,则该参数无效HWND_TOP:将窗口置于Z序的顶部。HWND_TOPMOST:将窗口置于Z序的顶部。窗口当前未被激活,也依然是顶部位置 最后一个参数uFlags可以是Z序中hWnd的前一个窗口句柄的或以下常用取值: SWP_HIDEWINDOW;隐藏窗口 SWP_SHOWWINDOW:显示窗口 SWP_NOMOVE指明X,Y参数无效 SWP_NOSIZE指明CX,CY参数无效 SWP_NOZORDER指明hWndInsertAfter参数无效 例子:设置一个窗口像PPS和任务栏那样,总在最前显示。 以"无标题.txt-记事本"窗口为例 1#include 依旧以"无标题.txt-记事本"窗口为例: 1#include 第七十九个CreateFile创建一个文件,或打开一个文件用于读写,函数返回文件句柄 1HANDLECreateFile(2LPCSTRlpFileName,//文件名3DWORDdwDesiredAccess,//指明对文件进行何种操作,是要读它(GENERIC_READ)还是要写入(GENERIC_WRITE)4DWORDdwShareMode,//指明文件可以同时被多个程序读写吗?FILE_SHARE_READ可以同时读,FILE_SHARE_WRITED可以同时写5LPSECURITY_ATTRIBUTESlpSecurityAttributes,//指向一个SECURITY_ATTRIBUTES结构的指针,一般为NULL67DWORDdwCreationDisposition,//安全属性,指明以何种方式打开或创建文件8DWORDdwFlagsAndAttributes,//指明文件的属性,隐藏?只读?系统文件?为NULL表示默认属性9HANDLEhTemplateFile//如果不为零,则指定一个文件句柄。新文件将从这个文件中复制扩展属性10);第五个参数dwCreationDisposition的常用取值及意思 TRUNCATE_EXISTING将现有文件缩短为零长度,清空文件的内容,文件必须已经存在 CREATE_ALWAYS创建一个文件,如果文件已经存在,则覆盖它 CREATE_NEW创建文件,如果文件已经存在,则函数执行失败 OPEN_ALWAYS打开文件,如果文件不存在,则创建它 OPEN_EXISTING打开文件,文件必须存在。 第六个参数dwFlagsAndAttributes的常用取值及其意思 FILE_ATTRIBUTE_NORMAL默认属性 FILE_ATTRIBUTE_HIDDEN隐藏 FILE_ATTRIBUTE_READONLY只读 FILE_ATTRIBUTE_SYSTEM系统文件 第八十个ReadFile根据文件句柄,从文件中读取一段数据 1BOOLWINAPIReadFile(2HANDLEhFile,//文件句柄3LPVOIDlpBuffer,//接收文件数据的缓存区4DWORDnNumberOfBytesToRead,//指明读取多少数据(字节)5LPDWORDlpNumberOfBytesRead,//实际读取数据6LPOVERLAPPEDlpOverlapped//一般为NULL,如文件打开时指定了FILE_FLAG_OVERLAPPED,该参才有具体取值。7);例子:读取txt文件的内容,假设E盘下有一个名a.txt的文件,文件内容为123456789 1#include 第八十一个WriteFile根据文件句柄,写入一段数据到文件中 1BOOLWriteFile(2HANDLEhFile,//文件句柄3LPCVOIDlpBuffer,//该缓存区的数据将要写入到文件里4DWORDnNumberOfBytesToWrite,//指明写入多少数据5LPDWORDlpNumberOfBytesWritten,//实际写入数据6LPOVERLAPPEDlpOverlapped//一般为NULL7);例子:在E盘创建一个名为aa.txt的文件,并向其写入数据 1#include 第八十二个SetFilePointer移动一个文件指针的位置 移动一个文件指针的位置有什么用呢,作用是读取一个文件里指定位置的数据,比如我只要读取文件中第四个字节到第七个字节这一段的数据,用SetFilePointer函数就可以完成。 1DWORDSetFilePointer(2HANDLEhFile,//文件句柄3LONGlDistanceToMove,//移动字节,负数表示反向移动4PLONGlpDistanceToMoveHigh,//为了支持超大文件而存在,一般为NULL5DWORDdwMoveMethod//从哪里开始移动,FILE_BEGIN从文件开始处开始移动,FILE_CURRENT当前位置,FILE_END文件末尾6);例子:假设E盘下有一个名为a.txt的文件,内容为"123456789",读取该文件第四个字节到第七个字节的数据 1#include 1#include 如果要在文件的末尾添加数据,就用这个语句:SetFilePointer(FileHandle,0,NULL,FILE_END); 第八十三个GetFileSize获取一个文件的大小 1DWORDGetFileSize(2HANDLEhFile,//文件句柄3LPDWORDlpFileSizeHigh//一般为NULL4);如获取a.txt文件的大小: 1#include 第八十四个SetTextColor根据窗口输出文本颜色 第一个参数是设备DC,第二个参数是一个COLORREF类型的颜色值,可用RGB进行转换。 第八十五个SetBkColor设置背景颜色 参数跟SetTextColor函数一样,第一个DC,第二个COLORREF 第八十六个GetWindowDC获取整个窗口设备上下文DC 像GetDC获取的只是客户区DC,不能对窗口标题栏,状态栏等进行操作。该函数用法跟GetDC一样,仅区域不一样。 例子:在一个窗口的标题栏输出文字 1#include 第八十七个GetDesktopWindow获取桌面窗口句柄 该函数没有参数,调用返回桌面窗口句柄 1#include 第八十八个CreateCompatibleBitmap根据DC创造一个兼容的位图 该函数需与CreateCompatibleDC函数配合使用 函数第一个参数是窗口DC,第二,三参数指明窗口宽高,函数返回位图句柄(HBITMAP) 如: 1char*p;23p=newchar[15];//知道字符串大小为15但此时p所指向的缓存区,没有具体取值。 而用CreateCompatibleBitmap函数,创建的位图,只是一个空壳子。数据没有赋值,那要怎样给数据赋值呢? 首先得把这个位图句柄选入一个DC(该DC必须为CreateCompatibleDC函数创建的)里,然后再用BitBlt函数具体给数据赋值就行了。 例子:实时获取屏幕图像 为了方便,在记事本窗口输出图像,自己就不创建窗口了(打开"无标题.txt-记事本") 1#include 第八十九个GetDIBits从一个兼容位图里获取位图数据先来分析一下位图文件信息结构,一个位图由以下四部分组成: 位图文件头(BITMAPFILEHEADER)//占14字节 位图信息头(BITMAPINFOHEADER)//占40字节 调色板(LOGPALLETE)//如果真彩位图,那该部分没有,直接是位图数据 实际位图数据 而GetDIBits函数获取的就是实际位图数据这一部分了。 接来看一下BITMAPFILEHEADER这个结构以及它成员的意思和取值 1typedefstructtagBITMAPFILEHEADER{2WORDbfType;//表示文件类型,值必须为0x4d423DWORDbfSize;//文件的大小4WORDbfReserved1;//保留,必须为05WORDbfReserved2;//保留,必须为06DWORDbfOffBits;//位图前三部分所占的字节,真彩色位图为547}BITMAPFILEHEADER;上面的成员,只有bfSize的取值不确定,其它都一样,也就是说,每个真彩位图,这几个成员取值都是一样的.下面的例子可以说明。 读取一个真彩位图的文件信息头。 1#include 1typedefstructtagBITMAPINFOHEADER{2DWORDbiSize;//本结构大小,为403LONGbiWidth;//位图的宽度,以像素为单位4LONGbiHeight;//位图的高度,以像素为单位5WORDbiPlanes;//目标设备的级别,必须是16WORDbiBitCount;//每个像素所占的位数,24表示真彩位图7DWORDbiCompression;//位图压缩类型,一般为BI_RGB(未经压缩)8DWORDbiSizeImage;//实际位图数据这部分的所占用的字节数9LONGbiXPelsPerMeter;//指定目标设备水平分辨率,单位像素/米,为010LONGbiYPelsPerMeter;//指定目标垂直分辨率真,单位像素/米,为011DWORDbiClrUsed;//指定目标设备实际用到的颜色数,如果该值为0,则用到的颜色数为2的biBitCount方12DWORDbiClrImportant;//表示图像中重要的颜色数,如果为0,则所有颜色都是重要的。13}BITMAPINFOHEADER;调色板(LOGPALLETE)由于大部分都是针对真彩位图操作,此部分略过 GetDIBits函数定义: 1intGetDIBits(23HDChdc,//位图兼容的DC45HBITMAPhbmp,//位图句柄67UINTuStartScan,//从哪行开始扫描89UINTcScanLines,//扫描多少行数据1011LPVOIDlpvBits,//接收数据的缓存区1213LPBITMAPINFOlpbi,//真彩位图,此处填文件信息头就行了1415UINTuUsage//真彩位图填DIB_RGB_COLORS,表示由R,G,B三色直接构成1617);