喜多郎 大蛇 下载:在VB6中用CopyMemory拷贝字符串的种种猫腻(二)
来源:百度文库 编辑:偶看新闻 时间:2024/05/17 01:34:06
在VB6中用CopyMemory拷贝字符串的种种猫腻(二)
出处:http://blog.csdn.net/slowgrace/archive/2009/09/14/4550116.aspx
- Sub test5()
- String1 = STR_E
- String2 = String$(7, 0)
- CopyMemory pString1, ByVal VarPtr(String1), 4
- CopyMemory ByVal String2, ByVal pString1, 14
- Debug.Print String2 '得到的不是PowerVB,而是“P o w e”?
- End Sub
(2)第2个CopyMemory从String1的地址拷贝14个字节。由于VB中字符串的内部表示是Unicode,所以这时得到的14个字节的内容是“P-\0-o-\0-w-\0-e-\0-r-\0-V-\0-B-\0-”(注意,其中的“-”是我加入用来分割字符的,并不真的包括在字符串内存中)。
(3)由于CopyMemory的第一个参数是ByVal String2,是一个字符串,而VB会自动对API函数中的字符串参数做UA转换。所以,系统会把14个字节的Unicode空字符串String2转为7个字节的ANSI空字符串,并存在一个临时变量中,假设叫_tmp。
(4)然后系统把拷来的14字节数据“P-\0-o-\0-w-\0-e-\0-r-\0-V-\0-B-\0-”向_tmp拷。注意_tmp只有7字节,所以这里有溢出的危险。
(5)由于_tmp只有7字节,所以_tmp实际只得到头7个字节的数据,就是“P-\0-o-\0-w-\0-e-”
(6)最后VB要把ANSI字串再转回Unicode字串,并把转回的结果赋给String2。AU转换就是是将英文的 1 个字节扩张为 2个字节,这样String2最终的内容是“P-\0-\0-\0-o-\0-\0-\0-w-\0-\0-\0-e-\0-”,用Debug打印出来,可不就是“P o w e”么? 下面这个表总结了上述过程:
CopyMemory pString1, ByVal VarPtr(String1), 4
CopyMemory ByVal String2, ByVal pString1, LenB(String1)
String2 = StrConv(String2, vbFromUnicode) '再做UA转换以抵消VB多做的一次AU转换 3.2 阿勇在11楼的代码——结果为何变胖
- '阿勇11楼
- Sub test8_Yong()
- Dim pString1 As Long
- String1 = STR_E
- String2 = String$(14, 0)
- CopyMemory pString1, VarPtr(String1), 4
- CopyMemory String2, ByVal pString1, 4
- Debug.Print String2, StrConv(String2, vbFromUnicode)
- End Sub
CopyMemory pString1, String1, 4CopyMemory pString2, String2, 4CopyMemory pString2, pString1, LenB (String1)初看起来,这个代码貌似是分别得到两个字符串缓冲区的指针,然后把String1的字符串缓冲区拷给String2,结果也是正确的。当真“通俗易懂、还不出错”。但是细想想,你会发现这一切都不大靠谱:(1)首先对于头2个CopyMemory而言,既然VB妈妈会做UA转换,那么pString1和pString2得到的应该分别是_tmp1和_tmp2的地址,而这两个临时变量在CopyMemory调用之后会被释放掉,也就是说pString1和pString2得到的其实是无效的地址(见下图)。
CopyMemory pString1, VarPtr(String1), 4CopyMemory pString2, VarPtr(String2), 4(2)其次,就算我们把头两个语句改成上面这样,第3个CopyMemory真的在拷贝字符串缓冲区么?看出来了么?要拷贝字符串缓冲区,第3个语句应该加上ByVal,像这样:
CopyMemory ByVal pString2, ByVal pString1, LenB (String1)(3)可是,诡异的是,就这么一段漏洞百出的代码,它的运行结果明明是正确的啊?这是为什么呢?看下面Tiger_Zhao的解释。
- Sub test9_Modest()
- Dim String1 As String
- Dim String2 As String
- Dim pString1 As Long
- Dim pString2 As Long
- '这 4 个变量每个长 4 字节,在栈上按地址从低到高为:
- '| pString2 | pString1 | String2 | String1 |
- String1 = "PowerVB"
- String2 = Space$(Len(String1))
- 'String1、String2 分别指向两个字符串
- CopyMemory pString1, String1, 4
- CopyMemory pString2, String2, 4
- 'pString1 、pString2 值为已被释放的临时变量的地址,无所谓
- CopyMemory pString2, pString1, LenB(String1)
- '由于不加 ByVal,其实是从变量 pString1 的地址向变量 pString2 的地址复制 14 个字节
- '等于直接操作栈内存,让变量向左复制(看后面插播的“覆盖模式”),于是
- '| pString2 : 原 pString1 的值
- '| pString1 : 原 String2 的字符串指针
- '| String2 : 原 String1 的字符串指针
- '| String1 : 不确定 |
- Debug.Print String2
- End Sub
(2)对于栈来讲,它的生长方向是向下的,是向着内存地址减小的方向增长。所以先声明的变量的内存地址会比后声明的高。比如上面的示例里那样。3.3.2 插播2:CopyMemory自动处理覆盖A: CopyMemory是Copy还是Cut?原来地址中内存的内容还在么?Q: 复制。源和目标内存不交叉,源不变;如果交叉,还会自动处理覆盖情况。A: “自动处理覆盖情况”是什么意思?是说:万一交叉了,还会把被覆盖的复原,而且把目的地址挪开点么?Q: 看下面的例子:
- '如果有一个数组 a() : 00-01-02
- 'a)
- CopyMemory a(1), a(0), 2
- '结果是 00-00-01,会避免:先用 a(0) 覆盖 a(1),然后再用 a(1) 覆盖 a(2),最终变成 00-00-00
- 'b)
- CopyMemory a(0), a(1), 2
- '结果是 01-02-02,会避免:先用 a(2) 覆盖 a(1),然后再用 a(1) 覆盖 a(0),最终变成 02-02-
在VB6中用Form1.TextWidth 可以求出字符宽,在vb.net里怎么求?
在VB6中用Form1.TextWidth 可以求出字符宽,在vb.net里怎么求?
如何在win xp中用键盘输入日语字符?
在VB6.0中用AOD连接ACCESS数据库如何实现多项高级查找
VB6.0中用什么报表最好?
MYSQL数据库中用什么表示任意字符?
vb6.0在不知道字符串长度的情况下,怎样把字符串的各个字符从右到左各取一次
在VB6.0中用OLE控件内嵌了EXCEL报表,怎样做一个自定义预览报表啊?请高手指点!!!!
用VB中用split分解字符 应该怎么写?谢谢
编写一个程序,实现任意类型的文件拷贝,并显示被拷贝的字符数。
在asp中用那个函数能把字符型如“2.6”转换成数字型的2.6 我用cint()和clng()都不成,转换成了3 !
创建一个标量函数,在一个字符串中用字符串1来替换所有的字符串2,并且把结果反转,显示为大写字符结果
ACCESS中用什么sql语句来截取字符和替换字符
在APPLET中用对话框
在FLASH中用标
在WONDONS中用DOS
VB6!!!!!!
如何在CS中用语音
怎么在自己中用搜索引擎
怎么在vmware中用光驱
在DOS中用注册表呀
怎样在魔兽中用中文名?
怎么在qq中用视频
如何在地址栏中用中文搜索