当前位置: 首页 > news >正文

通过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: _GUIDstd::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;
}

总结

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


http://www.mrgr.cn/news/62820.html

相关文章:

  • C#/WinForm如何制作Windows桌面特效(宠物等)
  • 【Mac】Homebrew
  • 块设备驱动的基本概念
  • PFC前端电路 -- EMI电路
  • rsync异地备份
  • cdga|一线城市与二线城市企业的数据治理落地差异
  • 【安装配置教程】一、windows安装并配置java8
  • RabbitMQ怎么保障消息的可靠性
  • aab上架谷歌市场流程(apk)
  • python爬取旅游攻略(1)
  • 强化学习数学基础学习(三)
  • 【随笔】为什么transformer的FFN先升维后降维FFN的作用
  • 搜维尔科技:Manus数据手套在水下捕捉精确的手指动作, 可以在有水的条件下使用
  • 全面解析云渲染:定义、优势、分类与发展历程
  • java-参数传递与接收
  • 基于SSM+小程序的宿舍管理系统(宿舍1)
  • 【VM实战】VMware迁移到VirtualBox
  • 【c++篇】:模拟实现string类--探索字符串操作的底层逻辑
  • vite构建Vue3项目:封装公共组件,发布npm包,自定义组件库
  • 利用GATK对RNA-seq数据做call SNP 或 INDEL分析
  • VScode + PlatformIO 了解
  • 案例精选 | 石家庄学院大日志场景下的实名审计实践
  • Rust: 加密算法库 ring 如何用于 RSA 数字签名?
  • 罗马仕、西圣、安克充电宝哪款品牌更好?综合测评对比谁是TOP.1
  • 为Meta Spark准备3D模型
  • vue简介