通过QAxObject关闭已经打开的指定名称的Word文档

文章目录

  • 项目场景:
  • 问题描述
  • 原因分析:
  • 解决方案:
    • 解决方案一:
    • 解决方案二:
  • 总结

项目场景:

工业上位机通常需要对测试的各种数据做一个报表导出功能,报表导出一般是基于一个模板导出。也就是先打开一个报表模板,在这个模板上进行数据的导入,最后再保存。


问题描述

在导出报表功能开发中,由于软件突发的崩溃导致报表导出中断,此时报表模板处于打开状态,重开软件就会出现异常。


原因分析:

由于每次打开软件都会清空报表模板缓存目录的所有文件,同时关闭的软件时候也会清空对应的目录文件。这里有报表目录的缓存目录这样做是为了确保报表模板的一致性,不会出现重复模板。由于软件在导出报表的时候出现崩溃,所以报表模板并没有在软件关闭的时候被删除,这就导致文档的进程始终运行。


解决方案:

解决方案一:

直接关闭整个wps或者word即可
这个方案属于一刀切,如果用户打开了其他的Word文档呢?那就影响了客户的使用体验。所以不合适。
方案的思路是,首先通过Windows的API获取到WPS的进程,将他关闭。

解决方案二:

关闭指定的文档,同时保留窗口状态(最大化最小化等)
这个方案是最优解,但是实现起来存在一些问题。
有两种方式去处理,第一种是通过Windows的API去找对应的PID,接着找对应文档名称,再发送信息让对应的进程关闭这个文档。
第二种是使用微软的COM接口,使用 Q A x O b j e c t QAxObject QAxObject来处理。

第一方式,我查了很多资料,翻遍了AI,都不能很好关闭的指定文档名称对应的进程,主要是找到这个指定文档进程,找不到。找到软件的PID可以。或许这里是我没找到,方法是有的,毕竟我对WIndowsAPI确实不是很熟悉。第一种方法,遂罢。

第二种方式,通过QAxObject来做。问题在于,怎么拿到已经存在的进程的COM接口?
网上关于QAxObject操作Word以及自己写相关接口,基本都是类似下面的写法

QAxObject* m_word=new QAxObject();
m_word->setControl("kwps.Application");

我们可以看到这其实是新建了一个对象,相当于新开了一个进程,并不是我们已经打开的文档对应的进程。
其实更好的情况应该是类似于拷贝构造函数,如下的写法

IDispatch* existPoint;//这里表示我们要的已经打开的WPS进程对应的COM指针
QAxObject* m_word=new QAxObject(existPoint);

所以现在的问题就成了如何找到这个进程对应的COM指针。
这里踩了不少坑,这里就不做阐述了,直接放一下代码,再配一下说明。

主要的流程就是获取打开指定名称的进程的唯一ID,即windows中的_GUID,接着转换一下格式,来获取当前已经激活进程的对应ID,再获取这个进程的COM接口,在使用QAxObject操作word那一套进行处理,关闭之类。这个VBA接口要参考一下微软的文档。
微软Word接口参考

void CloseWPSDocument(const std::string& documentpath)
{
	IDispatch* pDisp=nullptr;
	CLSID clsid;//进程的唯一ID: _GUID
	std::string strProcessID="kwps.Application";//由于数字的进程号直接转wchar_t类型有很多问题,所以这里直接用进程名称了
	//下面就是各种转格式,满足GetActiveObject函数的参数类型要求
	wchar_t wp[1024]{};
	int wide_len=MultiByteToWideChar(GetACP(),0,strProcessID.c_str(),-1,nullptr,0);
	MultiByteToWideChar(GetACP(),0,strProcessID.c_str(),-1,wp,wide_len);
	HRESULT hr=CLSIDFromProgID(wp,&clsid);
	//这个函数就把获取到的进程的COM接口返回给这个pDisp指针
	hr=GetActiveObject(clsid,nullptr,(IUnknown **)&pDisp);
	//IDispatch是COM中的一个接口,用于提供对象的属性和方法的动态访问。任何实现了IDispatch接口的对象都可以通过QAxObject进行操作
	QAxObject* m_word=new QAxObjcet(pDisp);
	//记录窗口状态
	int windowstate=m_word->property("WindowState").toInt();
	if(!m_word->isNull())
	{
		QAxObject* m_documents=m_word->querySubObject("Documents");
		QAxObject* m_document=m_documents->querySubObject("Open(QString&"),QString::fromStdString(documentPath));
		if(m_document)
			m_document->dynamicCall("Close(bool)",false);
		
	}
	//关闭文件后窗口会保持打开所以这里需要恢复初始状态
	m_word->setProperty("WindowState",windowsate);
	delete m_word;
}

总结

这篇博客的意义是记录一下删除文件出现异常的处理,由于网上没看到合适的解决方案,所以这里做一个记录。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/905479.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

PAT甲级-1074 Reversing Linked List

题目 题目大意 给一个链表的头结点和总节点个数,以及k。每k个节点的链表都要翻转。 思路 链表可以用一个结构体数组来存储,先遍历一遍,过滤掉不在链表中的节点。然后将过滤好的节点放入res数组中,每k个元素用一次reverse()&…

PHP + Windows小皮面板 + VScode 安装教程

目录 1. 小皮面板安装包 下载 2、配置MySQL 可以在cmd命令框中使用 3. VScode安装 如有错误,烦请批评指正 1. 小皮面板安装包 下载 官方地址https://old.xp.cn/download.html 下载完后,一路next,文件路径自定义 2、配置MySQL 可以在cm…

ESP8266联网

目录 1.ESP8266连接热点 2.ESP8266创建热点 创建热点的ESP8266 连接热点的ESP8266 3.发送网络请求 案例一 案例二 4.连接服务器 接收信息开关灯 发布消息开关灯 5.ESP8266创建HTTP服务 ​编辑 ​编辑 ​编辑 6.ESP8266HTTP请求控制灯 ​编辑 7.ESP8266接收后端数据…

聊一聊Qt中的按钮

目录 QAbstractButton 功能概述 快捷键 默认按钮 按钮状态 自动重复功能 切换按钮 信号 子类化 API列表 QPushButton 按钮外观与功能 默认按钮 按钮的状态与模式 使用建议 菜单按钮 API QToolButton 创建工具按钮 用途示例 自动抬起功能 图标设置 外观与…

使用RabbitMQ实现微服务间的异步消息传递

使用RabbitMQ实现微服务间的异步消息传递 RabbitMQ简介 安装RabbitMQ 在Ubuntu上安装RabbitMQ 在CentOS上安装RabbitMQ 配置RabbitMQ 创建微服务 生产者服务 安装依赖 生产者代码 消费者服务 消费者代码 运行微服务 消息模式 直接模式 生产者代码 消费者代码 扇出模式 生产…

「实战应用」如何在 DHTMLX Scheduler 中实现动态主题切换?

创建响应式、直观的 UI 需要适应用户对应用程序各个方面的偏好。其中一项可显著提升用户体验的热门功能是能够在明暗主题之间切换。它在日程安排日历等综合组件中尤其有用。 本文将指导您在 DHTMLX Scheduler 中实现动态主题切换,使其适应用户设置的首选系统主题。…

Marin说PCB之电源的Surface Current Density知多少?

小编我是一位资深的国漫迷,像什么仙逆,斗破,斗罗,完美世界,遮天,凡人修仙传,少年歌行等,为了可以看这些视频小编我不惜花费了攒了很多年的私房钱去开了这个三个平台的会员啊&#xf…

【YApi】接口管理平台

一、简介 YApi 是一个用于前后端开发团队协作的 API 管理平台,帮助团队更加高效地进行 API 接口的设计、测试、文档管理和版本控制等工作。 YApi 主要功能: API 设计和管理:提供 API 设计和文档生成工具,使开发者能够轻松创建、…

【C/C++】字符/字符串函数(1)——由string.h提供

零.导言 什么是字符/字符串函数呢? 其实就是一类用于处理字符和字符串的函数。 而其中一部分函数包含在头文件 string.h 中,有 strlen strcpy strcat strcmp strncpy strncat strncmp strstr strtok strerror 等等 接下来我将逐个讲解这些函数。 一.str…

简单的kafkaredis学习之redis

简单的kafka&redis学习之redis 2. Redis 2.1 什么是Redis Redis是一种面向 “Key-Value” 数据类型的内存数据库,可以满足我们对海量数据的快速读写需求,Redis是一个 NoSQL 数据库,NoSQL的全称是not only sql,不仅仅是SQL&…

在 Visual Studio 中使用 Eigen 库

在 Visual Studio 中使用 Eigen 库 参考教程: 在 Visual Studio 中配置 Eigen库_vs调用eigen-CSDN博客 Eigen 是一个开源的 C 库,主要用来支持线性代数,矩阵和矢量运算,数值分析及其相关的算法。Eigen 除了需要 C 标准库以外&am…

认证鉴权框架之—sa-token

一、概述 Satoken 是一个 Java 实现的权限认证框架,它主要用于 Web 应用程序的权限控制。Satoken 提供了丰富的功能来简化权限管理的过程,使得开发者可以更加专注于业务逻辑的开发。 二、逻辑流程 1、登录认证 (1)、创建token …

MES(Manufacturing Execution System)制造执行系统解决方案 :高效协同, 实现数字化智能工厂

文章目录 引言I 常用功能模块车间实时数据设备维修证书管理II UI设计III 术语5M1Esee also引言 MES软件即制造企业生产过程执行管理软件,是一套面向制造企业车间执行层的生产信息化管理系统。 MES 可以为企业提供包括制造数据管理、计划排程管理、生产调度管理、库存管理、质…

Qt 实战(10)模型视图 | 10.5、代理

文章目录 一、代理1、简介2、自定义代理 前言: 在Qt的模型/视图(Model/View)框架中,代理(Delegate)是一个非常重要的概念。它充当了模型和视图之间的桥梁,负责数据的显示和编辑。代理可以自定义…

“北斗+实景三维”,助力全域社会治理

在国家治理体系和治理能力现代化的大背景下,全域社会治理成为提升国家治理效能的关键。“北斗实景三维”技术组合,为全域社会治理提供了新的技术支撑和解决方案。本文将探讨这一技术如何助力全域社会治理,以及其在实际应用中的潜力和挑战。 …

mysql8.0.32升级到8.0.40

上篇8.0.32库的准备:mysql: error while loading shared libraries: libncurses.so.5: cannot open shared object file: No suc-CSDN博客 此篇测试升级到8.0.40 MySQL :: Download MySQL Community Server rootjyc:~# mysql -u root -pabcd1234 mysql: [Warning]…

高阶数据结构--图(graph)

图(graph) 1.并查集1. 并查集原理2. 并查集实现3. 并查集应用 2.图的基本概念3. 图的存储结构3.1 邻接矩阵3.2 邻接矩阵的代码实现3.3 邻接表3.4 邻接表的代码实现 4. 图的遍历4.1 图的广度优先遍历4.2 广度优先遍历的代码 1.并查集 1. 并查集原理 在一…

go 聊天系统项目-1

1、登录界面 说明:这一节的内容采用 go mod 管理【GO111MODULE‘’】的模块,从第二节开始使用【GO111MODULE‘off’】GOPATH 管理模块。具体参见 go 包相关知识 1.1登录界面代码目录结构 代码所在目录/Users/zld/Go-project/day8/chatroom/ 1.2登录…

支持向量机背后的数学奥秘

一、基本概念与原理 1.1 支持向量机的定义 支持向量机是一种二分类模型,其核心思想是在样本空间中寻找一个超平面,将不同类别的样本分开。这个超平面被称为决策边界或分隔超平面。支持向量是距离决策边界最近的点,这些点决定了决策边界的位…

C语言指针和数组相关习题

目录 sizeof和一维int数组sizeof和一维char数组strlen()和一维char数组sizeof和字符串strlen()和字符串指针变量指向字符串字面常量易错点sizeof(a):sizeof是操作符 当心整型提升sizeof和二维数组复习一下相关知识点练习题 一个离谱的错误指针1指针2指针3指针4指针5指针6指针7指…