WindowFromPoint 可以获得坐标对应的窗口的句柄,而这个句柄值是系统唯一的。
GetParent 可以获得给定窗口句柄的父窗口
GetWindow(hParent, GW_CHILD); 可以获得给定窗口的子窗口
::GetNextWindow(hChild,GW_HWNDNEXT); 结合上面的GetWindow函数就可以枚举特定窗口的子窗口,然后就可以枚举当前所有窗口
GetWindowText 和GetClassName分别可以获得窗口的类名和标题
GetDeskTopWindow 可以获得当前桌面句柄,这里的桌面并不是指用户桌面,而是当前桌面环境的第一个窗口,使用spy++观察如下:
由此我们可以首先得到桌面的句柄,然后通过上述函数枚举到当前所有的窗口。下面我们将会需要这一功能。
对应资源管理器黑色部分
可以发现,此区域并没有文件夹路径的信息。在其它区域使用spy++后发现:
我们可以发现,在地址栏存在当前的绝对路径,而我们平时习惯使用的下方的区域则与地址栏在同一个类的子类下方。那么我们就可以得到鼠标下面的窗口的句柄和类,然后得到顶层的“CabinetWClass”类,然后再枚举其子类就可以得到地址栏的地址。
系统有很多DirectUIHWND 类的窗口,但是当且仅当其父类窗口为“SHELLDLL_DefView”时代表的是一个资源管理器。
相应代码:
#include <Windows.h>#include <stdio.h>void EnumWindows(HWND hParent,LPCSTR szTargetClassName){ CHAR szClass[0x100]; HWND hChild = GetWindow(hParent, GW_CHILD); if (hChild) { EnumWindows(hChild,szTargetClassName); while (hChild = GetWindow(hChild, GW_HWNDNEXT)) { EnumWindows(hChild, szTargetClassName); } } GetClassNameA(hParent, szClass, 0x100); if (strcmpi(szTargetClassName,szClass) == 0) { HWND hEnumParent = hParent; for (int i = 0; i < 6; i++) { GetClassNameA(hEnumParent, szClass, 0x100); PRintf("%8p/t%s/r/n", hEnumParent, szClass); hEnumParent = GetParent(hEnumParent); } printf("/r/n"); }}int main(){ //EnumWindows(GetDesktopWindow(),"DirectUIHWND"); EnumWindows(GetDesktopWindow(), "SHELLDLL_DefView"); getchar(); getchar(); return 0;}通过查找窗口句柄可以发现其中三个句柄都属于同一个资源管理器窗口而另一个则同属于explorer 进程
3. 然后就是桌面窗口句柄的处理,同样使用spy++获得句柄并观察:
我们发现窗口使用的是SysListView32 类(CListCtrol控件也使用的这个类)而其父窗口类与资源管理器一样是SHELLDLL_DefView,通过枚举SHELLDLL_DefView 类及其父窗口发现:
系统中只有两个SHELLDLL_DefView 类的窗口,都是我们想要的^_~,另外:
如果上面的用户桌面是在桌面显示文件的情况下获得的,当用户桌面的图标不予显示,获得的将直接是SHELLDLL_DefView 类窗口。
接下来的工作比较简单,判断窗口类或其父窗口类是否为SHELLDLL_DefView,然后通过得到父类以及子类枚举即可获得相应路径:
核心代码:
// DemoDlg.cpp : 实现文件//#include "stdafx.h"#include "Demo.h"#include "DemoDlg.h"#include "afxdialogex.h"#ifdef _DEBUG#define new DEBUG_NEW#endif// CDemoDlg 对话框CDemoDlg::CDemoDlg(CWnd* pParent /*=NULL*/) : CDialogEx(IDD_DEMO_DIALOG, pParent){ m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);}void CDemoDlg::DoDataExchange(CDataExchange* pDX){ CDialogEx::DoDataExchange(pDX);}BEGIN_MESSAGE_MAP(CDemoDlg, CDialogEx) ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_BN_CLICKED(IDC_BUTTON1, &CDemoDlg::OnBnClickedButton1) ON_WM_LBUTTONUP()END_MESSAGE_MAP()// CDemoDlg 消息处理程序BOOL CDemoDlg::OnInitDialog(){ CDialogEx::OnInitDialog(); // 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动 // 执行此操作 SetIcon(m_hIcon, TRUE); // 设置大图标 SetIcon(m_hIcon, FALSE); // 设置小图标 // TODO: 在此添加额外的初始化代码 return TRUE; // 除非将焦点设置到控件,否则返回 TRUE}// 如果向对话框添加最小化按钮,则需要下面的代码// 来绘制该图标。 对于使用文档/视图模型的 MFC 应用程序,// 这将由框架自动完成。void CDemoDlg::OnPaint(){ if (IsIconic()) { CPaintDC dc(this); // 用于绘制的设备上下文 SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0); // 使图标在工作区矩形中居中 int cxIcon = GetSystemMetrics(SM_CXICON); int cyIcon = GetSystemMetrics(SM_CYICON); CRect rect; GetClientRect(&rect); int x = (rect.Width() - cxIcon + 1) / 2; int y = (rect.Height() - cyIcon + 1) / 2; // 绘制图标 dc.DrawIcon(x, y, m_hIcon); } else { CDialogEx::OnPaint(); }}//当用户拖动最小化窗口时系统调用此函数取得光标//显示。HCURSOR CDemoDlg::OnQueryDragIcon(){ return static_cast<HCURSOR>(m_hIcon);}void CDemoDlg::OnBnClickedButton1(){ SetCapture();}void CDemoDlg::OnLButtonUp(UINT nFlags, CPoint point){ ReleaseCapture(); //释放鼠标的捕获 CPoint Point(point); //获得当前鼠标的位置相对于整个屏幕的 CHAR szClass[100]; ClientToScreen(&Point); //转换成相对于当前用户的窗口的位置 HWND hChooseHandle = ::WindowFromPoint(Point); HWND hParent = ::GetParent(hChooseHandle); CHAR path[255]; // 得到当前鼠标所在的窗口,判断是桌面还是资源管理器 GetClassNameA(hParent, szClass, 100); if (_stricmp(szClass, "SHELLDLL_DefView") == 0) { hParent = ::GetParent(hParent); GetClassNameA(hParent, szClass, 100); if (_stricmp(szClass, "WorkerW") == 0) { SHGetSpecialFolderPathA(0, path, CSIDL_DESKTOPDIRECTORY, 0); MessageBoxA(NULL, path, NULL, MB_OK); } else { hParent = hChooseHandle; for (int i = 0; i < 6; i++) { hParent = ::GetParent(hParent); } CHAR* szBuffer[6] = { ("WorkerW"),("ReBarWindow32"),("Address Band Root"),("msctls_progress32"),("Breadcrumb Parent"),("ToolbarWindow32") }; for (int i = 0; i < 6; i++) { HWND hChild = ::GetWindow(hParent, GW_CHILD); while (hChild != NULL) { GetClassNameA(hChild, szClass, 100); if (_stricmp(szClass, szBuffer[i]) == 0) { hParent = hChild; break; } hChild = ::GetNextWindow(hChild, GW_HWNDNEXT); } } ::GetWindowTextA(hParent, path, 100);//得到资源管理器所代表的文件夹路径 MessageBoxA(NULL, path + strlen("路径:"), NULL, MB_OK); } } else { GetClassNameA(hChooseHandle, szClass, 100); if (_stricmp(szClass, "SHELLDLL_DefView") == 0) { SHGetSpecialFolderPathA(0, path, CSIDL_DESKTOPDIRECTORY, 0); MessageBoxA(NULL, path, NULL, MB_OK); } else { } } CDialogEx::OnLButtonUp(nFlags, point);}
新闻热点
疑难解答