调用writeprivateprofilestring函数如果键值类不存在默认构造函数会创建吗

随笔 - 26&
文章 - 0&评论 - 47&trackbacks - 0
[DllImport(kernel32.dll)]
引入kernel32.dll这个动态链接库,在这个动态链接库中包含了很多的windows api 函数,在windows api 对ini文件读写的方法经常被用到,下面摘录了别人的一段较详细的资料
namespace APIMethod{
&&& /// &summary&&&& /// Ini文件操作类&&& /// &/summary&&&& public sealed class IniUtility&&& {&&&&&&& private static string _filePath = string.E//文件路径
&&&&&&& /// &summary&&&&&&&& /// 文件路径&&&&&&& /// &/summary&&&&&&&& public static string FilePath&&&&&&& {&&&&&&&&&&& get { return _fileP }&&&&&&&&&&& set { _filePath = }&&&&&&& }
&&&&&&& /// &summary&&&&&&&& /// Windows API 对INI文件写方法&&&&&&& /// &/summary&&&&&&&& /// &param name="lpApplicationName"&要在其中写入新字串的小节名称。这个字串不区分大小写&/param&&&&&&&& /// &param name="lpKeyName"&要设置的项名或条目名。这个字串不区分大小写。用null可删除这个小节的所有设置项&/param&&&&&&&& /// &param name="lpString"&指定为这个项写入的字串值。用null表示删除这个项现有的字串&/param&&&&&&&& /// &param name="lpFileName"&初始化文件的名字。如果没有指定完整路径名,则windows会在windows目录查找文件。如果文件没有找到,则函数会创建它&/param&&&&&&&& /// &returns&&/returns&&&&&&&& [System.Runtime.InteropServices.DllImport("kernel32")]&&&&&&& private static extern long WritePrivateProfileString(string lpApplicationName, string lpKeyName, string lpString, string lpFileName);
&&&&&&& /// &summary&&&&&&&& /// Windows API 对INI文件读方法&&&&&&& /// &/summary&&&&&&&& /// &param name="lpApplicationName"&欲在其中查找条目的小节名称。这个字串不区分大小写。如设为null,就在lpReturnedString缓冲区内装载这个ini文件所有小节的列表&/param&&&&&&&& /// &param name="lpKeyName"&欲获取的项名或条目名。这个字串不区分大小写。如设为null,就在lpReturnedString缓冲区内装载指定小节所有项的列表&/param&&&&&&&& /// &param name="lpDefault"&指定的条目没有找到时返回的默认值。可设为空("")&/param&&&&&&&& /// &param name="lpReturnedString"&指定一个字串缓冲区,长度至少为nSize&/param&&&&&&&& /// &param name="nSize"&指定装载到lpReturnedString缓冲区的最大字符数量&/param&&&&&&&& /// &param name="lpFileName"&初始化文件的名字。如没有指定一个完整路径名,windows就在Windows目录中查找文件&/param&&&&&&&& /// 注意:如lpKeyName参数为null,那么lpReturnedString缓冲区会载入指定小节所有设置项的一个列表。&&&&&&& /// 每个项都用一个NULL字符分隔,最后一个项用两个NULL字符中止。也请参考GetPrivateProfileInt函数的注解&&&&&&& /// &returns&&/returns&&&&&&&& [System.Runtime.InteropServices.DllImport("kernel32")]&&&&&&& private static extern long GetPrivateProfileString(string lpApplicationName, string lpKeyName, string lpDefault, System.Text.StringBuilder lpReturnedString, int nSize, string lpFileName);
&&&&&&& /// &summary&&&&&&&& /// 向Ini文件中写入值&&&&&&& /// &/summary&&&&&&&& /// &param name="section"&小节的名称&/param&&&&&&&& /// &param name="key"&键的名称&/param&&&&&&&& /// &param name="value"&键的值&/param&&&&&&&& /// &returns&执行成功为True,失败为False。&/returns&&&&&&&& public static long WriteIniKey(string section, string key, string value)&&&&&&& {&&&&&&&&&&& if (section.Trim().Length &= 0 || key.Trim().Length &= 0 ||&&&&&&&&&&&&&&& value.Trim().Length &= 0) return 0;
&&&&&&&&&&& return WritePrivateProfileString(section, key, value, FilePath);&&&&&&& }
&&&&&&& /// &summary&&&&&&&& /// 删除指定小节中的键&&&&&&& /// &/summary&&&&&&&& /// &param name="section"&小节的名称&/param&&&&&&&& /// &param name="key"&键的名称&/param&&&&&&&& /// &returns&执行成功为True,失败为False。&/returns&&&&&&&& public static long DeleteIniKey(string section, string key)&&&&&&& {&&&&&&&&&&& if (section.Trim().Length &= 0 || key.Trim().Length &= 0) return 0;
&&&&&&&&&&& return WritePrivateProfileString(section, key, null, FilePath);&&&&&&& }
&&&&&&& /// &summary&&&&&&&& /// 删除指定的小节(包括这个小节中所有的键)&&&&&&& /// &/summary&&&&&&&& /// &param name="section"&小节的名称&/param&&&&&&&& /// &returns&执行成功为True,失败为False。&/returns&&&&&&&& public static long DeleteIniSection(string section)&&&&&&& {&&&&&&&&&&& if (section.Trim().Length &= 0) return 0;
&&&&&&&&&&& return WritePrivateProfileString(section, null, null, FilePath);&&&&&&& }
&&&&&&& /// &summary&&&&&&&& /// 获得指定小节中键的值&&&&&&& /// &/summary&&&&&&&& /// &param name="section"&小节的名称&/param&&&&&&&& /// &param name="key"&键的名称&/param&&&&&&&& /// &param name="defaultValue"&如果键值为空,或没找到,返回指定的默认值。&/param&&&&&&&& /// &param name="capacity"&缓冲区初始化大小。&/param&&&&&&&& /// &returns&键的值&/returns&&&&&&&& public static string GetIniKeyValue(string section, string key,string defaultValue,int capacity)&&&&&&& {&&&&&&&&&&& if (section.Trim().Length &= 0 || key.Trim().Length &= 0) return defaultV
&&&&&&&&&&& System.Text.StringBuilder strTemp = new System.Text.StringBuilder(capacity);&&&&&&&&&&& long returnValue = GetPrivateProfileString(section, key, defaultValue, strTemp, capacity, FilePath);
&&&&&&&&&&& return strTemp.ToString().Trim();&&&&&&& }
&&&&&&& /// &summary&&&&&&&& /// 获得指定小节中键的值&&&&&&& /// &/summary&&&&&&&& /// &param name="section"&小节的名称&/param&&&&&&&& /// &param name="key"&键的名称&/param&&&&&&&& /// &param name="defaultValue"&如果键值为空,或没找到,返回指定的默认值。&/param&&&&&&&& /// &returns&键的值&/returns&&&&&&&& public static string GetIniKeyValue(string section, string key, string defaultValue)&&&&&&& {&&&&&&&&&&& return GetIniKeyValue(section, key, defaultValue, 1024);&&&&&&& }
&&&&&&& /// &summary&&&&&&&& /// 获得指定小节中键的值&&&&&&& /// &/summary&&&&&&&& /// &param name="section"&小节的名称&/param&&&&&&&& /// &param name="key"&键的名称&/param&&&&&&&& /// &returns&键的值&/returns&&&&&&&& public static string GetIniKeyValue(string section, string key)&&&&&&& {&&&&&&&&&&& return GetIniKeyValue(section, key, string.Empty, 1024);&&&&&&& }&&& }}
阅读(...) 评论()读写文件的问题(GetPrivateProfileString,WritePrivateProfileString)
读写文件的问题(GetPrivateProfileString,WritePrivateProfileString)
编辑:www.fx114.net
本篇文章主要介绍了"读写文件的问题(GetPrivateProfileString,WritePrivateProfileString)
100080]",主要涉及到读写文件的问题(GetPrivateProfileString,WritePrivateProfileString)
100080]方面的内容,对于读写文件的问题(GetPrivateProfileString,WritePrivateProfileString)
100080]感兴趣的同学可以参考一下。
GetPrivateProfileString,WritePrivateProfileString
俺用这两个函数读写文件
文件的内容:
[project1]
GetPrivateProfileString读这个文件时先判断所有的“键"是否都存在总(共有几个键已知.比如从aaa到zzz)
如果不存在就用WritePrivateProfileString写入键并且赋初值然后再读
(如上面的文件没有aaa这个键,就用WritePrivateProfileString写入aaa=0)
请问一下,什么判断aaa,是否存在
因为不能对所有键重写并赋初值
哪位能说一下,这两个函数的工作机制,
很苦脑,就是调用WritePrivateProfileString写进文件后
马上突然断电,再开机的时候,发现要的内容没有写进文件,
感&觉WritePrivateProfileString不是对文件实时写入,
有没有解决办法,,其他的函数也可以
或是,所有的函数都只是对缓冲区操作,断电的时候都不可能来的及写进硬盘
如果是这样的话,有其他办法请各位推荐,
不好意思问题比较罗嗦,俺最多一次又只能酬谢100分,俺会另贴再酬谢100分的'********************************************************************************
'*&&&模块名称:mdlInIFile
'*&&&功能描述:处理配置文件模块
'*&&&设&&&&计:ajiu
'*&&&作&&&&者:ajiu
'********************************************************************************
Private&Declare&Function&GetComputerName&Lib&"kernel32"&Alias&"GetComputerNameA"&_
&&&&&&&&&&&&&&&&&&&&&&&&(ByVal&lpBuffer&As&String,&nSize&As&Long)&As&Long
Private&Declare&Function&GetSystemDirectory&Lib&"kernel32"&Alias&"GetSystemDirectoryA"&_
&&&&&&&&&&&&&&&&&&&&&&&&(ByVal&lpBuffer&As&String,&ByVal&nSize&As&Long)&As&Long
Private&Declare&Function&GetPrivateProfileString&Lib&"kernel32"&Alias&"GetPrivateProfileStringA"&_
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&(ByVal&lpApplicationName&As&String,&_
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ByVal&lpKeyName&As&Any,&_
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ByVal&lpDefault&As&String,&_
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ByVal&lpReturnedString&As&String,&_
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ByVal&nSize&As&Long,&_
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ByVal&lpFileName&As&String)&As&Long
Private&Declare&Function&WritePrivateProfileString&Lib&"kernel32"&Alias&"WritePrivateProfileStringA"&_
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&(ByVal&lpApplicationName&As&String,&_
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ByVal&lpKeyName&As&Any,&_
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ByVal&lpString&As&Any,&_
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ByVal&lpFileName&As&String)&As&Long
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
'********************************************************************************
'**&函数功能:从ini配置文件中读取指定段名、关键字名的值
'**&调用语法:&GetInIKeyValue(SectionName&as&string,KeyName&As&String,FileName&As&String)
'**&参数说明:
'**&&&&&&&&&SectionName&:段名
'**&&&&&&&&&KeyName&&&&&:关键字名
'**&&&&&&&&&FileName&&&&:ini文件名包括路径
'**&返&回&值:
'**&&&&&&&&&String&&&&&&:返回关键字值
'**&处理说明:
'**&&&&&&&&&调用API函数GetPrivateProfileString
'******************************************************************************
Public&Function&GetInIKeyValue(ByVal&SectionName&As&String,&_
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ByVal&KeyName&As&String,&_
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ByVal&FileName&As&String)&As&String
&&&&Dim&KeyValue$
&&&&Dim&strTmp&As&String
&&&&KeyValue$&=&String$(512,&"&")
&&&&GetPrivateProfileString&SectionName,&KeyName,&"",&KeyValue$,&512,&FileName
&&&&strTmp&=&Trim(KeyValue$)
&&&&GetInIKeyValue&=&Left(strTmp,&Len(strTmp)&-&1)
End&Function
'********************************************************************************
'**&函数功能:从ini配置文件中写入指定段名、关键字名及值
'**&调用语法:&SetInIKeyValue(SectionName&as&string,KeyName&As&String,KeyValue&as&string&,FileName&As&String)
'**&参数说明:
'**&&&&&&&&&SectionName&:段名
'**&&&&&&&&&KeyName&&&&&:关键字名
'**&&&&&&&&&KeyValue&&&&:关键字值
'**&&&&&&&&&FileName&&&&:ini文件名包括路径
'**&返&回&值:
'**&处理说明:
'**&&&&&&&&&调用API函数WritePrivateProfileString
'******************************************************************************
Public&Sub&SetInIKeyValue(ByVal&SectionName&As&String,&_
&&&&&&&&&&&&&&&&&&&&&&&&&&&ByVal&KeyName&As&String,&_
&&&&&&&&&&&&&&&&&&&&&&&&&&&ByVal&KeyValue&As&String,&_
&&&&&&&&&&&&&&&&&&&&&&&&&&&ByVal&FileName&As&String)
&&&&Dim&lng&As&Long
&&&&lng&=&WritePrivateProfileString(SectionName,&KeyName,&KeyValue,&FileName)
'********************************************************************************
'**&函数功能:读取系统目录路径
'**&调用语法:&GetSysDir()
'**&参数说明:
'**&返&回&值:
'**&&&&&&&&&String&&&&&&:系统目录
'**&处理说明:
'**&&&&&&&&&调用API函数GetSystemDirectory
'******************************************************************************
Public&Function&GetSysDir()&As&String
&&&&Dim&sysDir$
&&&&Dim&strTmp&As&String
&&&&sysDir&=&String$(128,&"&")
&&&&GetSystemDirectory&sysDir$,&127
&&&&strTmp&=&Trim(sysDir$)
&&&&GetSysDir&=&Left(strTmp,&Len(strTmp)&-&1)
End&FunctionOption&Explicit
'declares&for&ini&controlling
Private&Declare&Function&GetPrivateProfileSection&Lib&"kernel32"&Alias&"GetPrivateProfileSectionA"&(ByVal&lpAppName&As&String,&ByVal&lpReturnedString&As&String,&ByVal&nSize&As&Long,&ByVal&lpFileName&As&String)&As&Long
Private&Declare&Function&GetPrivateProfileString&Lib&"kernel32"&Alias&"GetPrivateProfileStringA"&(ByVal&lpApplicationName&As&String,&ByVal&lpKeyName&As&Any,&ByVal&lpDefault&As&String,&ByVal&lpReturnedString&As&String,&ByVal&nSize&As&Long,&ByVal&lpFileName&As&String)&As&Long
Private&Declare&Function&WritePrivateProfileSection&Lib&"kernel32"&Alias&"WritePrivateProfileSectionA"&(ByVal&lpAppName&As&String,&ByVal&lpString&As&String,&ByVal&lpFileName&As&String)&As&Long
Private&Declare&Function&WritePrivateProfileString&Lib&"kernel32"&Alias&"WritePrivateProfileStringA"&(ByVal&lpApplicationName&As&String,&ByVal&lpKeyName&As&Any,&ByVal&lpString&As&Any,&ByVal&lpFileName&As&String)&As&Long
'when&form&is&loaded
Private&Sub&Form_Load()
'if&error&occures&resume&still
On&Error&Resume&Next
'local&variables
Dim&File&As&String,&OFLen&As&Double,&_
&&&&Str&As&String
'set&our&varibles
File&=&"C:\temp.txt"
OFLen&=&FileLen(File)
'write&few&example&sections:
WriteIniSection&File,&"Test1",&""
WriteIniSection&File,&"Test2",&"Here&shoud&be&found&some&text"
'write&few&ini&strings
WriteIni&File,&"Test3",&"Ini1",&"This&is&ini&1"
WriteIni&File,&"Test1",&"Ini2",&"This&is&ini&2"
'inform&we're&written&the&data
MsgBox&Format((FileLen(File)&-&OFLen)&/&1024,&"0.00")&&&"&KB&data&written&to&"&&&Chr(34)&&&File&&&Chr(34)
'read&the&ini&file
Str&=&Str&&&"Test2&section:&"&&&vbTab&&&ReadIniSection(File,&"Test2")&&&vbCrLf
Str&=&Str&&&"Test1&section:&"&&&vbTab&&&ReadIniSection(File,&"Test1")&&&vbCrLf
Str&=&Str&&&"Ini1&string:&"&&&vbTab&&&ReadIni(File,&"Test3",&"Ini1")&&&vbCrLf
Str&=&Str&&&"Ini2&string:&"&&&vbTab&&&ReadIni(File,&"Test1",&"Ini2")&&&vbCrLf
'show&data
MsgBox&Str
'end&application
'//&INI&CONTROLLING&PROCEDURES
'reads&ini&string
Public&Function&ReadIni(Filename&As&String,&Section&As&String,&Key&As&String)&As&String
Dim&RetVal&As&String&*&255,&v&As&Long
v&=&GetPrivateProfileString(Section,&Key,&"",&RetVal,&255,&Filename)
ReadIni&=&Left(RetVal,&v&-&1)
End&Function
'reads&ini&section
Public&Function&ReadIniSection(Filename&As&String,&Section&As&String)&As&String
Dim&RetVal&As&String&*&255,&v&As&Long
v&=&GetPrivateProfileSection(Section,&RetVal,&255,&Filename)
ReadIniSection&=&Left(RetVal,&v&-&1)
End&Function
'writes&ini
Public&Sub&WriteIni(Filename&As&String,&Section&As&String,&Key&As&String,&Value&As&String)
WritePrivateProfileString&Section,&Key,&Value,&Filename
'writes&ini&section
Public&Sub&WriteIniSection(Filename&As&String,&Section&As&String,&Value&As&String)
WritePrivateProfileSection&Section,&Value,&Filename
End&Sub你留个Mail,我把一个完整的创建、删除INI文件键值及内容的例子发给你。太长了不好贴(名字很怪,联通的如意思邮别名,可以收的到)
不过上面说的我知道,WritePrivateProfileSection&
这函数我会用,就是出现了两个问题,,
1。什么判断,一个键是否存在
2,断电,数据就没有写进去lilaclone(阿九--云破月来花弄影)
感谢你给我的例子,可不是我遇到的问题
没有回的话,下午结贴mark一下&&急什么&&&现在没时间&上课中...1.先判断所有的“键"是否都存在
你可以读出该项目下所有键值&然后与已知所有键值比较
当然可以考虑程序Load时生成ini文件&一次写入&&省得这么麻烦&&&还要读还要检查&&没有还得写
2.应该实时写入,可能是正在写的时候掉电吧,可以实验:
把文件打开--写--查看,没有完成--&关闭,再打开---完成
始终关闭---写---打开查看,完成给你发了个例子,自己分析看第二个问题了
不可能实时写入硬盘的&
是先写入高速缓存的
有没有直接操作硬盘的可能UP好像有个磁盘加速的办法,,我没有用过
数据量小的话可以&先写CMOS,,
数据量多的话,,可以考滤外加电路你的问题都是怪怪的
一、不得利用本站危害国家安全、泄露国家秘密,不得侵犯国家社会集体的和公民的合法权益,不得利用本站制作、复制和传播不法有害信息!
二、互相尊重,对自己的言论和行为负责。
本文标题:
本页链接:VC API常用函数简单例子大全(1
我的图书馆
VC API常用函数简单例子大全(1
第一个:FindWindow根据窗口类名或窗口标题名来获得窗口的句柄,该函数返回窗口的句柄
函数的定义:HWND&WINAPI&FindWindow(LPCSTR&lpClassName&,LPCSTR&lpWindowName);
第一个参数填窗口的类名,第二个填窗口的标题名,其实是不需要同时填两个参数的,也就是说,你只要知道窗口的类名或窗口的标题就可以了,没有的那个就用NULL代替。
比如现在有一个窗口名为"无标题.txt&-&记事本"的记事本程序。那么我就可以用上面的函数获得这个窗口的句柄,那获得了这个窗口的句柄我可以干什么呢?作用可大了,因为很多操作窗口的函数,都需要窗口句柄作参数,如移动、改变窗口大小的MoveWindow函数,在这里举个例子,大家就更能体会到这个FindWindow的用法、用处。
FindWindow例子:已知一个窗口名称,写一个程序关闭该窗口,假设当前电脑正有一个窗口名为"无标题.txt&-&记事本"的记事本程序运行
#include&windows.h& //API函数的头文件 int main() { HWND //定义一个窗口句柄变量,用以存储找到的窗口句柄 wnd=FindWindow(NULL,"无标题.txt - 记事本"); //获得窗口名为"无标题.txt - 记事本"的窗口句柄 SendMessage(wnd,WM_CLOSE,0,0); //调用SendMessage函数,发送一个WM_CLOSE(关闭)消息给wnd窗口句柄。 return 0; }
如果要根据窗口类名来获得窗口句柄话,只要给函数的第一个参数填类名,第二个参数窗口名填NULL,即可,用Spy++可查看窗口类名。
第二个:SendMessage根据窗口句柄发送一个消息给窗口
函数定义:LRESULT&SendMessage(HWND&hWnd,UINT&Msg,WPARAM&wParam,LPARAM&IParam);
第一个参数是窗口句柄,第二参数个是消息类型,下面的消息表列举了所有消息,第三,四个参数是消息附带信息,解释依赖于消息类型,比如一个字符消息(WM_CHAR),那么第三个参数就储存有一个字符的ASCII码。
消息机制大家都应该知道吧,Windows是基于消息的系统,鼠标移动键盘按键都会产生消息。
接下来举一个例子,发送一个WM_CHAR消息给窗口,也就是模仿键盘按键,接收消息的窗口依旧以"无标题.txt&-&记事本"为例:
SendMessage例子:模仿键盘按键
#include&windows.h& int main() { HWND wnd=FindWindow(NULL,"无标题.txt - 记事本"); while(1) { SendMessage(wnd,WM_CHAR,WPARAM('a'),0); Sleep(300); } return 0; }
呵呵上面的例子是不是没用,这是为什么呢,哪里出错了吗?错倒是没有错,只是窗口句柄有问题,消息发送给了主窗口。接收消息的窗口不对。记事本窗口界面有些有什么东西呢?菜单,编辑框,&状态栏等控件,控件也是窗口,既然是窗口,那当然它们也有窗口句柄,而在记事本里是在哪里打字的?编辑框控件里打字的嘛!所以消息应该发送编辑框控件,那如何获得记事本里编辑框控件的窗口句柄呢?用FindWindow吗?不知道编辑框窗口标题名,类名也不知道,当然也有其它方法获取编辑框窗口标题名和窗口类名,如Spy++。关于如何获得编辑框句柄,将在以后的函数中会有介绍,这里我们就用WindowFromPoint这个函数来获取,这个函数获取窗口句柄的方法比较笨,(相对于我这个例子来说),这个函数是根据什么来获取窗口句柄的呢?根据屏幕坐标点,如屏幕坐标点20,20,当前是哪个窗口占有,就返回哪个窗口的句柄。有了这个函数,我们还需要一个函数GetCursorPos获取鼠标当前位置(针对于屏幕);
可行的例子:模仿键盘按键:
#include&windows.h& int main() { POINT //一个可储存坐标点的结构体变量,x横坐标,y,纵坐标,如curpos.x curpos.y while(1) { GetCursorPos(&curpos); //获取当前鼠标的位置,位置将储存在curpos里。 HWND hWnd = WindowFromPoint(curpos); //根据curpos所指的坐标点获取窗口句柄 SendMessage(hWnd,WM_CHAR,WPARAM('g'),0); //发送一个字符(按键)消息g给当前鼠标所指向的窗口句柄 Sleep(300); //睡眠三百毫秒,相当于等待三分之一秒 } }
这个程序一运行后,只要把鼠标指向要输入字符的窗口句柄,那么就相当于键盘每三分之一秒按了一个g键,试试吧!
如果这样觉得模仿键盘按键太麻烦的话,那么就用keybd_event这个函数,这个专门用于模仿键盘按键的,关于怎么用,自己百度一搜,就知道了。既然SendMessage能模仿键盘按键的话,那也能模仿鼠标左击,右击。而此时SendMessage函数第三,四个参数的解释就是储存有鼠标左击,右击时的位置。如模仿鼠标右击,想一想,一次鼠标右击有哪几步,分别是鼠标右键按下,鼠标右键松开,如果你按下鼠标右键不松开,那它是不是鼠标右击,不是的,直到你松开鼠标右键,才能算是一次完整的鼠标右击.鼠标右键按下的消息类型是“WM_RBUTTONDOWN”,右键松开的消息是“WM_RBUTTONUP”,那么一次完整的鼠标右击应该是:
SendMessage(wnd,WM_RBUTTONDOWN,0,0); //鼠标右键按下,第三,四个参数说明了鼠标按下时的位置 Sleep(100); //间隔100毫秒 SendMessage(wnd,WM_RBUTTONUP,0,0); //鼠标右键松开
同样,也有一个专门模仿鼠标动作的函数,mouse_event这个函数,可以模仿鼠标的移动,单击,双击等。以后会有专门介绍。
第三个:GetCursorPos获取鼠标当前位置(屏幕)
这个函数在SendMessage函数有介绍,这里仅举一个例子,在界面里不停的输出鼠标当前位置。
#include&windows.h& #include&stdio.h& int main() { POINT while(1) { GetCursorPos(&curpos); printf("x:%d,y:%d",curpos.x,curpos.y); Sleep(300); printf("\n"); } }
第四个:WindowFromPoint根据坐标点获得对应的窗口句柄
在SendMessage有解释,这里仅举一个例子,鼠标指向哪个窗口,就关闭哪个窗口。
#include&windows.h& int main() { Sleep(2500); //等待一会儿,用于把鼠标移到其它窗口上去,避免指向本身进程的窗口,关掉自己的窗口。 POINT while(1) { GetCursorPos(&curpos); HWND wnd=WindowFromPoint(curpos); SendMessage(wnd,WM_CLOSE,0,0); Sleep(300); } }
第五个MoveWindow根据窗口句柄移动窗口,改变窗口大小
函数定义:BOOL&MoveWindow(&HWND&hWnd,&int&X,&int&Y,&int&nWidth,&int&nHeight,&BOOL&bRepaint&);hWnd是要改变大小的窗口的句柄,x,y相对于屏幕的坐标,窗口左上角的位置与之相对应,nWidth和nHeight是窗口新的宽高,bRepaint指定窗口是否重画。这里依旧以"无标题.txt&-&记事本"为例子,改变这个窗口大小,并把窗口移到左上角去。
#include&windows.h& int main() { HWND wnd=FindWindow(NULL,"无标题.txt - 记事本"); MoveWindow(wnd,0,0,220,120,NULL); return 0; }
第六个ShowWindow设置窗口显示状态,如隐藏,最大化,最小化
函数定义BOOL&ShowWinow(HWND&hWnd,int&nCmdShow);& & & SW_HIDE:隐藏窗口并激活其他窗口。第一个参数hWnd指明了窗口句柄,第二个参数指明了窗口的状态,现在给出第二个参数常用取值范围:  SW_MAXIMIZE:最大化指定的窗口。  SW_MINIMIZE:最小化指定的窗口并且激活在Z序中的下一个顶层窗口。  SW_RESTORE:激活并显示窗口。如果窗口最小化或最大化,则系统将窗口恢复到原来的尺寸和位置。在恢复最小化窗口时,应用程序应该指定这个标志。& & & SW_SHOW:在窗口原来的位置以原来的尺寸激活和显示窗口。ShowWindow例子:程序运行后,在桌面上隐藏一个指定的窗口,并在4秒后再将其显示
#include&windows.h& int main() { HWND wnd=FindWindow(NULL,"无标题.txt - 记事本"); ShowWindow(wnd,SW_HIDE); Sleep(5000); ShowWindow(wnd,SW_SHOW); return 0; }
第七个SetCursorPos设置鼠标的位置、把鼠标移动到指定的位置
函数定义:BOOL&SetCursorPos(int&x,int&y);
这个函数的两个参数我想大家应该知道是什么意思吧,屏幕的坐标点。
直接看例子:
#include&windows.h& int main() { int sec=0; while(sec&200) { SetCursorPos(rand()%1024,rand()%768); //随机设置鼠标的位置 Sleep(20); sec++; } return 0; }
第八个CopyFile复制一个文件
如何复制一个文件,比如,我要把E盘的abb.txt的文本文件复制到d盘的zhengyong.txt,则调用语句
CopyFile("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获得窗口大小
#include&windows.h& #include&stdio.h& int main(int argc, char* argv[]) { HWND while(1) { wnd=FindWindow(NULL,"无标题.txt - 记事本"); RECT //专门用来存储窗口大小 GetClientRect(wnd,&rect); //获取窗口大小 printf("%d,%d,%d,%d\n",rect.left,rect.top,rect.right,rect.bottom); //输出窗口大小,试着用鼠标改变窗口大小 Sleep(300); } }
第十二个:GetCWindowRect获得窗口大小(相对屏幕)
#include&windows.h& #include&stdio.h& int main(int argc, char* argv[]) { HWND while(1) { wnd=FindWindow(NULL,"无标题.txt - 记事本"); RECT //专门用来存储窗口大小 GetWindowRect(wnd,&rect); //获取窗口大小 printf("%d,%d,%d,%d\n",rect.left,rect.top,rect.right,rect.bottom); //输出窗口大小,试着用鼠标改变窗口大小 Sleep(300); } }
试着去找一下GetClientRect和GetWindowRect之间有什么区别;
第十三个FindFirstFile寻找文件以及获得文件的信息
这里举一个例子吧,列举E盘第一目录下的所有文件,包括文件夹,结合FindNextFile
#include&windows.h& #include&stdio.h& int main() { BOOL done=TRUE; WIN32_FIND_DATA HANDLE hFind = FindFirstFile("e:\\*.*", &fd); //第一个参数是路径名,可以使用通配符,懂DOS的人应该知道吧!fd存储有文件的信息 while (done) { printf("%s\n",fd.cFileName); done=FindNextFile(hFind, &fd); //返回的值如果为0则没有文件要寻了 } return 0; }
当然也可以直接找一个文件,不使用通配符,但这样有什么意义呢?,如FindFirstFile("e:\\aaa.txt",&fd);其实这个可以获取一个文件的信息,如文件是不是隐藏的,或者有没有只读属性等。
当然通过控制通配符,也可以寻找特定类型的文件,比如我只要找文本文件,那么就是这个语句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根据窗口句柄获得窗口类名
函数定义:int&GetClassName(HWND&hWnd,&LPTSTR&IpClassName,&int&nMaxCount);
这种函数不需要再解释了吧,前面有太多类似的例子。
第十七个SetFileAttributes设置文件属性
函数定义:BOOL&SetFileAttributes(&LPCTSTR&lpFileName,&DWORD&dwFileAttributes);
这个函数的第二个参数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文件属性为隐藏,给它增加只读属性:
#include&windows.h& int main() { WIN32_FIND_DATA FindFirstFile("e:\\a.txt",&fd); fd.dwFileAttributes|=FILE_ATTRIBUTE_READONLY; //在原来的属性下增加只读属性 SetFileAttributes("e:\\a.txt",fd.dwFileAttributes); //设置文件的属性 return 0; }
第二个例子:如何去掉一个文件的属性
(补习一下,懂的人直接跳过)
我想懂这里的按位或、按位与或者按位异或运算的人应该知道该如何去掉一个文件的属性。其实一个文件信息都是以二进制代码说明的。
比如一个八位二进制码:,这里的每一位是不是只有0和1取值,不是0,就是1,正好符合一个文件属性的有无,如这个文件是隐藏的吗?只有是和不是,这样我们规定把这八位二进制码的第一位用于确定文件是否具有隐藏属性,如果为1那便是隐藏,无则没有,以此类推第二位就代表文件的只读,第三位系统。。。但要如何判断呢,或者把某一位的值改变呢,用按位运算就可以,,我要把第2位的值设为0,其它位上的值保持不变,用按位异或运算即可,与进行按位异或运算,但这里并不是与它本身进行运算,不管任何八位二进制数的值是多少只要与进行按位异或运算,那第二位都会变成0,而其它的位保持不变。这样为了方便,我们就把进行宏定义,方便记忆,这个二进制数的十进制为2。宏定义#define&FILE_ATTRIBUTE_READONLY&2
明白了这个我们就来清除一个文件的一种属性吧!
清除一个文件的隐藏属性,假设a.txt为隐藏文件:
#include&windows.h& int main() { WIN32_FIND_DATA FindFirstFile("e:\\a.txt",&fd); //获取文件信息 fd.dwFileAttributes^=FILE_ATTRIBUTE_HIDDEN; //在原来的属性下删除隐藏属性 SetFileAttributes("e:\\a.txt",fd.dwFileAttributes); //设置文件的属性 return 0; }
如果单单只针对文件的属性进行操作的话,可以用GetFileAttributes函数获取文件的属性,该函数只一个参数,那就是文件的路径,函数返回一个DWORD值,包含文件属性信息。
第十八个ShellExecute运行一个程序函数定义:ShellExecute(HWND&hwnd,&LPCSTR&lpOperation,&LPCSTR&lpFile,&LPCSTR&lpParameters,&LPCSTR&lpDirectory,&INT&nShowCmd);第一个参数hwnd是父窗口的句柄,可以为NULL,第二个参数lpOperation表示行为,第三个参数lpFile是程序的路径名,第四个参数lpParameters是给所打开程序的参数,可以为NULL,第五个参数lpDirectory可以为NULL,第六个参数nShowCmd跟ShowWindow函数的第二个参数一样,作用也一样,如果打开的程序有窗口的话,这个参数就指明了窗口如何显示.例如打开一个记事本:
ShellExecute(NULL,"open","NOTEPAD.EXE",NULL,NULL,SW_SHOWNORMAL);
而且这个函数还可以指定程序打开一个属于程序本身类型的文件,假如e盘有一个a.txt文件;我调用函数运行记事本程序并打开这个文本文件.
ShellExecute(NULL,"open","NOTEPAD.EXE","e:\\a.txt",NULL,SW_SHOWNORMAL);
这里由于记事本程序属于系统本身自带的程序,所以没有绝对路径.这个函数还可以打开一个网站:
ShellExecute(NULL,"open","",NULL,NULL,SW_SHOWNORMAL); ShellExecute(NULL,"open","C:",NULL,NULL,SW_SHOWNORMAL);
类似的函数还有WinExec,只有两个参数,它的最后一个参数跟ShellExecute函数的最后一个参数一样.而第一个参数则是程序路径名.举个例子:WinExce("NOTEPAD.EXE",SW_SHOWNORMAL);这个函数也可以给程序传递一个文件名供要运行的程序打开,那要如何加进去呢,这里又没有第三个参数,方法把路径名加在NOTPEPAD.EXE的后面,要以空格来分开如:
WinExce("NOTEPAD.EXE e:\\a.txt",SW_SHOWNORMAL);
第十九个PlaySound播放一个WAV文件
函数定义:BOOL&PlaySound(LPCSTR&pszSound,&HMODULE&hmod,DWORD&fdwSound);
第一个参数是WAV文件的路径名,第二个参数如果不是播放MFC里以资源ID命名的文件,则可以为空,第三个参数,指明了以何种方式播放文件。注意这个函数只能播放100K以下的WAV文件。
假如E盘有个a.wav文件,下面这个例子播放这个文件:
#include&windows.h& #include&mmsystem.h& //PlaySound函数的头文件 #pragma comment(lib, "winmm.lib") //链接库,PlaySound函数必须使用 int main()
{ PlaySound("e:\\19.wav",NULL,SND_SYNC); return 0; }
第二十个GetModuleFileName根据模块导入表获程序的完整路径
函数定义:DWORD&GetModuleFileName(&HMODULE&hModule,&LPTSTR&lpFilename,&DWORD&nSize&);
关于第一个参数,将在以后的动态链接库里会有介绍,这里我们只要获得程序本身的路径,那么第一个参数可以为空。
第二个参数用以存储路径,nSize指明字符数组大小。
这个举个例子,运行后,把自身程序移动到e盘下,并改名为a.
#include&windows.h& int main() { char szAppName[128]={0}; GetModuleFileName(NULL,szAppName,128); MoveFile(szAppName,"e:\\a.exe"); return 0; }
第二十一个CreateWindow创建一个窗口
//补习懂的人直接跳过
之前API函数的例子,都是针对DOS编程的,严格来说是在windows下的仿DOS(cmd)进行编程,编写控制台应用程序大家都知道,主函数是main,那针对windows编程的主函数也是main吗?不是的,windows下的主函数(入口函数)是WinMain。在定义main主函数的时候,可以给它带两个参数,也可以不带。而WinMain函数就不能这样了,它有固定的格式,它必须带四个参数。
现给出WinMain函数的固定格式:
int&WINAPI&WinMain(&HINSTANCE&hInstance,&HINSTANCE&hPrevInstance,&instance&LPSTR&lpCmdLine,&&int&nCmdShow)&
大家如果有兴趣可以通过其它渠道了解一下各参数的意思,现在我们只需要知道WinMain函数就是这样定义的,不理解也没关系。
知道了这个我们就来编一个WINDOWS程序吧!
因为我们是针对windows编程,所以要建一个Win32&Application工程,步骤是点击文件,然后选择新建,在弹出的对话框里选择工程,再选中Win32&Application&接着在右边的工程名称下填工程名称,名字随便取。之后点确定。接着又弹出了一个对话框,这里为了方便,我们选择“一个简单的&&Win32&程序”,点完成。接着双击WinMain弹出代码编辑窗口,做完这个我们就可以打代码了。
&简单的例子如下:
#include "stdafx.h" int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { while(1) Sleep(100); return 0; }
怎么样够简单吧,是不是觉得奇怪,怎么没有窗口,因为窗口要自己创建,不像控制台程序,只要一运行便会有窗口。虽然没有窗口,但你创建了一个进程,打开任务管理器,可以找到你所创建的那个进程,其实也没什么奇怪的,像WINDOWS本身的一些系统服务,也是只有进程,没有窗口的像spoolsv.exe,svchost.exe。
那要如何创建一个窗口呢?要创建一个窗口,就必须要向系统提供窗口的信息,如你要创建的窗口名字叫什么,窗口图标是什么,窗口大小,窗口背景色等,不然,系统怎么给你创建窗口呢?所以为了方便,VC就定义了一个结构,专门用存储窗口信息。
现给出这个结构的定义。
typedef struct _WNDCLASS {
UINT //描述类风格 WNDPROC lpfnWndP //窗口处理函数 int cbClsE //表示窗口类结构之后分配的额外的字节数。系统将该值初始化为0 int cbWndE //表示窗口实例之后分配的额外的字节数。系统将该值初始化为0 HINSTANCE hI // 应用程序实例句柄由WinMain函数传进来
HICON hI //窗口图标句柄
HCURSOR hC //窗口光标句柄 HBRUSH hbrB //画刷句柄 LPCTSTR lpszMenuN //窗口菜单名 LPCTSTR lpszClassN //窗口类名 } WNDCLASS, *PWNDCLASS;
好了,如果我们已经把窗口信息填好了,那我们要怎样把这个信息告诉系统呢,也就是把要创建窗口的信息传给系统。这里我们调用RegisterClass函数就能实现这个功能。注册完窗口,我们就要创建窗口,用CreateWindow函数就能实现,不要问为什么注册窗口后直接显示不就行了,还要搞什么创建窗口。这我也不知道,反正你只要记住这格式就行了,硬式规定的,你想创建一个窗口,就必须按这些步骤来。
好了,窗口创建了,我们就要调用ShowWindow函数显示窗口,然后用UpdateWindow函数刷新一下,确保窗口能立即显示。
以下详细实现代码:
#include "stdafx.h" #include&windows.h& int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { WNDCLASS //定义一个存储窗口信息WNDCLASS变量 wndcls.cbClsExtra=0; //默认为0 wndcls.cbWndExtra=0; //默认为0 wndcls.hbrBackground=(HBRUSH)GetStockObject(GRAY_BRUSH); //背景画刷 wndcls.hCursor=LoadCursor(NULL,IDC_CROSS); //十字光标 wndcls.hIcon=LoadIcon(NULL,IDI_ERROR); //窗口图标 wndcls.hInstance=hI //应用程序实例句柄由WinMain函数传进来
wndcls.lpfnWndProc=NULL; //窗口消息处理函数 wndcls.lpszClassName="windowclass"; //窗口类名 wndcls.lpszMenuName=NULL; //窗口菜单名,没有菜单,为NULL wndcls.style=CS_HREDRAW | CS_VREDRAW; //窗口类型,CS_HREDRAW和CS_VERDRAW 表明 //当窗口水平方向垂直方向的宽度变化时重绘整个窗口 RegisterClass(&wndcls); //把窗口信息提交给系统,注册窗口类 HWND //用以存储CreateWindow函数所创建的窗口句柄 hwnd=CreateWindow("windowclass","first windows",
WS_OVERLAPPEDWINDOW,0,0,600,400,NULL,NULL,hInstance,NULL);//创建窗口 ShowWindow(hwnd,SW_SHOWNORMAL); //窗口创建完了,显示它 UpdateWindow(hwnd); //更新窗口,让窗口毫无延迟的显示 return 0; }
是不是出错了,内存不能读取,为什么了呢,因为你创建的窗口没有消息处理函数,windows系统当然不允许这样一个窗口存在,对按键,鼠标都没有反应,这样的窗口是没有实际意义的。&&wndcls.lpfnWndProc=NULL;&//窗口消息处理函数,就是前面这句,必须要填
窗口过程(消息)处理函数,那这个函数是怎样定义的呢,像WinMain一样,它也有固定的格式。
窗口过程处理函数的格式:LRESULT&CALLBACK&WinSunProc(HWND&wnd,UINT&uMsg,WPARAM&wParam,LPARAM&lParam)
下面的这个是一个窗口创建的完整例子:
#include "stdafx.h" #include&windows.h& LRESULT CALLBACK WinSunProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam) { if(uMsg==WM_LBUTTONDOWN) MessageBox(NULL,"kdjfkdf","Kjdfkdfj",MB_OK); //处理鼠标按下消息,弹出消息框 return DefWindowProc(hwnd,uMsg,wParam,lParam); //未处理的消息通过DefWindowProc函数交给系统处理 } int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { WNDCLASS //定义一个存储窗口信息WNDCLASS变量 wndcls.cbClsExtra=0; //默认为0 wndcls.cbWndExtra=0; //默认为0 wndcls.hbrBackground=(HBRUSH)GetStockObject(GRAY_BRUSH); //背景画刷 wndcls.hCursor=LoadCursor(NULL,IDC_ARROW); //光标 wndcls.hIcon=LoadIcon(NULL,IDI_ERROR); //窗口图标 wndcls.hInstance=hI //应用程序实例句柄由WinMain函数传进来
wndcls.lpfnWndProc=WinSunP //窗口消息处理函数 wndcls.lpszClassName="windowclass"; //窗口类名 wndcls.lpszMenuName=NULL; //窗口菜单名,没有菜单,为NULL wndcls.style=CS_HREDRAW | CS_VREDRAW; //窗口类型,CS_HREDRAW和CS_VERDRAW 表明 //当窗口水平方向垂直方向的宽度变化时重绘整个窗口 RegisterClass(&wndcls); //把窗口信息提交给系统,注册窗口类 HWND //用以存储CreateWindow函数所创建的窗口句柄 hwnd=CreateWindow("windowclass","first windows",
WS_OVERLAPPEDWINDOW,0,0,600,400,NULL,NULL,hInstance,NULL); //创建窗口 ShowWindow(hwnd,SW_SHOWNORMAL); //窗口创建完了,显示它 UpdateWindow(hwnd); //更新窗口,让窗口毫无延迟的显示 MSG //消息结构类型 while(GetMessage(&msg,NULL,0,0)) //获取消息 { //TranslateMessage(&msg); //此函数用于把键盘消息(WM_KEYDOWN,WM_KEYUP)转换成字符消息WM_CHAR DispatchMessage(&msg); //这个函数调用窗口过程处理函数,并把MSG里的信息处理后传给过程函数的四个参数 } return 0; }
WinSunProc函数的四个参数,分别对应着SendMessage函数四个参数,详情参见SendMessage函数参数解释。
MSG类型解释&:
结构定义:
typedef struct tagMSG
{ HWND //hwnd表示消息将要发送给的窗口句柄 UINT //消息类型,如WM_WMCLOSE,WM_CHAR,WM_LBUTTONDOWN,参见消息表 WPARAM wP //消息附带信息,取值的意思具体依据消息类型而定 LPARAM lP //消息附带信息,取值的意思具体依据消息类型而定 DWORD //消息的发送时间,不常用 POINT //消息发送时,鼠标所在的位置,不常用 }MSG;
大家试着把上面的例子运行一遍,然后关掉窗口,再运行一遍,是不是出错了,因为前一个程序虽然窗口关闭了,但进程还在运行,还记得那个循环语句吗?while(GetMessage(&msg,NULL,0,0))就是这个。只要条件成立,进程就会一直运行下去。如何让这个循环结束呢?用&PostQuitMessage(0);&这个语句就行了,参数0表示给自身窗口发送一个退出消息,当GetMessage函数接到PostQuitMessage函数发出的消息后,就会返回0值。
如在窗口过程函数中处理窗口关闭WM_CLOSE消息:if(uMsg==WM_CLOSE)PostQuitMessage(0);&这样只要一关闭窗口,它的进程也会结束。
接下来解释一下CreateWindow函数参数的意思,函数定义
HWND CreateWindow(LPCTSTR lpClassName, //窗口类名,应与WNDCLASS结构里的成员lpszClassName一致 LPCTSTR lpWindowName,, //窗口标题名 DWORD dwStyle, //窗口的风格,取值参见表Style int x, int y, //x,y表示所创建窗口左上角位置 int nWidth, int nHeight, //nWidth,nHeight表示窗口的宽高 HWND hWndParent, //父窗口句柄,如果不是子窗口,这里取值为NULL HMENU hMenu, //菜单句柄,没菜单的话,取NULL值 HANDLE hlnstance, //对应着WinMain函数的第一个参数 LPVOID lpParam); //NULL
表Style:(参考:百度)
WS_BORDER:创建一个单边框的窗口。&  WS_CAPTION:创建一个有标题框的窗口(包括WS_BODER风格)。WS_CHILD:创建一个子窗口。这个风格不能与WS_POPUP风格合用。WS_CHLDWINDOW:与WS_CHILD相同。WS_CLIPCHILDREN:当在父窗口内绘图时,排除子窗口区域。在创建父窗口时使用这个风格。&  WS_CLlPBLINGS;排除子窗口之间的相对区域,也就是,当一个特定的窗口接收到WM_PAINT消息时,WS_CLIPSIBLINGS&风格将所有层叠窗口排除在绘图之外,只重绘指定的子窗口。如果未指定WS_CLIPSIBLINGS风格,并且子窗口是层叠的,则在重绘子窗口的客户区时,就会重绘邻近的子窗口。WS_DISABLED:创建一个初始状态为禁止的子窗口。一个禁止状态的窗口不能接受来自用户的输入信息.WS_DLGFRAME:创建一个带对话框边框风格的窗口。这种风格的窗口不能带标题条。WS_GROUP:指定一组控制的第一个控制。这个控制组由第一个控制和随后定义的控制组成,自第二个控制开始每个控制,具有WS_GROUP风格,每个组的第一个控制带有WS_TABSTOP风格,从而使用户可以在组间移动。用户随后可以使用光标在组内的控制间改变键盘焦点。&  WS_HSCROLL:创建一个有水平滚动条的窗口。&  WS_ICONIC:创建一个初始状态为最小化状态的窗口。与WS_MINIMIZE风格相同。&  WS_MAXIMIZE:创建一个初始状态为最大化状态的窗口。&  WS_MAXIMIZEBOX:创建一个具有最大化按钮的窗口。该风格不能与WS_EX_CONTEXTHELP风格同时出现,同时必须指定WS_SYSMENU风格。&  WS_OVERLAPPED:产生一个层叠的窗口。一个层叠的窗口有一个标题条和一个边框。与WS_TILED风格相同。&  WS_OVERLAPPEDWINDOW:创建一个具有WS_OVERLAPPED,WS_CAPTION,WS_SYSMENU&WS_THICKFRAME,WS_MINIMIZEBOX,WS_MAXIMIZEBOX风格的层叠窗口,与WS_TILEDWINDOW风格相同。&  WS_POPUP;创建一个弹出式窗口。该风格不能与WS_CHLD风格同时使用。&  WS_POPUWINDOW:创建一个具有WS_BORDER,WS_POPUP,WS_SYSMENU风格的窗口,WS_CAPTION和WS_POPUPWINDOW必须同时设定才能使窗口某单可见。&  WS_SIZEBOX:创建一个可调边框的窗口,与WS_THICKFRAME风格相同。&  WS_SYSMENU:创建一个在标题条上带有窗口菜单的窗口,必须同时设定WS_CAPTION风格。&  WS_TABSTOP:创建一个控制,这个控制在用户按下Tab键时可以获得键盘焦点。按下Tab键后使键盘焦点转移到下一具有WS_TABSTOP风格的控制。&  WS_THICKFRAME:创建一个具有可调边框的窗口,与WS_SIZEBOX风格相同。&  WS_TILED:产生一个层叠的窗口。一个层叠的窗口有一个标题和一个边框。与WS_OVERLAPPED风格相同。&  WS_TILEDWINDOW:创建一个具有WS_OVERLAPPED,WS_CAPTION,WS_SYSMENU,&WS_THICKFRAME,WS_MINIMIZEBOX,WS_MAXMIZEBOX风格的层叠窗口。与WS_OVERLAPPEDWINDOW风格相同。&  WS_VISIBLE创建一个初始状态为可见的窗口。&  WS_VSCROLL:创建一个有垂直滚动条的窗口。
&第二十二个GetMessage获取窗口消息
参照CreateWindow函数例子,以后的例子可能是在控制台下,也可能是Win32&Application,大家以后根据主函数判断该建什么工程。
第二十三个RegisterClass注册窗口类,参照CreateWindow
第二十四个UpdateWindow参照CreateWindow
第二十五个DispatchMessage参照CreateWindow
第二十六个LoadCursorFromFile从磁盘加载一个光标文件,函数返回该光标句柄
假设e盘下有一个名为a.cur的光标文件。
HCURSOR cursor //定义一个光标句柄,用于存放LoadCursorFromFile函数返回的光标句柄 cursor=LoadCursorFromFile("e:\\a.cur");
获得了光标句柄有什么用呢?看一下窗口类WNDCLASS里的hCursor成员,这个成员也是一个光标句柄,明白了吧!
第二十七个CreateSolidBrush创建一个画刷,函数返回画刷句柄
HBRUSH hbr=CreateSolidBrush(RGB(12,172,59));//三个数字分别表明RGB的颜色值,RGB根据三种颜色值返回一个COLORREF类型的值
第二十八个LoadImage装载位图、图标、光标函数
函数定义:HANDLE&LoadImage(HINSTANCE&hinst,LPCTSTR&lpszName,UINT&uType,int&cxDesired,int&CyDesired,UINT&fuLoad)
这里我们只要这个函数的几个简单功能:从磁盘加载位图,从磁盘加载图标,从磁盘加载光标。所以第一个参数hinst我们不用管它,直接填NULL就行,第二个参数lpszName是图片文件所在路径名,第三个参数uType指明要加载的是什么类型的图片,
是位图(填IMAGE_BITMAP),还是光标(填IMAGE_CURSOR),还是图标(填IMAGE_ICON)。第四个cxDesired和第五个参数CyDesired,指定要加载的图片的宽高(可以放大光标,或者缩小),如果加载的是位图的话,则两个参数必须为0,第六个参数fuLoad表示以何种方式加载文件,这里我们是从磁盘加载文件,所以填LR_LOADFROMFILE;
好了,假设e盘下有一个c.cur和i.ico文件。例子:设置窗口图标和光标,还有背景色
#include "stdafx.h" //这个头文件是编译器自动生成的,不是空工程,都会有, //如果是直接建C++源文件,包含这个头文件,会出错 #include &windows.h&
#include &stdio.h&
LRESULT CALLBACK WinSunProc(
HWND hwnd, // handle to window
UINT uMsg, // message identifier
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
); //窗口过程函数声明 int WINAPI WinMain(
HINSTANCE hInstance, // handle to current instance
HINSTANCE hPrevInstance, // handle to previous instance
LPSTR lpCmdLine, // command line
int nCmdShow // show state
//设计一个窗口类
wndcls.cbClsExtra=0;
wndcls.cbWndExtra=0;
wndcls.hbrBackground=CreateSolidBrush(RGB(12,172,59)); //画刷 wndcls.hCursor=(HCURSOR)LoadImage(NULL,"e:\\c.cur",IMAGE_CURSOR,24,24,LR_LOADFROMFILE); //加载光标 wndcls.hIcon=(HICON)LoadImage(NULL,"e:\\i.ico",IMAGE_ICON,48,48,LR_LOADFROMFILE); //加载图标 wndcls.hInstance=hI //应用程序实例句柄由WinMain函数传进来
wndcls.lpfnWndProc=WinSunP //定义窗口处理函数 wndcls.lpszClassName="windowclass";
wndcls.lpszMenuName=NULL;
wndcls.style=CS_HREDRAW | CS_VREDRAW;
RegisterClass(&wndcls);
//创建窗口,定义一个变量用来保存成功创建窗口后返回的句柄
hwnd=CreateWindow("windowclass","first window",
WS_OVERLAPPEDWINDOW,0,0,600,400,NULL,NULL,hInstance,NULL); //显示及刷新窗口
ShowWindow(hwnd,SW_SHOWNORMAL);
UpdateWindow(hwnd); //定义消息结构体,开始消息循环
while(GetMessage(&msg,NULL,0,0))
TranslateMessage(&msg);
DispatchMessage(&msg);
return msg.wP
//编写窗口过程函数
LRESULT CALLBACK WinSunProc(
HWND hwnd, // handle to window
UINT uMsg, // message identifier
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
switch(uMsg)
case WM_CHAR: //字符消息 char szChar[20];
sprintf(szChar,"char code is %c",wParam);
MessageBox(hwnd,szChar,"char",0);
case WM_LBUTTONDOWN: //鼠标左键按下消息 MessageBox(hwnd,"mouse clicked","message",0);
case WM_CLOSE:
if(IDYES==MessageBox(hwnd,"是否真的结束?","message",MB_YESNO)) {
DestroyWindow(hwnd); //销毁窗口,并发送WM_DESTROY消息给自身窗口 }
case WM_DESTROY: PostQuitMessage(0);
return DefWindowProc(hwnd,uMsg,wParam,lParam);
第二十九个GetDC根据窗口句柄获取设备上下文(DC)返回DC句柄
得到了一个窗口的设备上下文,就可以进行画图操作了,像画圆,画正方形,显示图片等函数都是要设备上下文(DC)句柄做参数的。
HDC dc //定义一个DC句柄 HWND wnd=FindWindow(NULL,"无标题.txt - 记事本"); //获取窗口句柄 dc=GetDC(wnd) //获取这个窗口的设备上下文
第三十个Rectnagle在窗口中画一个矩形
以"无标题.txt&-&记事本"窗口为例,在这个窗口简单的画一个矩形
#include&windows.h& void main() { HDC HWND wnd=FindWindow(NULL,"无标题.txt - 记事本"); dc=GetDC(wnd); //获取窗口设备上下文(DC) while(1) //用循环语句重复画,是为了确保不会被窗口刷新给刷掉 { Rectangle(dc,50,50,200,200); //画一个矩形 Sleep(200); } }
第三十个CreateToolhelp32Snapshot给当前进程拍一个照
HANDLE hProcessSnap=::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0); //记住这种格式就行了,返回的句柄,存储有进程信息,可以用Process32Firs函数找出来。
第三十一个Process32First根据CreateToolhelp32Snapshot函数返回的句柄获取进程信息
结合Process32Next函数使用,有点像文件寻找函数。
看完整例子:显示系统进程名,以及进程ID号
#include&windows.h& #include&tlhelp32.h& //声明快照函数的头文件 #include&stdio.h& int main() { PROCESSENTRY32 pe32; //进程的信息将会存储在这个结构里 //在使用这个结构之前,先设置它的大小 pe32.dwSize=sizeof(pe32); //给系统内的所有进程拍一个快照 HANDLE hProcessSnap=::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0); BOOL bMore=::Process32First(hProcessSnap,&pe32); //第一次查找 while(bMore) { printf("进程名称:%s\n",pe32.szExeFile); //szExeFile是进程名 printf("进程ID号:%u\n\n",pe32.th32ProcessID); //th32ProcessID是进程ID号 bMore=::Process32Next(hProcessSnap,&pe32); //寻找下个进程,函数返回0,则没有进程可寻 } return 0; }
第三十二个OpenProcess根据进程ID号获得进程句柄,句柄通过函数返回
函数定义:HANDLE&OpenProcess(&DWORD&dwDesiredAccess,&BOOL&bInheritHandle,&DWORD&dwProcessId);
第一个参数不要管它,填PROCESS_ALL_ACCESS,第二个参数也一样,填FALSE,那最后一个参数就是进程ID号。
第三十三个TerminateProcess结束一个进程(需进程句柄做参数)
该函数只有两个参数,第一个是进程句柄,第二个填0就行了。
现在给个例子:假设当前有一个进程名为abc.exe的进程正在运行,编一个程序结束它。
#include&windows.h& #include&tlhelp32.h& //声明快照函数的头文件 int main(int argc,char *argv[]) {
PROCESSENTRY32 pe32; //在使用这个结构之前,先设置它的大小 pe32.dwSize=sizeof(pe32); //给系统内的所有进程拍一个快照 HANDLE hProcessSnap=::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0); //遍历进程快照,轮流显示每个进程的信息 BOOL bMore=::Process32First(hProcessSnap,&pe32); while(bMore) { if(strcmp("abc.exe",pe32.szExeFile)==0) //如果找到进程名为abc.exe { HANDLE hProcess=OpenProcess(PROCESS_ALL_ACCESS,FALSE,pe32.th32ProcessID); //获取句柄 ::TerminateProcess(hProcess,0); //结束它 } bMore=::Process32Next(hProcessSnap,&pe32); //寻找下一个 } return 0; }
上面的这个例子,只能结束普通权限进程,如果为系统进程的话,则没有用,结束不了。在后面的提升权限函数,会有例子说明如何结束系统进程。
第三十四个CreatePen创建一个画笔(返回画笔句柄)
函数定义:BOOL&CreatePen(int&nPenStyle,&int&nWidth,&COLORREF&crColor);
第一个参数,表示是什么类型的线,取值有以下:
如创建一个画笔:HPEN&pen=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类型的参数
HBRUSH&brush=CreateSolidBrush(RGB(22,182,111));
第三十六个SelectObject把GDI对象选入相应的DC中
像画笔(句柄HPEN),画刷(HBURSH),位图(HBITMAP)等都是GID对象。因为画图函数,如画圆,画矩形,画直线,它们所画出图形,默认属性都是不变的,如线的宽度。那么想要改变画出来时线的宽度,比如我想画出来的图形它的线条宽度为5(像素),那么就要创建一个宽度为5的画笔,然后再通过SelectObject函数,给这个画笔选入,就可以了.
接下举个例子:SelectObject应用
#include "stdafx.h" #include&windows.h& LRESULT CALLBACK WinSunProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam) { static HPEN pen=CreatePen(PS_SOLID,3,RGB(255,78,99)); //创建画笔 static HBRUSH brush=CreateSolidBrush(RGB(22,182,111)); //创建画刷 if(uMsg==WM_PAINT) //窗口需要重画的时候 { HDC hDC;
PAINTSTRUCT
hDC=BeginPaint(hwnd,&ps); //BeginPaint只能在响应WM_PAINT,不能用GetDC获取设备上下文 SelectObject(hDC,pen); //选入画笔 SelectObject(hDC,brush); //选入画刷 Rectangle(hDC,100,100,200,200); EndPaint(hwnd,&ps);
} else if(uMsg==WM_CLOSE) //用户关闭了窗口 DestroyWindow(hwnd); //销毁窗口,并发送WM_DESTROY消息 else if(uMsg==WM_DESTROY) //如果窗口被销毁 PostQuitMessage(0); //让进程退出 return DefWindowProc(hwnd,uMsg,wParam,lParam); //未处理的消息通过DefWindowProc函数交给系统处理 } int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { WNDCLASS //定义一个存储窗口信息WNDCLASS变量 wndcls.cbClsExtra=0; //默认为0 wndcls.cbWndExtra=0; //默认为0 wndcls.hbrBackground=(HBRUSH)GetStockObject(GRAY_BRUSH); //背景画刷 wndcls.hCursor=LoadCursor(NULL,IDC_ARROW); //光标 wndcls.hIcon=LoadIcon(NULL,IDI_ERROR); //窗口图标 wndcls.hInstance=hI //应用程序实例句柄由WinMain函数传进来
wndcls.lpfnWndProc=WinSunP //窗口消息处理函数 wndcls.lpszClassName="windowclass"; //窗口类名 wndcls.lpszMenuName=NULL; //窗口菜单名,没有菜单,为NULL wndcls.style=CS_HREDRAW | CS_VREDRAW; //窗口类型,CS_HREDRAW和CS_VERDRAW 表明 //当窗口水平方向垂直方向的宽度变化时重绘整个窗口 RegisterClass(&wndcls); //把窗口信息提交给系统,注册窗口类 HWND //用以存储CreateWindow函数所创建的窗口句柄 hwnd=CreateWindow("windowclass","first windows",
WS_OVERLAPPEDWINDOW,0,0,600,400,NULL,NULL,hInstance,NULL); //创建窗口 ShowWindow(hwnd,SW_SHOWNORMAL); //窗口创建完了,显示它 UpdateWindow(hwnd); //更新窗口,让窗口毫无延迟的显示 MSG //消息结构类型 while(GetMessage(&msg,NULL,0,0)) //获取消息 { //TranslateMessage(&msg); //此函数用于把键盘消息(WM_KEYDOWN,WM_KEYUP)转换成字符消息WM_CHAR DispatchMessage(&msg); //这个函数调用窗口过程处理函数,并把MSG里的信息处理后传给过程函数的四个参数 } return 0; }
第三十七个&ReadProcessMemory根据进程句柄读取相应的一段内存(读其它进程里的内存)
函数定义:BOOL&ReadProcessMemory(HANDLE&hProcess,PVOID&pvAddressRemote,PVOID&pvBufferLocal,DWORD&dwSize,
PDWORD&pdwNumBytesRead);总共四个参数
第一个参数hProcess是远程进程句柄,被读取者&。第二个pvAddressRemote是远程进程中内存地址。&从具体何处读取
pvBufferLocal是本地进程中内存地址.&函数将读取的内容写入此处&,dwSize是要读取的字节数。要读取多少&
pdwNumBytesRead是实际读取的内容(函数执行后,实际读了多少字节,将存储在该变量里)
远程进程的内存地址是什么意思呢,比如我现在定义一个变量a,int&a;就是了,大家知道int型是占四个字节的,也就是说如果a变量所占的内存起始地址是0x1234,那么变量a就占用0x5,0x7这四个字节,这四个字节的内容决定了a变量的值。
好了知道了这个,我们就来举个例子,读取另一个进程里一个变量的值:需设计两个程序,一个用于读(Read)一个用于被读(BeRead);
那么要如何获得另一个进程中一个变量的地址呢?这里我们用一个简单的方法,让另一个进程自己去获取,然后输出地址值。
被读的程序代码如下:假设该进程名为:BeRead.exe
#include&stdio.h& int main() { int a=10; //要读取的变量。 printf("%x\n",&a); //输出这个变量的起始地址,假设输出为12ff7c while(1) { Sleep(1000); } return 0; }
必须先让这个程序运行,然后根据输出的地址值,才能在下面的程序填入地址值。
读取的程序代码如下:
#include&windows.h& #include&stdio.h& #include&tlhelp32.h& int main() { //先要获取进程句柄,如何获取,参照TerminateProcess函数,结束一个进程 HANDLE ReP PROCESSENTRY32 pe32; pe32.dwSize=sizeof(pe32); HANDLE hProcessSnap=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0); BOOL bMore=::Process32First(hProcessSnap,&pe32); while(bMore) { if(strcmp(pe32.szExeFile,"BeRead.exe")==0) //如果是BeRead.exe { ReProcess=::OpenProcess(PROCESS_ALL_ACCESS,FALSE,pe32.th32ProcessID); //获取该进程句柄 } bMore=Process32Next(hProcessSnap,&pe32); } int *ReAddress=(int *)0x12ff7c; //要读取的内存的地址值 int *p= ReadProcessMemory(ReProcess,ReAddress,p,4,&size); //读取BeRead进程的内存 printf("%d\n",*p); //输出读取来的值 return 0; }
第三十八个WriteProcessMemory根据进程句柄写入相应的一段内存(写入其它进程里的内存)
这个函数里的参数跟ReadProcessMemory函数参数意思一样,只不过一个是写,一个是读。
下面直接举个例子,形式跟读内存函数的例子一样。
被写的程序代码如下:假设该进程名为:BeWrite.exe
#include&stdio.h& int main() { int a=10; printf("%x\n",&a); //假设输出为12ff7c while(1) {
printf("%d\n",a); //每隔一秒输出,查看值有没有改变 Sleep(1000); } return 0; } 写入的代码如下: #include&windows.h& #include&stdio.h& #include&tlhelp32.h& int main() { HANDLE ReP PROCESSENTRY32 pe32; pe32.dwSize=sizeof(pe32); HANDLE hProcessSnap=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0); BOOL bMore=::Process32First(hProcessSnap,&pe32); while(bMore) { if(strcmp(pe32.szExeFile,"BeWrite.exe")==0) { ReProcess=::OpenProcess(PROCESS_ALL_ACCESS,FALSE,pe32.th32ProcessID); } bMore=Process32Next(hProcessSnap,&pe32); } int *ReAddress=(int *)0x12ff7c; int *p= *p=300; WriteProcessMemory(ReProcess,ReAddress,p,4,&size); return 0; }
第三十九个CreateThread创建一个线程(多线程)
线程是什么意思呢,代码是由线程来执行的,一个程序默认只有一个线程(主线程),打个比方,线程就好比一个人,而不同功能的代码或函数就好是一件件不同的事情,如洗碗,洗衣服,擦地。一个人要把这几种事情做完,可以有好几种方案,第一种就是,洗完碗,就去洗衣服,衣服洗完了,再去擦地。第二种就是:洗一分钟碗,再去洗一分钟衣服,再去擦一分钟,然后又去洗一分钟衣服.......直到做完。好了,现在你可以再创造一个人帮你做事,创造这个人后,你就叫他洗衣服,而你就洗碗,这样两件事就可以同时被做了。而这里的创造一个人指的就是CreateThread函数。
函数定义:HANDLE&CreateThread(LPSECURITY_ATTRIBUTES&lpThreadAttributes,DWORD&dwStackSize,LPTHREAD_START_ROUTINE&lpStartAddress,LPVOID&lpParameter,DWORD&dwCreationFlags,LPDWORD&lpThreadId);
该函数有六个参数,第一个参数不用管它,填NULL,第二个参数dwStackSize用于新线程的初始堆栈大小,默认为0,第三个lpStartAddress填函数名(指标),但这个函数必须是这种固定格式的DWORD&_stdcall&ThreadProc(LPVOID&lpParameter),新的线程将会执行这个函数里面的代码,直到函数结束,线程死亡。第四个lpParameter是一自定义参数,用户可以通过这个参数,传递需要的类型,这个参数与线程函数的参数相对应。第五个dwCreationFlags填0表示立即执行,如果是CREATE_SUSPENDED表示挂起,直到用ResumeThread函数唤醒。第六个lpThreadId填NULL就行了。
现举个例子,两个线程同时每隔一秒输出一个数字,也就是一秒会有两数字输出。
#include&windows.h& #include&stdio.h& DWORD _stdcall ThreadProc(LPVOID lpParameter) //线程执行函数 { int si=100; while(si&0) { printf("子线程输出数字:%d\n",si--); Sleep(1000); } return 0; } int main() { int mi=0; CreateThread(NULL,0,ThreadProc,NULL,0,NULL); //创建一个线程,去执行ThreadProc函数 while(mi&100) { printf("主线程输出数字:%d\n",mi++); Sleep(1000); } return 0; }
第四十个GetCurrentProcessId获得当前进程ID
DWORD currentPID; currentPID=::GetCurrentProcessId(); //返回进程ID号 cout&&currentPID&&
第四十一个CreateCompatibleDC创建一个兼容的内存设备上下文(DC)
简单的来说,就是复制一个模一样的DC。就把窗口看成一幅幅图画,窗口有大有小,里面的内容也不一样(颜色值),每个像素点的颜色值可能不一样,所以就用设备上下文来描述每个窗口的信息,对于DC具体是怎样描述设备上下文的,我们暂时还不需要知道,只要了解这个概念就行了。这个窗口信息,获得一个窗口设备上下文,就用GetDC函数就行了,如HDC&hDC=GetDC(hWnd);而CreateCompatibleDC的作用是根据一个设备上下文,再创建一个兼容的设备上下文,如&HDC&mDC=CreateCompatibleDC(hDC)。这样mDC里的信息就跟hDC里的一样,那这有什么用呢?这个将会在后面的BitBltl输出一个位图(合并两个DC)函数里会用到。
第四十二个GetObject获取一个对象信息(如位图,图标,光标)
函数定义:int&GetObject(HGDIOBJ&hgdiobj,&int&cbBuffer,&LPVOID&lpvObject);
第一个参数hgdiobj是对象句柄,第二个参数cbBuffer是待写入lpvObject指针指向缓存区数据大小,第三个参数lpvObject是一个指针,指向一个缓存区。
这里举一个获取位图的信息,获取位图的大小,假设E盘下有一个aa.bmp的位图文件,输出位图的宽高
#include&windows.h& #include&stdio.h& int main() { BITMAP bmI //这个结构存储位图信息 HBITMAP bmp=(HBITMAP)LoadImage(NULL,"e:\\aa.bmp",IMAGE_BITMAP,0,0,LR_LOADFROMFILE); GetObject(bmp,sizeof(BITMAP),&bmInfo); printf("位图宽:%d,位图高:%d\n",bmInfo.bmWidth,bmInfo.bmHeight); return 0; }
第四十三个BitBlt在窗口输出一个位图
其实倒不如说这个BitBlt函数是拷贝一个设备上下文(DC),或者合并两个窗口,再延伸一下,合并两个图片?也并无不可,往大了说,窗口难道不是图片吗?用截屏软件,把窗口截成图片,这样窗口便成了图片。可能有点瞎说,大家还是按照标准来吧,反正,你只要掌握这个函数就行了,而且这个概念也不会有什么影响,那就足够了。
BitBlt的作用跟把两幅图片合在一起一样,合并两幅图片。可能两幅图片大小不一样也可以合并,但合并DC就不行了,必须两个信息一样的DC才可以合并,那要如何确保两个DC一样呢?这就要用到CreateCompatibleDC函数了。
函数定义:BOOL&BitBlt(HDC&hdcDest,int&nXDest,int&nYDest,int&nWidth,int&nHeight,HDC&hdcSrc,int&nXSrc,int&nYSrc,DWORD&dwRop);
第一个参数hdcDest是原DC句柄,被覆盖的DC,nXdest,nYDest,nWidth,nHeight这四个参数,指明了一个矩形,覆盖原DC哪块区域。
第六个参数hdcSrc是覆盖的DC句柄,nXSrc,nYSrc参数指明从哪里开始覆盖。(覆盖DC的左上角),第九个参数dwPop表示以何种方式覆盖。因为这里我们只要输出一个位图,所以用SRCCOPY,直接覆盖。
好了,直接举个例子,在窗口输出一副图片,假设e盘下有一个aa.bmp的位图。为了方便,我们直接在记事本窗口输出位图,先运行一个窗口名为"无标题.txt&-&记事本"记事本窗口程序。
#include&windows.h& #include&stdio.h& int main() { BITMAP bmI //这个结构存储位图信息 HBITMAP bmp=(HBITMAP)LoadImage(NULL,"e:\\aa.bmp",IMAGE_BITMAP,0,0,LR_LOADFROMFILE); GetObject(bmp,sizeof(BITMAP),&bmInfo); //获取位图信息 HWND wnd=FindWindow(NULL,"无标题.txt - 记事本"); HDC hdc=GetDC(wnd); HDC memDC=::CreateCompatibleDC(hdc); //创造兼容的DC SelectObject(memDC,bmp); //选入位图 while(1) { BitBlt(hdc,0,0,bmInfo.bmWidth,bmInfo.bmHeight,memDC,0,0,SRCCOPY); //输出位图 Sleep(200);
} return 0; }
下面介绍一下BitBlt函数最后一个参数的常用取值及意思。
参考(百度)BLACKNESS:表示使用与物理调色板的索引0相关的色彩来填充目标矩形区域,(对缺省的物理调色板而言,该颜色为黑色)。&  DSTINVERT:表示使目标矩形区域颜色取反。&  MERGECOPY:表示使用布尔型的AND(与)操作符将源矩形区域的颜色与特定模式组合一起。&  MERGEPAINT:通过使用布尔型的OR(或)操作符将反向的源矩形区域的颜色与目标矩形区域的颜色合并。&NOTSRCCOPY:将源矩形区域颜色取反,于拷贝到目标矩形区域。&  NOTSRCERASE:使用布尔类型的OR(或)操作符组合源和目标矩形区域的颜色值,然后将合成的颜色取反。&PATCOPY:将特定的模式拷贝到目标位图上。&  PATPAINT:通过使用布尔OR(或)操作符将源矩形区域取反后的颜色值与特定模式的颜色合并。然后使用OR(或)操作符将该操作的结果与目标矩形区域内的颜色合并。&  PATINVERT:通过使用XOR(异或)操作符将源和目标矩形区域内的颜色合并。&  SRCAND:通过使用AND(与)操作符来将源和目标矩形区域内的颜色合并。&  SRCCOPY:将源矩形区域直接拷贝到目标矩形区域。&  SRCERASE:通过使用AND(与)操作符将目标矩形区域颜色取反后与源矩形区域的颜色值合并。&  SRCINVERT:通过使用布尔型的XOR(异或)操作符将源和目标矩形区域的颜色合并。&  SRCPAINT:通过使用布尔型的OR(或)操作符将源和目标矩形区域的颜色合并。&  WHITENESS:使用与物理调色板中索引1有关的颜色填充目标矩形区域。(对于缺省物理调色板来说,这个颜色就是白色)
第四十四个GetWindowText根据窗口句柄获得窗口标题名
函数定义:int&GetWindowText(HWND&hWnd,LPTSTR&lpString,int&nMaxCount);
第一个参数hWnd是要获取窗口标题名的窗口句柄,第二个lpString是个字符串,窗口标题名,将会存储在这里面,第三个参数nMaxCount指明了第二个参数字符数组的大小。
下面结合GetCursorPos和WindowFromPoint举个例子,鼠标指向哪个窗口,就在界面显示那窗口的标题名
#include&windows.h& #include&stdio.h& int main() { char Text[256]={0}; HWND POINT while(1) { GetCursorPos(&curpos); wnd = WindowFromPoint(curpos); GetWindowText(wnd,Text,256); printf("%s\n",Text); Sleep(300); } return 0; }
第四十五个SetWindowText根据窗口句柄设置窗口标题名
这个函数有两个参数,一个是窗口句柄,一个是标题名,这里就不需要解释了吧,直接看例子,设置一个窗口标题名,依旧以
"无标题.txt&-&记事本"为例。
#include&windows.h& #include&stdio.h& int main(int argc, char* argv[]) { HWND wnd=FindWindow(NULL,"无标题.txt - 记事本"); //获取窗口句柄 SetWindowText(wnd,"新的窗口标题"); //设置窗口标题名 return 0; }
第四十六个GetCurrentProcess获得当前线程句柄
没有参数,直接调用即可,该函数返回线程句柄
第四十七个OpenProcessToken获得一个进程的访问令牌句柄
获得一个进程的访问令牌有什么用呢?主要是为了修改它的权限,前面在介绍结束一个进程的时候说过了,无法结束系统进程,是什么原因呢,原因是调用OpenProcess函数失败,无法获取系统进程句柄而引起的,那为什么会失败呢,权限不够,普通程序的进程没有SeDeDebug权限,而一个进程的权限是与访问令牌相关的,这样我们只要获取一个进程的访问令牌句柄,再以这个句柄为参数调用相应的函数提升进程的权限为SeDeDebug就可以获取系统进程句柄,进而结束它。
函数定义:BOOL&OpenProcessToken(HANDLE&ProcessHandle,DWORD&DesiredAccess,PHANDLE&TokenHandle)
第一个参数ProcessHandle待获取的进程句柄,第二个参数DesiredAccess操作类型,填TOKEN_ADJUST_PRIVILEGES就行了,
第三个TokenHandle是访问令牌句柄的指针,该参数接收句柄。
如获得本进程的访问令牌句柄:HANDLE&hT
OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES,&hToken);
第四十七个LookupPrivilegeValue函数查看对应系统权限的特权值,返回信息到一个LUID结构体里上面讲过了,进程有权限一说,那么大家也能猜到,进程权限的信息也一定存储在一个结构体里,这个结构体描述了进程权限相关的一些信息。这个结构体在这里就不具体描述了,我们所要做的,只是把一个进程权限设置成SeDeDebug就行了,所以我们只要知道TOKEN_PRIVILEGES便是描述进程权限的结构体就可以了。而LookupPrivilegeValue函数是根据访问令牌句获取相应的权限信息吗?不是的。TOKEN_PRIVILEGES结构里的Privileges[0].Luid跟这个函数所查询的东西相对应,也就是说,如果进程是SeDeDeBug权限,那Privileges[0].Luid的取值是怎样的呢?用LookupPrivilegeValue函数便可以获取其取值。这个函数是这样定义的:BOOL&LookupPrivilegeValue(LPCTSTR&lpSystemName,LPCTSTR&lpName,PLUID&lpLuid);第一个参数lpSystemName通常都填NULL,本地系统调用,第二个参数lpName填要查询的权限名,如要查询的是SeDeDebug权限则取值是SE_DEBUG_NAME,第三个参数lpLuid接收其取值。如LUID&LookupPrivilegeValue(NULL,SE_DEBUG_NAME,&luid);
第四十八个AdjustTokenPrivileges调整一个进程的访问令牌信息(权限)
函数定义:BOOL&AdjustTokenPrivileges(HANDLE&TokenHandle,BOOL&DisableAllPrivileges,PTOKEN_PRIVILEGES&NewState,DWORD&BufferLength,PTOKEN_PRIVILEGES&PreviousState,PDWORD&ReturnLength)
第一个参数TokenHandle是令牌句柄,第二个是禁用所有权限标志,后面填FALSE就行了。第三个NewState是待刷进令牌句柄的PTOKEN_PRIVILEGES结构信息指针,第四个BufferLength指明TOKEN_PRIVILEGES结构大小,第五,六个参数填NULL就行了。
那么结束上面两个函数,提升一个进程权限制,让它能够结束系统进程的代码就是:
HANDLE hT OpenProcessToken( GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken ); TOKEN_PRIVILEGES LookupPrivilegeValue( NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid ); tp.PrivilegeCount = 1; //tp里其它一些属性设置 tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; AdjustTokenPrivileges( hToken, FALSE, &tp, sizeof( TOKEN_PRIVILEGES ), NULL, NULL );
只上把上面的代码,加入结束普通进程例子的前面,那么就能结束系统进程了。
第四十九个LoadLibrary加载动态链接库,返回动态链接库模块句柄
该函数只有一个参数,那就是动态链接库的名称,如user32.dll,函数返回HMOUDLE类型的模块句柄,获得了一个动态链接库的模块句柄,就可以调用GetProcAddress函数获得模块里面的函数地址,从而调用动态链接库里的函数。
第五十个GetProcAddress根据模块句柄获取相应的函数地址
提到GetProcAddress函数,不得不讲一下怎么设计一个动态链接库,这里我们就以自己设计动态链接库作为GetProcAddress函数的例子。
动态链接库里的函数相对于头文件的函数有什么优势呢?更节省内存,相对于比较常用的函数而已。如果在一个程序里,调用一个头文件里的函数的话,那不管如何,函数的代码就会被复制一份到当前程序里,所以,当有十几个程序调用同一个函数的时候,这个函数在内存中所占用的空间,就会有十几份,分别在各自调用的进程内存空间里,而动态链接库的函数,只在内存中有一份空间(公用空间)如果哪个程序要用到这个函数的话,只要给这个函数的地址,进程就可以跑到这个空间执行函数,那么如何获取函数地址呢,用GetProcAddress函数就行了。
下面我们就自己设计一个动态链接库,点“文件-&新建-&工程",然后选中“Win32&Dynamic-Link&Library”,再在右边给工程取一个名,点确定。接着弹出了一个对话框,询问希望创建什么类型,我们选择第二个“一个简单的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函数外定义一个函数就行了。
那么在动态链接库是如何定义函数呢?如果函数不需要导出的话,则跟普通函数定义没什么两样,导出是什么意思,就是可以用GetProcAddress函数获取地址的函数。那导出的函数要如何定义呢?只要在函数前面加上extern&"C"&__declspec(dllexport)就行了,声明导出函数,防止函数重命名。那么接下来就举个例子。
动态链接里的代码:
#include "stdafx.h" BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { return TRUE; } extern "C" __declspec(dllexport) int Add(int a,int b) { return a+b; }
点编译执行,然后就会弹出一个调试对话框,直接点取消,接着便生成了动态链接库DLL,然后到你的工程里把后缀名为dll的文件找到,
位置在MyProject\"你的工程名"\Debug下。接着把这个文件复制到要调用的工程下,或者直接复制C:\windows\system32目录下。
假设这个文件名为"sss.dll",那么要调用里面的Add函数便是如下代码:
HMODULE hmod=::LoadLibrary("sss.dll"); //获取sss.dll的模块,加载sss.dll动态链接库 typedef int (*pAdd)(int a,int b); //定义一个对应的函数型,以便识别 pAdd add=(pAdd)GetProcAddress(hmod,"Add"); //获取hmod模块里的Add函数地址 int a=add(3,5); //调用模块里的Add函数
第五十一个SetWindowsHookEx安装一个钩子
WINDOWS是基于消息的系统,鼠标移动,单击,键盘按键,窗口关闭等都会产生相应的消息,那么钩子是什么意思呢,它可以监控一个消息,比如在一个窗口里单击了一下,首先获得这个消息的,不是应用程序,而是系统,系统获取这个消息后,就去查看这个消息是在哪个窗口产生的,找到窗口后,再把消息投递到相应程序里的消息队列里,这之间有一个传递过程,那么钩子的作用就是在消息到达应用程序之前截获它,钩子可以关联一个函数(钩子处理函数),也就是说,如果对一个进程安装了一个钩子,进程再接收到相应在消息之前,会先去执行钩子所关联的函数,
先来看一下这个函数定义:
HHOOK&WINAPI&SetWindowsHookEx(int&idHook,HOOKPROC&lpfn,HINSTANCE&hmod,DWORD&dwThreadId)
第一个参数idHook指明要安装的钩子类型,如WH_KEYBOARD(键盘钩子),WH_MOUSE(鼠标钩子),第二个参数是钩子处理函数的地址,该函数必须是这种固定的格式:LRESULT&WINAPI&HookProc(int&nCode,WPARAM&wParam,LPARAM&lParam)
第三个参数hmod是

我要回帖

更多关于 函数极限不存在的情况 的文章

 

随机推荐