WINDOWS-基础:SafeArray的使用方法
1 SafeArray的作用
- 使用SafeArray SafeArray是VB中的数组存储方式。通过SafeArray,可以在VC++和VB间相互调用。
- SafeArray也是Automation中的标准数组存储方式。SAFEARRAY的主要目的是用于automation中的数组型参数的传递。因为在网络环境中,数组是不能直接传递的,而必须将其包装成SafeArray。
- 实质上SafeArray就是将通常的数组增加一个描述符,说明其维数、长度、边界、元 素类型等信息。
- SafeArray也并不单独使用,而是将其再包装到VARIANT类型的变量中,然后才作为参数传送出去。
- 在VARIANT的vt成员的值如果包含VT_ARRAY|...,那么它所封装的就是一个SafeArray,它的parray成员即是指向SafeArray的指针。
- SafeArray中元素的类型可以是VARIANT能封装的任何类型,包括VARIANT类型本身。
将SafeArray包装到VARIANT变量中
SAFEARRAY *pSa; VARIANT v1; VariantInit(&v1); v1.vt = VT_I4 | VT_ARRAY; // Array of 4 byte integers v1.parray = pSa;
2 SafeArray结构体
typedef struct tagSAFEARRAY
{
unsigned short cDims;//维数 unsigned short fFeatures;// 用来描述数组如何分配和如何被释放的标志 unsigned long cbElements;// 数组元素的大小 unsigned long cLocks;// 一个计数器,用来跟踪该数组被锁定的次数 void * pvData;// 指向数据缓冲的指针 SAFEARRAYBOUND rgsabound[ ];// 描述数组每维的数组结构,该数组的大小是可变的 } SAFEARRAY;
这个结构的成员(cDims,cLocks等)是通过API函数来设置和管理的。真正的数据存放在pvData成员中,而SAFEARRAYBOUND结构定义该数组结构的细节。以下就是该结构成员的简要描述:
rgsabound成员是一个SAFEARRAYBOUND结构的数组--每个元素代表SAFEARRAY的一个维。
typedef struct tagSAFEARRAYBOUND
{
unsigned long cElements;// 每维中元素的个数
unsigned long lLbound;//
} SAFEARRAYBOUND;
例如C语言中的数组int a[3][4][5]用安全数组表示的时候则 cDims=3 ;cbElements=sizeof(int) 元素 cElements lLbound
rgsabound[0] 3 0
rgsabound[1] 4 0
rgsabound[2] 5 0
3 SafeArray的初始化方法
方法一 利用SafeArrayAllocDescriptor和SafeArrayAllocData在堆上创建一维数组。 long nData[10]={1,2,3,4,5,6,7,8,9,10};//数据源
SAFEARRAY* pArray=NULL;
HRESULT hr=SafeArrayAllocDescriptor(,&pArray);
HRESULT SafeArrayAllocDescriptor
(
unsigned int cDims,
SAFEARRAY FAR* FAR* ppsaOut
);
pArray->cbElements=sizeof(nData[]);
pArray->rgsabound[].cElements=; pArray->rgsabound[].lLbound=; SafeArrayAllocData(pArray);
long* pData=NULL;
SafeArrayAccessData(pArray,(void**)&pData); long l(),h(); SafeArrayGetLBound(pArray,,&l);//维数索引从1开始
HRESULT SafeArrayGetLBound
(
SAFEARRAY FAR* psa,
unsigned int nDim,
long FAR* plLbound
);
SafeArrayGetUBound(pArray,,&h);
long Size=h-l+; SafeArrayAccessData(pArray,(void**)&pData); for(long Idx=l;Idx<Size;++Idx) { }
SafeArrayUnaccessData(pArray); pData[Idx]=nData[Idx];
方法二 用SafeArrayAllocDescriptor和SafeArrayAllocData在堆上创建二维数组
SAFEARRAY* pArray=NULL;
HRESULT hr=SafeArrayAllocDescriptor(,&pArray)
pArray->rgsabound[].lLbound=;
pArray->rgsabound[].cElements=;
pArray->rgsabound[].lLbound=;
pArray->rgsabound[].cElements=;
pArray->cbElements=sizeof(long);
hr=SafeArrayAllocData(pArray);
赋初值
long Demen[];
for(long i=;i<;++i)
{
for(long j=;j<;++j)
{
Demen[]=i;
}
}
在SafeArrayPutElement 函数中需要注意的是如何指定所需元素。SafeArrayPutElement 的第二个变量是一指针,它指向数组各维的索引向量。最右边的一维(最低位)放在向量的最前(index[0]);最左边的一维(最低位)放在向量的最后(index【cDims-1]】)。由于在C++中对多维数组的访问正好与此相反,所以需要特别注意这点。
即用SafeArrayPutElement对二维SAFEARRAY数组使用的时候下标要注意, Demen[1]代表行,Demen[0]代表列。 Demen[0]=j; ong x=i*j; SafeArrayPutElement(pArray,Demen,&x);
访问二维数组
for(long i=;i<;++i)
{
for(long j=;j<;++j)
{
http://9455.net九九文章网
} Demen[]=i; Demen[]=j; long x(); SafeArrayGetElement(pArray,Demen,&x); cout<<"("<<i<<","<<j<<") "<<x<<endl; }
SafeArrayDestroy(pArray);
在 SafeArrayPutElement 与 SafeArrayGetElement 函数的明显的局限性在于它们每次只能处理一个数值,在处理大量安全数组的数据时会极大地降低性能。此时,可以选择使用函数SafeArrayAccessData 和 SafeArrayUnaccessData。SafeArrayAccessData 和 SafeArrayUnaccessData 将数组锁定在内存中,并返回指向该安全数组数据的指针,这样便可以直接访问安全数组中的数据
例如
SafeArray* psa long * pData; long * pData; SafeArrayAccessData(psa, (LPVOID *)&pData); // Set or get any values in the array. *pData = ; *(pData + ) = ; *(pData + ) = ; *(pData + ) = ; *(pData + ) = ; *(pData + ) = ; *(pData + ) =; *(pData + ) = ; // Unlock the array.(pData is no longer valid.) SafeArrayUnaccessData(pSa); 然后进行如下操作 index[] = ; index[] = ; SafeArrayGetElement(pSa, index, &NewData); cout << NewData << endl;
则NewData的值为11
方法四:使用SafeArrayCreate在堆上创建一维数组
SAFEARRAYBOUND Bound[]; Bound[].lLbound=; Bound[].cElements=;
SAFEARRAY* pArray=SafeArrayCreate(VT_I4,,Bound);
long* pData=NULL;
HRESULT hr=SafeArrayAccessData(pArray,(void**)&pData);
long Low(),High();
SafeArrayGetLBound(pArray,,&Low);
SafeArrayGetUBound(pArray,,&High);
long Size=High-Low+;
for(long Idx=Low;Idx<Size;++Idx) { } SafeArrayUnaccessData(pArray);
SafeArrayDestroy(pArray);
pData[Idx]=Idx;
cout<<pData[Idx]<<endl;
方法五:使用SafeArrayCreate在堆上创建二维数组
SAFEARRAYBOUND Bound[]; Bound[].lLbound=; Bound[].cElements=; Bound[].lLbound=;
Bound[].cElements=; SAFEARRAY* pArray=SafeArrayCreate(VT_I4,,Bound); long Demen[]; for(long i=;i<;++i) { } for(long j=;j<;++j) { } Demen[]=i; Demen[]=j; long x=i*j; SafeArrayPutElement(pArray,Demen,&x);
//访问二维数组
for(long i=;i<;++i)
{
}
SafeArrayDestroy(pArray); for(long j=;j<;++j) { } Demen[]=i; Demen[]=j; long x(); SafeArrayGetElement(pArray,Demen,&x); cout<<"("<<i<<","<<j<<") "<<x<<endl;
根据MSDN中SafeArrayAllocDescriptor allows the creation of safe arrays that contain elements with data types other than those provided by After creating an array descriptor using SafeArrayAllocDescriptor, set the element
WINDOWS-基础:SafeArray的使用方法的更多相关文章
- Java基础 之 System.getProperty()方法
Java基础 之 System.getProperty()方法大全 public static void main(String[] args) { System.out.println(" ...
- Windows 系统 PostgreSQL 手工安装配置方法
自从2020年底开始接触 PostgreSQL 以来就喜欢上了这个数据库,个人感觉比 MySQL 好用,多表联合查询性能好很多,同时也不存在 SQLServer 的版权授权费用问题.搭配 .NET 开 ...
- SQLSERVER误删除了Windows登录用户验证方式使用Windows身份验证的解决方法
SQLSERVER误删Windows登录用户验证方式使用Windows身份验证的解决方法 今天看到这篇文章:没有了SA密码,无法Windows集成身份登录,DBA怎么办? 想起来之前着急哥问我的一个问 ...
- 转载扩展Windows Mobile模拟器存储空间的方法
扩展Windows Mobile模拟器存储空间的方法 在Windows Mobile应用程序开发的初期,可以使用SDK自带的模拟器来进行调试,这给我们开发人员提供了一种方便的途径.一般的应用程序,占用 ...
- 在Linux下和Windows下遍历目录的方法及如何达成一致性操作
最近因为测试目的需要遍历一个目录下面的所有文件进行操作,主要是读每个文件的内容,只要知道文件名就OK了.在Java中直接用File类就可以搞定,因为Java中使用了组合模式,使得客户端对单个文件和文件 ...
- Windows的拖放操作使用方法
Windows的拖放操作使用方法
- Linux和Windows下查看环境变量方法对比
摘自:Linux和Windows下查看环境变量方法对比 一.查看所有环境变量的名称和值 Linux下:export Windows下:set 二.根据名称查该环境变量的值 Linux下:echo $环 ...
- Delphi一共封装(超类化)了8种Windows基础控件和17种复杂控件
超类化源码: procedure TWinControl.CreateSubClass(var Params: TCreateParams; ControlClassName: PChar); con ...
- 在Linux下访问Windows共享目录的配置方法
在Linux下访问Windows共享目录的配置方法 1.在Windows上设置一个共享目录 如:将d:\RedHat_disk设置为共享目录 2.在Windows上创建一个用户,如tommy,密码11 ...
- windows 下共享内存使用方法示例
windows下共享内存使用方法较 linux 而言微微复杂 示例实现的功能 有一个视频文件,一块内存区域 : 程序 A,将该视频写入该内存区域 : 程序 B,从该内存区域读取该视频 : 代码模块实现 ...
随机推荐
- CF961G Partitions(第二类斯特林数)
传送门 对于每一个元素,我们只要能求出它的出现次数\(sum\),那么每个元素的贡献都是一样的,最终的答案为\(sum\times \sum_{i=1}^n w_i\) 那么分别讨论 如果这个元素自己 ...
- python中的三元表达式(三目运算符)
python中没有其他语言中的三元表达式,不过有类似的实现方法 其他语言中,例如java的三元表达式是这样 int a = 1; String b = ""; b = a > ...
- Java无模板导出Excel,Apache-POI插件实现
开发环境 jdk 1.8 Maven 3.6 Tomcat 8.5 SpringBoot 2.1.4.RELEASE Apache-POI 3.6 Idea 注意: 我是在现有的基于SpringBoo ...
- 基于IDEA实现SSM整合框架的搭建配置流程
1.创建数据库表,以员工信息表为例子: DROP TABLE IF EXISTS `em_info`; CREATE TABLE `em_info` ( `em_id` INT(50) NOT NUL ...
- 浅谈css常用伪类用法
着重写一下after和before的用法: css样式搞定:标签元素+伪类after a.'class名':after{//我的样式名称是这个,可以写成你自己的样式名称 content: '已打包'; ...
- JavaScript进阶 - 第10章 编程挑战
10-1 编程挑战 现在利用之前我们学过的JavaScript知识,实现选项卡切换的效果. 效果图:
- CC33:碰撞的蚂蚁
题目 在n个顶点的多边形上有n只蚂蚁,这些蚂蚁同时开始沿着多边形的边爬行,请求出这些蚂蚁相撞的概率.(这里的相撞是指存在任意两只蚂蚁会相撞) 给定一个int n(3<=n<=10000), ...
- redis之五大数据类型
redis之五大数据类型 redis redis的两种链接方式 简单链接 1234 import redisconn = redis.Redis(host='10.0.0.200',port=6379 ...
- BZOJ 4668: 冷战 并查集&&暴力LCA(雾)
利用并查集按秩合并,保存每个点合并的时间: 求时间时,就一直跳u=fa[u],并记录路径上时间的最大值,代表最后一次合并的时间 #include<cstdio> #include<i ...
- 【手撸一个ORM】第九步、orm默认配置类 MyDbConfiguration,一次配置,简化实例化流程
这个实现比较简单,事实上可配置的项目很多,如有需要,请读者自行扩展 using System; namespace MyOrm { public class MyDbConfiguration { p ...