在COM中使用數組參數-SafeArray

來源:互聯網
上載者:User

1      使用SafeArray

SafeArray是VB中的數組儲存方式。通過SafeArray,可以在VC++和VB間相互調用。SafeArray也是Automation中的標準數組儲存方式。

1.1     SafeArray處理函數

COM提供了一套API用於處理SafeArray。為了保證程式和SafeArray結構無關[1],程式中建立、讀取、更改和釋放SafeArray都應該通過這些API進行,而不應該直接讀寫SafeArray結構。

下面介紹常用的SafeArray處理函數。

            建立SafeArray

SAFEARRAY* SafeArrayCreate(

VARTYPE vt,

unsigned int cDims,

SAFEARRRAYBOUND * rgsabound

);

SAFEARRAY SafeArrayCreateEx(

VARTYPE vt,

unsigned int cDims,

SAFEARRRAYBOUND * rgsabound

PVOID pvExtra

);

SAFEARRAY* SafeArrayCreateVector(

VARTYPE vt,

long lLbound,

unsigned int cElements

);

SAFEARRAY* SafeArrayCreateVectorEx(

VARTYPE vt,

long lLbound,

unsigned int cElements,

LPVOID pvExtra

);

SafeArrayCreate於建立多維普通數組。SafeArrayCreateEx用於建立多維自訂類型或介面指標數組。SafeArrayCreateVector用於建立一維普通數組。SafeArrayCreateVectorEx用於建立一維自訂類型或介面指標數組。

vt值

類型

VT_UI1

無符號1位元組整數(BYTE)數組

VT_UI2

無符號2位元組整數(WORD)數組

VT_UI4

無符號4位元組整數(DWORD)數組

VT_UINT

不帶正負號的整數(UINT)數組

VT_INT

有符號整數(INT)數組

VT_I1

有符號1位元組整數數組

VT_I2

有符號2位元組整數數組

VT_I4

有符號4位元組整數數組

VT_R4

IEEE 4位元組浮點數(float)數組

VT_R8

IEEE 8位元組浮點數(double)數組

VT_CY

8位元組定點數貨幣值數組

VT_BSTR

VB字串數組

VT_DECIMAL

12位元組定點數(大數字)數組

VT_ERROR

標準錯誤編號數組

VT_BOOL

布爾值數組

VT_DATE

日期型數組

VT_VARIANT

VB Variant類型數組

lLbound是數組的最小下標,可以是取負數。cElements是數組的長度。數組的最大下標的值是最小下標加上數組長度減一。

SafeArrayCreateVector函數返回SafeArray結構的指標。

2. SafeArrayCreateVectorEx

SAFEARRAY* SafeArrayCreateVectorEx(

VARTYPE vt,            

long lLbound,          

unsigned int cElements,

LPVOID pvExtra

);

這個函數用於建立自訂類型或COM對象的SafeArray數組。和SafeArrayCreateVector類似,SafeArrayCreateVector也有類型、下界和長度的三個參數。SafeArrayCreateVectorEx還增加了一個參數pvExtra。

pvExtra的含義和vt的取值有關。當vt的取值在上表中的時候,pvExtra的取值沒有作用。當vt取值VT_RECORD時,SafeArrayCreateVectorEx返回一個自訂類型(結構structure或聯合union)的數組。這時,pvExtra必須是一個指向IRecordInfo的指標。

當vt取值是VT_UNKNOWN或VT_DISPATCH時。pvExtra是一個指向IID(介面GUID)的指標。在目前的COM規範中,pvExtra只能是IID_IUnknown和IID_IDispatch。並且必須和vt的取值一致。

a.   建立自訂類型數組

當vt是VT_RECORD時。pvExtra必須是一個IRecordInfo指標。絕大多數情況下,我們從TLB中取得自訂類型的IRecordInfo指標。以下是取得IRecordInfo的代碼:

IRecordInfo * pRecordInfo;

hr = GetRecordInfoFromGuids(

LibID,

MajorVer,

MinorVer,

LOCALE_USER_DEFAULT,

    TypeGUID,

&pRecordInfo);

上述代碼中,LibID是所TLB的GUID,MajorVer和MinorVer分別是TLB的主、次版本號碼,TypeGUID是自訂結構的GUID。

函數返回的是IRecordInfo介面的指標。

b.   建立COM對象數組

當需要建立COM數組時,可以使用IUnknown指標,也可以用IDispatch指標。如果需要使用其它指標類型,應該使用QueryInterface方法取得,而不能直接在數組中儲存。因為SafeArray數組的序列化程式只能處理IUnknown和IDispatch兩種指標類型,如果在數組中放其它介面類型的指標,可能在跨套間使用中會出現問題。

            讀取和寫入SafeArray數組。

讀寫SafeArray數組時。應該使用COM提供的標準API。COM提供了大量函數用於SafeArray數組的操作,本文中僅使用其中的兩個函數,SafeArrayAccessData和SafeArrayUnaccessData,和一些輔助用的函數。實際上是用這兩個函數就可以進行所有的數組操作了。其它的函數用於對單個元素的操作,由於使用不多,而且效率也不高,所以本文中不進行說明。

1. SafeArrayAccessData

這個函數用於擷取SafeArray的資料指標,並鎖定SafeArray數組的資料。在取得了資料指標之後,就可以直接存取SafeArray數組中的資料了。

如果數群組類型是Type,那麼所取得的資料指標實際上就是Type類型的數組的地址。在多維陣列的情況下,必須把多個維度下標轉換成一維下標進行訪問。

2. SafeArrayUnaccessData

這個函數的作用是對SafeArray資料解鎖,解鎖後,就不應該繼續對資料指標進行讀寫訪問。如果要訪問,必須重新擷取並鎖定資料。

3. 確定數組結構

在訪問數組之前,必須知道數組中資料的類型,、維數以及每個維度下界和長度。COM提供了取得這些數組參數的函數。

取得類型,返回“VT_”開頭的類型枚舉值:

HRESULT SafeArrayGetVartype (

    SAFEARRAY * pSA,

    VARTYPE * pVarType);

取得維數,返回數組的維數:

UINT SafeArrayGetDim (

    SAFEARRAY * pSA);

取得每個維度屬性,返回指定維數(nDim)的上界和下界(nDim從1開始):

HRESULT SafeArrayGetLBound (

    SAFEARRAY * pSA,

    UINT nDim,

    long * pLBound);

HRESULT SafeArrayGetUBound (

    SAFEARRAY * pSA,

    UINT nDim,

    long * pUBound);

取得自訂類型介面,對於自訂結構數組,返回自訂結構類型資料的指標:

HRESULT SafeArrayGetRecordInfo (

    SAFEARRAY * pSA,

    IRecordInfo ** ppRecordInfo);

4. 訪問普通一維數組

從SafeArrayAccessData返回的指標實際上就是C語言中的一維數組地址。在VC++中可以像訪問普通數組一樣讀寫這個數組。

需要注意的是,在C語言中,所有的數組下標都是從0開始的。而在SafeArray中,數組下標可以從任何數字開始。所以在訪問前必須進行轉換。轉換方法就是從SafeArray的下標中減去數組的下界,就可以得到C語言中數組的下標了。

如下:

Type * pData;

long LBound;

SafeArrayAccessData(pSA, (void HUGEP **) &pData);

SafeArrayGetLBound(pSA, 1, &LBound);

Type Item = pData[n – LBound];

5. 訪問多維陣列

訪問多維陣列和訪問一維數組類似,只是要把多維下標轉換成一維下標。把多維下標轉換成一維下標的方法和在數組指標中介紹的是相似的。

設:有n個維度,每個維度長度(上界減去下界加一)分別是L1、L2、…、Ln。要轉換的下標是X1、X2、…、Xn。可以根據下述公式轉換成一維數組的下標。

X1+X2*L1+X3*(L1*L2)+X4*(L1*L2*L3)+…+Xn*(L1*L2*…*L(n-1))

6. 訪問自訂結構數組

訪問自訂結構數組的時候,可以使用#iimport自動產生或者IDL編譯產生的類型定義。如果沒有辦法取得自訂結構的聲明,可以使用IRecordInfo介面中的方法間接訪問自訂結構。

首先需要取得自訂結構的長度,這可以通過IRecordInfo::GetSize方法取得。

訪問自訂結構中的欄位內容,通過IRecordInfo::GetField和IRecordInfo::PutField方法實現。

通過IRecordInfo中的其它方法還可以取得每個欄位的屬性內容。大家可以參考相關文檔。

            釋放SafeArray數組

釋放SafeArray數組應該通過COM的支援函數:

HRESULT SafeArrayDestroy(SAFEARRAY * pSA);

1.3     使用SafeArray的IDL定義

每個介面都要通過IDL組建代理程式和佔位程式碼。為了使代理和佔位程式能夠正確地對參數進行序列化,必須正確的書寫IDL定義。

MIDL工具直接支援SafeArray類型資料的傳遞。但是,在傳遞SafeArray資料的時候,必須通過SAFEARRAY的指標進行。困難在於,VC++ 6.0的添加方法和添加屬性的工具不能夠正確的處理SafeArray數組的情況。

在IDL中,數組必須指定類型,如下:

[id(10)] HRESULT Foo([in] SAFEARRAY(LONG) pParam);

在實現的函式宣告中,要使用相應的指標類型:

HRESULT Foo(SAFEARRAY * pParam);

輸出和輸入輸出類型的數組參數,在IDL中必須使用指標參數,而在函式宣告中則是雙重指標。

[id(11)] HRESULT Foo2([out] SAFEARRAY(LONG) * ppParam);

函式宣告如下:

HRESULT Foo2(SAFEARRAY ** ppParam);

1.4     VARIANT和SafeArray

在VB的介面中,經常通過VARIANT傳遞數組參數。這裡簡述一下使用VARIANT參數傳遞數組中需要注意的地方。

            輸入數組

對於輸入數組,可以使用VARIANT指標,也可以使用VARIANT型別參數。在這兩種情況下,VARIANT中的類型是不同的。

當使用VARIANT指標時,輸入的VARIANT參數的類型(vt參數的值)是VT_ARRAY | VT_BYREF | VT_xxx。此時,使用VARIANT參數的pparray欄位取得SafeArray指標。

如果參數是VARIANT,輸入的VARIANT參數的類型(vt參數的值)是VT_ARRAY | VT_xxx。使用VARIANT參數的parray欄位取得SafeArray指標。

必須注意這兩種情況下,VARIANT的類型不同,所以代碼也會有區別。

            輸出數組

輸出和輸入輸出數組,必須使用VARIANT指標,這時,VARIANT類型是VT_ARRYA | VT_BYREF | VT_xxx。

1.5     SafeArray記憶體管理

使用COM專用的建立和銷毀API函數處理SafeArray。

對於輸入型的SafeArray,調用方負責建立和銷毀SafeArray;對於輸出型的SafeArray,由被呼叫者建立,調用方銷毀;輸入輸出型SafeArray,調用方建立,被呼叫者可以銷毀並重新建立,最終由調用方銷毀。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.