假设一个类Class1,包含一个属性Name'Class1
Public Name as String窗体中定义一个结构myType,如下:Private Type myType
Name as Class1
end Type
[Code=VB]
然后执行一个方法
[code=VB]
private sub Copydata()
Dim t As myType, t1 As myType, l As Long
Set t.Name = New Class1
t.Name.Name = "abcdefg"
CopyMemory ByVal VarPtr(t1), ByVal VarPtr(t), 4
'CopyMemory t1,t,4
Debug.Print t1.Name.Name
end Sub执行该段代码Debug.Print语句将输出t1的属性值,说明结构复制成功,单步执行到那句也没问题.但是这个过程一执行完,就报内存读写错误,IDE直接挂掉.这是怎么回事?t1的内存不能正确释放?
Public Name as String窗体中定义一个结构myType,如下:Private Type myType
Name as Class1
end Type
[Code=VB]
然后执行一个方法
[code=VB]
private sub Copydata()
Dim t As myType, t1 As myType, l As Long
Set t.Name = New Class1
t.Name.Name = "abcdefg"
CopyMemory ByVal VarPtr(t1), ByVal VarPtr(t), 4
'CopyMemory t1,t,4
Debug.Print t1.Name.Name
end Sub执行该段代码Debug.Print语句将输出t1的属性值,说明结构复制成功,单步执行到那句也没问题.但是这个过程一执行完,就报内存读写错误,IDE直接挂掉.这是怎么回事?t1的内存不能正确释放?
这两句都是用地址传送
CopyMemory ByVal VarPtr(t1), ByVal VarPtr(t), 4
CopyMemory t1,t,4
结果都是一样的崩溃
http://topic.csdn.net/u/20090901/09/dddf35aa-7838-4415-85b2-222358422d81.html
以前用到copymemory拷贝字符串的时候都是瞎猫撞到死耗子,碰巧对了。没仔细想过。
要知道VB中的对象变量,只是一个32位Long指针,指向Com对象二进制流在内存中的首地址。
这个二进制流的头四个字节也是一个Long地址,指向著名的vTable(COM虚函数表)
vTable中第二与第三个函数,就是加减引用的计数器,每一个对象变量引用该对象,计数加1,反之,变量失效时,减1
说了半天,我想,你应该明白了,你这种复制,绕过了VB的引用计数,直接复制了一个COM指针,用这个复制的指针同样可操作,同一个COM,但VB并不知道,你引用了它,这是很危险的行为。
因为,引用计数,关系到对象何时被销毁,当引用计数为0时,VB会自动把它清理出内存,而复制的指针却还指向那个早已不存在的地址(VB不知道你指向它,没把你算个数^_^)
更可怕的是,复制指针,做为一个VB对象变量,在失效时,VB也会清理它,因指针不为0,Vb就会天真地以为,它也引用了一个对象,当然要去访问,其指向的那个早已不存在地址,其后果,只能是崩溃!你这两个对象变量,都是过程中的局部变量,所以,在过程结束时,会被清理,崩溃就在这时发生。若把它们声明为窗体变量,那崩溃将在窗本关闭时发生;若声明为全局变量,那崩溃将在程序关闭时发生。总之,等着你的只有崩溃,它早晚是要发生的^_^要想不崩溃,也简单,就是复制后,一定要还原,VB就是这点好:不记仇,好借好还,再借不难,破坏了VB的东西,你只要还原,VB可以当做什么也没发生,绝不计较!把这个过程,改成上面这样,就可以,保你不崩溃。(用一个空结构,还原t1)
Private Sub Copydata()
Dim t As myType, t1 As myType, l As Long, t2 As myType
Set t.Name = New Class1
t.Name.Name = "abcdefg"
CopyMemory ByVal VarPtr(t1), ByVal VarPtr(t), 4
'CopyMemory t1,t,4
Debug.Print t1.Name.Name
CopyMemory ByVal VarPtr(t1), ByVal VarPtr(t2), 4
End Sub
怕你不好理解,才像上面那样写,其实最后一句也可以,写成:
CopyMemory ByVal VarPtr(t1.Name), 0&, 4
注意,0&是指针的值,不是指针,所以不能byval其实,这种不增加引用,用假变量访问COM,早已是一种成熟的VB邪术,最常见的应用就是不用模块直接在类中处理窗体消息。你可以绕开VB的类型检查,享受Object类型的万能,又可获得前期绑定的特权。
增加与解除引用,是VB自家的事,与Copy出来的指针无关。
销毁对象,同样是VB自家的事