qt-获取任务栏运行的程序(一)

很多时候我们想要拿到任务栏上开启的程序,比如下面所示:

我们以window为例说明

  下面的代码主要部分就是通过一个回调函数: EnumWindows()

1、声明一个函数   static BOOL CALLBACK StaticEnumWindowsProc(HWND hwnd, LPARAM lParam);

2、实现如下

BOOL Widget::StaticEnumWindowsProc(HWND hwnd, LPARAM lParam)
{
    //窗口是否可视
    if (!::IsWindowVisible(hwnd))
        return TRUE;

    //窗口是否可激活
    if (!::IsWindowEnabled(hwnd))
        return TRUE;

    //确定给定窗口是否是最小化(图标化)的窗口。
    //if(IsIconic(hwnd))
      //  return TRUE;

    //窗口是否具有父窗口?
    HWND hParent = (HWND)GetWindowLong(hwnd, GWL_HWNDPARENT);
    //父窗口是否可激活?
    //据 Spy++ 观察,如“运行”对话框等被应列入列表的程序有一个隐藏的,具有 WS_DISABLED 的父窗口
    if (IsWindowEnabled(hParent))
        return TRUE;
    //父窗口是否可视?
    if (IsWindowVisible(hParent))
        return TRUE;

    LONG gwl_style = GetWindowLong(hwnd, GWL_STYLE);
    if ((gwl_style & WS_POPUP) && !(gwl_style & WS_CAPTION))
        return TRUE;

    CHAR caption[256];
    memset(caption, 0, sizeof(caption));
    ::GetWindowTextA(hwnd, caption, 255);

    if (strcmp(caption, ""))
    {
        if (GetClassLong(hwnd, GCL_HICON))
        {
            HICON hIcon =(HICON)GetClassLong(hwnd, GCL_HICON);
            if(hIcon)
            {
                handleIcon.push_back(hIcon);
                handleWindow.push_back(hwnd);
            }
        }
    }

    return TRUE;
}

3、然后调用 回调函数。在win32环境下,EnunWindows(StaticEnumWindowPro, NULL).如果是Qt环境,则EnumWindows(StaticEnumWindowsProc,reinterpret_cast<LPARAM>this)

---------------我是分割线--------------------

通过上面的几步,我们把符合条件的窗口句柄以及要用的图标句柄添加到QVector中(QVector<HWND> handleWindow; QVector<HICON>handleIcon)。下面就是把拿到的句柄展示出来

-----------------------GGGGGGG----------

4、我是在qt环境下显示的,当然你习惯用vc,那就用MFC的控件。

在一个QWidget中放置了一个QGridLayout布局,然后把QtoolButton用来显示图标。如下

void Widget::InitBtnIcon()
{
    int i;
    int nIconCount = 0;
    CHAR szProgramName[256] = {0};
    QString strName;

    nIconCount = handleIcon.count();
    if(nIconCount <= 0)
        return;

    if(nIconCount > 6)
    {
        nIconCount = 6;
        m_rightBtn->setVisible(true);
    }

    //加一个定时器,每隔一段时间就运行一遍Enumwindows
    //给6个Button默认的图标
    for(i = 0; i < nIconCount; i++)
    {
        //------------------
        //QPixmap pixmap = QtWin::fromHBITMAP(GetScreenCapture(handleWindow[i + m_nBtnMove]));
       // m_arrAction[i]->setIcon(pixmap);
        //m_arrAction[i]->setIconSize(QSize(pixmap.width(), pixmap.height()));
        //-----------------
        m_arrAction[i]->setIcon(QtWin::fromHICON(handleIcon[i + m_nBtnMove]));
//        m_arrAction[i]->setIconSize(QSize(QtWin::fromHICON(handleIcon[i]).width(),
//                                          QtWin::fromHICON(handleIcon[i]).height()));

        m_arrAction[i]->setIconSize(QSize(32, 32));

        //---------------
        //QPixmap pixmap = QtWin::fromHBITMAP(GetScreenCapture(handleWindow[i + m_nBtnMove]));
        //m_arrAction[i]->setIcon(pixmap);
        //m_arrAction[i]->setIconSize(QSize(pixmap.width(), pixmap.height()));
        //m_arrAction[i]->setIconSize(fromHBITMAP(GetScreenCapture()).);
        //---------------
        //screen capture
        //QScreen *screen = QGuiApplication::primaryScreen();
        //screen->grabWindow(GetWindowLong(handleWindow[i+ m_nBtnMove],GWL_ID),0,0,-1,-1).save("captureImg1.jpg","jpg");
        //screen->grabWindow(GetWindowLong(handleWindow[1],GWL_ID),0,0,-1,-1).save("captureImg3.jpg","jpg");
        //GetModuleFileName(handleWindow[i], szProgramName, 255);
        GetWindowTextA(handleWindow[i+ m_nBtnMove], szProgramName, 255);
        strName = QString::fromLocal8Bit(szProgramName);
        //strName = strName.lastIndexOf("\\");
        //m_arrAction[i]->setText(strName);
        m_arrAction[i]->setToolTip(strName);
        //m_arrAction[i]->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
    }
}

5、添加按钮的响应槽

for(int i = 0; i < 6; i++)
    {
        connect(m_arrAction[i], SIGNAL(clicked()), m_pSignalArrBtns, SLOT(map()));
        m_pSignalArrBtns->setMapping(m_arrAction[i], i);
    }
    connect(m_pSignalArrBtns, SIGNAL(mapped(int)), this, SLOT(slotClickBtn(int)));

  因为同一类型的控件很多,我们用到一个信号影射。这样,通过nIndex可以确定是谁发出的信号。然后下面是slotClickBtn()的实现

//ShowWindow(handleWindow[nIndex + m_nBtnMove], SW_RESTORE);
    ::SetWindowPos(handleWindow[nIndex + m_nBtnMove], 0, 0, 0, 0, 0,SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_SHOWWINDOW);

    //QScreen *screen = QGuiApplication::primaryScreen();
    //screen->grabWindow(GetWindowLong(handleWindow[i+ m_nBtnMove],GWL_ID),0,0,-1,-1).save("captureImg1.jpg","jpg");
    //screen->grabWindow(GetWindowLong(handleWindow[1],GWL_ID),0,0,-1,-1).save("captureImg4.jpg","jpg");

    //QMessageBox::information(this, "ddd", QString::number(nIndex));
    //GetScreenCapture(handleWindow[nIndex]);

  通过以上几步,我们大体就可以得到想要的结果,效果图如下:

但是有几个问题,第一:最小化的程序开的窗口不能识别,比如QQ,酷狗等。估计是因为窗口风格是WS_EX_LAYERED的原因。第二:资源管理器明显拿不到

 

注意,这几个函数需要添加头文件的支持:

#include<Windows.h> 以及静态库的支持  #pragma  comment(lib, "user32.lib")

如果是qt环境,则添加如下:

#include "Windows.h"  #include <QtWin>  、qtwinextras/qwinfunctions、以及库依赖#pragma  comment(lib, "user32.lib"), 并且在.pro文件中添加  QT += winextras

 

完成源代码如下:

邮箱xxxx

 

如果是用MFC的方式实现,那么用下面的方法:

// File: OpenProgramOnTaskbar.h

#pragma once
#include <vector>

struct TaskInfo 
{
    // 程序名称
    CString strProgramName;

    // 窗口句柄
    HWND hWnd;
};

class TaskbarInfo
{
public:
    // 回调函数
    static BOOL CALLBACK EnumWindowProc(HWND hWnd, LPARAM lParam);
public:

    // 记录在任务栏打开的程序
    std::vector<TaskInfo> m_TaskbarInfoArr;

    // 顶层窗口句柄
    HWND m_hWnd;

public:
    TaskbarInfo();
    ~TaskbarInfo();
    
    // 获得在任务栏打开程序信息
    void GetTaskbarInof (void);

    // 获得顶层窗口句柄,失败返回NULL
    HWND GetTopWnd (void);
};

  

// File: OpenProgramOnTaskbar.cpp

#include "stdafx.h"        // 如果编译出错,请删除这句
#include "OpenProgramOnTaskbar.h"

#include "Psapi.h"
#pragma comment(lib, "Psapi.lib")  

TaskbarInfo::TaskbarInfo()
{

}

TaskbarInfo::~TaskbarInfo()
{

}

void TaskbarInfo::GetTaskbarInof (void)
{
    EnumWindows(EnumWindowProc, (LPARAM)this);
}

BOOL CALLBACK TaskbarInfo::EnumWindowProc(HWND hWnd, LPARAM lParam)
{
    TaskbarInfo * pTaskbarInfo = (TaskbarInfo*)lParam;

    TCHAR szWindow[256]={0};
    TaskInfo taskInfo;

    ::GetWindowText(hWnd, szWindow, 255); //获取窗口标题
    if ( ::IsWindow(hWnd) &&
        ::IsWindowVisible(hWnd) &&
        (::GetWindowLong(hWnd, GWL_EXSTYLE)&WS_EX_TOOLWINDOW)!=WS_EX_TOOLWINDOW &&
        ::GetWindowLong(hWnd, GWL_HWNDPARENT)==0 )
    {
        DWORD dwPID;  //保存进程标识符

        GetWindowThreadProcessId(hWnd, &dwPID);  //接受一个窗口句柄。dwPID保存窗口的创建者的进程标识符,GetWindowThreadProcessId返回值是该创建者的线程标识符
        HANDLE hBrowser = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID);  //打开一个已存在的进程对象,并返回进程的句柄,这就是我们要的进程句柄了

        WCHAR exePath[256];
        memset(exePath, 0, 256);
        //获取程序的path,并保存到exePath
        GetModuleFileNameEx(hBrowser, NULL, exePath, MAX_PATH);
        CString strTemp = exePath;
        strTemp.MakeLower();
        
        // 过滤在桌面打开的文件夹等
        if (!strTemp.IsEmpty() && strTemp.Find(_T("explorer.exe")) == -1)
        {
            taskInfo.strProgramName = szWindow;
            taskInfo.hWnd = hWnd;
            pTaskbarInfo->m_TaskbarInfoArr.push_back(taskInfo);
            memset(szWindow, 0, 256);
        }
    }
    return TRUE;
}

HWND TaskbarInfo::GetTopWnd (void)
{
    DWORD dwPID;  //保存进程标识符
    HWND hWnd = NULL;
    hWnd = ::GetForegroundWindow();

    GetWindowThreadProcessId(hWnd, &dwPID);  //接受一个窗口句柄。dwPID保存窗口的创建者的进程标识符,GetWindowThreadProcessId返回值是该创建者的线程标识符
    HANDLE hBrowser = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID);  //打开一个已存在的进程对象,并返回进程的句柄,这就是我们要的进程句柄了

    WCHAR exePath[256];
    memset(exePath, 0, 256);
    //获取程序的path,并保存到exePath
    GetModuleFileNameEx(hBrowser, NULL, exePath, MAX_PATH);
    CString strTemp = exePath;
    strTemp.MakeLower();

    if (!strTemp.IsEmpty() && strTemp.Find(_T("explorer.exe")) == -1)
    {
        m_hWnd = hWnd;
        if (m_hWnd != NULL)
        {
            return m_hWnd;
        }
    }

    return NULL;
}

  

posted @ 2017-08-30 09:22  Qt王二狗  阅读(2757)  评论(0)    收藏  举报