VB真是想不到系列之四:VB指针葵花宝典之SafeArray

发表于:2007-07-01来源:作者:点击数: 标签:
本系列文章可见: VB 真是想不到系列之四:VB指针葵花宝典之SafeArray 关键字:VB、HCAK、指针、SafeArray、数组指针、效率、数组、排序 难度:中级或高级 要求:熟悉VB,了解基本的排序算法,会用VC更好。 引言: 上回说到,虽然指针的运用让我们的数组排序

本系列文章可见:
   

               VB真是想不到系列之四:VB指针葵花宝典之SafeArray
关键字:VB、HCAK、指针、SafeArray、数组指针、效率、数组、排序
难度:中级或高级
要求:熟悉VB,了解基本的排序算法,会用VC更好。

引言:
    上回说到,虽然指针的运用让我们的数组排序在性能上有了大大的提高,但是CopyMemory始终是我们心里一个挥之不去的阴影,因为它还是太慢。在C里我们用指针,从来都是来去自如,随心所欲,四两拨千斤;而在VB里,我们用指针却要瞻前顾后,哪怕一个字节都要用到CopyMemory乾坤大挪移,真累。今天我们就来看看,能不能让VB里的指针也能指哪儿打哪儿,学学VB指针的凌波微步。
    各位看官,您把茶端好了。
   
    一、帮VB做点COM家务事
    本系列开张第一篇里,我就曾说过VB的成功有一半的功劳要记到COM开发小组身上,COM可是M$公司打的一手好牌,从OLE到COM+,COM是近十年来M$最成功技术之一,所以有必要再吹它几句。
    COM组件对象模型就是VB的基础,Varinat、String、Current、Date这些数据类型都是COM的,我们用的CStr、CInt、CSng等Cxxx函数根本就是COM开发小组写的,甚至我们在VB里用的数学函数,COM里都有对应的VarxxxDiv、VarxxxAdd,VarxxxAbs。嘿嘿,VB开发小组非常聪明。我们也可以说COM的成功也有VB开发小组和天下无数VB程序员的功劳,Bill大叔英明地将COM和VB捆绑在一起了。
    所以说,学VB而不需要了解COM,你是幸福的,你享受着VB带给你的轻松写意,她把那些琐碎的家务事都干了,但同时你又是不幸的,因为你从来都不曾了解你爱的VB,若有一天VB对你发了脾气,你甚至不知该如何去安慰她。所以,本系列文章将拿出几大篇来教大家如何帮VB做点COM方面的家务事,以备不时之需。
    想一口气学会所有COM家务事,不容易,今天我们先拿数组来开个头,更多的技术我以后再一一道来。
   
    二、COM自动化里的SafeArray
    就象洗衣机、电饭堡、吹尘器,VB洗衣服、做饭、打扫卫生都会用到COM自动化。它包含了一切COM里通用的东西,所有的女人都能用COM自动化来干家务,无论是犀利的VC、温柔的VB、还是小巧的VBScript,她们都能用COM自动化,还能通过COM自动化闲话家常、交流感情。这是因为COM自动化提供了一种通用的数据结构和数据转换传递的方式。而VB的数据结构基本上就是COM自动化的数据结构,比如VB里的数组,在COM里叫做SafeArray。所以在VB里处理数组时我们要清楚的知道我们是在处理SafeArray,COM里的一种安全的数组。
    准备下厨,来做一道数组指针排序的菜,在看主料SafeArray的真实结构这前,先让我们来了解一下C里的数组。
    在C和C++里一个数组指针和数组第一个元素的指针是一回事,如对下:
    #include <iostream>
    using namespace std;
    int main() {
      int a[10];
      cout << "a = " << a << endl;
      cout << "&a[0] =" << &a[0] << endl;
    } ///:~
    可以看到结果a和&a[0]是相同的,这里的数组是才数据结构里真实意义上的数组,它们在内存里一个接着一个存放,我们通过第一个元素就能访问随后的元素,我们可以称这样的数组为"真数组"。但是它不安全,因为我们无法从这种真数组的指针上得知数组的维数、元素个数等非常重要的信息,所以也无法控制对这种数组的访问。我们可以在C里将一个二维数组当做一维数组来处理,我们还可以通过一个超过数组大小的索引去访问数组外的内存,但这些都是极不安全的,数组边界错误可以说是C里一个非常容易犯却不易发现的错误。
    因此就有了COM里的SafeArray安全数组来解决这个问题,在VB里我们传递一个数组时,传递的实际上COM里的SafeAraay结构指构的指针,SafeAraay结构样子如下:
    Private Type SAFEARRAY
       cDims As Integer         ´这个数组有几维?
       fFeatures As Integer     ´这个数组有什么特性?
       cbElements As Long       ´数组的每个元素有多大?
       cLocks As Long           ´这个数组被锁定过几次?
       pvData As Long           ´这个数组里的数据放在什么地方?
       ´rgsabound() As SFArrayBOUND
    End Type
    紧接在pvData这后的rgsabound是个真数组,所以不能在上面的结构里用VB数组来声明,记住,在VB里的数组都是SafeArray,在VB里没有声明真数组的方法。
    不过这不是问题,因为上面SFArrayBOUND结构的真数组在整个SAFEARRAY结构的位置是不变的,总是在最后,我们可以用指针来访问它。SFArrayBOUND数组的元素个数有cDims个,每一个元素记录着一个数组维数的信息,下面看看它的样子:
    Private Type SAFEARRAYBOUND
        cElements As Long      ´这一维有多少个元素?
        lLbound As Long        ´它的索引从几开始?
    End Type
    还有一个东西没说清,那就是上面SAFEARRAY结构里的fFeatures,它是一组标志位来表示数组有那些待性,这些特性的标志并不需要仔细的了解,本文用不上这些,后面的文章用到它们时我会再来解释。
   看了上面的东西,各位一定很头大,好在本文的还用不了这么多东西,看完本文你就知道其实SafeArray也不难理解。先来看看如下的声明:
   Dim MyArr(1 To 8, 2 To 10) As Long
   这个数组做为SafeArray在内存里是什么样子呢?如图一:

cDims = 2

fFeatures =
FADF_AUTO AND FADF_FIXEDSIZE

位置
0
cbElements = 4   LenB(Long) 4
cLocks = 0 8
pvData(指向真数组) 12
rgsabound(0).cElements = 8 16
rgsabound(0).lLbound = 1 18
rgsabound(1).cElements = 9 22
rgsabound(1).lLbound = 2 26


















































cDims = 2



fFeatures =
FADF_AUTO AND FADF_FIXEDSIZE

位置
0
cbElements = 4   LenB(Long) 4
cLocks = 0 8
pvData(指向真数组) 12
rgsabound(0).cElements = 8 16
rgsabound(0).lLbound = 1 18
rgsabound(1).cElements = 9 22
rgsabound(1).lLbound = 2

26



图一 :SafeArray内存结构

原文转自:http://www.ltesting.net