SAFEARRAY

什麼是SAFEARRAY呢?可以理解爲一個數組,可以定義維數、長度、邊界、元素類型等信息,差不多相當於C#中的List 。


一般什麼時候用呢?
在編寫COM組件時,需要一次傳遞很多的數據時,使用SAFEARRAY會很方便;
VB和C之間,或VB和VC++之間傳遞數組或字符串,用C、C++或ATL創建DLL時用SAFEARRAY。


怎麼用呢

#include <OAIdl.h>//首先要加頭文件
//**************//
SAFEARRAY * pSA;
SAFEARRAYBOUND arrbound[1];//設置維度
int arrsize = 50;
arrbound[0].lLbound = 0;//設置第一維的起始下標
arrbound[1].cElements = (long)arrsize; //數組的長度

//創建類型爲double的數組。.建立多維普通數組。
pSA = SafeArrayCreate(VT_R8, 1, arrbound);//其中VT_R8代表double類型(見文後類型附錄),其他類型有相對的代號 
for (long i=0;i<4;i++)
{
    Safe
}


//用完了之後釋放
HRESULT

類型附錄

byte VT_UI1 非負字節
Short VT_I2 有符號16位短整型
Long VT_I4 有符號32位長整型
float VT_R4 一個IEEE 4字節實型數字
double VT_R8 一個IEEE 8字節實型數字
VARIANT_BOOL VT_BOOL 16位布爾 0=false, 0xFFFF=true
SCODE VT_ERROR 16位錯誤碼
CY VT_CY 16位貨幣結構
DATE VT_DATE 使用雙精度數字表示的日期
BSTR VT_BSTR visual basic風格的字符結構
DECIMAL VT_DECIMAL 一個十進制的結構
IUnknown VT_UNKNOWN 一個COM接口的指針
IDispatch VT_DISPATCH COM Dispatch接口的指針
SAFEARRAY * VT_ARRAY 一個用作傳送數組數據的特別結構
VARIANT * VT_VARIANT 一個VARIANT結構的指針
void * 普通的指針
VT_BYREF 任何類型(除指針外)的指針

本人也寫了一個demo.把很多情況都包括進去了。
一般在用C#調用C++代碼是需要用這個東西,傳點東西出去。但是對於多維的還不怎麼熟悉,特別是下標從處理。

// CPlus1.cpp : 此文件包含 "main" 函數。程序執行將在此處開始並結束。
//

#include "pch.h"
#include <iostream>
#include <OAIdl.h>
#include <comdef.h> 
using std::cout;
using std::endl;
using std::cerr;
int main()
{
#pragma region wax
    std::cout << "Hello World!\n"; 
    SAFEARRAY * pSA=NULL;
    SAFEARRAYBOUND arrbound[1];                     //設置維度
    int arrsize = 3;
    arrbound[0].lLbound = 0;                        //設置第一維的起始下標
    arrbound[0].cElements = (long)arrsize;          //數組的長度

    //創建類型爲double的數組。.建立多維普通數組。
    pSA = SafeArrayCreate(VT_R8, 1, arrbound);//第一個參數表示類型,第二個參數表示創建數組的維數,第三個參數是對這個數組各個維度的描述

    _variant_t vValue[3];
    vValue[0] =long(4);
    vValue[1] =long(6);
    vValue[2] = long(7);
    for (long index = 0; index < 3; index++)
    {
        if (FAILED(SafeArrayPutElement(pSA, &index, &vValue[index])))//第一個參數指向SAFEARRAY的指針;第二個參數是longx型數組指針,表示SAFEARRAY元素下標,即唯一確定一個SAFEARRAY元素,第三個參數就是要放置那個值的指針。
        {
            MessageBox(NULL, L"出毛病了", L"提示", MB_OK | MB_ICONWARNING);
        }
        //如果希望在局部變量的作用域內使用同名的全局變量,可以在該變量前加上::
    }
    //VARIANT vsaValue;
    //vsaValue.vt = VT_ARRAY | VT_R8;
    //V_ARRAY(&vsaValue) = pSA;      //完成封裝 或者vsaValue.parray = pSA;
    //
    //////第一種方法SafeArray數組的讀取
    ////BYTE buf[3];  //創建一個緩衝區,將數據讀進去。
    ////for (long index = 0; index < 3; index++)
    ////{
    ////    ::SafeArrayGetElement(vsaValue.parray,&index,buf+index);
    ////}
    //////或者直接讀用SafeArrayAccessData直接讀取

    ////第二種方法訪問一維數組
    ////void HUGEP**  ppvData;
    ////SafeArrayAccessData(pSA, ppvData);
    ////或者像下面這樣:
    ////double * pData= NULL; //或者
    //BYTE buf[3];
    //long *LBoud=NULL;
    //long *UBoud=NULL;
    //SafeArrayAccessData(pSA, (void HUGEP **)&buf);
    //SafeArrayGetLBound(pSA, 1, LBoud);//第一個參數數組指針,第二個是指定的維數,第三個是指定的上界和下界。
    //SafeArrayGetUBound(pSA, 1, UBoud);//第三個是指定的上界和
    //
    ////::Write(buf, 3);
    ////double item = pData[3 - *LBoud];
    //  //解鎖數據
    //::SafeArrayUnaccessData(pSA);

    //用完了之後釋放
    SafeArrayDestroy(pSA);

//************************************第二種方法**************************//
    ////與上面不同的是一個單維,一個多維,一個沒用描述器,一個用了描述器。
    long l2Arr[4][3] = { {3,15,9},{27,14,98},{35,11,6},{19,4,61} };
    /*以下代碼執行:
    1#:將l2Arr二維數組寫入安全數組
    2#:再從安全數組中讀出二維數組*/
    SAFEARRAY* lpSafeArr = NULL;                            //上面的沒有用描述器。
    HRESULT hr = SafeArrayAllocDescriptor(2, &lpSafeArr);   //爲安全數組描述器分配內存,這個數組的維數是2
    if (SUCCEEDED(hr))
    {
        lpSafeArr->cDims=2;     //維數
        lpSafeArr->cbElements = sizeof(l2Arr[0][0]);        //每個數組元素的大小(字節單位)
        lpSafeArr->fFeatures = FADF_AUTO | FADF_FIXEDSIZE;  //表明該二維數組具有固定的大小並且保存在棧上(而不是分配於堆上)
        lpSafeArr->pvData=l2Arr;                        //安全數組的數據

        lpSafeArr->rgsabound[0].lLbound = 0;                //下標起始於0
        lpSafeArr->rgsabound[0].cElements = 4;          //有4個元素(4行)

        lpSafeArr->rgsabound[1].lLbound = 0;                //下標起始於0
        lpSafeArr->rgsabound[1].cElements = 3;          //有3個元素(3列)

        hr = SafeArrayAllocData(lpSafeArr);
        if (SUCCEEDED(hr))
        {
            long rgIndices[2] = { 0,0 };

            unsigned long nRowCount = lpSafeArr->rgsabound[0].cElements;
            unsigned long nColCount = lpSafeArr->rgsabound[1].cElements;

            long lLBound1, lLBound2, lUBound1, lUBound2;
            SafeArrayGetLBound(lpSafeArr, 1, &lLBound1);//0
            SafeArrayGetUBound(lpSafeArr, 1, &lUBound1);//2
            SafeArrayGetLBound(lpSafeArr, 2, &lLBound2);//0
            SafeArrayGetUBound(lpSafeArr, 2, &lUBound2);//3

            //1# 將l2Arr二維數組寫入安全數組
            for (long i = lLBound2; i <= lUBound2; i++)
            {
                rgIndices[1] = i;//行索引
                for (long j = lLBound1; j <= lUBound1; j++)
                {
                    rgIndices[0] = j;//列索引
                    hr = SafeArrayPutElement(lpSafeArr, rgIndices, &(l2Arr[i][j]));
                    if (FAILED(hr))
                    {
                        cerr << "SafeArrayPutElement Failure.\n";
                        return -1;
                    }
                }
            }

            //2# 從安全數組中讀出二維數組
            for (long i = lLBound2; i <= lUBound2; i++)
            {
                rgIndices[1] = i;//行索引
                for (long j = lLBound1; j <= lUBound1; j++)
                {
                    rgIndices[0] = j;//列索引
                    long lEleVal;
                    hr = SafeArrayGetElement(lpSafeArr, rgIndices, &lEleVal);
                    if (SUCCEEDED(hr))
                    {
                        cout << lEleVal;
                        ((j + 1) % (lUBound1 + 1) == 0) ? cout << endl : cout << "\t";
                    }
                }
            }
            SafeArrayDestroyData(lpSafeArr);
        }
        SafeArrayDestroyDescriptor(lpSafeArr);
    }
}

參考1
參考2
參考3

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章