其实这个问题我很早很早以前就发现了,只是一直没留意,也不在意。今天无意中又用VB写了一个程序全部使用NTDLL导出函数编写,又出现了这样的情况,这样就由不得我不注意了,经过我的反复测试以及反汇编验证,证实了vb6_sp6在调用某些API(测试的应该有很多API存在这样的问题)存在内存泄露问题或者是函数调用失败。请大家先看我写的简单两段代码。代码一:Option Explicit
Private Const MEM_RELEASE = &H8000
Private Const MEM_COMMIT = &H1000
Private Const PAGE_EXECUTE_READWRITE = &H40
Private Declare Function VirtualAlloc Lib "kernel32" (lpAddress As Any, ByVal dwSize As Long, ByVal flAllocationType As Long, ByVal flProtect As Long) As Long
Private Declare Function VirtualFree Lib "kernel32" (lpAddress As Any, ByVal dwSize As Long, ByVal dwFreeType As Long) As LongPrivate Sub Code1()
    Dim Base As Long
    Base = VirtualAlloc(ByVal 0&, 100, MEM_COMMIT, PAGE_EXECUTE_READWRITE)
    If Base Then
        MsgBox Hex(Base)
        MsgBox VirtualFree(ByVal Base, 0, MEM_RELEASE)
        MsgBox Hex(GetLastError)
    End If
End Sub这段代码是申请一段内存,然后马上释放它,代码没什么难以理解的非常简单。大家仔细看代码上好像也不存在有什么问题,那么问题在什么地方呢?我一句一句来解析首先“Base = VirtualAlloc(ByVal 0&, 100, MEM_COMMIT, PAGE_EXECUTE_READWRITE)”
这行代码申请了一段长100字节的内存跟踪结果成功申请了得出某地址,然后我用msgbox把地址显示出来
这时这段地址是可用的,大家可以使用一些内存察看编辑工具,比如冰刃之类的。然后调用“VirtualFree ByVal Base, 0, MEM_RELEASE"释放内存,失败了。我检查了很久参数和API声明均没发现有什么问题那么问题出在什么地方呢?为了求证我写了代码二,也就是代码一最终在Ring3层调用的API函数代码二:Option Explicit
Private Const MEM_RELEASE = &H8000
Private Const MEM_COMMIT = &H1000
Private Const PAGE_EXECUTE_READWRITE = &H40
Private Declare Function VirtualAlloc Lib "kernel32" (lpAddress As Any, ByVal dwSize As Long, ByVal flAllocationType As Long, ByVal flProtect As Long) As Long
Private Declare Function VirtualFree Lib "kernel32" (lpAddress As Any, ByVal dwSize As Long, ByVal dwFreeType As Long) As LongPrivate Sub Code2()
    Dim ntStatus As Long
    Dim AllocationSize As Long
    Dim ReturnLength As Long
    Dim Base As Long
    
    AllocationSize = 100
    ntStatus = ZwAllocateVirtualMemory(-1, _
                                       Base, _
                                       0, _
                                       AllocationSize, _
                                       MEM_COMMIT, _
                                       PAGE_EXECUTE_READWRITE _
                                       )
                                           
    If ntStatus >= 0 And Base Then
        MsgBox Hex(Base)
        AllocationSize = 0
        ntStatus = ZwFreeVirtualMemory(-1, Base, AllocationSize, MEM_RELEASE)
        MsgBox Hex(ntStatus)
    End If
End Sub同样出错在ZwFreeVirtualMemory这句上,这时函数有返回值,值为&HC00000F2查阅相关定义为
STATUS_INVALID_PARAMETER_4,说明第四个参数存在问题。这句话可就那纳闷了,好在前段时间在64位编程时也遇到这样的问题后来经过跟踪分析知道是传进去的数据按32位传进去的前面位补了FFFFFFFF所以出了错。我就猜测估计这里也是这样的问题然后我通过windbg进行双机调试断点下在nt!NtFreeVirtualMemory上发现了确实在第四个参数上进行了检测而这时我们传进去的值和我们本来想传进去的值有出入

解决方案 »

  1.   

    kd> kv
    ChildEBP RetAddr  Args to Child              
    f8589d4c 8053d808 0000008c 0012fab8 0012fac8 nt!NtFreeVirtualMemory (FPO: [Non-Fpo])
    f8589d4c 7c92eb94 0000008c 0012fab8 0012fac8 nt!KiFastCallEntry+0xf8 (FPO: [0,0] TrapFrame @ f8589d64)
    0012f95c 7c92da54 004036fd 0000008c 0012fab8 ntdll!KiFastSystemCallRet (FPO: [0,0,0])
    0012f960 004036fd 0000008c 0012fab8 0012fac8 ntdll!NtFreeVirtualMemory+0xc (FPO: [4,0,0])
    WARNING: Stack unwind information not available. Following frames may be wrong.
    0012fadc 00402aae 000004bc 00401ca8 0012fb20 111111111+0x36fd
    0012fb14 733baea0 0014c158 0012fb30 00401830 111111111+0x2aae
    0012fb30 733bae7d 00401830 0012fbec 00000002 MSVBVM60!CallProcWithArgs+0x1e
    0012fb48 733bae35 0014c18c 0012fc2c 0012fbec MSVBVM60!InvokeVtblEvent+0x32 (FPO: [4,0,2])
    0012fb68 733a460b 0014c174 733b42df 00dffc54 MSVBVM60!InvokeEvent+0xaf
    0012fb70 733b42df 00dffc54 0012fc50 733b31a4 MSVBVM60!DESK::AddRef+0x13 (FPO: [1,0,0])
    0012fb7c 733b31a4 0012fc2c 0012fbec 00000002 MSVBVM60!DESK::AddCtlRef+0x16 (FPO: [0,0,1])
    00000000 00000000 00000000 00000000 00000000 MSVBVM60!EvtErrFireWorker+0x240'Ebp
    kd> dd f8589d4c
    f8589d4c  00000283 8053d808 0000008c 0012fab8
    f8589d5c  0012fac8 ffff8000 0012fadc 7c92eb94
    f8589d6c  badb0d00 0012f968 f91a2d98 f91a2dcc
    f8589d7c  00000000 00000000 00000000 00000000
    f8589d8c  00000000 00000000 00000000 00000023
    f8589d9c  00000023 7c92eb94 0012f38c 00df1fa4
    f8589dac  00000001 ffffffff 0000003b 000000a4
    f8589dbc  73467324 73473bbd 0012fadc 00000000可以看出第四个参数值竟然是ffff8000,而我们需要传进去的是&H8000也就是32768,可见问题出在这里,为更进一步证实我又用IDA看了静态代码,大家请看下面的反汇编代码片断.text:004037CF                 push    0FFFF8000h
    .text:004037D4                 push    eax
    .text:004037D5                 push    offset dword_407034
    .text:004037DA                 push    ecx
    .text:004037DB                 call    sub_401FB4 '这里就是调用Dllfunctioncall来调用API,而这次调用的正是ZwFreeVirtualMemory
    .text:004037E0                 mov     [ebp+var_14C], eax
    .text:004037E6                 call    esi ; __vbaSetSystemError
    .text:00401FB4 sub_401FB4      proc near               ; CODE XREF: sub_402B60+B98p
    .text:00401FB4                                         ; sub_402B60+C7Bp ...
    .text:00401FB4                 mov     eax, dword_407468
    .text:00401FB9                 or      eax, eax
    .text:00401FBB                 jz      short loc_401FBF
    .text:00401FBD                 jmp     eax
    .text:00401FBF ; ---------------------------------------------------------------------------
    .text:00401FBF
    .text:00401FBF loc_401FBF:                             ; CODE XREF: sub_401FB4+7j
    .text:00401FBF                 push    offset off_401F9C
    .text:00401FC4                 mov     eax, offset DllFunctionCall
    .text:00401FC9                 call    eax ; DllFunctionCall
    .text:00401FCB                 jmp     eax
    .text:00401FCB sub_401FB4      endp我们可以看到上面的反汇编代码中明显VB编译器把&H8000写成了0FFFF8000h,好到目前位置我们已经发现了问题所在那么这个问题怎么解决呢?
    其实解决方法也很简单,主要是VB编译器把&H8000也就是Private Const MEM_RELEASE = &H8000看成了&HFFFF8000,在这里我们先不管他为什么会这样我们这次主要是为了解决问题,那么我们怎么解决呢?我们需要Vb把数值识别正确即可比如我们可以这样定义“Private Const MEM_RELEASE = 32768”或者这样定义都可以“Private Const MEM_RELEASE = &H8000&”显示的让VB知道这个是个LONG类型.这样再使用上面代码就没问题了。正确代码如下:Option Explicit
    'Private Const MEM_RELEASE = 32768
    Private Const MEM_RELEASE = &H8000&
    Private Const MEM_COMMIT = &H1000
    Private Const PAGE_EXECUTE_READWRITE = &H40
    Private Declare Function VirtualAlloc Lib "kernel32" (lpAddress As Any, ByVal dwSize As Long, ByVal flAllocationType As Long, ByVal flProtect As Long) As Long
    Private Declare Function VirtualFree Lib "kernel32" (lpAddress As Any, ByVal dwSize As Long, ByVal dwFreeType As Long) As LongPrivate Declare Function ZwFreeVirtualMemory Lib "ntdll.dll" (ByVal ProcessHandle As Long, _
                                                                  ByRef BaseAddress As Long, _
                                                                  ByRef FreeSize As Long, _
                                                                  ByVal FreeType As Long _
                                                                  ) As Long                                                                  
    Private Declare Function ZwAllocateVirtualMemory Lib "ntdll.dll" (ByVal ProcessHandle As Long, _
                                                                      ByRef BaseAddress As Long, _
                                                                      ByVal ZeroBits As Long, _
                                                                      ByRef AllocationSize As Long, _
                                                                      ByVal AllocationType As Long, _
                                                                      ByVal Protect As Long _
                                                                      ) As Long
                                                                     
    Private Sub Form_Load()
        Call Code1
        Call Code2
    End SubPrivate Sub Code1()
        Dim Base As Long
        Base = VirtualAlloc(ByVal 0&, 100, MEM_COMMIT, PAGE_EXECUTE_READWRITE)
        If Base Then
            MsgBox Hex(Base)
            MsgBox VirtualFree(ByVal Base, 0, MEM_RELEASE)
        End If
    End Sub
    Private Sub Code2()
        Dim ntStatus As Long
        Dim AllocationSize As Long
        Dim ReturnLength As Long
        Dim Base As Long
        
        AllocationSize = 100
        ntStatus = ZwAllocateVirtualMemory(-1, _
                                           Base, _
                                           0, _
                                           AllocationSize, _
                                           MEM_COMMIT, _
                                           PAGE_EXECUTE_READWRITE _
                                           )
                                               
        If ntStatus >= 0 And Base Then
            MsgBox Hex(Base)
            AllocationSize = 0
            ntStatus = ZwFreeVirtualMemory(-1, Base, AllocationSize, MEM_RELEASE)
            MsgBox Hex(ntStatus)
        End If
    End Sub
      

  2.   

    顶!高深!以前也遇到过必须Private Const MEM_RELEASE = &H8000&这类必须为LONG类型的申明,但没有深究为什么……,但Private Const MEM_RELEASE as long = &H8000这样可以吗?呵呵希望楼主帮忙看看这个,谢谢:
    http://topic.csdn.net/u/20100219/22/3af9c43e-7e6d-404c-9b47-4601f8c5d59e.html?11308
      

  3.   


    Private Const MEM_RELEASE as long = &H8000
    这样也不行,要让vb知道值是long而不是让编译器去给它补值
      

  4.   

    本来 long (32bit) 就需要 写成 &HFF00&
    某些API其实是 short (16bit) integer( -32768 ~ 32767 (因为是 16位操作系统中留下来的API)
    你输入37268 > 32767 超出其范围,溢出了.http://forums.techguy.org/software-development/495522-vb6-h-constants.html&HFF00 is hex FF00 a short (16bit) integer
    &HFF00& is hex 0000FF00 a long (32bit) integer
    &HFF0000 is hex 00FF0000 a long (32bit) integer
    65536 is hex 00010000 is a long (32bit) remember the max value for a short integer is 65535 or (FFFF).例子:Option ExplicitPrivate Const i = 32768
    Private Const j = &H8000 '<--这里其实是 -32768 为什么呢? 因为是short (16bit) integerPrivate Const m = 32768
    Private Const n = &H8000& '<--这个才是32768,因为是long (32bit) integerPrivate Sub Command1_Click()
        If i = j Then
            MsgBox ("True") '不会经过这里的.
        End If
        
        If m = n Then
            MsgBox ("True")
        End If
    End Sub
      

  5.   

    CTRL + C , CTRL + V
    然后这个网站引用,那个网站应用,就造成了一堆的错误
      

  6.   

    其实这还是算是VB的Bug比如这样写 VirtualFree(ByVal Base, 0, 32768)是没问题的但是如果这样写就有问题了 VirtualFree(ByVal Base, 0, &H8000)真不知道vb编译时是怎么识别的
      

  7.   

    应该是C++的原型,转成VB后,因为类型转换时的差别,而引起的问题
      

  8.   

    我赞同5楼Lost_Painting的观点:
    Private Const j = &H8000 '<--这里其实是 -32768 为什么呢? 因为是short (16bit) integer
      

  9.   

    比如MSDN中在Val Function的说明中就有举例:
    In the code below, Val returns the decimal value -1 for the hexadecimal value shown:Val("&HFFFF")
      

  10.   

    看来VB有时候调用API的时候,不如自己操作内存了,呵呵。
      

  11.   

    好像是变量如果没有指定类型的话,编译器会以最小的容器来装它,我记得以前遇到类似的问题,好像是两个short范围内的数相乘结果溢出,非要强制指定它是long,具体的记不清了,现在手头没VB6试
      

  12.   

    估计这是从16位版的VB遗留下来的问题吧.
    因为VB6在从255到255以上的操作时表现正常,只在32767到32767以上的数值自动转换时发生问题. 
    说明它在对待未指定类型整数的时候总是"想到"Integer,然后需要写代码的时候"提醒"一下,它才会当成32位的Long来看待,貌似后娘. 
    例:print 200*2 不会溢出, print 32000*2 溢出了.
      

  13.   

    这与 API 没有关系,而是非常容易被人忽略的 VB 常识。16进制值本身是无符号的,但是 VB 的 Integer/Long 都是有符号的。 
    在编译整数常数时,如果没有指定类型,总是优先用 Integer 类型来存放。Private Const MEM_RELEASE = &H8000
    Private Const MEM_COMMIT = &H1000 
    &H8000 和 &H1000 用两字节就能存放,所以是 Integer 类型。但是因为符号的关系,&H8000 成了负数。
    然后在调用函数时,应为需要 Long 类型,就自动做 Integer->Long 的类型转换,扩充的高2字节按最高位填充,即负数扩充的是 &HFFFF0000,所以 &H8000 成了 &HFFFF8000。Private Const MEM_RELEASE As Long= &H8000
    即使变量声明为 Long,但是编译时先解析常数 &H8000,这是个 Integer,然后生成 Long 类型的常量 MEM_RELEASE 时,也要做 Integer->Long 的类型转换,也成了 &HFFFF8000。
    与上面的区别只是在编译时做的类型转换而不是运行时。Private Const MEM_RELEASE As Long= &H8000&
    但是加了 & 后缀,常数强制解释成 Long 型,直接就是 &H00008000,就不会有这个问题。
      

  14.   

    学习啦!vb 的 integer 默认为 16 位,害人不浅!
      

  15.   


    这点有点说不过去比如这样声明问题依然存在 “Private Const MEM_RELEASE as long = &H8000”
    这样按理说已经把MEM_RELEASE定义成LONG类型的常数了那么&H8000就是有效值范围内,但是在编译时VB还是把它看成了&HFFFF8000我估计是VB编译器识别问题,为什么这么说呢?为什么独独是32768呢?经过我多次测试和反汇编发现VB编译气会把下面这段数值识别成&HFFFFXXXX具体值是&H8000到&HFFFF也就是32768到65536之间的数值为什么会这样目前我也不知道为什么。
    不过不管具体什么原因,我觉得这是Vb的一个bug,而很多程序员,几乎是80%(因为我google了下发现全都是这样声明的)的vb程序员都没有意识到这个问题,那么大家在使用这个函数释放内存时就会造成内存泄露了,也就表现为为什么有些VB程序越用内存占用越大估计和这个问题有关系。因为很多程序员根本就没有去检测VirtualFree这个函数调用是否成功基本上都是这样写的“VirtualFree ByVal Base, 0, MEM_RELEASE”可想而知这样的定义造成了什么样的严重后果。假想我们一个程序或者定时器或者一个频繁调用的过程需要每次都分配一小块内存那么我们正好使用了VirtualAlloc(这样的人不少,用惯API或者其他语言转过来的人基本上都会这样用)那么可想而知这个内存泄露问题就严重了。所以请大家高度重视此问题。
      

  16.   

    辛好!我早都不用 integer 类型了。普通变量,我都声明为Long型。
      

  17.   


    这点有可能
    我觉得是微软在设计VB IDE时忽略了这个问题。
      

  18.   

    32768~65535的数,能用short装下,但符号是负的,也就是说32768~65535实际上被VB解释成了-32768~-1
    再转换成long的时候,由于符号原因,自然就变成&HFFFF8000了也就是说,VB里的数值类型并没有有符号和无符号之分,可能VB当时为了兼容易用等,设计了short能装下-32768~32767 或者 0~65535 这两种范围,但实际上内存里的数是一样的
      

  19.   

    你把两个概念混淆了,MEM_RELEASE 是常量,&H8000 是常数。
    As Long 只对常量起作用。
    常数 &H8000 始终是一个 Integer。
      

  20.   


    这点我没搞混淆是字写错了,我不明白VB是怎么处理&H8000的,通过你上面的解释大概明白了。
    现在看来都是VB IDE造成的或者说设计问题吧。其实两个字节能装下&H8000没错就是因为又要转换成LONG所以出了问题,都怪VB自己内部处理的机制转过来转过去终于出错了
      

  21.   

    其实如果是这样的话,那么Vb在调用类似API就还会出现这样的情况下比如这次的API其实是对参数检查上才出现了这样的问题
        //
        // Check to make sure FreeType is good.
        //
        if ((FreeType & ~(MEM_DECOMMIT | MEM_RELEASE)) != 0) {
            return STATUS_INVALID_PARAMETER_4;
        }    //
        // One of MEM_DECOMMIT or MEM_RELEASE must be specified, but not both.
        //    if (((FreeType & (MEM_DECOMMIT | MEM_RELEASE)) == 0) ||
            ((FreeType & (MEM_DECOMMIT | MEM_RELEASE)) ==
                                (MEM_DECOMMIT | MEM_RELEASE))) {
            return STATUS_INVALID_PARAMETER_4;
        }其实做这样检测的函数很多,只要存在上面转换的动作的参数也就是数值在32768-65536之间的值进行传递并且改底层实现函数又进行该参数检测的话就问题导致API函数调用失败,而我们这次讨论的函数就会导致内存没有被释放掉,导致最终内存泄露
      

  22.   


    为什么会将 &H8000 转换成  &HFFFF8000 ...是因为.. 这样转换之后, 他们的值相等...................(并非完全相等, 而是某种角度上来讲)编译器如果不这么做, 他就不是一个好的编译器, 这个问题可以去看编译原理, 虽然这看上去编译器好像很弱智的样子............
      

  23.   

    计算机组成原理→DOS命令→汇编语言C语言、代码书写规范→数据结构、编译原理、操作系统→计算机网络、数据库原理、正则表达式→其它语言、架构……
      

  24.   

    位运算的方法进行数值对比,检测的方法非常值得推荐, 因为位运算的速度非常快api的代码用这种方法检测参数, 问题不大, 还是传入的数据有错, 归根结底.....
      

  25.   

    这不是 VB 的问题,而是程序员的问题。
    要用 VB 的思想来思考,VB 的十六进制常数是可以有符号的,所以 &H8000 就是 -32768,要表示 +32768 就应该用 &H8000&,没有任何的二义性。
    调用函数时将参数的值 +32768 写成了 -32768,就是程序员的问题。就像车辆靠右行驶一样,不用疑问,遵守规则就行。
      

  26.   


    在非 API 的代码中,我也遇到过 Long 型赋值需要加 & 后缀的情况。最初没有注意,在一些特殊情况下出现异常,跟踪调试才发现是这个问题。
      

  27.   

    这里发言,表示您接受了CSDN社区的用户行为准则。
    请对您的言行负责,并遵守中华人民共和国有关法律法规,尊重网上道德。
    转载文章请注明出自“CSDN(www.csdn.net)”。如是商业用途请联系原作者。
      

  28.   


    恩这话说的没错,用什么东西就要遵守这东西定制的规则。
    但是试问下,如果不是偶然遇到这样的问题再把这个问题提出来,这里有多少人注意到呢?或者自己回去翻下代码看你的代码是不是也存在这样的问题呢?虽然知道这些规则,但是在编写代码的时候有几个能意识到这个问题呢?其实至少从这件事情我们知道了一些现象和学习到了一些东西,需要我们警惕的一些问题等。
    一:抄袭现象特别严重,不然也不会出现搜索Google竟然全部(有夸张的成分,但是大家自己搜索下就知道了)都是这样声明
    二:在做语言之间转换时要特别注意各语言环境之间的区别,就拿这次的问题C定义也就是“#define MEM_RELEASE 0x8000”,而我们转换成VB很可能就不小心转换成了“Const MEM_RELEASE = &H8000”,事实很多人都是这样转换的。
    三:基础要打好啊(不要向我学习),要有良好的编程习惯
    四:...等大家补充啊
      

  29.   

    没人能够不犯错,但是为什么要费那么大的劲做双机调试呢?
    如果你不是对自己的代码太自信,只要在 VB 调试中 Debug.Print MEM_RELEASE 看看早就发现问题了。
      

  30.   

    窗户纸捅破了,也就明白了,关键是学会一种思考的方式才可能举一反三。Tiger_Zhao解释的很好
      

  31.   


    其实这问题还真难被发现,不然估计早有人提出来了。正好我是在使用ntdll的导出函数时发现的如果kernel32的估计就发现不了,因为大家都喜欢“VirtualFree ByVal Base, 0, MEM_RELEASE”这样了事,根本没有检查函数是否调用成功了,就算检查了也只知道失败了为什么失败估计也很难找。而我刚好使用ntdll!NtFreeVirtualMemory刚好有返回值,而且返回值(STATUS_INVALID_PARAMETER_4)提示了我第四个参数出了问题,我才注意了这个参数,开始也不层怀疑是传进去的值有问题,所以就跟踪,才慢慢确定真正出错的原因.
      

  32.   

    C程序里面
    char c;
    c=128;
    printf("%02X",c);
    输出地结果并不是80,而是前面补了一堆FF的东西。如果
    char c;
    c=128;
    printf("%02X",c & 0xFF);或者
    unsigned char c; //声明为无符号数
    c=128;
    printf("%02X",c);
    就可以输出预期的结果。应该同样是因为符号位引起的问题。
      

  33.   

    顶一下,原来如此.话说,CSDN现在的引用咋乱七八糟了?
      

  34.   


    其实我还没明白为什么Private Const MEM_RELEASE as long = &H8000 不行。
    它与Private Const MEM_RELEASE =&H8000& 有什么不同。同样声明了类型为Long,为什么不同呢?
      

  35.   

    VB6 的IDE开发环境是有问题的。
    例如:在IDE下,一个对象的颜色值为&H80000012&,但把这个颜色值赋给一个Long型变量lColor时,颜色值后面的&符号会自动消失:lColor=&H80000012,隐式转换成Long型吗?不是,赋给一个没有类型的变量也是这样。不明白为什么会这样!
      

  36.   

    因为 &H80000012 超过 2 字节,必定是 Long。
    在输入这类常数时养成末尾输入 & 的习惯,VB-IDE 会自动帮你格式化来确定末尾是否需要保留这个 & 符号。
      

  37.   


    哦,经过测试,原来是这样:lColor=&H8000&,这样不会丢失后面的&符号,但多一个0会丢失:lColor=&H80000,成了这样。说明IDE丢失&符号后自动转换成了Long型。
    Debug.Print TypeName(&H8000), TypeName(&H8000&), TypeName(&H80000)可以测试。
    第一个是Integer型,后面两个是Long型。
      

  38.   


    声明了MEM_RELEASE的类型为Long,却没有声明H8000的类型,因为H8000还在integer类型的范围之内,所以VB自动把它识别为integer型。
    把integer类型数据赋值给long型变量,需要进行类型转换,这时候要把2字节的intege扩展为4字节的long,方法应该是左补符号位。所以当integer符号位为1的时候,转成long会变成前面都是FF。
    Private Const MEM_RELEASE =&H8000&则是声明了H8000是long,符号位是0
      

  39.   


    其实这个问题,可以说是人为错误也可以说是编译器问题
    为什么这么说呢人为的可以这么说,只要后面加个"&"即可,但是这是需要一些因数存在的情况下。比如时刻能想到这个常量的值是两个字节存放得了的,可能会存在转换(这里存在很多问题谁能一眼看出这个常数值是几个字节能存放的呢?当然都知道四个字节肯定能放下,但是谁知道VB会进行优化呢?而且声明成十六进制本来就难一眼看出数值的大小范围,当然如果有个好的编程习惯,什么常量我后面都加个"&"就行了,当然也有例外的)。编译器一说,是因为本来类型就是LONG了为什么要进行多次转换而导致最终错误,C其他语言就没这样的问题,出现这样的问题就是因为Vb优化或者太“保姆”造成的,而且象这些常数比如&H8000谁一下子能想到它是否可以两个字节存放,谁会想到VB会进行多次转换,因为常量的类型本来就是LONG你干什么要帮我转换?不转换不就没事了吗?当然这只是我个人的看法,我觉得这点VB IDE确实存在问题。至于我为什么不按VB思路来思考问题,说实话我一个自学而成的人对于基础是最薄弱的一关,你们不说我还不知道可能发生这些情况,我也是根据自己的经验,进行反编译调试跟踪找出问题所在然后才想出解决方法的。而且就这个问题,我想一般人还真发现不了我上面都做了解释了,就算你知道Vb把&H8000转换成了&HFFFF8000你也会觉得正常,不会怀疑因为这个转换而导致函数调用失败,如果不是我进行大量的测试并且恰好使用ntdll的导出函数有了返回值进一步一步的跟踪验证反汇编跟踪会发现这个问题吗?
      

  40.   

    65 楼给出了 VC 编译器一样的情况。
    VC 十六进制是无符号的,但是不能把这个规则套用到 VB 中。所以说你没有用 VB 的规则对待问题。就像车辆靠右行驶还是靠左行驶,无所谓好坏,规则而已。
    但是如果不遵守当地的规则逆行,就是有错。
      

  41.   

    道理说出来显得很简单,不过俺之前确实没想到过这个事情,万一碰上了估计被挫败的可能性>=99.9999999% ,要感谢陈辉的提醒
    说C里面不存在这个问题我是不同意的
    我写C程序的时候碰到过好几次类似的情况,吃了几次亏,现在就比较注意了。
    比如:
    char c;
    c=0x80;
    if(c==0x80)   //if((unsigned char)c==0x80)这个可以判断为真
    {
        XXXXXX;//很多编译器编译的程序根本不会执行到这一步
    }
    明明给c赋值为0x80,下面偏偏告诉你c不等于0x80。
      

  42.   

    我晕,这么简单的问题被楼主搞的那么复杂啊。VB里面声明(signed)long型常量一定是&HXXXX&这种样子的啊。如果是&HXXXX的话,就是(signed)Integer,然后赋值给(signed)long的话编译器就会转换。如果是正数前面就加0000,如果是负数前面就加FFFF&H8000~&HFFFF这个范围内的数都是负数(符号位也就是最高位 = 1),前面会加FFFF
    &H0000~&H7FFF这个范围内的数是正数,前面会加0000
      

  43.   

    顶  飘过 没用过此类API
      

  44.   

    顶  也飘过 没用过此类API
      

  45.   

    必须顶尤其感谢 chenhui530 提出这样的问题讨论!
    #30,#47,#51,#65,#76,#77,#82,#85,感谢各位!