首页 > 代码库 > SAFEARRAY基本用法详解

SAFEARRAY基本用法详解

使用ADO技术连接数据库时,经常要用到SAFEARRAY传递参数(我遇到的是向数据库添加数据时,有一种方法要用到SAFEARRAY)。我也是花了几天,断断续续的在看SAFEARRAY,刚开始的时候也是非常迷糊,不知道这是什么,只有照着书把代码敲到了电脑上,第二次还是不明白这些代码都做了什么,变量和参数都什么意思。今天下午在网上,书上包括直接在VS上看变量的定义,总算大概了解了点,基本掌握了一维数组的用法,下面是我自己对SAFEARRAY的理解,不当之处,还望之处,不懂之处,欢迎讨论。

首先要知道,SafeArray也并不单独使用,而是将其再包装到VARIANT类型的变量中,然后才作为参数传送出去。

一、要打包的数据和需要定义的变量

<span style="white-space:pre">	</span>_variant_t vValue[4];
	vValue[0] = _bstr_t("CSDN");
	vValue[1] = _bstr_t("心中有道");
	vValue[0] = _bstr_t("博客");
	vValue[0] = _bstr_t("SAFEARRAY");

	SAFEARRAY *psaValue;
	SAFEARRAYBOUND rgsaBound[1];
	VARIANT vsaValue;

二、各变量的意义

SAFEARRAY就是所谓的安全数组,psaValue是一个指向SAFEARRAY的指针,在VC中,SAFEARRAYBOUND的定义如下:

typedef struct tagSAFEARRAYBOUND
    {
    ULONG cElements;
    LONG lLbound;
    } 	SAFEARRAYBOUND;

typedef struct tagSAFEARRAYBOUND *LPSAFEARRAYBOUND;


SAFEARRAYBOUND是一个结构体,里面有两个变量,ULONG cElements表示的是元素的数目(更准确的说是在本维中的数目);LONG lLbound表示的是一个逻辑起点序号,实际访问内存的时候,安全数组会将程序指定的序号减去lLbound,比如你将其设置为10000,a[10000]这相当于A[0],a[999]数组越界,所以在没有特殊要求的情况下,lLbound一般为0。还有一点,定义的时候是SAFEARRAYBOUND rgsaBound[1], 这点要解释一下,rgsaBound[1]表示的是一位数组,二维数组要定义为rgsaBound[2],这里主要讲解一位数组,更高维数大家可以去搜一下,和一维的相似。

VARIANT vsaValue,这个就是最终要的得到的变量了,可以把这个变量作为参数传出去。

三、实现代码及函数、参数意义

<span style="white-space:pre">	</span>psaValue = http://www.mamicode.com/SafeArrayCreate(VT_VARIANT, 1, rgsaBound);>
代码不是很多,甚至很少,但是代码要一句一句的讲下

1、创建SAFEARRAY

<span style="white-space:pre">	</span>psaValue = http://www.mamicode.com/SafeArrayCreate(VT_VARIANT, 1, rgsaBound);

第一个参数VT_VARIANT表示数组的类型,第二个参数表示创建数组的维数,本例中是一维,第三个参数是对这个数组各个维度的描述。
SafeArrayCreate()就是创建SAFEARRAY的函数,准确的说是在堆中创建了一个SAFEARRAY,也就是说在这个函数里面,调用了new或者malloc()之类的申请了一个空间(我有个疑问是这个空间是否需要自己用delete释放,C++学的不好,对这不太清楚)。还有一些函数是在栈(也就是临时变量)中实现了SAFEARRAY,这个函数我还没了解,就不在这讨论了。

2、放置元素到数组中

<span style="white-space:pre">	</span>for (long i = 0; i < 4; i++)
	{
		SafeArrayPutElement(psaValue, &i, &vValue[i]);
	}

严格的来讲,这段代码只能在一维数组中使用,当然,如果一维数组够用的话,这个方法也挺方便的,下面这段代码是比较准确的:
<span style="white-space:pre">	</span>long demen[1];
	for (int i = 0; i < 4; i++)
	{
		demen[i] = i;
		SafeArrayPutElement(psaValue, demen, &vValue[i]);
	}
	//如果是二维数组,应该这样
	/*
	long demen[2];
	for (int i = 1; i < 4; i++)		//假设是一个4*4的二维数组
	{
		for (int j = 1; j < 4; j++)
		{
			demen[0] = i;
			demen[1] = j;
			SafeArrayPutElement(psaValue, demen, &x);
		}
	}
	*/

第一个参数是指向SAFEARRAY的指针;第二个参数是long型数组指针,表示SAFEARRAY元素的下标,即唯一确定一个SAFEARRAY元素;第三个参数就是要放置的那个值得指针了。

3、指明vsaValue存放值得类型

<span style="white-space:pre">	</span>vsaValue.vt = VT_ARRAY | VT_VARIANT;

在VARIANT的vt成员的值如果包含VT_ARRAY,那么它所封装的就是一个SAFEARRAY,它的parray成员即是指向SAFEARRAY的指针。
VT_ARRAY说明vsaValue封装的是一个SAFEARRAY,VT_VARIANT说明SAFEARRAY的元素是VARIANT类型。

4、完成封装

<span style="white-space:pre">	</span>V_ARRAY(&vsaValue) = psaValue;<span style="white-space:pre">		</span>//等价于<span style="white-space:pre">	vsaValue.parray = psaValue;</span>

V_ARRAY()是VC中的一个宏,定义如下:
#define V_ARRAY(X)       V_UNION(X, parray)
#define V_UNION(X, Y)   ((X)->Y)


到这也算差不多了,第一次在CSDN上写一个讲解,纪念一下大笑