使用Excel COM组件导出数据后释放 Excel进程不能正常结束
2010-05-27 16:02
274 查看
分析一下自己的错误:
首先用Range的GetItem取到的是一个VARIANT,内含IDispatch接口,我一直以为内含的是一个BSTR,所以我已一开始直接用
_bstr_t bs(rg.GetItem(_variant_t((short)1),_variant_t((short)2)));
来获取字符串(主要是的确能获得字符串),根据lop5712(LOP)的提醒,发现返回的VARIANT是接口并不是BSTR;
看来_bstr_t这个类可以把IDispatch接口直接转换为字符串。
跟踪代码发现,在给一个_bstr_t或COleVariant赋值VARIANT类型的时候,如果VARIANT不是VT_BSTR,这时候_bstr_t会调用OLE函数VariantChangeType进行类型转换,根据MSDN说明,如果转换是从一个IDispatch到BSTR,这时VariantChangeType会尝试接口的Value属性,而rg.GetItem返回的接口的确存在Value属性,因而_bstr_t和COleVariant能取到值。
根据上述原因,我们应该释放VARIANT所含的接口,但我用#import 指令导入Excel库的时候,却没有碰到这个问题,看来两种方式的代码是有区别的。
首先谈一下#import导入的情况:
Range 的GetItem声明为:
inline _variant_t Excel::Range::GetItem ( const _variant_t & RowIndex, const _variant_t & ColumnIndex ) {
VARIANT _result;
_com_dispatch_method(this, 0xaa, DISPATCH_PROPERTYGET, VT_VARIANT, (void*)&_result,
L "/x000c/x080c ", &RowIndex, &ColumnIndex);
return _variant_t(_result, false);
}
这种情况下返回的是_variant_t(_result, false);
也就是说已经对返回的VARIANT用_variant_t包装了,而且重要的是第二个参数,第二个参数false告诉_variant_t包装VARIANT时仅仅把内容完整的复制过来,如果不含这个false(默认为true),_variant_t将采用OLE函数VariantCopy,根据MSDN,VariantCopy在碰到BSTR时会再分配一个空间,碰到接口类型时将对接口添加一个引用,所以_variant_t(_result, false)直接把返回值存起来,并在析构的时候自动释放内含的IDispatch。
再来看一下用MFC导入的情况:
声明如下:
VARIANT Range::GetItem(const VARIANT& RowIndex, const VARIANT& ColumnIndex)
这时候返回的是未经过包装的VARIANT,不会自动释放,需要手动完成。
如果用_bstr_t bs(rg.GetItem(_variant_t((short)1),_variant_t((short)2)));
将丢失返回的VARIANT,这就是我发生的错误。
我看到有的网站上的例子是这样的:
_variant_t vt(rg.GetItem(_variant_t((short)1),_variant_t((short)2)));
或
_variant_t vt=rg.GetItem(_variant_t((short)1),_variant_t((short)2));
这样做其实也是有问题的,虽然取到了VARIANT的值,但是不带false的_variant_t会添加一个引用,析构_variant_t只会Release一次,仍然造成对象释放不完全。
解决办法:每次VARIANT中的内容取出来后,调用VariantClear() 将VARIANT清除就好了
首先用Range的GetItem取到的是一个VARIANT,内含IDispatch接口,我一直以为内含的是一个BSTR,所以我已一开始直接用
_bstr_t bs(rg.GetItem(_variant_t((short)1),_variant_t((short)2)));
来获取字符串(主要是的确能获得字符串),根据lop5712(LOP)的提醒,发现返回的VARIANT是接口并不是BSTR;
看来_bstr_t这个类可以把IDispatch接口直接转换为字符串。
跟踪代码发现,在给一个_bstr_t或COleVariant赋值VARIANT类型的时候,如果VARIANT不是VT_BSTR,这时候_bstr_t会调用OLE函数VariantChangeType进行类型转换,根据MSDN说明,如果转换是从一个IDispatch到BSTR,这时VariantChangeType会尝试接口的Value属性,而rg.GetItem返回的接口的确存在Value属性,因而_bstr_t和COleVariant能取到值。
根据上述原因,我们应该释放VARIANT所含的接口,但我用#import 指令导入Excel库的时候,却没有碰到这个问题,看来两种方式的代码是有区别的。
首先谈一下#import导入的情况:
Range 的GetItem声明为:
inline _variant_t Excel::Range::GetItem ( const _variant_t & RowIndex, const _variant_t & ColumnIndex ) {
VARIANT _result;
_com_dispatch_method(this, 0xaa, DISPATCH_PROPERTYGET, VT_VARIANT, (void*)&_result,
L "/x000c/x080c ", &RowIndex, &ColumnIndex);
return _variant_t(_result, false);
}
这种情况下返回的是_variant_t(_result, false);
也就是说已经对返回的VARIANT用_variant_t包装了,而且重要的是第二个参数,第二个参数false告诉_variant_t包装VARIANT时仅仅把内容完整的复制过来,如果不含这个false(默认为true),_variant_t将采用OLE函数VariantCopy,根据MSDN,VariantCopy在碰到BSTR时会再分配一个空间,碰到接口类型时将对接口添加一个引用,所以_variant_t(_result, false)直接把返回值存起来,并在析构的时候自动释放内含的IDispatch。
再来看一下用MFC导入的情况:
声明如下:
VARIANT Range::GetItem(const VARIANT& RowIndex, const VARIANT& ColumnIndex)
这时候返回的是未经过包装的VARIANT,不会自动释放,需要手动完成。
如果用_bstr_t bs(rg.GetItem(_variant_t((short)1),_variant_t((short)2)));
将丢失返回的VARIANT,这就是我发生的错误。
我看到有的网站上的例子是这样的:
_variant_t vt(rg.GetItem(_variant_t((short)1),_variant_t((short)2)));
或
_variant_t vt=rg.GetItem(_variant_t((short)1),_variant_t((short)2));
这样做其实也是有问题的,虽然取到了VARIANT的值,但是不带false的_variant_t会添加一个引用,析构_variant_t只会Release一次,仍然造成对象释放不完全。
解决办法:每次VARIANT中的内容取出来后,调用VariantClear() 将VARIANT清除就好了
相关文章推荐
- 使用Excel COM组件导出数据后释放Excel资源
- 在使用 ADO.NET 导出 Excel 文件时,设置 IMEX=1 仍不能导出所有数据的解决办法
- 在使用 ADO.NET 导出 Excel 文件时,设置 IMEX=1 仍不能导出所有数据的解决办法
- 在使用 ADO.NET 导出 Excel 文件时,设置 IMEX=1 仍不能导出所有数据的解决办法
- Asp.Net MVC 使用FileResult导出Excel数据文件
- 使用C#导入导出数据到Excel
- php导出数据到excel,防止身份证等数字字符格式变成科学计数的方-------缺点,必须使用table tr td
- 使用ADO.net将数据导出到Excel并提供下载
- Java中使用Apache POI实现数据的Excel导入和导出
- C# 导入excel数据,解决关闭excel后不能释放资源的问题
- 使用PHP导入Excel和导出数据为Excel文件
- 使用phpExcel实现Excel数据的导入导出(完全步骤)
- PLSQL导出大量数据-超出excel限制,使用csv
- 使用PHP导入Excel和导出数据为Excel文件
- .NET使用NPOI将数据导出/导入到Excel文件介绍
- 使用jxl导出大数据量EXCEL时内存溢出的解决办法
- 使用Apache的POI,将数据导出至EXCEL
- WEB程序中使用EXCEL在服务器上无法结束进程的处理
- 使用jxl导出大数据量EXCEL时内存溢出的解决办法
- Asp.Net MVC5 使用NPIO导出Excel数据文件方法总结