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

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值