假设一个类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的内存不能正确释放?

解决方案 »

  1.   

    CopyMemory 是怎么声明的?用地址传送.
      

  2.   

    Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
    这两句都是用地址传送
        CopyMemory ByVal VarPtr(t1), ByVal VarPtr(t), 4
        CopyMemory t1,t,4
    结果都是一样的崩溃
      

  3.   

    参考:
    http://topic.csdn.net/u/20090901/09/dddf35aa-7838-4415-85b2-222358422d81.html
      

  4.   

    只能学习,不敢评论
    以前用到copymemory拷贝字符串的时候都是瞎猫撞到死耗子,碰巧对了。没仔细想过。
      

  5.   

    不过感觉用copymemory拷贝class,有点玄。堆上的事情,谁晓得呢
      

  6.   

    CopyMemory ByVal VarPtr(t1), ByVal VarPtr(t), 4这么写是不行的,因为Vb类对象不是一个简单的数据结构,这点与C++ 的类是不同的,是不能这样复制的,除非你完全了解vb 类对象的数据存储结构。
      

  7.   

    COM成员,哪怕是最简单Public声明的变量属性,都是经过封装的。
    要知道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类型的万能,又可获得前期绑定的特权。
      

  8.   

    感谢小吉给出了WHY并同时给出了HOW!
      

  9.   

    噢,原来需要用这个办法销毁对象,难怪我set t1.name=nothing无效。引申一下,用这个办法是不是可以解除循环引用?
      

  10.   

    copy出来的对象变量,只是借用了一个VB变量的壳,跟对象引用根本不是一回事。
    增加与解除引用,是VB自家的事,与Copy出来的指针无关。
      

  11.   

    还有,我提供的办法,并不是销毁对象,只是为了防止因为VB不知情,导致重复销毁,而还原那个假变量的本来的nothing面目。
    销毁对象,同样是VB自家的事
      

  12.   

    如果反汇编过或者在OD之类调试过VB程序就知道了。或许VB运行效率低下就是因为包装的太多了吧。