Dim strTest As String
strTest = "ok"
Debug.Print VarPtr(strTest)
Debug.Print StrPtr(strTest)

解决方案 »

  1.   

    你可以看看  学习再学习  地帖子!地址:http://www.csdn.net/expert/topic/533/533904.xml?temp=.5899774
      

  2.   

    回复人: AdamBear(学习再学习) (  ) 信誉:97  2002-2-20 18:55:25  得分:0  
     
     
      我的第一篇文章《VB到底为我们做了什么》已经发给了CSDN文档,已经
    两天了,还在审核中,不知是不是他们认为我的结论有问题。
        文章有8000字,所以不好在这里贴。
        只有继续等,想先看看的人,留下你们的Mail,给你们发。
        第二篇《API和COM,文档里不清楚的问题》正在写,东西在我脑子里,
    不过,我想用实例和实验来说明问题,所以还要准备一些代码。
        因为写东西,所以比较忙,只能断断续续来看看CSDN的贴子了。
        下面这个贴子刚更新过,内存共享和进程通讯的新版本,前天刚加上的。
    我曾说这是这方面最快的方法,但在那个VC的DLL代码中有个位置我说错了,
    我在VC中用了ASNI和Unicode的转换,我说要避免这种转换只有什么Variant或
    Byte Array, 实际上就用BSTR也可以不转换,我是在写API调用的问题时突然
    意识到这个问题的,不过技术本身上应该还是最快的。
    你们可以看看下面的贴子中我的更新部分:
       http://www.csdn.net/Expert/Topicview.asp?id=516072    我也知道acptvb不好回答我这些问题,不过我们应该强烈要求他回答。我可以先告诉大家,由第1个问题而来的惊人猜想,我会在第一篇和第二篇文章
    里用实验来证明我的猜想,这个猜想就是凡是能够被重新定义的VBA函数在效率
    上就还有提高的必要。甚至就在VB中自己写也能写出比VBA函数更快的函数(如
    果你不怕可能产生的问题的话),当然VB已经对绝大部分计算相关的函数进行了
    优化,但仍有不少漏掉了,比如Rnd。Bruce是我佩服的一位大师,不是因为他的技术有多么历害,而是因为他的研究和
    创新精神,现在我把他的《VB核心编程》中关于CopyMemory的部分拿出给大家看看,
    让我们不能不佩服Bruce:
    同时也to Chice_wxg(我怕谁?我是谁!我是流氓我最贼。):【CopyMemory:一个奇怪而可怕的传奇】
        关于这个用于复制内存内容的WIN32函数为什么叫CopyMemory,有一个很长的奇怪故事,尽管Visual Basic和Windows API中没有这种函数。
        最开始是我想要查找WIN16 hmemcpy函数的WIN32等价函数,以用于VisualBasic 4.0版中。没有这个函数,哪怕是一个说明这个函数已经废弃的注释也没有。
        最后我可提出的一个最接近的函数,CopyMemory函数,它与hmemcpy有着相同的参数,并且其文档也相同。不幸的是,不管你在WIN32文档中读过什么,其中没有像CopyMemory这样的东西。你可以使用DumpBin实用程序来搜索所有32位DLL,但是你将不会找到有任何DLL包含有CopyMemory。
        如果你仔细地搜索WIN32的C包含文件,你将会在WINBASE.H中发现如下内容:
    #define CopyMemory RtlCopyMemory
    #define MoveMemory RtlMoveMemory
    #define ZeroMemory RtlZeroMemory
        它指示CopyMemory是名为RtlCopyMemory的函数的另一个名称。不要问为什么;只需要在KERNEL32.DLL中查找RtlCopyMemory。同样,没有。WIN32包含文件中的其他跟踪显示了其原因:在WINNT.H中包含有类似于如下的内容:
    #define RtlCopyMemory(dst, src, len) memcpy(dst, src, len)
        也就是说,RtlCopyMemory是C语言memcpy函数的一个别名,但是你不能在Basic中使用memcpy或其他任何C语言库函数。文档中声称CopyMemory是一个Windows函数而不是一个C语言函数,显然它是在说谎。如果它不是从一个DLL中输出,则你不能调用它。KERNEL32.DLL确实包含有一个用于RtlCopyMemory的项。如果你查看WIN32文档,你将看到MoveMemory与CopyMemory做相同的事情,除了它们处理重叠内存的方式不同之外。我不能想像这样一种情况,一个Basic程序将会去复制重叠的内存。没有理由不使用MoveMemory来代替它。名称CopyMemory看起来比hmemcpy或MoveMemory更智能一些,因此我对于16位和32位版本都使用这个别名:
    #If Win32 Then
      Declare Sub CopyMemory Lib "KERNEL32" Alias "tlMoveMemory"(_lpvDest As Any, lpvSource As Any, ByVal cbCopy As Long)
    #else
      Declare Sub CopyMemroy Lib "KERNEL" Alias "memcpy" ( _lpvDest As Any, lpvSource As Any, ByVal cbCopy As Long)
    #End If
        Windows API类型库具有一个CopyMemory函数的等价(或者几乎是等价)。上面解释了我为什么使用CopyMemory,但是为什么其他每一个人都使用CopyMemory呢?因为我把一份拷贝发送到了Microsoft的一个内部别名,并且某个读到它的人决定它应该成为一篇很好的Knowledge Base文章。我同意了,但条件是他们在提到这一段时说明这是摘录我的书。我认为这是一个好广告。自那以后,我读到了一些文章,在VBITS会议上听到一些人谈论CopyMemory,仿佛它真正存在一样。但是他们没有提到本书才是它的源来。因此不要被错误的广告所蒙蔽。如果他们谈论RtlMoveMemory,则他们是自己想出来的。如果他们谈论CopyMemory,则他们是从我这里得到的(或许他们自己还不知道)。
        
        嘿嘿,怎么样,Bruce Mckinney酷! 
     
      

  3.   

    VarPtr
    StrPtr这两个函数是没有公布的
    具体使用情况请参阅Microsoft网站
      

  4.   

    我现在上网条件不好,所以更新较慢,很多东西只有线下写,下面的东西
    就是我今晚在家刚写好的:   好,我今天来解达我这四个问题。
    第1个问题,诚如我如说,是猜想,如果我在什么地方用了"推论"这个词,那是
    一时激动说错了。我在《VB到底为我们做了什么》中进行了实验,不过那都是
    表面上,你要验证只有自己去跟踪VB的程序,我这么做了,所以我了解一些不为
    人知的东西,不是我要卖关子,我是想让你们自己去试试,我在文章里有几处错误
    (找错是一种能力,Bruce大师的错误我就发现了几处),你如果自己跟踪过程序
    就能明白错在什么地方(可以给个提醒,我说rtc开头的引入函数被直接调用?
    我说__vbaAbsI4比rtcAbsVar快4倍?不要完全相信我的结论,自己去实验。那几个
    错误正是给那些懒汉们一点教训)。
    (to to  hx(乱云山风)你觉得有错真不容易,我们就是要有这种不相信任何未经自己
    验证的技术之精神,如果你能发现我还不知道的错误,我另开贴子给你分!)
    当然要我自己给我的猜想的可信度打80分,但是这里面有意外,有些没有以__vba开头
    的函数也一样没有什么COM调用,一样经过优化,我下面要说的VarPtr就是这样一个不
    能再优化的函数。还有,虽然rtc开头的函数大部分由于COM调用而变慢,我们也应该
    相信VB开发小组这样做有他们的道理,因为他们要考虑到比我们更多的情况,更可况
    VB根本就建COM之上,有些东西想不用COM都不行。千万不要因为多用了一点额外的CPU
    时间,就否定一切COM调用,VB的成功有一半功劳要给COM开发小组,我们用的CInt,
    CLong之类的函数不过是VB开发小组对COM自动化数据类型转换函数一层薄薄的包装。
    VB和COM的高度合作是任何语言无法比拟的,这是他的优点。所以,能够被改写的以
    rtc开头的函数,你的确可以改写而获得性能上的些许提高,但你可能失去更多,比如
    VB文档里经常说的VB的稳定性,尤其在多线程环境里。我提出这个问题,只是想引起大
    家的思考,和对VB原理的探索,另外也是想哗众取宠而已。第2个问题,我本想在第二篇文章里讲,不过写文章不象写贴子,你可以顺着写,不改。
    我和第一篇文章就花了我两个整天,而现在我白天还要上班(不喜欢的工作也要干,
    因为我父母看不惯我整天在家里玩电脑),所以文章可能会更慢点,不过我不会食言。
    VarPtr, StrPtr, ObjPtr我现在告诉大家它们根本就是一个函数,在C里的样子是这样
    的:
    long VarPtr(void* pv){
        return (long)pv;
    }
    仅此而已,不信你用我在第一篇文章里提供的察看类型库函数对应MSVBVM60.DLL中
    输出函数序号的小程序看看。它们的序号都是644, 对应的在DLL中的函数就是一个
    VarPtr,注意它没有用__vba开头,但我们来看看的汇编代码就知道它已经够优化了:
    j = VarPtr(i)004020FC   lea         eax,[i]     
    004020FF   push        eax           '参数中的地址值压栈。
    00402100   call        ___vba@00194188 (004011c2)   '调用输入函数
    00402105   mov         dword ptr [j],eax___vba@00194188:      '跳转到输入函数,就是VarPtr的地址。
    004011C2   jmp         dword ptr [__imp_@__vba@00194188 (0040108c)]'下面就是真正的VarPtr
    660E2C86   mov         eax,dword ptr [esp+4]
    660E2C8A   ret         4              '弹出压栈的参数的地址并返回。
    最后是一句:    lea    dword ptr[j], eax 相比其它VB函数,这是有限几个我用汇编看得懂的非常清晰的函数。
    如果你用j = StrPtr(strTmp)来看,仅仅是前两句压栈的方式不同,
    变成了push dword ptr[strTmp],所以同一个函数因为VB对其参数
    处理不同而有不同的功能,懂汇编的从上面就能看出,ValPtr返回
    的东西,是一个地址值,这个地址值所对应的指针所指之处和用StrPtr
    返回的指针所指是相同的。再看看下面的类型库,就知道为什么VB
    会这么做,根本就不是VB对VarPtr做了什么处理,不过是类型库定义
    上的小技巧而已,对第3个问题的解答同样需要API定义上的小技巧。
    这几个XxxPtr在类型库中是这样的:
            [entry(0x60000006), hidden]
            long _stdcall VarPtr([in] void* Ptr);
            [entry(0x60000007), hidden]
            long _stdcall StrPtr([in] BSTR Ptr);
            [entry(0x60000008), hidden]
            long _stdcall ObjPtr([in] IUnknown* Ptr);
    看看StrPtr,其中BSTR就是C里面的char*或unsigned short, 但由于
    压的是指针所指地址,因为返回的strTmp[0]的地址。
        怎么样,我不再多说了,你可以想一想。我们传的是地址,API需要的是地址,为什么我们不能给Unicode API
    传地址,比如我们用SetWindowTextW为什么就不行,连Bruce大师都说
    不可以,其实Bruce大师想复杂了或者说Bruce大师产生了盲点,它认为
    为,API里定义的字符串是String, 而VB会对String进行Unicode到Ansi的
    转换,因此不用库型库你不可能调用Unicode的API,但是为什么我们非要
    给API传BSTR的String?我试过用ByRef的String,但该死的VB还是进行了
    转换,我在VC的DLL里收到还是一个指向临时ANSI字串的指针,我也一时
    产生盲点,连传指向String的指针的指针都要转换,看来是没办法了。
    盲点就是我们为什么非要在传String时传String, 我们对自定义类型不是
    一直传一个代表地址值的long型吗?有时候问题简单得你一时想不到。
    同时,在问题1中我们知道StrPtr我们可以改写。结合问题1和上面的提示
    你们能不能想出问题3的解决方案呢?算我布置的一个作业。
        这个方案非常有实用价值,因为当程序使用有字串的API,面又在
    Win2000下运行时,VB会从U转到A,但Win2000又要从A转到U,两次不必要
    的转换开销很大,这个方案的价值就是:一我们可以象VC里一样通过不同
    编译参数编译不同平台的版本,二是再动动脑,我们还可以在运行时决定
    用什么的版本,虽然这样程序会大点,但能在两个平台上都高效运行。
        另这个方法不知是不是我第一个想出来,我也不敢把这个方法打上我的
    商标,但希望你们能自己想出来,我思考着我快乐着。    我又花了这么多时间,呵呵,文章可能又要出慢点了。
      

  5.   

    VarPtr:变量的地址
    StrPtr:字符串的地址
    ObjPtr:对象的地址