SAFEARRAY使用实例

From: http://blog.csdn.net/csfreebird/article/details/234547

目录:
SAFEARRAY使用实例
目录:
前言:
何谓SAFEARRAY:
创建SAFEARRAY:
方法一:使用SafeArrayAllocDescriptor在栈上创建一维数组
方法二:使用SafeArrayAllocDescriptor和SafeArrayAllocData在堆上创建一维数组
方法三:使用SafeArrayAllocDescriptor和SafeArrayAllocData在堆上创建二维数组
方法四:使用SafeArrayCreate在堆上创建一维数组
方法五:使用SafeArrayCreate在堆上创建二维数组
方法六:使用SafeArrayCreateEx创建包含结构的一维数组
访问SAFEARRAY:
方法一:使用SafeArrayAccessData方法
方法二:使用SafeArrayGetElement和SafeArrayPutElement
CComSafeArray类介绍:
基本的入门例子:
注意事项:
前言:
SAFEARRAY使用总是困扰很多人,为了把这个问题说个明白,我把我目前掌握的知识做个总结
何谓SAFEARRAY:
SAFEARRAY实际上是一个结构,关于这部分可以参考MSDN。
ms-help://MS.MSDNQTR.2003FEB.2052/automat/htm/chap7_9ntx.htm
我们不需要关心16位操作系统下的定义,因为我们团队只在WIN2000以上平台下开发。
创建SAFEARRAY:
方法一:使用SafeArrayAllocDescriptor在栈上创建一维数组
     //创建SAFEARRAY数组,每个元素为long型,该数组是一维数组
     long nData[10]={1,2,3,4,5,6,7,8,9,10};
     SAFEARRAY* pArray=NULL;
     HRESULT hr=SafeArrayAllocDescriptor(1,&pArray);//创建SAFEARRAY结构的对象
     pArray->cbElements=sizeof(nData[0]);
     pArray->rgsabound[0].cElements=10;
     pArray->rgsabound[0].lLbound=0;
     pArray->pvData=nData;
     pArray->fFeatures=FADF_AUTO|FADF_FIXEDSIZE;//FADF_AUTO指定在栈上分配数据,并且大小不可以改变(固定为10)
    
     //访问SAFEARRAY数组
     long* pValue=NULL;
     SafeArrayAccessData(pArray,(void**)&pValue);
     long Low(0),High(0);
     hr=SafeArrayGetLBound(pArray,1,&Low);//维数索引从1开始
     hr=SafeArrayGetUBound(pArray,1,&High);//维数索引从1开始
     SafeArrayUnaccessData(pArray);
     SafeArrayDestroy(pArray);
这种方法在栈上分配数组元素所占的空间,即nData数组所用的空间
方法二:使用SafeArrayAllocDescriptor和SafeArrayAllocData在堆上创建一维数组
     //创建SAFEARRAY数组,每个元素为long型,该数组是一维数组
     long nData[10]={1,2,3,4,5,6,7,8,9,10};
     SAFEARRAY* pArray=NULL;
     HRESULT hr=SafeArrayAllocDescriptor(1,&pArray);//创建SAFEARRAY结构的对象
     pArray->cbElements=sizeof(nData[0]);
     pArray->rgsabound[0].cElements=10;
     pArray->rgsabound[0].lLbound=0;
     SafeArrayAllocData(pArray);
     long* pData=NULL;
     SafeArrayAccessData(pArray,(void**)&pData);
     long l(0),h(0);
     SafeArrayGetLBound(pArray,1,&l);
     SafeArrayGetUBound(pArray,1,&h);
     long Size=h-l+1;
     SafeArrayAccessData(pArray,(void**)&pData);
     for(long Idx=l;Idx<Size;++Idx)
     {
         pData[Idx]=nData[Idx];
     }
     SafeArrayUnaccessData(pArray);
     //访问SAFEARRAY数组
     long* pValue=NULL;
     SafeArrayAccessData(pArray,(void**)&pValue);
     long Low(0),High(0);
     hr=SafeArrayGetLBound(pArray,1,&Low);//维数索引从1开始
     hr=SafeArrayGetUBound(pArray,1,&High);//维数索引从1开始
     SafeArrayUnaccessData(pArray);
     SafeArrayDestroy(pArray);
方法三:使用SafeArrayAllocDescriptor和SafeArrayAllocData在堆上创建二维数组
SAFEARRAY* pArray=NULL;
     HRESULT hr=SafeArrayAllocDescriptor(2,&pArray);
     pArray->rgsabound[0].lLbound=0;
     pArray->rgsabound[0].cElements=3;
     pArray->rgsabound[1].lLbound=0;
     pArray->rgsabound[1].cElements=3;
     pArray->cbElements=sizeof(long);
     hr=SafeArrayAllocData(pArray);
     long lDimension[2];
     long x=1;
     //为第一行赋值
     for(long i=0;i<3;++i)
     {
         lDimension[1]=0;//
         lDimension[0]=i;//
         SafeArrayPutElement(pArray,lDimension,&x);
         x++;
     }
     //为第二行赋值
     for(long i=0;i<3;++i)
     {
         lDimension[1]=1;//
         lDimension[0]=i;//
         SafeArrayPutElement(pArray,lDimension,&x);
         x++;
     }
    
     //读取SafeArray中第二行第三列的数据
     long y(0);
     lDimension[1]=1;
     lDimension[0]=2;
     SafeArrayGetElement(pArray,lDimension,&y);
     SafeArrayDestroy(pArray);
二维SAFEARRAY数组使用的时候下标要注意,这里采用的是列主序的方式,即lDimension[1]代表行,lDimension[0]代表列。
方法四:使用SafeArrayCreate在堆上创建一维数组
     SAFEARRAYBOUND Bound[1];
     Bound[0].lLbound=0;
     Bound[0].cElements=10;
     SAFEARRAY* pArray=SafeArrayCreate(VT_I4,1,Bound);
     long* pData=NULL;
     HRESULT hr=SafeArrayAccessData(pArray,(void**)&pData);
     long Low(0),High(0);
     SafeArrayGetLBound(pArray,1,&Low);
     SafeArrayGetUBound(pArray,1,&High);
     long Size=High-Low+1;
     for(long Idx=Low;Idx<Size;++Idx)
     {
         pData[Idx]=Idx;
         cout<<pData[Idx]<<endl;
     }
     SafeArrayUnaccessData(pArray);
     SafeArrayDestroy(pArray);
方法五:使用SafeArrayCreate在堆上创建二维数组
     SAFEARRAYBOUND Bound[2];
     Bound[0].lLbound=0;
     Bound[0].cElements=3;
     Bound[1].lLbound=0;
     Bound[1].cElements=3;
     SAFEARRAY* pArray=SafeArrayCreate(VT_I4,2,Bound);
    
     long Demen[2];
     for(long i=0;i<3;++i)
     {
         for(long j=0;j<3;++j)
         {
              Demen[1]=i;
              Demen[0]=j;
              long x=i*j;
              SafeArrayPutElement(pArray,Demen,&x);
         }
     }
     //访问二维数组
     for(long i=0;i<3;++i)
     {
         for(long j=0;j<3;++j)
         {
              Demen[1]=i;
              Demen[0]=j;
              long x(0);
              SafeArrayGetElement(pArray,Demen,&x);
              cout<<"("<<i<<","<<j<<") "<<x<<endl;
         }
     }
     SafeArrayDestroy(pArray);
方法六:使用SafeArrayCreateEx创建包含结构的一维数组
使用SAFEARRAY传递UDT(自定义结构)是一项常用的技术,MSDN文档描述得比较齐全,要注意的一点是,自定义结构要求有自己的GUID,这必须在IDL文件中定义。同时还必须要使用IRecordInfo接口,该接口将和数组一起传递出去,IRecordInfo接口内部记录了UDT的描述信息。
IDL文件中:
[uuid(810930AA-9229-46e7-B20C-41F6218D0B1A)]
struct _BookMarkSchema
{
     BSTR Name;
     BSTR Context;
     BSTR Time;
};
interface IShape : IDispatch
{
[id(6), helpstring("获取属于某用户的书签名称列表")] HRESULT GetBookMarkName([in] BSTR UserID,[out] SAFEARRAY(struct _BookMarkSchema)* pBookMarkNames);
}
library SarstShapeLib
{
    
     importlib("stdole2.tlb");
     [
         uuid(DBDCC0F1-38F3-4EB4-A5BD-79A3707BDE9C),
         helpstring("Shape Class")
     ]
     coclass Shape
     {
         [default]interface IShape;
     };
     struct _BookMarkSchema;
};
方法的实现为:
STDMETHODIMP CShape::GetBookMarkName(BSTR UserID,SAFEARRAY** pBookMarkNames)
{
     //获得GIS库信息
     CSarstConfigure Configure;
     string Flag("GIS");
     string IP,Database,UserName,Key,Context;
     Configure.GetDatabaseInfo(Flag,IP,Database,UserName,Key,Context);
     //读取图层属性数据
     USES_CONVERSION;
     string user(CString(UserID).GetBuffer());
     string sql("SELECT 书签名,书签描述,时间 FROM 用户书签表 where 用户ID='"+user+"' order by 时间 desc");
     FBData data(IP,Database,UserName,Key);
     table t=data.GetTable(sql);
     if(t.empty())
     {
         return S_FALSE;
     }
     //创建SafeArray
     IRecordInfo* pRecordInfo=NULL;
     HRESULT hr=::GetRecordInfoFromGuids(LIBID_SarstShapeLib,1,0,GetUserDefaultLCID(),IID_STRUCT_BookMarkSchema,&pRecordInfo);
     if(FAILED(hr))
         return E_FAIL;
     *pBookMarkNames=::SafeArrayCreateVectorEx(VT_RECORD,0,long(t.size()-1),(void*)pRecordInfo);
     _BookMarkSchema* pData=NULL;
     hr=::SafeArrayAccessData(*pBookMarkNames,(void**)&pData);
     for(int i=0;i<int(t.size()-1);i++)
     {
         t[i+1].at(0).CopyTo(&pData[i].Name);
         t[i+1].at(1).CopyTo(&pData[i].Context);
         t[i+1].at(2).ChangeType(VT_BSTR);
         t[i+1].at(2).CopyTo(&pData[i].Time);
     }
     ::SafeArrayUnaccessData(*pBookMarkNames);
     pRecordInfo->Release();
     return S_OK;
}
访问SAFEARRAY:
方法一:使用SafeArrayAccessData方法
这种方法可以参见创建SAFEARRAY之方法一
请注意,访问完后要调用SafeArrayUnaccessData方法,并且调用SafeArrayDestroy销毁数组
这种方式通常用于访问一位数组
方法二:使用SafeArrayGetElement和SafeArrayPutElement
这种方法可以参见创建SAFEARRAY之方法五
这种方式在访问多维数组的时候很有用
CComSafeArray类介绍:
基本的入门例子:
可以参见下面的MSDN链接
ms-help://MS.MSDNQTR.2003FEB.2052/vclib/html/vclrfCComSafeArray.htm
注意,我个人认为本例有错,应该最后加上一句代码delete pSar;
因为虽然pvData指针指向的内存是在堆中,但是tagSAFEARRAY结构对象生存在new开辟的堆上,如果不delete的话,将会内存泄漏。
注意事项:
1) SetAt方法有问题
HRESULT SetAt(LONG lIndex, const T& t, BOOL bCopy = TRUE)
     {
         bCopy;
         ATLASSERT(m_psa != NULL);
         if(m_psa == NULL)
              return E_FAIL;
             
         LONG lLBound = GetLowerBound();
         ATLASSERT(lIndex >= lLBound);
         ATLASSERT(lIndex <= GetUpperBound());
         if ((lIndex < lLBound) || (lIndex > GetUpperBound()))
              return E_INVALIDARG;
             
         ((T*)m_psa->pvData)[lIndex-lLBound] = t;
         return S_OK;
我们可以看到,MSDN中描述的bCopy如果为true将创建数据的副本,在代码中并没有实现,事实上bCopy参数并没有起到任何作用,不知道怎么会出现这样的错误。因此,如果我们在添加BSTR或者VARIANT类型的元素时必须先复制一份副本,然后传递给Add方法(Add方法内部调用Set方法)。
比如:m_sa.Add(CComVariant(bstr));
看到这里我还有一个奇怪的地方
((T*)m_psa->pvData)[lIndex-lLBound] = t;并没有使用SafeArrayAccessData方法获取指针,实际上SafeArrayAccessData和直接使用m_psa->pvData方法的区别在于前者要增加引用计数,而后者不会增加。因为这里如果使用SafeArrayAccessData的话,必然也要使用SafeArrayUnaccessData方法,为了效率这里省略。


============================================================================

以下是本人一个MFC对话框程序中按钮的点击事件,测试如何使用SafeArray的。

void CTSafeArrayDlg::OnButton1() 
{VARIANT va = m_clock.GetVariant();SAFEARRAY *pArray = va.parray;HRESULT hr;long low = 0, high = 0;long *pValue = NULL;CString message;SafeArrayAccessData(pArray, (void HUGEP**)&pValue);	// Increments the lock count of an array, and retrieves a pointer to the array data	hr = SafeArrayGetLBound(pArray, 1, &low);			// 取得数组左下标hr = SafeArrayGetUBound(pArray, 1, &high);			// 取得数组右下标	TRACE("low = %d, high = %d\n", low, high);for(int i = low; i <= high; i++)TRACE("pValue[%d] = %d\n", i, pValue[i]);SafeArrayUnaccessData(pArray);						// Decrements the lock count of an array, and invalidates the pointer retrieved by SafeArrayAccessDataSafeArrayDestroy(pArray);
}


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/404539.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

前端第一天 HTML基础

前端第一天 HTML基础 1.是什么 HTML里值得记住的就几个点&#xff0c;第一&#xff0c;这东西还有自身也有结构 这东西是个超文本&#xff0c;可以挂载文字图片视频或者别的超文本自身可以通过各种各样的tag进行标记&#xff0c;排版给浏览器提供渲染的依据&#xff0c; 2.…

把一个结构体当做属性后碰到的问题

当我把一个"结构体"在类中当做属性后, 在实用中可以直接读取结构体成员, 但不能直接写入...下面是由此引发的小练习:unit Unit1;interfaceusesWinapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,Vcl.Controls, Vcl.…

VC6 + OpenCV1.0实现图片缩放显示

用vc6新建一个win32控制台程序&#xff0c;代码&#xff1a; /*功能&#xff1a;实现加载jpg图片&#xff0c;并进行缩放显示开发环境: winXP vc6 openCV1.0头文件路径:D:\opensource\opencv1.0\cv\includeD:\opensource\opencv1.0\cxcore\includeD:\opensource\opencv1.0\ot…

view2.0移植自定义图标,带颜色修改

1.下载你的iconfont项目 1.将图标添加到项目&#xff0c;修改font-family值 2.下载项目打包文件&#xff0c;解压后如图所示 我们只关心里面的iconfont.css和iconfont.json 我们在这个文件夹&#xff0c;新建一个convert.js,内容如下 //convert.js let path1 "./iconf…

[react] react中你用过哪些第三方的中间件

[react] react中你用过哪些第三方的中间件 redux-thunk: Redux的异步处理方案,actionCreator中可以返回一个函数&#xff08;即可以dispatch一个function&#xff09;&#xff0c;函数内在写异步的代码redux-saga: Redux的异步处理方案&#xff0c;没有破坏redux中dispatch一个…

从PeopleEditor控件中取出多用户并更新到列表

如果一个列表中有一个字段类型为用户或用户组&#xff0c;并且设置为用户&#xff0c;允许多值的话&#xff0c;那么用代码进行更新的时候就必须将这个字段的值赋成SPFieldUserValueCollection类型&#xff0c;以下代码即为从PeopleEditor控件中取出多个用户并返回一个SPFieldU…

[react] 怎样在react中使用innerHTML?

[react] 怎样在react中使用innerHTML&#xff1f; 使用dangerouslySetInnerHTML属性,该属性传入一个对象&#xff0c;对象中__html属性的值即时innerHTML的富文本代码 个人简介 我是歌谣&#xff0c;欢迎和大家一起交流前后端知识。放弃很容易&#xff0c; 但坚持一定很酷。…

vc++出现warningC4819的处理方法

From: http://blog.sina.com.cn/s/blog_93e339ba01014fiw.html 编译VC程序的时候出现如下提示警告&#xff1a; warning C4819: The file contains a character that cannot berepresented in the current code page (936). Save the file inUnicode format to prevent data l…

H3C——路由策略和策略路由实例配置

配置如下&#xff1a;[IP]int s0/2/0[IP-Serial0/2/0]ip add 202.112.1.10 28[IP-Serial0/2/0]int s0/2/1[IP-Serial0/2/1]ip add 61.67.1.10 28 [IP-Serial0/2/1]int lo0[IP-LoopBack0]ip add 10.10.10.10 32[IP]ip route-static 0.0.0.0 0 202.112.1.9 指条静态缺省路由到R1 …

[react] 请说说什么是useState?为什么要使用useState?

[react] 请说说什么是useState&#xff1f;为什么要使用useState&#xff1f; useState是React原生的Hook&#xff0c;它接受一个参数&#xff0c;这个参数可以是对象或者普通的基本数据类型的值&#xff0c;也可以是一个有返回值的函数&#xff0c;useState函数返回一个数组&…

vc2010+openCV1.0实现将指定目录下的所有jpg文件缩放后存放到目标文件夹

开发环境&#xff1a;winXP vc2010 OpenCV1.0 OpenCV1.0安装目录&#xff1a; D:\opensource\opencv1.0 源代码&#xff1a; /*功能&#xff1a;将指定目录下的所有JPG文件进行缩放后存放到目标文件夹开发环境: winXP vc2010 openCV1.0头文件路径:D:\opensource\opencv1.…

功能:人脉(People Hub)7-固定到“开始”屏幕

如果是您的亲人和密友&#xff0c;再或者是领导和重要客户。 您需要经常沟通&#xff0c;可以将他的联系人头像固定在开始屏幕上&#xff0c;方便您的沟通。方法&#xff1a;很简单&#xff0c;“长按该联系人”后&#xff0c;有菜单出现&#xff0c;选择弹出菜单中的“固定到‘…

[react] react中的setState缺点是什么呢?

[react] react中的setState缺点是什么呢&#xff1f; 调用时机不恰当的话可能引起循环调用的问题&#xff1a;比如在componentWillUpdate render componentDidUpdate调用都有可能引起这种问题setState可能会引用不必要的re-render&#xff1a;setState任何值都会引起组件的ren…

一个系统中同时使用VC6.0+OpenCV1.0和VS2010+OpenCV2.4.6.0的方法

From: http://blog.csdn.net/zzy7222872/article/details/6047446 以前用的是VC6.0OpenCV1.0的组合&#xff0c;一直用的很好。一般的图像处理算法都可以实现&#xff0c;现在突然想搞一下立体视觉方面的东西&#xff0c;查看了OpenCV的手册&#xff0c;发现立体视觉上的大部…

[react] 请说说什么是useEffect?

[react] 请说说什么是useEffect&#xff1f; useEffect是副作用函数&#xff0c;第一个参数是函数&#xff0c;第二个参数是依赖的数据数组&#xff0c;当依赖数组中的数据变化时&#xff0c;触发第一个参数函数的执行。有以下的几种使用方式 模拟componentDidMount&#xff…

《OEA - 实体扩展属性系统 - 设计方案说明书》

这篇设计文档是 12 月份写来参加公司的研发峰会的&#xff0c;自己倒是信心满满&#xff0c;不过最后还是没有入围。现在想想也没啥大用&#xff0c;所以贴出来&#xff0c;期待与园友交流。 文档有点长&#xff0c;没全部贴在博客中&#xff0c;有兴趣的可以下载附件中的 PDF。…

Python与C/C++ 模块相互调用

From: http://hi.baidu.com/jintuguo/item/45639b4e7cda3c9f833ae1bb Python调用C动态链接库 Python调用C库很简单,不经过任何封装打包成so,再使用python的ctypes调用即可。 <test.cpp 生成动态库的源文件> #include <stdio.h> extern "C" { void…

[react] 在构造函数中调用super(props)的目的是什么?

[react] 在构造函数中调用super(props)的目的是什么&#xff1f; 这是ES6的语法。class组件继承自React.Component&#xff0c;super(props)之后&#xff0c;有以下几个作用&#xff1a; 初始化props&#xff0c;虽然不进行super(props)操作&#xff0c;组件在实例化时react也…

coverage.py - python 单元测试覆盖率统计工具

前提&#xff1a;1.假定已经安装好coverage.py&#xff08;ubuntu 10.10python.2.7coverage3.5.1&#xff09;2.项目里有模块do.py以及测试它的单元测试模块doTEST.py命令行&#xff1a;$ cd /home/user1/workspace/hp1$ coverage run doTEST.py$ coverage report$ coverage ht…

[react] 为什么建议setState的第一个参数是callback而不是一个对象呢?

[react] 为什么建议setState的第一个参数是callback而不是一个对象呢&#xff1f; React 为了优化性能&#xff0c;有可能会将多个 setState() 调用合并为一次更新。 因为this.props和this.state 可能是异步更新的&#xff0c;你不能依赖他们的值计算下一个state(状态)。以下面…