温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

VBS字符串如何在内部实现

发布时间:2021-10-12 09:59:10 来源:亿速云 阅读:118 作者:小新 栏目:开发技术

小编给大家分享一下VBS字符串如何在内部实现,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!



VBS 是基于微软的 ActiveX/COM 技术实现的,而 COM 对象为了做到支持任何语言,定义了一系列通用的数据类型,微软称之为自动化对象类型(Automation data types),其中之一就是 BSTR。VBS 在内部是以 BSTR 来表示字符串的,BSTR 在 WTypes.h 中定义:

复制代码 代码如下:


typedef wchar_t WCHAR;
typedef WCHAR OLECHAR;
typedef OLECHAR *BSTR;

从定义可以看出,BSTR 是指向 wchar_t 类型(也就是 C 语言中的 Unicode)的指针,但是 BSTR 并不是普通的 wchar_t 指针。标准 BSTR 指向一个有长度前缀和 NUL 结束符的 wchar_t 数组。BSTR 的前4字节是一个表示字符串长度的前缀。BSTR 长度域的值是字符串的字节数,并且不包括 NUL 结束符。常用的 BSTR 处理函数请参考 MSDN 文档。

理论说的有点抽象,下面用代码来说明:

复制代码 代码如下:


str = "Hello" & Chr(0) & "world"


这是一句很简单的 VBS 代码,但是 VBScript 解释器在内部做了什么呢?其实就是初始化了一个 BSTR 变量(不考虑字符串连接过程):

复制代码 代码如下:


/* 仅仅为了演示,实际代码肯定不是这样的 */
BSTR str = SysAllocStringLen(L"Hello\0world", 11);为了更清楚地了解 BSTR 的结构,我们换一种写法:

/* BSTR 包含长度前缀,但是却实际指向第一个字符 */
wchar_t arr[] = {22,0,'H','e','l','l','\0','w','o','r','l','d','\0'};
BSTR str = &arr[2];这个 BSTR 在内存中的结构为:

00000000 16 00 00 00 48 00 65 00 6C 00 6C 00 6F 00 00 00
00000010 77 00 6F 00 72 00 6C 00 64 00 00 00


橙色表示四个字节的长度前缀。红色高亮表示 BSTR 指针的当前指向,蓝色高亮表示字符串中的 Chr(0) 字符,绿色高亮表示 BSTR 的结束字符 NUL(该字符是 SysAllocStringLen 函数加上去的,因为是 Unicode,所以要占两个字节)。也就是说,如果不考虑前面四个字节,BSTR 就是 C 语言中的 null-terminated string。

再看一段 VBS 代码:

MsgBox Len(str)用 MsgBox 来显示刚才定义的字符串长度,VBScript 解释器内部又做了什么呢?是不是像 C 语言标准库函数 strlen 一样,遍历整个字符串,以 NUL 作为字符串结束的标识呢?

复制代码 代码如下:


/* C语言 strlen 函数的简单实现 */
size_t strlen (const char * str)
{
const char *eos = str;
while( *eos++ ) ;
return( (int)(eos - str - 1) );
}


答案显然是否定的,因为字符串中含有 Chr(0),如果像 strlen 这样实现,那么就会被 Chr(0) 截断,Len 函数应该返回5才对,然而实际上返回的是11这个正确的数字。

VBS 的 Len 函数内部应该是这么实现的:

复制代码 代码如下:


/* 同上,仅为演示 */
size_t Len(const BSTR str)
{
return SysStringLen(str);
}


或者不调用 Windows API,由于 BSTR 前4个字节前缀表示字符串的字节数(不包括结尾的 BUL 字符),所以只要移动一下指针就行了:

复制代码 代码如下:


/* 强制转换成int指针减一后读取,然后除以2(一个Unicode字符两字节) */
size_t Len(const BSTR str)
{
return *((int *)str - 1) / 2;
}


可以看出,由于 BSTR 的长度可以通过前缀取得,并不需要以 NUL 来作为字符串结束符,也就是说,VBS 字符串是 binary safe (二进制安全)的。

那么为什么下面的代码只能显示 Hello 呢?

MsgBox str这看起来好像和上面说的矛盾,其实不然。VBS 字符串的确是兼容 Chr(0) 字符的,MsgBox 之所以会被 Chr(0) 截断,是因为 MsgBox 在内部调用了 MessageBox 函数,而该函数是以 NUL 作为字符串结束符的。

复制代码 代码如下:


/* 简单起见只实现一个参数
* MessageBox 的第二个参数是以 NUL 作为结束符的
* Pointer to a null-terminated string that contains the message to be displayed.
* 所以 VBS 字符串中包含的 Chr(0) 会把字符串截断
*/
int MsgBox(const BSTR str)
{
return MessageBoxW(NULL, str, L"", 0);
}


也就是说,如果 VBS 内置的函数或者 COM 组件的某些方法在其内部实现中调的 Windows API 的字符串参数是以 NUL 作为结束符的话,就会被 Chr(0) 字符截断。

以上是“VBS字符串如何在内部实现”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注亿速云行业资讯频道!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

vbs
AI