如果你用C++来编写COM,那么你将必不可少的使用这三个类型。使用这三种wrapper class毫无疑问会简化我们的编程,使得使用SAFEARRAY, VARIANT和BSTR简单。但是,使用这三个类型依然需要小心,因为使用不当的话,就会造成内存泄漏,或效率降低。
1. 如果拷贝两个BSTR
假如我们一个BSTR,这个时候我希望复制一份BSTR,并丢弃之前的BSTR。通常我们会这么写:
<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>-->CComBSTRStringToBSTR(conststring&sVal)
{
CComBSTRbstrValue=sVal.data();
returnbstrValue;
}
intmain()
{
CComBSTRvValue=StringToBSTR("value");
return0;
}
当然,上面这个程序没有任何问题,不会有任何内存泄漏的可能。但是,你有没有上面代码里都发生了什么了?
答案很简单,在函数StringToBSTR里面,讲bstrValue返回的时候,会调用CComBSTR::Copy(),在Copy()里面将会调用
::SysAllocStringByteLen()
这个函数。而后在给vValue赋值的时候,又 会调用一次
::SysAllocString()
显而易见,开销很大。
那么,我们将怎么改进这段代码了?
<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>-->BSTRStringToBSTR(conststring&sVal)
{
CComBSTRbstrValue=sVal.data();
returnbstrValue.Detach();
}
intmain()
{
CComBSTRvValue.Attach(StringToBSTR("value"));
return0;
}
这样,通过CComBSTR::Detach(),我们将BSTR返回回来,通过CComBSTR::Attach(),我们将BSTR指针存储起来。这样,就减小了两次开销,大大提高了效率,也不会造成内存效率。
2. 如何使用CComSafeArray
使用CComSafeArray的一个最大的好处,就是它会自动释放元素是VARIANT和BSTR。也就是说,如果你的类型是VARIANT,它会自动调用::VariantClear()。如果你的类型是BSTR,他会自动调用::SysStringFree()方法。但是使用它的时候,同样要小心。
2.1 成对使用::SafeArrayAccessData()和::SafeArrayUnaccessData()
我们有时候会这样使用CComSafeArray的元素:
<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>-->voidDoSomething()
{
CComSafeArray<double>pSafeArray(3);
double*pVal=NULL;
::SafeArrayAccessData(pSafeArray.m_psa,(void**)&pVal);
//handletheelementsthroughthepVal;
}
因为::SafeArrayAccessData 方法会在SFAEARRAY上给lock加1. 如果上面程序显示调用CComSafeArray::Destroy()函数,你检查它返回来的HRESULT的时候,应该是下面的值:
hr 0x8002000d 内存已锁定。 HRESULT
如果你不仔细检查,那么将造成CComSafeArray没有释放。
2.2 从CComSafeArray转为成CComVariant
有时候我们使用CComVariant包装SAFEARRY。你会这样写代码:
<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>-->voidDoSomething()
{
CComSafeArray<double>pSafeArray(3);
//fillthesafearray
CComVariantv=pSafeArray.Detach();
}
你可能会任务CComVariant会存储pSafeArray的指针。可惜,你错了。
CComVariant会调用::SafeArrayCopy 来完成赋值操作。而你的pSafeArray已经调用了Detach()操作,那么它里面的SAFEARRAY就变成了孤儿,没有人去释放它了。
那么你应该怎么写了?
你可以这么写:
<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>-->voidDoSomething()
{
CComSafeArray<double>pSafeArray(3);
//fillthesafearray
CComVariantv=pSafeArray.m_psa;
}
这样,CComVariant会调用::SafeArrayCopy 来完成复制操作,而CComSafeArray也会保证在析构的时候释放里面的SAFEARRAY。
使用上面三个wrapper类,确实可以很方便我们编程,也能避免很多memory leak。但是,使用他们同样要小心,不然,同样会造成性能损失,或者,更糟糕的,内存泄漏。
相关推荐
ATL提供了很多复杂数据类型的包装类,使用这些包装类可以大大减小开发工作量,演示类常见CComBSTR CComVariant CComPtr的使用方法和注意事项。
5. `CComVariant`类:学习如何使用`CComVariant`存储和操作不同类型的值,尤其是日期和时间。 6. 异常处理:ATL和MFC都支持异常处理,了解如何编写健壮的代码以处理可能出现的错误。 通过研究这个压缩包的内容,...
ATL通过一系列智能类,如CComBSTR、CComVariant、CComPtr和CComQIPtr,为开发者提供了便捷的封装和管理机制。 #### 字符串与字符集 在COM组件开发中,处理不同字符集的需求十分常见。ATL为此提供了一系列字符串...
在VC++编程环境中,获取Microsoft Word文档的相关属性信息是一项常见的任务,这有助于处理和管理文档。本示例着重介绍如何利用VC++来提取Word文档的元数据,如标题、主题、作者、模板以及备注等信息。这些信息对于...
在字符串处理方面,书中涵盖了C++、COM和ATL中的相关知识,让开发者能熟练掌握智能类型如CComPtr、CComQIPtr、CComBSTR和CComVariant的使用。此外,还探讨了实现IUnknown接口的不同选项,帮助开发者选择最适合的方法...
由于HTML结构可能会变化,你需要使用DOM API查找正确的元素ID或类名,然后使用IHTMLElement::setAttribute方法设置值。例如,如果用户名输入框的ID是"username",密码输入框的ID是"password",则可以这样操作: ```...
解释了在处理多字节字符集(MBCS)时,strxxx()函数和_mbsxxx()函数的区别和使用场景。 21.8. Win32 API中的MBCS 和 Unicode的二种字符集 介绍了Windows编程中如何处理MBCS和Unicode两种字符集,以及API调用的选择...
本文介绍了三种常用的VC调用JavaScript的方法:通过`execScript`方法调用、使用`GetIDsOfNames`和`Invoke`方法以及利用`IScriptControl::raw_Eval`方法。每种方法都有其特点和适用场景,开发者可以根据实际需求选择...
总的来说,这个"MFC使用ADO连接MySQL的例子"是一个很好的学习资源,它展示了如何在MFC应用中集成数据库操作,尤其是对于登录和注册这类常见的需求。通过实践这个项目,开发者可以加深对MFC、ADO以及数据库编程的理解...
在IT行业中,开发工具的选择和使用对于项目的效率和质量至关重要。本话题主要涉及的是如何在Visual Studio 2017(VS2017)环境下,免注册调用大漠插件的收费版类库。大漠插件是一款功能强大的文本处理和图像识别工具...
1. ADO库的使用,包括Connection、Command和Recordset对象。 2. 数据库连接字符串的构建。 3. 二进制数据在数据库中的存储和检索。 4. 使用参数化SQL语句进行数据操作。 5. 文件I/O操作,将JPEG图像数据与数据库数据...
现在我们有了Excel文件列表,接下来使用MFC的`COleDispatchDriver`和`COleClientItem`来与Excel进行交互。首先,我们需要包含必要的头文件,如`#import`来导入Excel的自动化接口: ```cpp #import "libid:00020813-...
本文将深入探讨如何使用C++结合ADO(ActiveX Data Objects)技术来访问数据库,实现数据的读取、写入和更新操作。 首先,ADO是Microsoft提供的一种数据访问接口,它基于组件对象模型(COM)并封装了ODBC(Open ...
在探讨如何使用VC++(Visual C++)创建和读取XML文件之前,我们先了解下XML及其重要性。XML(Extensible Markup Language,可扩展标记语言)是一种标记语言,类似于HTML,但更侧重于数据的结构化表示,而非显示格式...
1. **初始化和打开记录集**:首先,你需要创建一个`CDynamicAccessor`实例,然后使用`Open`方法打开一个`IAccessor`接口,该接口可以从`ICommand::Execute`或`IAccessor::CreateAccessor`获得。`Open`方法会解析记录...
我们通常会使用Microsoft Office的自动化接口,如Excel Automation API,来创建和修改Excel工作簿。具体来说,我们需要利用`COleDispatchDriver`类作为桥梁,与Excel的对象模型进行交互。 首先,为了初始化Excel...
这个接口提供了一种直接与AD交互的方法,相比使用`IADs`(IDispatch)对象,它提供了更高效和更直接的访问方式。本文将详细介绍如何在C++环境下,特别是VC6或VC7.0(Visual Studio 2003)中,使用`IDirectoryObject`...
完成操作后,使用`Workbook::SaveAs`方法保存文件,指定文件路径和保存类型。最后,别忘了通过`Quit`方法关闭Excel应用程序实例,释放资源。 7. **错误处理** 操作Excel时,务必处理可能出现的异常和错误。例如,...
CComBSTR script = L"document.querySelector('.content').style.fontSize = '24px';"; pDispatch->Invoke(0x6A, IID_IDispatch, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &varResult, script, NULL, NULL, NULL); ...