vfp 中使用 BStr, SafeArray


当我们调用其它语言编写的 DLL 或使用某些 COM / OCX 对象时,我们经常碰到要传递 BSTR 类型的字符串和 SafeArray 类型数组的问题。

BSTR  来自于 Basic 的字符串结构( Basic STRing),其结构是:[Length prefix] + [Data string] + [Terminator]
Length prefix  - 长度前缀, 4 字节, 不包含尾部结束标识的数据长度
Data string - 字符串数据, UniCode(Window)/Ansi(Mac) 格式, 中间可以包含 /0x00
Terminator - 结束标识, 两个 /0x00

要在 vfp 中构造这样的字符串有两种办法:
1. 利用 api 函数来构造,例如:
 m.cAnsiStr = 'ABCDEFG'
 m.cUnicodeStr = StrConv( m.cAnsiStr, 5 )

 Declare Long SysAllocString In Oleaut32 String sz
 m.pBStr = SysAllocString( m.cUnicodeStr+Chr(0)+Chr(0) )         && 指向 BSTR 的指针
 * ---------------------------------------------------------------------------------------
 * 这里我们可以看看 pBStr 指向地址的内容
 * ? StrConv( Sys( 2600, m.pBStr-4, 20 ), 15 )
 * 显示: 0E00000041004200430044004500460047000000
 * 其中
 *  长度前缀: 0E000000 - 14,也就是 cUnicodeStr  的长度
 *  字符数据: 4100420043004400450046004700 - cUnicodeStr 的内容
 *  结束符号: 0000
 * ---------------------------------------------------------------------------------------
 Declare Long SysFreeString In Oleaut32 String bstr
 SysFreeString( m.pBStr - 4 )                && 释放这个 BSTR

2. 自己构造,例如,用于 Window 平台的 BSTR:
 m.cAnsiStr = 'ABCDEFG'
 m.cUnicodeStr = StrConv( m.cAnsiStr + Chr(0), 5 )
 m.cBStr = BinToC( Len( m.cAnsiStr )*2, '4rs' ) + m.cUnicodeStr

实际应该用哪种要看被调用的函数声明方式,第二种方法传送的是指向完整结构的 BSTR 指针,因为 vfp 没有函数可以得到它自己的字符串地址指针,所以只能传送整个串的起始地址;但第一种方式传递的是指向 BSTR 中数据起始位置的指针,这也是为什么调用 SysFreeString 时要减去 4 的原因,不减去这个 4,SysFreeString 会返回串冲突错误(错误码 32)。

如果你同时熟悉 vfp 和 vb 的话,那么下面的代码:

m.cAnsiStr = 'ABCDEFG'
m.cUnicodeStr = StrConv( m.cAnsiStr + Chr(0), 5 )

m.cBStr = BinToC( Len( m.cAnsiStr )*2, '4rs' ) + m.cUnicodeStr
? Func1( m.cBStr )                       && 这里传送的相当于 vb 中 VarPtr( cBStr )

Declare Long SysAllocString In Oleaut32 String sz
m.pBStr = SysAllocString( m.cUnicodeStr )
? Func1( m.pBStr )                      && 这里传送的相当于 vb 中 StrPtr( cUnicodeStr )

===========================================================================

 

SafeArray 安全数组

SafeArray 的结构其实就是 vb 中数组结构,MS 的描述如下:
typedef struct tagSAFEARRAY {
   USHORT cDims;   // 这个数组有几维?
   USHORT fFeatures;  // 这个数组有什么特性?
   ULONG cbElements;  // 数组的每个元素有多大?
   ULONG cLocks;    // 这个数组被锁定过几次?
   PVOID pvData;    // 这个数组里的数据放在什么地方?
   SAFEARRAYBOUND rgsabound[ 1 ];
} SAFEARRAY

其中的 SAFEARRAYBOUND 定义如下:
typedef struct tagSAFEARRAYBOUND {
   unsigned long cElements;    // 这一维有多少个元素?
   long lLbound;     // 它的索引从几开始?
} SAFEARRAYBOUND

如果在 vb 中用 Dim MyArray ( 1 TO 8, 2 TO 10 ) As Long 来定义一个数组的话,实际的内存结构为:
 

cDims = 2

fFeatures =
FADF_AUTO AND FADF_FIXEDSIZE

位置
0
cbElements = 4   LenB(Long)4
cLocks = 08
pvData(指向真数组)12
rgsabound(0).cElements = 816
rgsabound(0).lLbound = 118
rgsabound(1).cElements = 922
rgsabound(1).lLbound = 226

只有其中的“真数组”才存有真正的数组数据,它们与 C 中的数组结构是相同的。
同样的,Oleaut32 中也提供了创建/销毁/维护 SafeArray 的函数: SafeArrayCreate / SafeArrayDestroy / SafeArray...


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值