widgetcontainer.cpp 6.76 KB
#include "widgetcontainer.h"

#ifdef Q_OS_WIN32
#include <string>
#include <functional>
#include <iostream>
#include <fstream>
#include <QProcess>
#include <QWindow>
#include <QDebug>
#include <QVBoxLayout>
#include <QFileInfo>

WidgetContainer::WidgetContainer(QWidget *parent)
  :QMainWindow(parent)
{

}

WidgetContainer::~WidgetContainer()
{
    if (nullptr != mHandleExternWindow) {
        mHandleExternWindow->setParent(nullptr);
    }
}

bool WidgetContainer::createContainer(const QString &iAppName, const QStringList &iOpenParam, bool iAutoOpen)
{
    Q_UNUSED(iAutoOpen)
    QList<DWORD> procIdLst = findProcessId(iAppName);

    //kill the processes
    for (DWORD procId: procIdLst) {
        QProcess process;
        process.start("Taskkill", QStringList() << "/PID" << QString::number(procId) << "/F");
        process.waitForStarted();
        process.waitForReadyRead();
        process.waitForBytesWritten();
    }

    DWORD procId = qStartUpProcessSyn(iAppName, iOpenParam);
    if (procId == 0) {
        return false;
    }

    handle_data data;
    data.processId = procId;
    data.wndHandle = nullptr;

    EnumWindows([](HWND wnd, LPARAM lParam)->BOOL
    {
        handle_data &data = *(handle_data*)lParam;
        DWORD thProcId = 0;
        GetWindowThreadProcessId(wnd, &thProcId);
        //check if it is mainwindow
        BOOL isMainWnd = GetWindow(wnd, GW_OWNER) == nullptr && IsWindowVisible(wnd);

        if (thProcId == data.processId && isMainWnd) {
            data.wndHandle = wnd;
            return -1;
        }
        return 1;
    }
    , (LPARAM)&data);
    if (nullptr == data.wndHandle) {
        return false;
    }
    mHandleExternWindow = QWindow::fromWinId((WId) data.wndHandle);
    if (nullptr != mHandleExternWindow) {
        mWgtContainer = createWindowContainer(mHandleExternWindow, this);
        mWgtContainer->setMinimumSize(500, 300);
        mWgtContainer->activateWindow();
        mWgtContainer->setFocus();
        setCentralWidget(mWgtContainer);
        return true;
    }
    return false;
}

bool WidgetContainer::eventFilter(QObject *obj, QEvent *ev)
{
    if (obj == this->parent()) {
        if (ev->type() != QEvent::HoverMove && ev->type() != QEvent::Paint) {
            if (ev->type() == QEvent::WindowDeactivate) {
                QPoint cursorPos = QCursor::pos();
                QPoint gTopLeft = this->mapToGlobal(mWgtContainer->geometry().topLeft());
                QPoint gBottomRight = this->mapToGlobal(mWgtContainer->geometry().bottomRight());
                QRect rec(gTopLeft, gBottomRight);
                if (rec.contains(cursorPos)) {
                    mWgtContainer->setFocus();
                }
            }
        }
    }
    return false;
}

QList<DWORD> WidgetContainer::findProcessId(const QString &iAppName)
{
    QFileInfo fileInfo(iAppName);
    QString appName = fileInfo.fileName();
    HANDLE hProcessSnap = nullptr;
    PROCESSENTRY32 pe32;

    // Take a snapshot of all processes in the system.
    hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (hProcessSnap == INVALID_HANDLE_VALUE) {
        return QList<DWORD>();
    }

    // Set the size of the structure before using it.
    pe32.dwSize = sizeof(PROCESSENTRY32);

    // Retrieve information about the first process,
    // and exit if unsuccessful
    if (!Process32First(hProcessSnap, &pe32)) {
        CloseHandle(hProcessSnap);
        return QList<DWORD>();
    }

    // Now walk the snapshot of processes, and
    // find out the app's handle
    QList<DWORD> processIdLst;
    do {
#ifndef UNICODE
        if (std::string(pe32.szExeFile).find(appName.toStdString()) != std::string::npos) {
            processIdLst << pe32.th32ProcessID;
        }
#else
        if (std::wstring(pe32.szExeFile).find(appName.toStdWString()) != std::wstring::npos) {
            processIdLst << pe32.th32ProcessID;
        }
#endif

    } while (Process32Next(hProcessSnap, &pe32));

    return processIdLst;
}

DWORD WidgetContainer::startUpProcess(const QString &iAppName, const QString &iArguments)
{
    Q_UNUSED(iArguments);
#ifndef UNICODE
    std::string filePath = iAppName.toStdString();
    std::ifstream ifExists(filePath);
    bool fileExists = true;
    if (!ifExists.good()) {
        fileExists = false;
        QString path(std::getenv("path"));
        for (const QString& onePath: path.split(";")) {
            std::ifstream ifExists(QString(onePath + "/" + iAppName).toStdString());
            if (ifExists.good()) {
                filePath = QString(onePath + "/" + iAppName).toStdString();
                fileExists = true;
                break;
            }
        }
    }
#else
    std::wstring filePath = iAppName.toStdWString();
    std::wifstream ifExists(filePath);
    bool fileExists = true;
    if (!ifExists.good()) {
        fileExists = false;
        QString path(std::getenv("path"));
        for (const QString& onePath: path.split(";")) {
            std::wifstream ifExists(QString(onePath + "/" + iAppName).toStdWString());
            if (ifExists.good()) {
                filePath = QString(onePath + "/" + iAppName).toStdWString();
                fileExists = true;
                break;
            }
        }
    }
#endif

    if (!fileExists) {
        return 0;
    }

    // additional information
    STARTUPINFO si;
    PROCESS_INFORMATION pi;

    // set the size of the structures
    ZeroMemory( &si, sizeof(si) );
    si.cb = sizeof(si);
    ZeroMemory( &pi, sizeof(pi) );

    // start the program up
    CreateProcess(filePath.c_str(),   // the path
        NULL,        // Command line
        NULL,           // Process handle not inheritable
        NULL,           // Thread handle not inheritable
        FALSE,          // Set handle inheritance to FALSE
        0,              // No creation flags
        NULL,           // Use parent's environment block
        NULL,           // Use parent's starting directory
        &si,            // Pointer to STARTUPINFO structure
        &pi             // Pointer to PROCESS_INFORMATION structure (removed extra parentheses)
        );
    // Close process and thread handles.
    CloseHandle( pi.hProcess );
    CloseHandle( pi.hThread );
    return pi.dwProcessId;
}

DWORD WidgetContainer::qStartUpProcessSyn(const QString &iAppName, const QStringList &iArguments)
{
    mProcess = new QProcess(this);
    mProcess->start(iAppName, iArguments);
    mProcess->waitForStarted();
    mProcess->waitForReadyRead();
    mProcess->waitForBytesWritten();
    return mProcess->pid()->dwProcessId;
}

HWND WidgetContainer::findWindowHandle(const QString &iClassName, const QString &iWindowName)
{
#ifdef UNICODE
    return FindWindow(iClassName.toStdWString().data(), iWindowName.toStdWString().data());
#else
    return FindWindow(iClassName.toStdString().data(), iWindowName.toStdString().data());
#endif
}
#endif