geral吧 关注:5贴子:215
  • 7回复贴,共1

【windows API】资料集合

只看楼主收藏回复

http://blog.163.com/ac_bc/blog/static/6016475201181434423705/
【TITLE】GetWindowLong说明及应用
“窗口类的封装,从全局窗口消息处理到窗口对象消息处理的映射方法:
对界面进行封装,一般都是一个窗口一个类,比如实现一个最基本的窗口类CMyWnd,你一定会把窗口过程作为这个类的成员函数,但是使用WINAPI创建窗口时必须注册类WNDCLASS,里面有个成员数据lpfnWndProc需要WNDPROC的函数指针,一般想法就是把窗口类的消息处理函数指针传过去,但是类成员函数除非是静态的,否则无法转换到WNDPROC,而全局的消息处理函数又无法得到窗口类对象的指针。这里有几种解决办法:
一种解决方法是用窗口列表,开一个结构数组,窗口类对象创建窗口的时候把窗口HWND和this指针放入数组,全局消息处理函数遍历数组,利用HWND找出this指针,然后定位到对象内部的消息处理函数。这种方法查找对象的时间会随着窗口个数的增多而增长。
另一种方法比较聪明一点,WNDCLASS里面有个成员数据cbWndExtra一般是不用的,利用这点,注册类时给该成员数据赋值,这样窗口创建时系统会根据该值开辟一块内存与窗口绑定,这时把创建的窗口类的指针放到该块内存,那么在静态的窗口消息循环函数就能利用GetWindowLong(hWnd,GWL_USERDATA)取出该指针,return (CMyWnd*)->WindowProc(...),这样就不用遍历窗口了。但是这样一来就有个致命弱点,对窗口不能调用SetWindowLong(hWnd,GWL_USERDATA,数据),否则就会导致程序崩溃。幸好这个函数(特定这几个参数)是调用几率极低的,对于窗口,由于创建窗口都是调用窗口类的Create函数,不用手工注册WNDCLASS类,也就不会调用SetWindowLong函数。但是毕竟缺乏安全性,而且当一秒钟内处理的窗口消息很多时,这种查找速度也可能不够快。
创建窗口时: SetWindowLong( m_hWnd, GWL_USERDATA, (LONG) this );
函数功能描述: 用这个函数能够获得指定窗口的信息
函数原型: LONG GetWindowLong( HWND hWnd,int nIndex )
参数: hWnd:指定窗口的句柄; nIndex:需要获得的信息的类型
nIndex取值如下:
GWL_EXSTYLE 得到扩展的窗口风格
GWL_STYLE 得到窗口风格
GWL_WNDPROC 得到窗口回调函数的地址,或者句柄。得到后必须使用CallWindowProc函数来调用
GWL_HINSTANCE 得到应用程序运行实例的句柄
GWL_HWNDPARENT 得到父窗口的句柄
GWL_ID 得到窗口的标识符
GWL_USERDATA 得到和窗口相关联的32位的值(每一个窗口都有一个有意留给创建窗口的应用程序是用的32位的值)
当hWnd标识一个对话框时可以使用下面的值:
Value Action
DWL_DLGPROC 得到对话框回调函数的地址,或者句柄。得到后必须使用CallWindowProc函数来调用
DWL_MSGRESULT 得到对话框回调函数中消息处理过程的返回值
DWL_USER 得到额外的应用程序私有信息,如一些句柄和指针等
返回值:成功时,返回一个请求的32位的值;失败时,返回0,可以使用GetLastError来取得错误信息
示例:
long nStyle = ::GetWindowLong(hWnd, GWL_STYLE); // hWnd是一个编辑框的句柄
if(nStyle & ES_PASSWORD)
{
AfxMessageBox("这是一个密码域");
}
下面是一个具体的应用:
星号密码查看工具大家都用过吧?现在我们自己来写一个超级简单的。密码框其实就是Windows的一个子窗口,显示星号是因为密码框设置了EM_SETPASSWORDCHAR属性,只要我们把密码框的EM_SETPASSWORDCHAR属性去掉,那么密码就会以明文显示了。我们可以给程序发送消息去掉EM_SETPASSWORDCHAR属性,通过安装鼠标钩子监视鼠标动作,如果用户单击的是密码框,那么就发送一个去除密码属性的消息。
本文使用的编程工具为VC6.0,具体实现步骤和代码如下。
1)生成一个基于对话框的程序pass。打开passDlg.cpp,加入下面的全局变量和鼠标钩子函数。
HHOOK g_hHook = NULL;//全局钩子函数句柄
//鼠标钩子函数
LRESULT CALLBACK HookProc( int code, WPARAM wParam,LPARAM lParam )
{
HWND hwnd;
POINT point;
GetCursorPos(&point);
//得到鼠标位置
hwnd=::WindowFromPoint(point);
//得到包含鼠标的窗口句柄
long nStyle=::GetWindowLong(hwnd,GWL_STYLE);
//得到窗口风格
EVENTMSG *event=(EVENTMSG *)lParam;
if(event->message==WM_LBUTTONDOWN)
//是否为鼠标左键
{
if(nStyle & ES_PASSWORD)
//是否为密码框
{
::PostMessage(hwnd, EM_SETPASSWORDCHAR,0,0);
//去掉密码属性
}
}
return CallNextHookEx(g_hHook,code,wParam,lParam);
}
这里需要注意的是,程序中的::PostMessage(hwnd, EM_SETPASSWORDCHAR,0,0);只能是PostMessage,而不能用SendMessage代替。
2)添加“开始探测”按钮及响应函数OnOK(),并在函数中安装钩子。
void CPassDlg::OnOK()
{
g_hHook=SetWindowsHookEx(WH_JOURNALRECORD,HookProc,GetModuleHandle(NULL),0);
//安装钩子
}
钩子的第三部分使用GetModuleHandle(NULL)函数,意为把自己作为保存钩子的DLL。
3)添加“取消退出”按钮及响应函数OnExit(),并在函数中卸载钩子。
void CPassDlg::OnExit()
{
if(g_hHook)
UnhookWindowsHookEx(g_hHook);
//卸载钩子
exit(0);
}
至此,整个程序就编写完成了。打开我们的程序,按下“开始探测”按钮,再打开需要输入密码的程序试试,是不是以明文显示了?用这个小程序可以搞定系统的密码设置、Outlook或防范不严的程序密码,但对有专门防范的程序就不行了,比如新版QQ。


IP属地:广东1楼2014-06-02 23:45回复
    【title】关于WM_CHAR 消息的解读
    http://blog.csdn.net/daiyutage/article/details/8573735
    一直都以为OnChar消息函数 或者 说 WM_CHAR 可以处理所有的按键信息。原来是错误的,WM_CHAR 对应的只是字符而不是按键。其中,字符是指的0-127内的ASCII码。具体的说明参照以下的文章。
    http://hi.baidu.com/%BF%AA%D0%C4_%D0%D6%B5%DC/blog/item/170b5273f26e7a1f8601b0c1.html
    理解虚拟键码、扫描码和ASCII字符码
    在编写MFC应用程序过程中,需要对原有的CEdit作功能上的扩展,新生成的类CEditEx继承于CEdit,只允许用户输入数字和小数点。
    要实现只允许用户输入数字和小数点,需要屏蔽非数字和小数点的字符,屏蔽工作在OnChar消息函数中进行:当按下键盘后,解发WM_CHAR消息,并进入OnChar消息函数,用::isdigit(nChar)验证数字,用nChar == '.'验证小数点,满足其一即调用父类OnChar函数继续处理:CEdit::OnChar(nChar, nRepcnt, nFlag)。
    另外,一些按键如ESC、Tab键,当按下后并不能够触发WM_CHAR消息并进入OnChar消息函数,这时需要在PreTranslateMessage函数中用::TranslateMessage函数对pMsg消息翻译处理,其实也就是在这个函数中将虚拟键码(Virtua- Key) 即pMsg->wParam重新翻译为ASCII字符码,当翻译的ASCII字符码在0-127之间时,将向消息队列中递交字符消息WM_CHAR。
    试一下:如果在调用::TranslateMessage函数后立刻用GetMessage截获消息MSG,将会发现下一个消息是WM_CHAR,并且wParam已被翻译为ASCII字符码。
    理解1.
    OnChar函数参数变量nChar是ASCII字符码,经过试验只有当按键所对应的ASCII码在0-127之间时才触发WM_CHAR消息,并进入OnChar消息函数,例如:键入上下左右键,是不会进入OnChar函数的。
    理解2.
    如果对计算机键盘I/O比较了解,应该知道键盘上每一个键对应一个扫描码,扫描码是由OEM生商制定的,不同厂商生产的键盘同样一个按键的扫描码都有可能出现不一致的情况,为摆脱由于系统设备不一致造成扫描码不一致的情形,通过键盘驱动程序将扫描码映射为统一的虚拟键码表示,如回车键定义为VK_RETURN,其16进制值为0x0D。


    IP属地:广东2楼2014-06-02 23:45
    回复
      【title】INI相关,获取所有键值
      INI文件常被用作配置文件,因此来说是典型的一个文件操作应用,不论是VC或VB/DELPHI几乎都要和INI文件打交道,面对一个指定节点和格式的INI文件,我们如何读取其中的节点和键值,如何修改键值等都是需要熟悉掌握的。无意在网上发现的C++读写INI配置文件的例子,觉得挺有用,分享给喜欢VC的朋友们,代码是这样的:
      void CIniFileDlg::OnButread()
      {
      // TODO: Add your control notification handler codehere
      CFileDialog dlg(TRUE,NULL,NULL,OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT,
      "AllFiles(*.ini)|*.ini||",AfxGetMainWnd()); //构造文件打开对话框
      CString strPath;
      if (dlg.DoModal() == IDOK) //判断是否按下"打开"按钮
      {
      strPath = dlg.GetPathName();//获得文件路径
      CString section; //定义字符串变量
      GetPrivateProfileSectionNames(section.GetBuffer(0),100,strPath);//获取节名
      char keys[MAX_PATH]= {0}; //定义一个字符数组
      GetPrivateProfileSection(section,keys,MAX_PATH,strPath);//获取键名和键值
      char *cmp ="="; //定义一个字符指针
      int pos = strcspn(keys,cmp); //查找=在字符串中的位置
      char vals[MAX_PATH] = {0}; //定义字符数组
      strncpy(vals,keys,pos); //赋值键名
      char* ptmp =keys+pos+1; //将字符指针指向键值
      m_Section.SetWindowText(section); //设置编辑框节名文本
      m_KeyOne.SetWindowText(vals); //设置编辑框键名文本
      m_ValOne.SetWindowText(ptmp); //设置编辑框键值文本
      int len = strlen(ptmp); //获取字符串长度
      ptmp+=len+1; //指向下一个键名
      pos =strcspn(ptmp,cmp); //查找=在字符串中的位置
      memset(vals,0,MAX_PATH); //初始化vals
      strncpy(vals,ptmp,pos); //赋值键名
      m_KeyTwo.SetWindowText(vals); //设置键名文本
      ptmp+=pos+1; //指向键值
      m_ValTwo.SetWindowText(ptmp); //设置键值编辑框文本
      len = strlen(ptmp); //获取字符串长度
      ptmp+=len+1; //指向下一个键名
      pos =strcspn(ptmp,cmp); //查找=在字符串中的位置
      memset(vals,0,MAX_PATH); //初始化vals
      strncpy(vals,ptmp,pos); //赋值键名
      ptmp +=pos+1; //指向键值
      m_KeyThree.SetWindowText(vals); //设置编辑框键名文本
      m_ValThree.SetWindowText(ptmp); //设置编辑框键值文本
      }
      }
      void CIniFileDlg::OnButwrite()
      {
      CStringsection,keyOne,keyTwo,keyThree,valOne,valTwo,valThree; //定义字符串变量
      CFileDialogdlg(FALSE,NULL,NULL,OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT,
      "AllFiles(*.ini)|*.ini||",AfxGetMainWnd()); //构造文件另存为对话框
      CStringstrPath; //声明变量
      if (dlg.DoModal() == IDOK) //判断是否按下"保存"按钮
      {
      strPath = dlg.GetPathName();//获得文件保存路径
      if (strPath.Right(4) != ".ini")//判断文件扩展名
      {
      strPath += ".ini"; //设置文件扩展名
      }
      m_Section.GetWindowText(section);//获取节名
      m_KeyOne.GetWindowText(keyOne);//获取键名
      m_KeyTwo.GetWindowText(keyTwo);//获取键名
      m_KeyThree.GetWindowText(keyThree); //获取键名
      m_ValOne.GetWindowText(valOne);//获取键值
      m_ValTwo.GetWindowText(valTwo);//获取键值
      m_ValThree.GetWindowText(valThree); //获取键值
      WritePrivateProfileString(section,keyOne,valOne,strPath);//写入键名和键值
      WritePrivateProfileString(section,keyTwo,valTwo,strPath);//写入键名和键值
      WritePrivateProfileString(section,keyThree,valThree,strPath);//写入键名和键值
      }
      }
      代码省去了窗体部分的代码,只给大家帖出了关键代码,请了解!


      IP属地:广东3楼2014-06-10 20:47
      收起回复
        【title】GetPrivateProfile系列函数,INI相关
        string strPath(CONFIG);
        strPath += "\\LOG.ini";
        cout<<strPath<<endl;
        int res = WritePrivateProfileStringA("section", "key1", "123", strPath.c_str());//0表示失败,非0表示成功
        cout<<res<<endl;
        int num = GetPrivateProfileIntA("section", "key1", 100, strPath.c_str());//如果没有section和key1的话才会返回默认值100
        cout<<num<<endl;
        char str[10];
        num = GetPrivateProfileStringA("section2", "key3", "no find", str, sizeof(str), strPath.c_str());//会忽略value前的空格
        cout<<num<<endl;
        cout<<str<<endl;
        char str2[50];
        num = GetPrivateProfileSectionA("section", str2, sizeof(str2), strPath.c_str());
        cout<<num<<endl;
        for (char *p = str2; p < str2 + 50; p++)
        {
        cout<<*p;
        }
        cout<<endl;
        配置文件格式:

        结果:

        1.GetPrivateProfileInt函数
        GetPrivateProfileInt =>从ini文件取得数值
         <参数>
           lpApplicationName:
           lpKeyName:
         nDefault:
           lpFileName:
         <返回值>
        取得数值
        说明:
          为初始化文件中指定的条目获取一个整数值
        返回值:
          Long,找到的条目的值;如指定的条目未找到,就返回默认值。如找到的数字不是一个合法的整 数,函数会返回其中合法的一部分。如,对于“xyz=55zz”这个条目,函数返回55。这个函数也能理解采用标准C语言格式的十六进制数字:用0x作为 一个十六进制数字的前缀——所以0x55ab等价于vb的&H55AB
        参数类型及说明:
          lpApplicationName String,指定在其中查找条目的小节。注意这个字串是不区分大小写的
          lpKeyName String,欲获取的设置项或条目。这个支持不区分大小写
          nDefault Long,指定条目未找到时返回的默认值
          lpFileName String,初始化文件的名字。如果没有指定完整的路径名,windows就会在Windows目录中搜索文件
        2.GetPrivateProfileString 函数
        GetPrivateProfileString =>从ini文件取得文字列
         <参数>
           lpAppName:
           lpKeyName:
           lpDefault:
           lpReturnedString:
           nSize:
           inifilename:
        <返回值>
        取得字符串 (lpReturnedString)。同时返回一个整数,大小为取得字符串的长度。
        说明:
          为初始化文件中指定的条目取得字串
        返回值:
          Long,复制到lpReturnedString缓冲区的字节数量,其中不包括那些NULL 中止字符。如lpReturnedString缓冲区不够大,不能容下全部信息,就返回nSize-1(若lpApplicationName或 lpKeyName为NULL,则返回nSize-2)
        参数类型及说明:
          lpApplicationName String,欲在其中查找条目的小节名称。这个字串不区分大小写。如设为vbNullString,就在lpReturnedString缓冲区内装载这个ini文件所有小节的列表
          lpKeyName String,欲获取的项名或条目名。这个字串不区分大小写。如设为vbNullString,就在lpReturnedString缓冲区内装载指定小节所有项的列表
          lpDefault String,指定的条目没有找到时返回的默认值。可设为空("")
          lpReturnedString String,指定一个字串缓冲区,长度至少为nSize
          nSize Long,指定装载到lpReturnedString缓冲区的最大字符数量
          lpFileName String,初始化文件的名字。如没有指定一个完整路径名,windows就在Windows目录中查找文件
        3.GetPrivateProfileSection函数
        GetPrivateProfileSection
        功能:
        GetPrivateProfileSection =>从指定的文件中取得全部的关键字的值
        DWORD GetPrivateProfileSection(
        LPCTSTR lpAppName,
        LPTSTR lpReturnedString,
        DWORD nSize,
        LPCTSTR lpFileName);
        说明:
          获取指定小节所有项名和值的一个列表
        返回值:
          Long,装载到lpReturnedString缓冲区的字符数量。如缓冲区的容量不够大,不能容下所有信息,就返回nSize-2
          同时返回一个整数,大小为取得字符串的长度,包括NULL字符,不包括最后的NULL字符
        参数类型及说明:
          lpAppName String,欲获取的小节。注意这个字串不区分大小写
          lpReturnedString String,项和值字串的列表。每个字串都由一个NULL字符分隔,最后一个字串后面用两个NULL字符中止
          nSize Long,lpReturnedString缓冲区的大小。在windows系统中最大值为32767
          lpFileName String,初始化文件的名字。如没有指定完整路径名,windows就在Windows目录中查找文件
        4.WritePrivateProfileString函数
        功能:
        WritePrivateProfileString=>修改指定的文件中指定的关键字的值
        <参数>
           lpApplicationName:欲在其中查找条目的小节名称。这个字串不区分大小写。
           lpKeyName:欲获取的设置项或条目。这个支持不区分大小写
           lpString:要修改的值的字符串
           lpFileName:初始化文件的名字。如果没有指定完整的路径名,windows就会在Windows目录中搜索文件
        返回值:
        0表示失败,非0表示成功


        IP属地:广东4楼2014-06-10 20:50
        收起回复
          【title】CSocket
          CSocket::Create 初始化(一般写服务器程序都不要用为好,用下面的 CSocket::Socket 初始化)
          CSocket::Socket初始化
          CSocket::SetSockOpt 设置socket选项
          CSocket::Bind 绑定地址端口
          CSocket::Connect 连接
          CSocket::Listen 监听
          CSocket::Accept 接收外部连接的socket
          CSocket::Send 发送内容
          CSocket::Receive 接收内容
          CSocket::Close 关闭(不等于delete)


          IP属地:广东7楼2015-03-03 23:07
          回复