如何获得指定进程的主窗口

来源:互联网 发布:大学书包知乎 编辑:程序博客网 时间:2024/05/04 00:37

 

我们知道一个进程可能是没有主窗口(比如系统的服务进程)而有的进程可能又拥有不止一个的主窗口(比如OutLook软件),那么我们该如何才能取得指定进程的所有主窗口呢?

我们必须明确我们感兴趣“主窗口”这个概念,到底什么样的窗口才是主窗口,他应该具有那些特点。
首先,主窗口必须是可见的也就是拥有WS_VISABLE属性(其实也有很多不可见的主窗口,但是我们在这里暂不考虑
      这一点)
其次,主窗口应该是没有父窗口,也就是他的父窗口句柄为NULL.。

有了这两个条件我们就可以着手实现部分了。

要取得指定进程的主窗口的一般方法为
使用EnumWindows函数,枚举出所有的符合主窗口条件的上层窗口,然后通过GetWindowThreadProcessId函数获得
窗口所属的进程ID,如果所得到的进程ID和已知的进程ID相同,就说明该窗口是这个进程的一个主窗口。
上面就是基本的思路。

下面是本人设计的一个类,用来实现此项功能

#pragma once
#include <windows.h>
#include <vector>
class CProcessMainWndArray {
    DWORD m_dwProcessId;
    std::vector<HWND> m_vHwnd;
public:
    CProcessMainWndArray(DWORD dwProcessId = 0)
     : m_dwProcessId(dwProcessId) {
        m_vHwnd.clear();
        EnumWindows(enumProc, (LPARAM)this);
    }
    ~CProcessMainWndArray() {};
private:
    static BOOL __stdcall enumProc(HWND hWnd, LPARAM lParam) {
        CProcessMainWndArray* pWndIterator = (CProcessMainWndArray*)lParam;
        DWORD dwCurProcessId;
        GetWindowThreadProcessId(hWnd, &dwCurProcessId);
        if ((GetWindowLong(hWnd, GWL_STYLE) & WS_VISIBLE) &&
            GetParent(hWnd) == NULL &&
            (dwCurProcessId == pWndIterator->getCurProcessId())) {
            pWndIterator->getMainHwndArray()->push_back(hWnd);
        }
        return TRUE;
    }
private:
    DWORD getCurProcessId()
        { return m_dwProcessId; }
    std::vector<HWND>* getMainHwndArray()
        { return &m_vHwnd; }
public:
    bool isEmpty()
        { return m_vHwnd.empty(); }
    std::vector<HWND>::iterator begin()
        { return m_vHwnd.begin(); }
    std::vector<HWND>::iterator end()
        { return m_vHwnd.end(); }
    size_t size()
        { return m_vHwnd.size(); }
    HWND operator[](int nIndex)
        { return m_vHwnd[nIndex]; }
};

该类的使用非常简单,例如

#include <iostream>

int main()
{
    //0x0524为目标进程的ID
    CProcessMainWndArray wnd(0X0524);

    if (wnd.isEmpty()) {
        std::cout << "There are no main windows in target process" <<  std::endl;
        return -1;
    }
    //第一种方法
    std::cout << "The handles of this process are : " << std::endl;

    std::vector<HWND>::iterator iter = wnd.begin();
    for (iter; iter != wnd.end(); ++iter) {
        char szHwnd[MAX_PATH] = { 0 };
        sprintf(szHwnd, "0x%x", *iter);
        std::cout << szHwnd << std::endl;
    }

    //第二种方法
    std::cout << "The handles of this process are : " << std::endl;

    for (size_t i = 0; i < wnd.size(); i++) {
        char szHwnd[MAX_PATH] = { 0 };
        sprintf(szHwnd, "0x%x", wnd[i]);
        std::cout << szHwnd << std::endl;
    }
 
    return 0;
}

//类的构造函数
//参数:dwProcessId目标进程的ID
//该函数的功能主要是枚举系统的所有上层窗口,并将窗口句柄记录在vector之中
CProcessMainWndArray(DWORD dwProcessId = 0)
  : m_dwProcessId(dwProcessId) {
    m_vHwnd.clear();
    EnumWindows(enumProc, (LPARAM)this);
}

//枚举窗口的回调函数
//参数:hWnd窗口句柄
//      lParam:应用程序定义的的32位值,在这里为CProcessMainWndArray类型的指针
//函数功能:回调函数用来枚举所有的上层窗口,并将符合条件窗口句柄存入m_vHwnd之中
//
static BOOL __stdcall enumProc(HWND hWnd, LPARAM lParam) {
    CProcessMainWndArray* pWndIterator = (CProcessMainWndArray*)lParam;
    DWORD dwCurProcessId;
    GetWindowThreadProcessId(hWnd, &dwCurProcessId);
    if ((GetWindowLong(hWnd, GWL_STYLE) & WS_VISIBLE) &&
        GetParent(hWnd) == NULL &&
        (dwCurProcessId == pWndIterator->getCurProcessId())) {
        pWndIterator->getMainHwndArray()->push_back(hWnd);
    }
    return TRUE;
}

//得到进程ID
DWORD getCurProcessId()
    { return m_dwProcessId; }

//得到记录窗口句柄的m_vHwnd的指针
std::vector<HWND>* getMainHwndArray()
    { return &m_vHwnd; }

//判断数组(m_vHwnd)是否为空,如果为空,说明该进程没有主窗口
bool isEmpty()
    { return m_vHwnd.empty(); }

//得到指向m_vHwnd第一个元素的迭代器
std::vector<HWND>::iterator begin()
    { return m_vHwnd.begin(); }

//得到指向m_vHwnd最后一个元素后面位置的迭代器
std::vector<HWND>::iterator end()
    { return m_vHwnd.end(); }

//取得m_vHwnd中句柄的数量
size_t size()
    { return m_vHwnd.size(); }

//运算符重载,用于返回存在于m_vHwnd数组中指定下标的句柄
HWND operator[](int nIndex)
    { return m_vHwnd[nIndex]; }


本例是参考msdn上的一篇文章,然后根据自己的思路重写了一个,放在这里和大家共享,希望能起到一个
抛砖引玉的作用,如果大家有其他好的方法,希望不吝赐教! :)