Chinaunix首页 | 论坛 | 博客
  • 博客访问: 399349
  • 博文数量: 57
  • 博客积分: 193
  • 博客等级: 入伍新兵
  • 技术积分: 1192
  • 用 户 组: 普通用户
  • 注册时间: 2012-12-13 14:37
个人简介

当以艺术眼光看程序,寻找程序后面的原理,做到化而不忘

文章分类

全部博文(57)

文章存档

2017年(5)

2015年(7)

2014年(27)

2013年(18)

我的朋友

分类: Windows平台

2013-05-19 08:53:20

------------------------------------------------------------------------
---
VC 驿站

多抽出一分钟时间来学习,让你的生命更加精彩!
C、C++、VC++ 各种学习资源,免费教程,期待您的加入!
动画教程只是起到技术交流的作用,请大家不用利用此方法做非法用途.
由此动画造成的任何后果和动画作者及本站无关.
------------------------------------------------------------------------
----------------
大家好,我是Syc
今天给大家做的教程是:
vc++高级班之窗口篇[1]---MFC对话框程序框架的讲解
------------------------------------------------------------------------
----------------
①、编程环境:
操作系统:Windows XP Professional Sp3
编译器:
Visual Studio 2008 Professional + Sp1 + Visual Assist X
下载地址:

②、学习过程中可以看的书籍,里面说到了我的不同时期看的不同书籍,希望对大
家有帮助:
我的程序员学习路程【一】:
我的程序员学习路程【二】:
我的程序员学习路程【三】:
我的程序员学习路程【四】:

③、MFC的入口点函数;
④、SDK与MFC中的窗口处理函数对比;
⑤、工程向导生成的其他函数讲解;
⑥、为程序添加登陆对话框:
1、添加对话框资源并进行编辑:讲解下资源的复制;
2、对话框资源类的关联;
3、登陆对话框的弹出;
4、进行简单的用户名、密码验证:

CString strID, strPass;
GetDlgItemText(IDC_ID_EDIT, strID);
GetDlgItemText(IDC_PASS_EDIT, strPass);
if (strID.IsEmpty() || strPass.IsEmpty()){
 MessageBox(_T("用户名或密码不能为空!"), _T("友情提示"));
 return;
}else if (strID != _T("cctry") || strPass != _T("123")){
 MessageBox(_T("用户名或密码错误!"), _T("友情提示"));
 return;
}

------------------------------------- End 

------------------------------------------------------------------------

---
VC 驿站

多抽出一分钟时间来学习,让你的生命更加精彩!
C、C++、VC++ 各种学习资源,免费教程,期待您的加入!
动画教程只是起到技术交流的作用,请大家不用利用此方法做非法用途.
由此动画造成的任何后果和动画作者及本站无关.
------------------------------------------------------------------------

----------------
大家好,我是Syc
今天给大家做的教程是:
vc++高级班之窗口篇[2]---MFC的消息映射机制
------------------------------------------------------------------------

----------------
①、映射机制的原理
Windows 下的程序包括 Windows 系统都是基于消息机制的。
MFC消息映射机制的具体实现方法是:在每个能接收和处理消息的类中,定义一个

消息和消息响应函数的静态对照表,即消息映射表;
在消息映射表中,消息与对应的消息处理函数指针是成对出现的。某个类能处理的

所有消息及其对应的消息处理函数的地址都列在这个类所对应的静态表中;
当有消息需要处理时,程序只要搜索该消息静态表,查看表中是否含有该消息,就

可以知道该类能否处理此消息;
如果能处理该消息,则同样依照静态表能很容易找到并调用对应的消息处理函数!

②、一般情况下,一个MFC的消息映射在程序中有三处相关信息:1》消息响应函数

的声明 2》消息响应函数实现 3》用来关联消息和消息响应函数的宏
具体见示例代码……更为详细的讲解参见《深入浅出MFC 第二版 简体中文版》 - 侯

杰:


③、针对不同的 Windows 消息,MFC提供了不同的消息映射宏,主要分为如下六类

1、Windows 消息映射宏
Windows 消息映射宏用于处理普通的窗口消息。此类消息映射宏前缀为“ON_WM_”,

并且没有参数;

2、命令消息映射宏
命令消息 WM_COMMAND 是一种特殊的窗口消息,它从一个窗口发送到另一个窗口,

以处理来自用户的请求,是 ON_COMMAND 宏和 ON_COMMAND_RANGE 宏;

3、控件通知消息映射宏
控件通知消息是指控件窗口发送到其父窗口的消息,其消息映射宏为 ON_CONTROL

和 ON_CONTROL_RANGE,有时在程序中并不见 ON_CONTROL 宏,而见

ON_BN_CLICKED 宏,
其实 ON_CONTROL 宏派生出许多的映射宏,包括 ON_BN_CLICKED 宏等;

4、控件通知消息映射宏
控件通知消息映射宏处理的窗口消息有 WM_COMMAND,WM_NOTIFY,其消息映射宏有

ON_NOTIFY 和 ON_NOTIFY_RANGE;

5、反射消息映射宏
反射消息是指子窗口向父窗口发送的通知消息或控件通知消息,父窗口将该消息转

化为相应的反射消息发送给子窗口优先处理。
处理窗口消息 WM_NOTIFY+WM_REFLECT_BASE 的宏是 ON_NOTIFY_REFLECT,处理窗

口消息 WM_COMMAND+WM_REFLECT_BASE 的宏是 ON_CONTROL_REFLECT,
还有其他的反射消息宏,具体请参考MDSN。

6、扩展消息映射宏
有 ON_COMMAND | ON_COMMAND_RANGE | ON_NOTIFY | ON_NOTIFY_RANGE ……
 
④、自定义消息的发送与响应:
1、自定义消息号:#define WM_CCTRY_MSG (WM_USER+100)
2、在头文件中添加消息响应函数的声明:afx_msg LRESULT OnCcTryMsg(WPARAM

wParam, LPARAM lParam);
3、在CPP文件中添加消息响应函数的实现:
LRESULT CXXXDlg::OnCcTryMsg(WPARAM wParam, LPARAM lParam) {
 //相关代码;
}
4、在 BEGIN_MESSAGE_MAP 与 END_MESSAGE_MAP 之间加入消息的映射代码:

ON_MESSAGE(WM_CCTRY_MSG, &CDlgTestDlg::OnCcTryMsg)
5、消息的发送:

------------------------------------- End

-------------------------------------------

 

 


------------------------------------------------------------------------

---
VC 驿站

多抽出一分钟时间来学习,让你的生命更加精彩!
C、C++、VC++ 各种学习资源,免费教程,期待您的加入!
动画教程只是起到技术交流的作用,请大家不用利用此方法做非法用途.
由此动画造成的任何后果和动画作者及本站无关.
------------------------------------------------------------------------

----------------
大家好,我是Syc
今天给大家做的教程是:
vc++高级班之窗口篇[3]---窗口的枚举与查找
------------------------------------------------------------------------

----------------
①、使用 GetWindow 进行窗口枚举:
TCHAR titleText[MAX_PATH] = {0};

HWND nHwnd = ::GetWindow(::GetDesktopWindow(), GW_CHILD);
while(nHwnd != NULL) {
 ::GetWindowText(nHwnd, titleText, MAX_PATH);
 if (_tcslen(titleText) > 0) MessageBox(titleText);

 nHwnd = ::GetWindow(nHwnd, GW_HWNDNEXT);
}

②、使用 FindWindowEx 进行窗口枚举:
TCHAR titleText[MAX_PATH] = {0};

HWND nHwnd = ::FindWindow(NULL, NULL);
while(nHwnd != NULL) {
 ::GetWindowText(nHwnd, titleText, MAX_PATH);
 if (_tcslen(titleText) > 0) MessageBox(titleText);

 nHwnd = ::FindWindowEx(0, nHwnd, NULL, NULL);
}
 
③、使用 EnumWindows 进行窗口枚举:
EnumWindows(EnumWindowsProc, NULL);
……
BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
{
 TCHAR titleText[MAX_PATH] = {0};
 ::GetWindowText(hwnd, titleText, MAX_PATH);
 if (_tcslen(titleText) > 0) AfxMessageBox(titleText);

 return TRUE;
}

④、使用 EnumChildWindows 进行子窗口的枚举:
EnumChildWindows 照比 EnumWindows 只是多了一个指定父窗口的窗口句柄的参数


所以这个函数的使用算是留给大家的一个小作业,自己课后实践一下!

⑤、使用 FindWindow 进行窗口的查找:
HWND hCalc = ::FindWindow(_T("SciCalc"), _T("计算器"));
if (hCalc){
 ::SetWindowText(hCalc, _T("VC驿站 专用计算器!"));
}

⑥、使用 FindWindowEx 进行子窗口的查找:
HWND hCalc = ::FindWindow(_T("SciCalc"), _T("计算器"));
if (hCalc){
 ::SetWindowText(hCalc, _T("VC驿站 专用计算器!"));
 HWND hEdit = ::FindWindowEx(hCalc, NULL, _T("Edit"), NULL);
 ::SetWindowText(hEdit, _T("1234567890"));
 //::SendMessage(hEdit, WM_SETTEXT, 0, (LPARAM)_T("1234567890"));
}

⑦、鉴于 FindWindowEx 找子控件的不确定性,
可以使用 GetDlgItem 来获取对话框内部的子控件窗口句柄:

HWND hEdit = ::GetDlgItem(hCalc, 0x193);

⑧、其他 Window 操作相关 API 函数:
⑨、获取窗口的进程ID:GetWindowThreadProcessId
------------------------------------- End

-------------------------------------------

------------------------------------------------------------------------

---
VC 驿站

多抽出一分钟时间来学习,让你的生命更加精彩!
C、C++、VC++ 各种学习资源,免费教程,期待您的加入!
动画教程只是起到技术交流的作用,请大家不用利用此方法做非法用途.
由此动画造成的任何后果和动画作者及本站无关.
------------------------------------------------------------------------

----------------
大家好,我是Syc
今天给大家做的教程是:
vc++高级班之窗口篇[4]---让程序只运行一个实例
------------------------------------------------------------------------

----------------
大家都看过或者使用过类似只运行一个实例的程序,比如:QQ游戏、部分浏览器

等等!
让一个程序只运行一个实例的方法有多种,但是原理都类似,也就是在程序创建后

,有窗口的程序在窗口创建前,
检查系统中是否已经设置了某些特定标志,是否创建了一些全局唯一的东西,或者

让程序的多个实例都能看到的东西,
如果有则说明已经有一个实例在运行了,则当前程序通知用户如何如何,然后程序

退出,当然方法有很多种,各有各的优缺点!

①、创建互斥体 Mutex 法:
但是单纯的使用互斥体的话不能取得已经创建的实例窗口局柄,因此无法激活已经

启动的实例窗口;
HANDLE m_hMutex = ::CreateMutex(NULL, FALSE, _T("{6668BB0A-DE0C-499d-

8520-79653FF9B2EB}"));
if ( GetLastError() == ERROR_ALREADY_EXISTS ){
 AfxMessageBox(_T("已经有一个实例正在运行中……"));
 CloseHandle(m_hMutex);
 m_hMutex = NULL;
 return FALSE;
}
//其他代码,比如对话框的创建及弹出等等

if (m_hMutex) {
 CloseHandle(m_hMutex);
 m_hMutex = NULL;
}

===================================================
②、通过 FindWindow 进行窗口的查找,若发现则说明已经运行过一个实例,并将

其窗口激活:
HWND hWnd = ::FindWindow(_T("#32770"), _T("DlgTest"));
if (hWnd != NULL) {
 AfxMessageBox(_T("已经有一个实例正在运行中……"));
 ::ShowWindow(hWnd, SW_NORMAL);
 ::SetForegroundWindow(hWnd);
 return FALSE;
}
此种方法不是很好,如果窗口标题改变了或者每个窗口实例的标题不一样,就找不

到了!

===================================================
③、设置窗口属性 SetProp + EnumWindows 法!
1、加入全局变量的定义及枚举窗口函数:
TCHAR g_szPropName[] = _T("{12AA5160-5215-435b-AE3C-60C9E65615CE}");
HANDLE g_hValue = (HANDLE)9527;

BOOL CALLBACK EnumWndProc(HWND hwnd, LPARAM lParam)
{
 HANDLE hProp = GetProp(hwnd, g_szPropName);
 if(hProp == g_hValue) {
  *(HWND *)lParam = hwnd;
  return FALSE;
 }
 return TRUE;
}

2、窗口的枚举以及属性的添加:
//OnInitDialog() 中加入以下代码:
HWND hPreWnd = NULL;
::EnumWindows(EnumWndProc, (LPARAM)&hPreWnd);
if (hPreWnd != NULL) {
 AfxMessageBox(_T("已经有一个实例正在运行中……"));
 ::ShowWindow(hPreWnd, SW_NORMAL);
 ::SetForegroundWindow(hPreWnd);
 ExitProcess(0);
 return FALSE;
}
::SetProp(m_hWnd, g_szPropName, g_hValue);

3、窗口属性的删除:
OnDestroy() 函数中加入以下代码:
::RemoveProp(m_hWnd, g_szPropName);

===================================================
④、使用全局共享变量的共享节法实现单实例运行;
1、新建共享节:
#pragma data_seg("Shared")
HWND hPreWnd = NULL;
#pragma data_seg()
#pragma comment(linker, "/Section:Shared,RWS")

2、OnInitDialog() 函数中加入以下代码:
if (hPreWnd == NULL) {
 hPreWnd = m_hWnd;
} else {
 AfxMessageBox(_T("已经有一个实例正在运行中……"));
 ::ShowWindow(hPreWnd, SW_NORMAL);
 ::SetForegroundWindow(hPreWnd);
 ExitProcess(0);
 return FALSE;
}

===================================================
⑤、互斥体+自定义广播系统消息法;
1、系统消息的注册:
#define REG_MSG (_T("{7510EF00-BADA-48de-A6CE-5FBC817616DD}"))
UINT WM_ACTIVE_MSG = ::RegisterWindowMessage(REG_MSG);

2、发现实例后,进行消息的广播:
InitInstance() 函数中添加如下代码:

HANDLE m_hMutex = ::CreateMutex(NULL, FALSE, _T("{6668BB0A-DE0C-499d-

8520-79653FF9B2EB}"));
if ( GetLastError() == ERROR_ALREADY_EXISTS ){
 AfxMessageBox(_T("已经有一个实例正在运行中……"));
 CloseHandle(m_hMutex);
 m_hMutex = NULL;

 DWORD dwRecipients = BSM_APPLICATIONS;
 ::BroadcastSystemMessage(BSF_NOHANG, &dwRecipients,

WM_ACTIVE_MSG, 0, 0);

 return FALSE;
}
//其他窗口创建之类的代码
if (m_hMutex) {
 CloseHandle(m_hMutex);
 m_hMutex = NULL;
}

3、窗口类中全局变量的作用域扩展:
extern UINT WM_ACTIVE_MSG;

4、窗口类中自定义消息的响应:
afx_msg LRESULT OnActiveMsg(WPARAM wParam, LPARAM lParam);
ON_REGISTERED_MESSAGE(WM_ACTIVE_MSG, &CDlgTestDlg::OnActiveMsg)
LRESULT CDlgTestDlg::OnActiveMsg(WPARAM wParam, LPARAM lParam)
{
 ::ShowWindow(m_hWnd, SW_NORMAL);
 ::SetForegroundWindow(m_hWnd);
 return TRUE;
}
------------------------------------- End

-------------------------------------------

------------------------------------------------------------------------

---
VC 驿站

多抽出一分钟时间来学习,让你的生命更加精彩!
C、C++、VC++ 各种学习资源,免费教程,期待您的加入!
动画教程只是起到技术交流的作用,请大家不用利用此方法做非法用途.
由此动画造成的任何后果和动画作者及本站无关.
------------------------------------------------------------------------

----------------
大家好,我是Syc
今天给大家做的教程是:
vc++高级班之窗口篇[5]---Windows消息的发送
------------------------------------------------------------------------

----------------
①、Windows 标准消息的发送
Windows 系统的标准消息有很多,一般是以 WM_ 开头的,比如:WM_KEYDOWN、

WM_MOUSEMOVE 等等!
这里我们选几个常用的并且有代表性的给大家进行讲解!
===================================================
②、按钮左键单击消息的发送:同样适用于 CheckBox、RadioBox
HWND hDlgWnd = ::FindWindow(_T("#32770"), _T("MsgTest"));
if (hDlgWnd){
 ::ShowWindow(hDlgWnd, SW_NORMAL);
 ::SetForegroundWindow(hDlgWnd);
 HWND hBtn = ::GetDlgItem(hDlgWnd, 0x3E8);
 ::SendMessage(hBtn, BM_CLICK, 0, 0);
}
MSDN搜索关键字:Button Messages
===================================================
③、下拉选择框控件消息的发送:
//插入字符串:
HWND hDlgWnd = ::FindWindow(_T("#32770"), _T("MsgTest"));
if (hDlgWnd){
 ::ShowWindow(hDlgWnd, SW_NORMAL);
 ::SetForegroundWindow(hDlgWnd);
 HWND hComboBox = ::GetDlgItem(hDlgWnd, 0x3EA);
 ::SendMessage(hComboBox, CB_INSERTSTRING, -1, (LPARAM)_T

("CcTry.CoM"));
 ::SendMessage(hComboBox, CB_SETCURSEL, 5, 0);
}
===================================================
④、给对话框发送鼠标右键消息,看现象并讲解 SendMessage 与 PostMessage 的

区别:
HWND hDlgWnd = ::FindWindow(_T("#32770"), _T("MsgTest"));
if (hDlgWnd){
 ::PostMessage(hDlgWnd, WM_RBUTTONDOWN, MK_RBUTTON, MAKELPARAM

(20, 20));
 ::PostMessage(hDlgWnd, WM_RBUTTONUP, 0, MAKELPARAM(20, 20));
}
===================================================
⑤、跟进MFC的类的成员函数,获取其实现方式:
MFC 有一点好处就是所有的源代码都能看到,可以看看其内部究竟是如何封装的,

以及都调用了哪些SDK函数!
对 SDK 编程也是有很多值得学习的地方的,比如封装的思想、调用 API 函数的方

式等等!

1、部分MFC成员函数:CComboBox::InsertString、CListCtrl::DeleteItem 等等


2、CWnd::ModifyStyleEx
------------------------------------- End

-------------------------------------------

------------------------------------------------------------------------

---
VC 驿站

多抽出一分钟时间来学习,让你的生命更加精彩!
C、C++、VC++ 各种学习资源,免费教程,期待您的加入!
动画教程只是起到技术交流的作用,请大家不用利用此方法做非法用途.
由此动画造成的任何后果和动画作者及本站无关.
------------------------------------------------------------------------

----------------
大家好,我是Syc
今天给大家做的教程是:
vc++高级班之窗口篇[6]---打造自己的“按钮激活专家”
------------------------------------------------------------------------

----------------
①、按钮激活专家介绍:
可以突破灰色(禁用)按钮的限制,是一款很实用的小巧软件。
大家发现有些没有注册的软件有些什么确定、激活的按钮是不能点的,所以这个软

件可以去除软件不能点击的部位,操作十分简单!
===================================================
②、主要用到的函数:
SetTimer、WindowFromPoint、EnumChildWindows、EnableWindow 等!
大部分函数以前都给大家讲过的!
===================================================
③、对话框样式的修改及控件的添加;
===================================================
④、添加置顶选项代码:
void CDlgTestDlg::OnBnClickedTopmostCheck()
{
 CButton *pTopMostCheck = (CButton *)GetDlgItem

(IDC_TOPMOST_CHECK);
 int iCheck = pTopMostCheck->GetCheck();
 if (iCheck == BST_CHECKED){
  SetWindowPos(&CWnd::wndTopMost, 0, 0, 0, 0, SWP_NOSIZE|

SWP_NOMOVE);
 }else{
  SetWindowPos(&CWnd::wndNoTopMost, 0, 0, 0, 0,

SWP_NOSIZE|SWP_NOMOVE);
 }
}
===================================================
⑤、添加激活按钮响应函数:
void CDlgTestDlg::OnBnClickedStartActive()
{
 static BOOL bStart = FALSE;
 if(bStart == FALSE) {
  bStart = TRUE;
  GetDlgItem(IDC_START_ACTIVE)->SetWindowText(_T("停

止!"));
  SetTimer(1, 200, NULL);
 } else {
  bStart = FALSE;
  GetDlgItem(IDC_START_ACTIVE)->SetWindowText(_T("开始激活

!"));
  KillTimer(1);
 }
}

⑥、添加定时器响应函数:
void CDlgTestDlg::OnTimer(UINT_PTR nIDEvent)
{
 TCHAR szTitle[MAX_PATH] = {0};
 HWND hTopWnd = ::GetForegroundWindow();
 ::GetWindowText(hTopWnd, szTitle, MAX_PATH);
 SetDlgItemText(IDC_STATIC_SHOW, szTitle);

 EnumChildWindows(hTopWnd, EnumChildProc, NULL);

 CDialog::OnTimer(nIDEvent);
}

⑦、添加枚举子窗口回调函数:
BOOL CALLBACK EnumChildProc(HWND hWnd, LPARAM lParam)
{
 if( !IsWindowEnabled(hWnd) ){
  EnableWindow(hWnd, TRUE);
 }
 return TRUE;
}

⑧⑨⑩
------------------------------------- End

-------------------------------------------


------------------------------------------------------------------------

---
VC 驿站

多抽出一分钟时间来学习,让你的生命更加精彩!
C、C++、VC++ 各种学习资源,免费教程,期待您的加入!
动画教程只是起到技术交流的作用,请大家不用利用此方法做非法用途.
由此动画造成的任何后果和动画作者及本站无关.
------------------------------------------------------------------------

----------------
大家好,我是Syc
今天给大家做的教程是:
vc++高级班之窗口篇[7]---打造自己的星号密码查看器
------------------------------------------------------------------------

----------------
①、星号密码查看器介绍:
星号密码的杀手,能够很方便显示星号密码框的密码,有助于找回已经遗忘的密码


===================================================
②、获取星号密码的原理:
上世纪90年代使用过 Windows3.x 的人可能很少有人了解这类操作系统中存在着密

码保护的漏洞,如果选择密码控件中的“****”文本然后复制到剪贴板上,
那么看到的将不是“****”而是密码的原始文本。微软发现了Windows3.x 这个问题

并在新的版本Windows95 中修改了这个漏洞。

但是 Windows95 存在着新的安全漏洞,可以设计出间谍程序从当前运行的程序中

得到密码控件中的密码(方法见下文)。然而,微软在 Window2000 中又修补了这

个问题,
是判断消息发送的来源进程是否与当前密码控件属于同一进程,如果不是则返回

ERROR_ACCESS_DENIED 错误!但是也是有方法的,那就是利用 DLL 进程注入,
向密码控件发送 WM_GETTEXT、EM_GETLINE 消息来进行密码的获取!

编辑框 Edit 控件 是Windows的一个标准控件,当把其 Password 属性设为 True

时,就会将输入的内容屏蔽并变为星号(*),从而达到保护的目的。
但是 Edit 框中的内容可通过编程的方式发送 WM_GETTEXT、EM_GETLINE 消息来进

行获取。
黑客程序就是利用 Edit 控件的这个特性,通过 SendMessage 向此窗口发送

WM_GETTEXT 或 EM_GETLINE 消息,这样Edit框中的内容就一目了然了! 
下面就给大家演示下这个技术,不过这里面只做技术讨论,希望大家不要用于非法

用途!天若有情天亦老,人间正道是沧桑!
===================================================
③、对话框样式的修改及控件的添加、图标资源的添加;
===================================================
④、添加置顶选项功能,见上节;
===================================================
⑤、CStatic 派生类的添加:CDragStatic 以及控件类型变量的绑定;
===================================================
⑥、CDragStatic::OnLButtonDown 事件的添加:
void CDragStatic::OnLButtonDown(UINT nFlags, CPoint point)
{
 SetCapture(); //设定鼠标消息的发送窗口为当前窗口
 HCURSOR hc = LoadCursor(AfxGetApp()->m_hInstance,

MAKEINTRESOURCE(IDC_CURSOR1));
 ::SetCursor(hc);
 HICON hIcon = LoadIcon(AfxGetApp()->m_hInstance,

MAKEINTRESOURCE(IDI_ICON2));
 this->SetIcon(hIcon);
 SetTimer(1, 400, NULL);

 CStatic::OnLButtonDown(nFlags, point);
}
===================================================
⑦、CDragStatic::OnLButtonUp 事件的添加:
void CDragStatic::OnLButtonUp(UINT nFlags, CPoint point)
{
 ReleaseCapture();
 HICON hIcon=LoadIcon(AfxGetApp()->m_hInstance,MAKEINTRESOURCE

(IDI_ICON1));
 this->SetIcon(hIcon);
 KillTimer(1);

 CStatic::OnLButtonUp(nFlags, point);
}
===================================================
⑧、添加 CDragStatic::OnTimer 定时器响应:
void CDragStatic::OnTimer(UINT_PTR nIDEvent)
{
 HWND deskWnd = ::GetDesktopWindow();
 HDC deskDC = ::GetWindowDC(deskWnd);
 int oldRop2 = SetROP2(deskDC, R2_NOTXORPEN);

 CPoint pt;
 GetCursorPos(&pt);

 HWND parentWnd = ::WindowFromPoint(pt);
 HWND hTargetWnd = ::GetWindow(parentWnd, GW_CHILD);

 CRect tempRc;
 while (hTargetWnd){
  ::GetWindowRect(hTargetWnd, &tempRc);
  if(::PtInRect(&tempRc, pt)){
   break;
  }else{
   hTargetWnd = ::GetWindow(hTargetWnd,

GW_HWNDNEXT);
  }
 }

 if ( !hTargetWnd ) hTargetWnd = parentWnd;

 //窗口标题、编辑框文本的获取
 
 CRect mRect;
 ::GetWindowRect(hTargetWnd, &mRect);

 if( mRect.left < 0 ) mRect.left = 0;
 if (mRect.top < 0 ) mRect.top = 0;

 HPEN newPen = ::CreatePen(0, 3, RGB(125, 0, 125));
 HGDIOBJ oldPen = ::SelectObject(deskDC, newPen);

 ::Rectangle(deskDC, mRect.left, mRect.top, mRect.right,

mRect.bottom);
 Sleep(200);
 ::Rectangle(deskDC, mRect.left, mRect.top, mRect.right,

mRect.bottom);

 ::SetROP2(deskDC, oldRop2);
 ::SelectObject( deskDC, oldPen);

 ::DeleteObject(newPen);
 ::ReleaseDC(deskWnd, deskDC);
 deskDC = NULL;

 CStatic::OnTimer(nIDEvent);
}
===================================================
⑨、窗口标题、编辑框文本的获取
LRESULT nLen = ::SendMessage(hTargetWnd, WM_GETTEXTLENGTH, 0, 0);
if (nLen > 0){
 nLen += 1;
 TCHAR *pszBuf = new TCHAR[nLen];
 ZeroMemory(pszBuf, nLen);
 ::SendMessage(hTargetWnd, WM_GETTEXT, nLen, (LPARAM)pszBuf);
 GetParent()->SetDlgItemText(IDC_STATIC_SHOW, pszBuf);
 delete [] pszBuf;
}
===================================================

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

*
// SmallestWindowFromPoint
// Notice: from PasswordSpy by Brian Friesen
//
// Find the smallest window still containing the point
//
// WindowFromPoint returns the first window in the Z-order ->
// if the password control is sorounded by a Group Box or some other

control,
// WindowFromPoint returns the handle to the sorounding control instead
// to the password control.
************************************************************************

/
HWND SmallestWindowFromPoint(POINT point)
{
 RECT rect, rcTemp;
 HWND hParent, hWnd, hTemp;

 hWnd = ::WindowFromPoint(point);
 if( hWnd != NULL ) {
  ::GetWindowRect(hWnd, &rect);
  hParent = ::GetParent(hWnd);

  // Has window a parent ?
  if(hParent != NULL) {
   // Search down the Z-Order
   hTemp = hWnd;
   do {
    hTemp = ::GetWindow(hTemp, GW_HWNDNEXT);

    // Search window contains the point,

hase the same parent, and is visible?
    ::GetWindowRect(hTemp, &rcTemp);
    if(::PtInRect(&rcTemp, point) &&

::GetParent(hTemp) == hParent && ::IsWindowVisible(hTemp)){
     // Is it smaller?
     if(((rcTemp.right - rcTemp.left)

* (rcTemp.bottom - rcTemp.top)) < ((rect.right - rect.left) *

(rect.bottom - rect.top))) {
      // Found new smaller

window!
      hWnd = hTemp;
      ::GetWindowRect(hWnd,

&rect);
     }
    }
   } while(hTemp != NULL);
  }
 }

 return hWnd;
}

////////////////////////////////////////////////////////////////////////

/////////////
HWND hTargetWnd = SmallestWindowFromPoint(pt);
if (GetWindowThreadProcessId(GetSafeHwnd(), NULL) ==

GetWindowThreadProcessId(hTargetWnd, NULL)) {
 GetParent()->SetDlgItemText(IDC_STATIC_SHOW, _T(""));
 return;
}
------------------------------------- End

-------------------------------------------


------------------------------------------------------------------------

---
VC 驿站

多抽出一分钟时间来学习,让你的生命更加精彩!
C、C++、VC++ 各种学习资源,免费教程,期待您的加入!
动画教程只是起到技术交流的作用,请大家不用利用此方法做非法用途.
由此动画造成的任何后果和动画作者及本站无关.
------------------------------------------------------------------------

----------------
大家好,我是Syc
今天给大家做的教程是:
vc++高级班之窗口篇[8]---模拟鼠标、键盘操作
------------------------------------------------------------------------

----------------
①、鼠标点击之发消息方式:
//对话框右键单击
HWND hDlgWnd = ::FindWindow(_T("#32770"), _T("MsgTest"));
if (hDlgWnd){
 ::PostMessage(hDlgWnd, WM_RBUTTONDOWN, MK_RBUTTON, MAKELPARAM

(20, 20));
 ::PostMessage(hDlgWnd, WM_RBUTTONUP, 0, MAKELPARAM(20, 20));
}

//鼠标左键单击按钮
HWND hDlgWnd = ::FindWindow(_T("#32770"), _T("MsgTest"));
if (hDlgWnd){
 ::ShowWindow(hDlgWnd, SW_NORMAL);
 ::SetForegroundWindow(hDlgWnd);
 HWND hBtn = ::GetDlgItem(hDlgWnd, 0x3E8);
 ::SendMessage(hBtn, BM_CLICK, 0, 0);
}

//另一种单击按钮的实现
HWND hDlgWnd = ::FindWindow(_T("#32770"), _T("MsgTest"));
if (hDlgWnd){
 ::ShowWindow(hDlgWnd, SW_NORMAL);
 ::SetForegroundWindow(hDlgWnd);
 HWND hBtn = ::GetDlgItem(hDlgWnd, 0x3E8);
 ::PostMessage(hBtn, WM_LBUTTONDOWN, MK_LBUTTON, MAKELPARAM(10,

10));
 ::PostMessage(hBtn, WM_LBUTTONUP, 0, MAKELPARAM(10, 10));
}
===================================================
②、鼠标点击之 mouse_event 方式:
HWND hDlgWnd = ::FindWindow(_T("#32770"), _T("MsgTest"));
if (hDlgWnd){
 ::ShowWindow(hDlgWnd, SW_NORMAL);
 ::SetForegroundWindow(hDlgWnd);
 HWND hBtn = ::GetDlgItem(hDlgWnd, 0x3E8);
 CRect mRect;
 ::GetWindowRect(hBtn, &mRect);
 SetCursorPos(mRect.left+3, mRect.top+3);

 mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
 Sleep(100);
 mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
}

===================================================
③、程序是死的人的活的,以上两种方法不行的话,还有第三种:
//快捷键方式:
HWND hDlgWnd = ::FindWindow(_T("KugouMainPlayer"), NULL);
if (hDlgWnd){
 ::ShowWindow(hDlgWnd, SW_NORMAL);
 ::SetForegroundWindow(hDlgWnd);
 keybd_event(VK_F5, 0, 0, 0);
 Sleep(100);
 keybd_event(VK_F5, 0, KEYEVENTF_KEYUP, 0);
}
 
//全局热键方式:
HWND hDlgWnd = ::FindWindow(_T("KugouMainPlayer"), NULL);
if (hDlgWnd){
 keybd_event(VK_CONTROL, 0, 0, 0);
 keybd_event(VK_MENU, 0, 0, 0);
 keybd_event(VK_F5, 0, 0, 0);
 Sleep(100);
 keybd_event(VK_F5, 0, KEYEVENTF_KEYUP, 0);
 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
}
===================================================
④、用 keybd_event 模拟字符输入:
#define IsKeyPressed(nVirtKey)  ((GetKeyState(nVirtKey) & (1<<(sizeof

(SHORT)*8-1))) != 0)
#define IsKeyToggled(nVirtKey)  ((GetKeyState(nVirtKey) & 1) != 0)

void CDlgTestDlg::OnBnClickedBtn()
{
 HWND hNotepad = ::FindWindow(_T("Notepad"), _T("无标题 - 记事

本"));
 ::ShowWindow(hNotepad, SW_NORMAL);
 ::SetForegroundWindow(hNotepad);

 BOOL bToggled = IsKeyToggled(VK_CAPITAL);
 if (bToggled) {
  keybd_event( VK_CAPITAL, 0, KEYEVENTF_EXTENDEDKEY, 0);
  Sleep(20);
  keybd_event( VK_CAPITAL, 0, KEYEVENTF_EXTENDEDKEY |

KEYEVENTF_KEYUP, 0);
 }

 CString strOut(_T("AbCd"));
 for (int idx = 0; idx < strOut.GetLength(); idx++)
 {
  TCHAR ch = strOut.GetAt(idx);
  if (_istlower(ch)) {
   keybd_event(_totupper(ch), 0, 0, 0);
   Sleep(20);
   keybd_event(_totupper(ch), 0, KEYEVENTF_KEYUP,

0);
  }else{
   keybd_event(VK_SHIFT, 0, 0, 0);
   keybd_event(ch, 0, 0, 0);
   Sleep(20);
   keybd_event(ch, 0, KEYEVENTF_KEYUP, 0);
   keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
  }
  Sleep(50);
 }

 if (bToggled) {
  keybd_event( VK_CAPITAL, 0, KEYEVENTF_EXTENDEDKEY, 0);
  Sleep(20);
  keybd_event( VK_CAPITAL, 0, KEYEVENTF_EXTENDEDKEY |

KEYEVENTF_KEYUP, 0);
 }
}
keybd_event 第一个参数传递大写字母,实际输入小写字母;
keybd_event 第一个参数传递小写字母,实际输出对应的数字,是不正确的

所以,传进小写字母,并且要显示小写字母,就要转换到大写字母进行传入,
传进大写字母,并且要显示大写字母,要借助于 Shift 键+大写字母进行传入
===================================================
⑤、SendInput 方式:
Windows NT/2000/XP/Vista/7 及以后的操作系统中,微软不建议使用

mouse_event、keybd_event 等模拟鼠标、键盘事件的 API 函数,
建议的方式是使用 SendInput 函数:

HWND hDlgWnd = ::FindWindow(_T("KugouMainPlayer"), NULL);
if (hDlgWnd){
 INPUT iPut[6] = {0};
 iPut[0].type = iPut[1].type = iPut[2].type = iPut[3].type =

iPut[4].type = iPut[5].type = INPUT_KEYBOARD;

 iPut[0].ki.wVk = iPut[5].ki.wVk = VK_CONTROL;
 iPut[1].ki.wVk = iPut[4].ki.wVk = VK_MENU;
 iPut[2].ki.wVk = iPut[3].ki.wVk = VK_F5;

 iPut[3].ki.dwFlags = iPut[4].ki.dwFlags = iPut[5].ki.dwFlags =

KEYEVENTF_KEYUP;
 iPut[0].ki.time = iPut[1].ki.time = iPut[2].ki.time =

GetTickCount();
 Sleep(100);
 iPut[3].ki.time = iPut[4].ki.time = iPut[5].ki.time =

GetTickCount();

 SendInput(sizeof(iPut)/sizeof(iPut[0]), iPut, sizeof(INPUT));
}
===================================================
※※※ 小作业:使用 SendInput 函数模拟鼠标按键消息!
------------------------------------- End

-------------------------------------------

------------------------------------------------------------------------

---
VC 驿站

多抽出一分钟时间来学习,让你的生命更加精彩!
C、C++、VC++ 各种学习资源,免费教程,期待您的加入!
动画教程只是起到技术交流的作用,请大家不用利用此方法做非法用途.
由此动画造成的任何后果和动画作者及本站无关.
------------------------------------------------------------------------

----------------
大家好,我是Syc
今天给大家做的教程是:
vc++高级班之窗口篇[9]---为窗口添加信息提示功能
------------------------------------------------------------------------

----------------
①、声明 CToolTipCtrl 类型对象:
CToolTipCtrl m_pToolTipCtrl;
===================================================
②、CToolTipCtrl 的创建:
if( !m_pToolTipCtrl.Create(this) ) return FALSE;
===================================================
③、添加需要提示的控件:
CString strTip = _T("C:\\Documents and Settings\\Syc\\Application Data\

\Microsoft\\Internet Explorer\\Quick Launch\\");
m_pToolTipCtrl.AddTool(GetDlgItem(IDC_EDIT), strTip);
SetDlgItemText(IDC_EDIT, strTip);
===================================================
④、添加虚函数 PreTranslateMessage
BOOL CDlgTestDlg::PreTranslateMessage(MSG* pMsg)
{
 if(pMsg->message == WM_LBUTTONDOWN ||
  pMsg->message == WM_LBUTTONUP ||
  pMsg->message == WM_MOUSEMOVE)
  m_pToolTipCtrl.RelayEvent(pMsg); //传递一个鼠标消息给工

具提示控件处理

 return CDialog::PreTranslateMessage(pMsg);
}
===================================================
⑤、为控件添加动态提示内容:
前三步不变,在调用 AddTool 增加 ToolTip 时不指定显示的字串,而是使用

LPSTR_TEXTCALLBACK 参数;
并启用目标窗口的 ToolTip 属性:EnableToolTips(TRUE);
===================================================
⑥、增加消息映射:
afx_msg BOOL OnTtnNeedText(UINT id, NMHDR *pNMHDR, LRESULT *pResult);
ON_NOTIFY_EX(TTN_NEEDTEXT, 0, &CDlgTestDlg::OnTtnNeedText)
===================================================
⑦、添加 OnTtnNeedText 函数实现:
BOOL CDlgTestDlg::OnTtnNeedText(UINT id, NMHDR *pNMHDR, LRESULT

*pResult)
{
 UNREFERENCED_PARAMETER(id);

 TOOLTIPTEXT *pTTT = (TOOLTIPTEXT *)pNMHDR;
 UINT_PTR nID = pNMHDR->idFrom; //获得目标窗口ID,有可能是HWND
 BOOL bRet = FALSE;

 if (pTTT->uFlags & TTF_IDISHWND) { //表明nID是否为HWND

  bRet = TRUE;
  CString strText;
  // idFrom is actually the HWND of the tool
  nID = ::GetDlgCtrlID((HWND)nID); //从HWND得到ID值,当然

你也可以通过HWND值来判断
  switch (nID)
  {
  case IDC_EDIT:
  case IDC_BTN:
   strText.Empty();
   GetDlgItemText(nID, strText);
   pTTT->lpszText = (LPTSTR)(LPCTSTR)strText;
   pTTT->hinst = AfxGetResourceHandle();
  default:break;
  }
 }

 *pResult = 0;

 return bRet;
}
===================================================
※※※ 小作业:学会 CToolTipCtrl 类的其他成员函数的使用!
一款非常漂亮的开源 ToolTip 类:

------------------------------------- End

-------------------------------------------

------------------------------------------------------------------------

---
VC 驿站

多抽出一分钟时间来学习,让你的生命更加精彩!
C、C++、VC++ 各种学习资源,免费教程,期待您的加入!
动画教程只是起到技术交流的作用,请大家不用利用此方法做非法用途.
由此动画造成的任何后果和动画作者及本站无关.
------------------------------------------------------------------------

----------------
大家好,我是Syc
今天给大家做的教程是:
vc++高级班之窗口篇[10]---屏幕截图功能的实现
------------------------------------------------------------------------

----------------
①、对整个屏幕截图:
void GetScreenCapture(LPCTSTR lpszSavePath)
{
 ASSERT(lpszSavePath);
 int screenWidth = GetSystemMetrics(SM_CXSCREEN);
 int screenHeight = GetSystemMetrics(SM_CYSCREEN);

 CDC *pDC = CDC::FromHandle(::GetDC(NULL));

 CDC memDc;
 memDc.CreateCompatibleDC(pDC);

 CBitmap mBmp, *pOldBmp = NULL;
 mBmp.CreateCompatibleBitmap(pDC, screenWidth, screenHeight);
 pOldBmp = memDc.SelectObject(&mBmp);

 memDc.BitBlt(0, 0, screenWidth, screenHeight, pDC, 0, 0,

SRCCOPY);

 CImage img;
 img.Attach(mBmp);
 img.Save(lpszSavePath);

 memDc.SelectObject(pOldBmp);
 ::ReleaseDC(NULL, pDC->m_hDC);
}
===================================================
②、对指定窗口截图:
void GetWndCapture(HWND hTargetWnd, LPCTSTR lpszSavePath)
{
 ASSERT(lpszSavePath);
 CRect mRect;
 GetWindowRect(hTargetWnd, &mRect);

 CDC *pDC = CDC::FromHandle(::GetDC(hTargetWnd));

 CDC memDc;
 memDc.CreateCompatibleDC(pDC);

 CBitmap mBmp, *pOldBmp = NULL;
 mBmp.CreateCompatibleBitmap(pDC, mRect.Width(), mRect.Height());
 pOldBmp = memDc.SelectObject(&mBmp);

 memDc.BitBlt(0, 0, mRect.Width(), mRect.Height(), pDC, 0, 0,

SRCCOPY);

 CImage img;
 img.Attach(mBmp);
 img.Save(lpszSavePath);

 memDc.SelectObject(pOldBmp);
 ::ReleaseDC(NULL, pDC->m_hDC);
}
===================================================
③、CDC、CClientDC、CPaintDC、CWindowDC 等设备描述表的区别:

CDC是Windows绘图设备的基类,其他相关DC都是其派生类,具体见MSDN类的结构图


(1)在 Windows 中,显示工作是基于设备环境的。所谓设备环境(DC)是一种

Windows 数据结构,该结构包含应用程序设备输出时所需要的信息;
(2)在使用任何绘图函数之前必须建立一个设备环境对象;
(3)在 Visual C++ 的MFC中提供了设备环境类CDC,它封装了绘图所需要的所有

函数,其中包括了大多数的 Windows API 中的 GDI 函数:包括画圆、画线、写字

、改变文字的颜色、字体等等……

CClientDC 类:
CClientDC类也是CDC类的派生类。它只能在窗口的客户区(即窗口中除了边框、标

题栏、菜单栏以及状态栏外的中间部分)中进行绘图,坐标点(0,0)通常指的是

客户区的左上角。
它的构造函数调用GetDC函数,而析构函数调用ReleaseDC函数。

CClientDC(客户区设备上下文)用于客户区的输出,它在构造函数中封装了

GetDC(),在析构函数中封装了ReleaseDC()函数。一般在响应非窗口重画消息(如

键盘输入时绘制文本、鼠标绘图)绘图时要用到它。用法是:
CClientDC dc(this); //this一般指向本窗口或当前活动视图
dc.TextOut(10,10,str,str.GetLength());
//利用dc输出文本,如果是在CScrollView中使用,还要注意调用OnPrepareDC

(&dc)调整设备上下文的坐标。

CPaintDC 类:
(1)CPaintDC类是CDC类的一个派生类,该类一般用在响应WM_PAINT消息的函数

OnPaint()中;
(2)WM_PAINT消息是当窗口的某个区域需要重画时激发的窗口消息。当程序中的

消息循环接到WM_PAINT消息时就自动调用消息处理函数OnPaint(),如果在OnPaint

函数内定义了CPaintDC类的对象,通过这个类对象就可以使用CDC类的成员函数完

成视图客户区中的图形绘制操作;

(3)CPaintDC用于响应窗口重绘消息(WM_PAINT)时的绘图输出。CPaintDC在构

造函数中调用BeginPaint()取得设备上下文,在析构函数中调用EndPaint()释放设

备上下文。EndPaint()除了释放设备上下文外,还负责从消息队列中清除WM_PAINT

消息。因此,在处理窗口重画时,必须使用CPaintDC,否则WM_PAINT消息无法从消

息队列中清除,将引起不断的窗口重画。CPaintDC也只能用在WM_PAINT消息处理之

中。

CWindowDC 类:
(1)CWindowDC类也是CDC类的派生类。其成员函数可以在窗口的客户区和非客户

区(即窗口的边框、标题栏、菜单栏以及状态栏)中绘图,坐标点(0, 0)是指整

个窗口的左上角。
而 CClientDC,CPaintDC 只能在客户区绘制图形;

(2)坐标原点是在窗口的左上角,CClientDC,CPaintDC 下坐标原点是在客户区

的左上角;
(3)同CClientDC类一样,它的构造函数调用GetDC函数,而析构函数调用

ReleaseDC函数;
(4)关联一特定窗口,允许开发者在目标窗口的任何一部分进行绘图,包含边界

与标题,这种 DC 同 WM_NCPAINT 消息一起发送。

〓〓〓 注:在绘图时推荐使用 CClientDC、CPaintDC 和 CWindowDC 对象,而不

推荐直接使用CDC对象!

CMetaFileDC 类
CMetaFileDC 类提供了一个面向Windows图元文件的设备环境,封装了在一个

Windows图元文件中绘图的方法。
图元文件是一个与设备无关的图片的集合,由于它对图像的保存比像素更精确,因

而往往在要求较高的场合下使用,例如:AutoCAD的图形保存等。

实例:
CClientDC dc(this); //this一般指向本窗口或当前活动视图
dc.TextOut(10, 0, str, str.GetLength());

CClientDC *pDC = new CClientDC(this);
CWindowDC dc(this);
===================================================
④、几个设备环境类的主要差别:
CWindowDC 类与 CPaintDC 、CClientDC 类的区别主要有以下两个方面:
(1)用 CPaintDC 和 CClientDC 类的对象绘制图形时,绘制区只能在客户区,而

不能在非客户区;而CWindowDC 类既可以在窗口的客户区也可以在非客户区进行图

形绘制。
(2)在CWindowDC 绘图类下,坐标系是建立在整个窗口上的,在像素坐标方式下

,坐标原点在整个窗口的左上角;
而在 CPaintDC 和 CClientDC 绘图类下,坐标系是建立在客户区上的,在像素坐

标方式下,坐标原点在客户区的左上角。

CPaintDC 类与 CClientDC 类的区别:
CPaintDC 类的对象应用在 OnPaint 函数中,以响应 Windows 的 WM_PAINT 消息

;而 CClientDC 类的对象应用在非响应消息 WM_PAINT 的情况下。
CPaintDC 类响应 WM_PAINT 消息,并自动完成绘制,这对维护图形的完整性有着

重要的作用。
CClientDC 类可以实时地将图形绘制到屏幕上,不需要重画;而如果用 CPaintDC

类的对象完成同样的工作,只能发出消息让屏幕上包含这条直线的区域重画,以把

这条直线绘制到屏幕上。
===================================================
⑤、设备环境类的使用方法
CDC 类:
因为CDC类不能用窗口对象指针初始化对象,所以,一般不直接定义对象。

CPaintDC 类:
CPaintDC 类一般用在窗口类OnPaint函数中,可采用如下代码定义一个CPaintDC类

对象:
CPaintDC dc(this);
以上代码定义了一个CPaintDC类的对象dc,并用当前的窗口对象指针this对对象进

行了初始化。CClientDC 和 CWindowDC类也采用这样的方法。

CClientDC 类:
可利用以下代码定义一个对象:CClientDC dc(this);

CWindowDC 类:
利用以下代码创建一个CWindowDC类的对象:CWindowDC dc(this);
===================================================
⑥、三种DC的示例代码:
CClientDC clientDC(this);
clientDC.MoveTo(0, 0);
clientDC.LineTo(100, 100);

CWindowDC wndDC(this);
wndDC.MoveTo(0, 0);
wndDC.LineTo(200, 100);

CPaintDC paintDC(this);
paintDC.MoveTo(50, 50);
paintDC.LineTo(150, 100);
===========================================================
※※※ 小作业:让用户从编辑框输入坐标(x,y,宽,高),对这个用户指定的

区域进行截图!
------------------------------------- End

----------------------------------------------------------------

 

 

阅读(3242) | 评论(0) | 转发(0) |
0

上一篇:用Perl解析DLL

下一篇:Perl文件夹操作

给主人留下些什么吧!~~