开发环境
win7、office 2010。qt4、qt5都可以。vs版本匹配qt即可。
qtcreator对于超大cpp、h文件支持不如vs,例如50m的cpp文件,不推荐。
导出com组件接口类
运行regedit调出注册表编辑工具查询。
com的id在HKEY_LOCAL_MACHINE\SOFTWARE\Classes\TypeLib\中找。
搜索值“Microsoft Word 14.0 Object Library”可以找到“Microsoft Word”的guid为{000209FF-0000-0000-C000-000000000046}。
用qt自带的dumpcpp工具导出com组件的接口类,例如2013年,我导出word用的命令行为:
D:>C:\Qt\4.8.4\bin\dumpcpp {00020905-0000-0000-C000-000000000046}
dumpdoc:导出COM对应的QT可使用的接口文档。
D:>C:\Qt\4.8.4\bin\dumpdoc Word.Application -o word.html
dumpdoc、dumpcpp如果没有,那么源代码在C:\Qt\4.8.4\tools\activeqt。
其它接口的导出示例:
D:>C:\Qt\4.8.4\bin\dumpcpp {00020813-0000-0000-C000-000000000046} 导出excel
D:>C:\Qt\4.8.4\bin\dumpcpp {2DF8D04C-5BFA-101B-BDE5-00AA0044DE52} 导出office
Outlook,PowerPoint等等都类似。
不同office版本、不同office软件的guid不一样,在注册表中找到即可。
工程设置
工程设置中加入axcontainer。
工程中加入上一步导出的h、cpp文件。
示例代码
#include “word.h” //dumpcpp导出的代码文件
#include <ole2.h>
#include < QCoreApplication >
bool OpenDoc(const QString &doc_file_name){
Word::Application word;
word.SetVisible(true);
Word::Documents *docs = word.Documents();
if (docs == NULL)
{
word.Quit();
return false;
}
Word::Document *doc = docs->Open(QVariant(doc_file_name), QVariant(false), QVariant(true));
if (doc == NULL)
{
docs->Close();
word.Quit();
return false;
}
return true;
}
dumpcpp导出代码与dynamicCall、querySubObject代码之间的差别
以下方式函数名在字符串内,编译调试不太方便。优点是,只用了部分接口,dll文件较小,几百k。
bookmarkCode->dynamicCall(“Select(void)”);
bookmarkCode->querySubObject(“Range”)->setProperty(“Text”, strContent);
采用dumpcpp导出的接口代码是完整的office操作代码,编译出的dll文件较大,10M起。优点是,所有接口都有,编写代码方便。
任意功能的cpp实现
打开word、excel之类软件的宏录制功能,手动操作一次(希望用cpp代码实现的功能),停止宏录制,编辑刚才录制的宏,可以看到某种操作对应的vba代码。
cpp代码与vba代码有一定的相似,有的函数名完全相同,有的多了set、get。有的可以作为关键字去搜索。
找一个中文版的VBAWD10.CHM,有一定的参考作用。
例如:excel cell SetValue函数写超过256字节会失败(并不报错,只是未写入)。通过宏录制可知,ActiveCell.FormulaR1C1 = “1”,猜测有一个SetFormulaR1C1函数可用,测试发现可以支持256字节以上的字符串输入。
例如:通过宏录制可以知道excel行列自动适应内容变窄可以用AutoFit函数。隐藏行列可以用SetHidden(true)。
excel与word table之间的冲突问题
在一个进程内部,如果dll a操作了word table,那么dll b操作excel table时就无法将text写入cell。反之亦然。
跨进程没有此问题。
各种已知的资源释放都无用。
office com组件没有源码,无法调试,找不到原因。
解决办法:通过进程调用方式实现其中一个模块。