MFC对EXCEL的操作
MFC对EXCEL的操作
要说做OLE Automation容器,我还是喜欢VB,简单死了。用VC,TMD能麻烦死你,
不过使用起来“麻烦”也正是说明它相当灵话。其实用VC实现自
动化容器也只是麻烦,并不难。我们一起来试试看怎么样?
要做Excel的OLE自动化,前提当然是你得对Excel的可编程对象十分了解,
了解它的最好方法就是使用VBA。为了让大家有个比较,我们将首先用一
段VB代码来实现一个最简单的Excel功能,再偿试用VC来实现同样的功能,
看看工作量的差别有多大。
用VB实现自动化容器的好处是你根本不用知道什么是自动化,这就是我最
喜欢的傻瓜用法。真的吗?真的!不信我信就试试看!各位,请打开笔记
本,启动VB6,建立一个标准工程,然后选择“工程”->“引用”,再选
中“Microsoft Excel 8.0 Object Library”点OK,Excel对像库就装载
进来了,就这么简单!然后在窗体建立一个命令按钮并输入如下代码:
Private Sub Command1_Click()
Dim xlsApp As Application
Dim xlsWorkSheet As Worksheet
Dim xlsRange As Range
' 第一段
Set xlsApp = CreateObject("Excel.Application.8")
xlsApp.Visible = True
'第二段
xlsApp.SheetsInNewWorkbook = 1
'第三段
With xlsApp.Workbooks
If (.Count = 0) Then
.Add
End If
End With
'第四段
Set xlsWorkSheet = xlsApp.Worksheets.Item(1)
xlsWorkSheet.Range("A1").Value = "用VB做,多简单!"
End Sub
上述代码启动Excel并在A1单元格中输入了几个字,这可能是做这
个操作所用的最少代码(省略了错误处理)。第一段建立了一个
Excel对象并将Excel程序的窗口显示出来;第二段设置在一个新工
作簿中的工作表数为1;第三段检查如果没有可用的工作簿则添加一
个;第四段则向A1单元格里写入了一句话。
快运行一遍程序看看,是不是很简单?哈哈!别高兴得太早,我们
要接触VC做OLE自动化了!心脏不好的朋友请把速效救心丹放在身边!
如果你接触过OLE自动化,那一定知道IDispatch接口了,它是OLE自
动化的核心接口,恐怕这是至今为止最慢的一个接口了,呵呵!
微软的软件工程师们就是热心肠,他们怕用MFC的广大程序员累着,
专门做了一个类来封装IDispatch接口,这个类就是COleDispatchDriver,
它包装了IDispatch接口的复杂性,然而IDispatch复杂在什么地方
呢?到MSDN上查一下,也许你会注意到它的Invoke接口函数了?该
函数应该算是IDispatch的核心函数,因为它将负责所有从自动化对
象中调用方法、设置属性值以及取得属性值的所有操作。
也许你看到该函数的原型以后会很softly的说:“TNND!这参数也TMD
太多了!”是呀!要不然怎么说VC程序员的眼神儿要好呢!光对齐
参数就得要求你8.6的好眼睛,至于老花眼,干脆就不能做OLE程序,
更别提COM接口了!嘻嘻!下面我们仔细研究一下该函数吧:
dispIdMember:该参数是一个DISPID类型。它唯一地指定了待调用
的函数或属性。要知道,Invoke可不像我们这样按名称来确定一个
函数或一个属性,它是拿这个参数做为函数指针数组的索引。如果
你只知道该函数的名字而不知道这个索引值怎么办呢?不要紧,你
可以用IDispatch::GetIDsOfNames从函数名称得到DISPID。怎么样?
这个参数是不是很好填?
请注意Invoke的wFlags参数,它可以是
DISPATCH_METHOD、
DISPATCH_PROPERTYGET、
DISPATCH_PROPERTYPUT
分别表示Invoke函数的工作性质为:调用方法、取得属性值、设置
属性值。COleDispatchDriver将上述三个操作分成了三个函数:
InvokeHelper、GetProperty和SetProperty,分解了Invoke函数的
功能。
另外,请注意pDispParams
参数,为了支持有不同参数个数的不同方法,Invoke使用了参数数
组来批量的接受参数,这个很苯的方法却很实用,你觉得呢?
哇塞!要是这么详细地说下去,我不得写一本书?!得!我们还是
启动VC玩儿点实用的吧!用向导生成一个Dialog base的框架,并画
一个按钮。接下来就是一堆复杂的工作了!
首先在stdafx.h里加入对IDispatch接口提供支持的头文件:
#include 《afxDisp.h》
再在应用程序类的InitInstance()函数里加入:
AfxOleInit(); // 初始化OLE Automation库
我们应该怎么引用Excel对象库呢?按Ctrl+W启动Class Wizard,
再选择“Add Class...”->“From a type library...”,然后
选择“c:\program files\microsoft office\office”目录下的
“Excel8.olb”,随后在“confirm classes”对话框的List box
中将列出所有Excel8对象库中可用的对象。按住ctrl键再用箭头
选中Sheets、_Application、_Worksheet、_Workbook、Workbooks、
Range几个对象,按确定。哈!你看到在ClassView窗口中多出的
几个类吗?现在Excel就可以任由我们摆布啦!
好了,VC的灵话性在这儿将会体现出来了,我们生成的几个Excel
对象有很多已定义好的函数,但它们可能并不完全适合我们,哈!
我们可以跟据需要来修改这些函数!!当然不能乱改,前提是我
们必须对Excel VBA有详细的了解!
比如Workbooks类中的Add函数有一个Template参数用于指定模板文
件,但大多数情况我们用不着模板文件,怎么办呢?你是否记得在
VBA中这个参数是一个可选项?那就改呗!我们可以用C++的特性,
重载这个函数!在左边的Workbooks上右键->“Add member
function...”,然后在function type中输入“LPDISPATCH”,在
fucntion declaration输入“Add()”然后按OK。然后按如下方法
编辑该函数,大家看到,我们只是将Template参数去掉了,然而
继续保留对InvokeHelper的调用,请别忘记,MFC自动化类通常都
是从COleDispatchDriver派生的。
LPDISPATCH Workbooks::Add()
{
LPDISPATCH result;
InvokeHelper(0xb5, DISPATCH_METHOD, VT_DISPATCH,
(void*)&result, NULL);
return result;
}
为对话框上的按钮生成一个函数吧,我们要写VC代码了!别忘了在
对话框的实现文件中加入#include"excel8.h"呀!
准备好了吗?代码如下!!!!!
void CExcelOleDlg::OnButton1()
{
LPDISPATCH pDispatch = NULL;
LPUNKNOWN pUnknown = NULL;
CLSID clsid;
_Application appExcel;
LPDISPATCH pWorkbooks = NULL;
Workbooks Workbooks;
LPDISPATCH pWorkbook = NULL;
LPDISPATCH pWorksheets = NULL;
Sheets Worksheets;
LPDISPATCH pWorksheet = NULL;
_Worksheet Worksheet;
LPDISPATCH pWorkRange = NULL;
Range WorkRange;
CLSIDFromProgID( L"Excel.Application.8", &clsid );
// 看指定的对象是否已经运行
if ( SUCCEEDED(GetActiveObject(
clsid, NULL, &pUnknown )) )
{
VERIFY( SUCCEEDED(pUnknown->QueryInterface(
IID_IDispatch, (void**)&pDispatch )) );
ASSERT( pDispatch );
appExcel.AttachDispatch( pDispatch );
pUnknown->Release();
}
else
{
// 没运行。那就建立Excel.Application.8对象
if ( ! appExcel.CreateDispatch(
(LPCTSTR)"Excel.Application.8") )
{
MessageBox(
"can not found the Excel.Application.8 object!");
return;
}
}
// 显示并激活Excel窗口
// XLMAIN 是用Spy++查到的
HWND hWndExcelMain = ::FindWindow( "XLMAIN", NULL );
ASSERT( hWndExcelMain );
::ShowWindow( hWndExcelMain, SW_SHOW );
::UpdateWindow( hWndExcelMain );
::BringWindowToTop( hWndExcelMain );
// 设置在一个新工作簿中的工作表数为1
appExcel.SetSheetsInNewWorkbook( 1 );
// 得到工作簿集的IDispatch,并绑定到Workbooks对象
pWorkbooks = appExcel.GetWorkbooks();
ASSERT( pWorkbooks );
Workbooks.AttachDispatch( pWorkbooks );
// 如果工作簿集是空的,那就添加一个工作簿
if ( Workbooks.GetCount() == (long)0 )
{
pWorkbook = Workbooks.Add();
ASSERT( pWorkbook );
}
// 得到工作表集(同上)
pWorksheets = appExcel.GetWorksheets();
ASSERT( pWorksheets );
Worksheets.AttachDispatch( pWorksheets );
// 激活第一个工作表
pWorksheet = Worksheets.GetItem(
COleVariant((short)1) );
ASSERT( pWorksheet );
Worksheet.AttachDispatch( pWorksheet );
Worksheet.Select( COleVariant((short)TRUE) );
// 得到A1区域的引用
pWorkRange = Worksheet.GetRange(
COleVariant("A1"), COleVariant("A1"));
WorkRange.AttachDispatch( pWorkRange );
WorkRange.SetValue(
COleVariant("多简单!就是麻烦一点儿!") );
if ( pWorkbook )
pWorkbook->Release();
}
请注意,上述代码中除了了加入错误检查之外,还判断指定的对象是否已经
运行,如果已经运行则直接引用该对象,否则才建立新对象,其它的和上面
VB程序的功能相同!!!竟然多了这么多代码,真让人不可思议!
快累死我了!我是实在没力气解释这段VC程序了,感兴趣的朋友可以拿它和
上面的VB程序对照一下,回头再讨论这个问题吧!啊!哈---依呀累死我了!!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix