1. 程式人生 > >Qt學習筆記:清除用QAxObject建立的Office程序

Qt學習筆記:清除用QAxObject建立的Office程序

環境

系統:Windows10 64位 家庭中文版
Qt版本:5.6.0 msvc2013 32位
編譯器:Visual Studio 2013 專業版

目的

在Qt中,當程式非正常關閉時,用QAxObject建立的Office程序不會隨著程式的關閉而關閉,導致程序殘留。我們需要及時地清理這些程序,注意:不能不加區分地清理Office的程序,因為Office程序有可能是Qt程式建立的也有可能是Office本身建立的。

步驟

1.獲取殘留的Office程序的Pid,關鍵程式碼:

//根據程序名獲取pid
QList<int> Widget::getListPidByName(const char *strName)
{
    QList<int> lstPid;
    HANDLE hProcess;
    PROCESSENTRY32 processEntry;
    processEntry.dwSize = sizeof(PROCESSENTRY32);
    BOOL bRet;
    //進行程序快照
    hProcess = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); //TH32CS_SNAPPROCESS快照所有程序
    //開始程序查詢
    bRet = Process32First(hProcess, &processEntry);
    //迴圈比較,得出ProcessID
    while(bRet)
    {
        QString temp = QString::fromWCharArray(processEntry.szExeFile);
        if(strcmp(strName, temp.toLocal8Bit()) == 0)
        {
            lstPid.append(processEntry.th32ProcessID);
        }
        bRet = Process32Next(hProcess, &processEntry);
    }
    return lstPid;
}

2.根據程序的Pid獲取父Pid,關鍵程式碼:

//根據程序的Pid獲取父Pid
DWORD Widget::getParentPidByPid(DWORD dwProcessId)
{
    LONG                        status = -1;
    DWORD                       dwParentPid = (DWORD)-1;
    HANDLE                      hProcess = NULL;
    PROCESS_BASIC_INFORMATION   processBasicInformation;

    PROCNTQSIP NtQueryInformationProcess = (PROCNTQSIP) GetProcAddress(
                GetModuleHandle(L"ntdll"), "NtQueryInformationProcess");

    if (NULL == NtQueryInformationProcess)
    {
        return (DWORD)-1;
    }
    // Get process handle
    hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, dwProcessId);
    if (!hProcess)
    {
        return (DWORD)-1;
    }

    // Retrieve information
    status = NtQueryInformationProcess(hProcess,
                                       ProcessBasicInformation,
                                       (PVOID)&processBasicInformation,
                                       sizeof(PROCESS_BASIC_INFORMATION),
                                       NULL
                                       );

    //注意:這裡要用32位的編譯器,64位的編譯器得到的不是0而是 -1073741820
    if (!status)
    {
        dwParentPid = processBasicInformation.InheritedFromUniqueProcessId;
    }

    CloseHandle(hProcess);

    return dwParentPid;
}

3.根據父Pid來決定要不要殺死這個程序,關鍵程式碼:

//殺死程序
void Widget::killProcess(const QList<int> &lstSubPid, const QList<int> &lstParentPid)
{
    int nParentPid = -1;
    //遍歷子程序
    for (int i = 0; i < lstSubPid.count(); ++i)
    {
        //獲取子程序的父程序
        nParentPid = getParentPidByPid(lstSubPid.at(i));
        //如果這個程序是由某個父程序建立的,則殺死
        if (lstParentPid.contains(nParentPid))
        {
            HANDLE hProcess = NULL;
            //開啟目標程序
            hProcess = OpenProcess(PROCESS_TERMINATE,FALSE, lstSubPid.at(i));
            if (hProcess == NULL)
            {
                qDebug()<<"Open Process fAiled ,error:"<<GetLastError();
            }
            //結束目標程序
            DWORD ret = TerminateProcess(hProcess,0);
            if(ret == 0)
            {
                qDebug()<<"kill task faild,error:"<<GetLastError();
            }
            else
            {
                qDebug()<<"kill task success ------------------------------------------------";
            }
        }
    }
}

注意:這裡這樣做的原因是:用QAxObject建立的Office程序的父程序和用Office建立的Office程序的父程序不是同一個程序。
示例原始碼