SAFEARRAY使用实例
生活随笔
收集整理的這篇文章主要介紹了
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); }總結
以上是生活随笔為你收集整理的SAFEARRAY使用实例的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: RabbitMQ学习3----运行和管理
- 下一篇: 【数据结构】栈的基本操作