Qt进程间使用Windows API通信

66 篇文章 3 订阅

一、前言

最近在想Qt如何远程更新程序,Qt将程序打包发布之后,如果在代码中做了一些细微的修改,只需要更新xxx.exe即可更新程序。如果没有自动远程更新程序,则需要我们自己将可执行程序发给对方,这样很麻烦。所以在程序中增加一个更新模块,一启动或按键触发去比对远程服务器上的软件版本号,如果软件版本号高于当前版本号,则弹窗选则更新或取消。然后把可执行文件下载下来,删除原先的可执行文件,把新下载的可执行文件改名,并放到合适的路径即完成远程更新。

问题就在如果我下载完,把程序关闭了(删除原先的可执行文件),谁去做后面这些工作呢?(把新下载的可执行文件改名,并放到合适的路径)

然后我就想到了,委托更新辅助程序去完成这个任务,主程序下载完成之后,使用​​QProcess process; process.start ("更新辅助程序.exe");​​启动更新辅助程序,退出主程序,然后完成后续操作(把新下载的可执行文件改名,并放到合适的路径)。

所以这就涉及到了进程间通信的问题!

二、效果展示

 

Qt学习基地:C/C++项目实战/Qt5/C语言/c++/数据库/OpenCV/MFC/QT项目-学习视频教程-腾讯课堂

三、接口详解

​​PostMessage​​是Windows API中的一个常用函数,用于将一条消息放入消息队列中。并且不会等待响应的线程处理消息,而是直接返回,简而言之就是异步。

​​SendMessage​​作用一样,但是会等到结果返回,简而言之就是同步。

BOOL WINAPI PostMessage(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);

​​hWnd​​​:其窗口程序接收消息的窗口的句柄。可取有特定含义的两个值:

|值| 含义 |

|:–|:–|

| HWND_BROADCAST | 消息被寄送到系统的所有顶层窗口,包括无效或不可见的非自身拥有的窗口、被覆盖的窗口和弹出式窗口;消息不被寄送到子窗口 |

| NULL | 此函数的操作和调用函数dwThread设置为当前线程的标识符PostThreadMessage函数一样 |

​​Msg​​:指定被寄送的消息;

​​wParam​​:指定附加的消息特定的信息;

​​LParam​​:指定附加的消息特定的信息;

​​返回值​​:如果函数调用成功,返回非零,否则函数调用返回值为零;

LRESULT SendMessage(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);

同上

​​返回值​​:指定消息处理的结果,依赖于所发送的消息;

接收消息的时候,使用Qt5中的方法是在的类中,重新实现nativeEvent函数(Qt4的时候使用winEvent,从Qt5开始,就使用nativeEvent),这个方法既可以拦截系统信息,也可以拦截通过​​postMessage​​​、​​sendMessage​​发送的自定义消息。

[virtual protected] bool QWidget::nativeEvent(const QByteArray &eventType, void *message, long *result);

​​eventType​​​:windows平台的值是​​windows_generic_MSG​​;

​​message​​:类型为MSG*,存储的就是PostMessage中的Msg;

​​Result​​:类型为LRESULT,返回的值;

​​返回值​​:如果返回true,表示停止这个消息;如果返回false,这个消息就继续传递给Qt,Qt会将这个消息转变为Qt event并将它发送给响应的控件;

四、关键代码

发送函数

void MainWindow::on_pushButton_clicked()
{
//查找窗口句柄(L 将该字符串当做Unicode来编译)
HWND hWnd = FindWindow(NULL, L"接收窗口");
if (hWnd == 0) {
return;
}
if (NULL != hWnd) {
QString command = ui->plainTextEdit->toPlainText();
std::string param = command.toStdString();
COPYDATASTRUCT data; //使用COPYDATA的方式进行数据传递
data.dwData = 0; //指定传输的数据
data.cbData = param.length(); //指定数据大小
data.lpData = &param[0]; //指向要传递到接收应用程序的数据的指针。可以为空
SendMessage(hWnd, WM_COPYDATA, 0, (LPARAM)&data);
}
}

接收函数

bool ReceiveWidget::nativeEvent(const QByteArray &eventType, void *message, long *result)
{
if (eventType == "windows_generic_MSG") //windows平台
{
MSG* msg = reinterpret_cast<MSG*>(message);
if (msg->message == WM_COPYDATA)
{
COPYDATASTRUCT *data = reinterpret_cast<COPYDATASTRUCT*>(msg->lParam);
QTextCodec *gbk = QTextCodec::codecForName("utf-8");
QString recevice = gbk->toUnicode((char *)(data->lpData));//转码
ui->plainTextEdit->appendPlainText(QString("系统收到消息:%1").arg(recevice));
return true;//消息不再进行传递,不再处理
}
}
return QWidget::nativeEvent(eventType, message, result);
}

五、完整代码

#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QDebug>
#include <QWidget>
#include <QTextCodec>
#include "receivewidget.h"
#ifdef Q_OS_WIN
#include <windows.h>
#endif
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
ReceiveWidget* rWidget;
private slots:
void on_pushButton_clicked();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
this->setWindowTitle("发送窗口");
rWidget = new ReceiveWidget;
rWidget->show();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_clicked()
{
//查找窗口句柄(L 将该字符串当做Unicode来编译)
HWND hWnd = FindWindow(NULL, L"接收窗口");
if (hWnd == 0) {
return;
}
if (NULL != hWnd) {
QString command = ui->plainTextEdit->toPlainText();
std::string param = command.toStdString();
COPYDATASTRUCT data; //使用COPYDATA的方式进行数据传递
data.dwData = 0; //指定传输的数据
data.cbData = param.length(); //指定数据大小
data.lpData = &param[0]; //指向要传递到接收应用程序的数据的指针。可以为空
SendMessage(hWnd, WM_COPYDATA, 0, (LPARAM)&data);
}
}

#ifndef RECEIVEWIDGET_H
#define RECEIVEWIDGET_H
#include <QDebug>
#include <QWidget>
#include <QTextCodec>
#ifdef Q_OS_WIN
#include <windows.h>
#endif
namespace Ui {
class ReceiveWidget;
}
class ReceiveWidget : public QWidget
{
Q_OBJECT
public:
explicit ReceiveWidget(QWidget *parent = nullptr);
~ReceiveWidget();
bool nativeEvent(const QByteArray &eventType, void *message, long *result);
private:
Ui::ReceiveWidget *ui;
};
#endif // RECEIVEWIDGET_H
#include "receivewidget.h"
#include "ui_receivewidget.h"
ReceiveWidget::ReceiveWidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::ReceiveWidget)
{
ui->setupUi(this);
this->setWindowTitle("接收窗口");
}
ReceiveWidget::~ReceiveWidget()
{
delete ui;
}
bool ReceiveWidget::nativeEvent(const QByteArray &eventType, void *message, long *result)
{
if (eventType == "windows_generic_MSG") //windows平台
{
MSG* msg = reinterpret_cast<MSG*>(message);
if (msg->message == WM_COPYDATA)
{
COPYDATASTRUCT *data = reinterpret_cast<COPYDATASTRUCT*>(msg->lParam);
QTextCodec *gbk = QTextCodec::codecForName("utf-8");
QString recevice = gbk->toUnicode((char *)(data->lpData));//转码
ui->plainTextEdit->appendPlainText(QString("系统收到消息:%1").arg(recevice));
return true;//消息不再进行传递,不再处理
}
}
return QWidget::nativeEvent(eventType, message, result);
}

 进群领取qt开发学习资料以及技术交流  在下方↓↓↓↓↓↓↓↓

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值