利用mfc打开txt,网页和office

碰到了一些问题,也学习到了些新东西,记录一下。

最近项目里需要开发一个新功能,接受客户端指令然后打开一些常用软件:文本,网页,office办公软件。

以前做过一个项目就是对网页的操作,当时是使用ShellExecute函数来解决的,ShellExecute函数是用来运行一个外部程序的,第二个参数设置为操作,我们设置为“open”,第三个参数为应用程序所在的路径,我们这里要打开的是网页,可以直接输入网站名,比如想要打开百度就设置为"http://www.baidu.com",最后一个参数设置为SW_SHOWNORMAL让该程序显示,即:

ShellExecute(NULL, "open", "http://www.baidu.com", NULL, NULL, SW_SHOWNORMAL);

这样就可以打开一个浏览器了。

创建并打开txt我也想用这个函数,于是我的思路就是这样的:

首先先利用CFile创建一个.txt文件,为了可以多次创建我们要避免重名,在对话框类里面声明一个成员变量int TxtNum来记录已经创建的txt数量,第一个创建的txt名字叫做“新建文本文档.txt”,第二个叫做“新建文本文档 (2).txt”,以此类推创建之后就可以利用ShellExecute函数将其打开,果然效果不错。

最后就是office了,那么office能不能也用这种简单的办法呢?我之所以有这个疑虑是有原因的,以前有过几次CFile创建的.m文件后缀名虽然是对的但是用MatLab却打不开。于是我就在我电脑上做了个实验,我的电脑上装的是office2010,Word后缀名是“.docx”,ppt是“.pptx”,Exel是“.xlsx”,我用上述的办法创建文件并打开有了以下发现:word,ppt可以,但是Exel试图打开的时候发现它显示文件损坏,后缀名改为“.xls”后弹出对话框:“您尝试打开的文件xxxx.xls的格式与文件扩展名指定的格式不一致,点击“是”后仍然好用。

不过我觉得这仍算是个BUG总出现这个客户看了也不好,于是我就换了个方法来实现,利用COM来实现,实际上非常简单,就是加载很麻烦,找了好久才找到方法这里以exel为例,其他的都差不多。

在做之前我们要清楚目的,只是完成一个简单的打开操作,不需要其他功能,所以只需使用CApplication 、 CWorkbooks这两个类就可以,所以要添加相应的头文件,建议不要手动添加,我使用的开发环境是vs2010 ,英文版的自己翻译吧,点击项目->添加类,弹出对话框双击里面的TypeLib中的MFC类,然后在弹出的对话框里来源选择注册表,在右边能找到Microsoft Exel。。。。。。,(word和ppt的操作一样,名字就是相应的word和powerpoint),接口只需要_Appliction和workbooks,点击“〉”然后点击完成。打开相应的.h文件,把第一句话Import。。。。。。。。。。。给去掉,在用到的地方加上头文件就可以了。

然后实现初始化,在app类里的InitInstance()函数(这个得重写,网上很多这里不赘述)里加上AfxOleInit()。

我们需要通过读取socket的线程中接受指令,然后发消息给主线程打开exel,自己定义个消息,然后SendMessage把消息发送过去,消息相应函数里实现打开功能,代码如下:

CApplication app;  
CWorkbooks books;  
 if(!app.CreateDispatch("Excel.Application"))  
  {  
 AfxMessageBox("无法启动Excel服务器!");  
return -1;  
   } 

app.put_Visible(TRUE);
books.AttachDispatch(app.get_Workbooks());
 books.Add(vtMissing);
return 0;



app.put_Visible(TRUE);这句话是必须的否则不显示,看不出效果,vtMissing这个从字面上就很好理解:缺省值,Add函数里的参数是一个你希望打开exel的一个模板,我们不需要那么复杂,直接使用系统默认的模板就可以,所以使用vtMissing,这是头文件里自带的,不要自己声明。

效果是弹出对话框“无法启动Excel服务器!”,奔泪。

仔细看下调试下的输出,显示:

0x7691c54f 处最可能的异常: 因为应用程序正在发送一个输入同步呼叫,所以无法执行传出的呼叫。

Warning: CreateDispatch returning scode = RPC_E_CANTCALLOUT_ININPUTSYNCCALL ($8001010D).

这个错误就很明显了,SendMessage发送消息的时候是不会立刻返回的,阻塞住了CreateDispatch的动作,所以将SendMesaage改成PostMessage就可以,PostMessage只是负责将消息发送出去,然后立刻返回,不会阻塞。

运行下,果然效果就好得多,不会出现错误对话框,还有不要将app和bookRealse或者Close否则Exel打开就立刻关掉了,无法操作。

解决同一个问题可能会有很多种思路,不同的思路解决问题效率,效果是不同的,有些思路实现起来很简单,效率也很高,但是可能只能针对一些情况,其他复杂的情况可能就无法处理,有些实现起来比较复杂,但是由于考虑的比较全面所以出现的错误就比较少,所以以后编程的时候要换不同思路去想,这样才能提升程序的适用性。

猜你喜欢

转载自blog.csdn.net/qq_15106323/article/details/75096164