Qt加载第三方程序并将其显示在主界面中

代码说明:

 Widget 类:

Widget(QWidget *parent = nullptr): 构造函数,设置窗口标题和大小,启动外部程序,并创建WindowChecker对象和子线程。
~Widget(): 析构函数,终止外部程序并清理资源。
onWindowChanged(HWND hwnd): 槽函数,当检测到窗口变化时调用,嵌入新的外部窗口。
embedExternalWindow(HWND hwnd, QWidget *parentWidget): 将外部窗口嵌入到Qt窗口中,设置外部窗口的父窗口和大小、位置。
WindowChecker 类:

WindowChecker(DWORD processId): 构造函数,初始化processId和currentHwnd。
~WindowChecker(): 析构函数。
checkWindows(): 检查窗口函数,调用EnumWindows枚举所有顶层窗口。
EnumWindowsProc(HWND hwnd, LPARAM lParam): 回调函数,用于枚举所有顶层窗口,检查窗口是否属于目标进程并发出信号。
QThread:

创建QThread对象并将WindowChecker对象移动到子线程。
使用QTimer定期触发子线程的窗口检查。

 

.pro文件 

QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++17

# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
    main.cpp \
    widget.cpp \
    windowchecker.cpp

HEADERS += \
    widget.h \
    windowchecker.h

FORMS += \
    widget.ui

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

win32:LIBS += -luser32

RESOURCES += \
    descr.qrc

.h文件 

windowchecker.h 

#ifndef WINDOWCHECKER_H
#define WINDOWCHECKER_H

#include <Windows.h>
#include <QObject>
#include <QTimer>
#include <QDebug>

class WindowChecker : public QObject
{
    Q_OBJECT

public:
    WindowChecker(DWORD processId);
    ~WindowChecker();

public slots:
    void checkWindows();

signals:
    void windowChanged(HWND hwnd);

private:
    static BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam);
    DWORD processId;
    HWND currentHwnd;
};



#endif // WINDOWCHECKER_H

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QProcess>
#include <QThread>
#include <QVector>
#include "windowchecker.h"
#include <QMetaType>

QT_BEGIN_NAMESPACE
namespace Ui {
class Widget;
}
QT_END_NAMESPACE


class Widget : public QWidget
{
    Q_OBJECT

public:
     Widget(QWidget *parent = nullptr);
    ~Widget();
  // void embedExternalWindow(HWND hwnd, QWidget *parentWidget);

public slots:
    void onWindowChanged(HWND hwnd);


private:
    void embedExternalWindow(HWND hwnd, QWidget *parentWidget);


    Ui::Widget *ui;
    QProcess *process;
    HWND currentHwnd;
    QThread *checkerThread;
    WindowChecker *windowChecker;
    DWORD processId;


};
#endif // WIDGET_H

.cpp

 windowchecker.cpp

#include "windowchecker.h"

// WindowChecker 构造函数
WindowChecker::WindowChecker(DWORD processId)
    : processId(processId)
    , currentHwnd(nullptr)
{
}

// WindowChecker 析构函数
WindowChecker::~WindowChecker() {}

// 回调函数,用于枚举所有顶层窗口
BOOL CALLBACK WindowChecker::EnumWindowsProc(HWND hwnd, LPARAM lParam)
{
    WindowChecker *checker = reinterpret_cast<WindowChecker*>(lParam);
    DWORD windowProcessId;
    GetWindowThreadProcessId(hwnd, &windowProcessId);

    // 如果窗口属于目标进程,并且窗口是可见的
    if (windowProcessId == checker->processId && hwnd != checker->currentHwnd && IsWindowVisible(hwnd))
    {
        checker->currentHwnd = hwnd;
        emit checker->windowChanged(hwnd);
        return FALSE; // 停止枚举窗口
    }
    return TRUE; // 继续枚举窗口
}

// 检查窗口函数
void WindowChecker::checkWindows()
{
    EnumWindows(EnumWindowsProc, reinterpret_cast<LPARAM>(this));
}

 

whidgt.cpp 

#include "widget.h"
#include "ui_widget.h"
#include <QApplication>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
    , process(nullptr)
    , currentHwnd(nullptr)
    , checkerThread(new QThread(this))
    , windowChecker(nullptr)
    , processId(0)
{
    ui->setupUi(this);
    setWindowTitle("Qt Main Window");
    //resize(1200, 800);

    // 启动外部程序
    process = new QProcess(this);
    // 替换为实际的外部程序路径
  
    process->start("C:\\Users\\ROG10030\\Desktop\\NetAssist.exe");

    // 获取进程ID
    processId = process->processId();
    qDebug() << "进程ID:\n" << processId <<"\n";

    // 创建 WindowChecker 对象
    windowChecker = new WindowChecker(processId);

    // 将 WindowChecker 移动到子线程
    windowChecker->moveToThread(checkerThread);

   // 将 HWND 注册为元类型。让 Qt 的元对象系统识别并正确处理 HWND 类型的参数。
    qRegisterMetaType<HWND>("HWND");

    // 连接信号和槽
    connect(checkerThread, &QThread::started, windowChecker, &WindowChecker::checkWindows);
    connect(windowChecker, &WindowChecker::windowChanged, this, &Widget::onWindowChanged);


    // 使用定时器定期触发子线程的窗口检查
    QTimer *timer = new QTimer(this);
    connect(timer, &QTimer::timeout, windowChecker, &WindowChecker::checkWindows);
    timer->start(1000); // 每秒检查一次

    checkerThread->start();
}

/*
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    // 设置主窗口的大小
    setWindowTitle("Qt Main Window");
    resize(800, 600);

    // 创建 QWidget 作为外部程序窗口的容器
    //QWidget *container = new QWidget(this);
    //container->setGeometry(10, 10, 780, 580);

    // 启动外部程序
    process = new QProcess(this);
    process->start("D:\\Program Files (x86)\\Everything\\Everything.exe"); // 替换为实际的外部程序路径

    // 使用定时器等待外部程序启动
    QTimer::singleShot(400, this,[this]() {
        // 外部程序窗口的句柄(需要根据实际情况获取)
        HWND hwnd = FindWindow(NULL, L"Everything"); // 替换为实际窗口标题

        if (hwnd) {
            embedExternalWindow(hwnd, ui->widget);
        } else {
            qWarning() << "无法找到外部程序窗口";
        }
    });
}
*/
Widget::~Widget()
{
    delete ui;
    if (process) {
        process->terminate(); // 终止外部程序
        process->waitForFinished(); // 等待外部程序退出
    }

    checkerThread->quit();
    checkerThread->wait();
    delete windowChecker;

}

// 当窗口变化时的槽函数
void Widget::onWindowChanged(HWND hwnd)
{
    qDebug() << "当窗口变化时的槽函数";
    currentHwnd = hwnd;
    embedExternalWindow(hwnd, ui->widget);
}


void Widget::embedExternalWindow(HWND hwnd, QWidget *parentWidget)
{
    if (hwnd == nullptr || !IsWindow(hwnd)) {
        qWarning() << "无效的外部窗口句柄\n";
        return;
    }

    // 设置外部窗口的父窗口为 Qt 窗口
    SetParent(hwnd, (HWND)parentWidget->winId());

    // 设置外部窗口的大小和位置
    RECT rect;
    GetClientRect((HWND)parentWidget->winId(), &rect);
    MoveWindow(hwnd, 0, 0, rect.right, rect.bottom, TRUE);

    qDebug() << "嵌入成功";

    // 使外部窗口响应 Qt 窗口的消息
    SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) | WS_CHILD);

    // 确保外部窗口能够接收鼠标输入
    SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_CONTROLPARENT);
}

 

main.cpp

#include "widget.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();
    return a.exec();
}

 目前上述程序调用绿色软件没有问题,调用安装程序,微信,向日葵等在有的电脑上不行,原因未知

  • 11
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值