不会退出Do循环

时间:2015-03-27 20:54:57

标签: excel-vba vba excel

有人能告诉我为什么这段代码永远不会退出Do循环?我已经设法提出了一个解决方案,但我很困惑为什么它不能正常工作。在Excel 2003或2010下运行的结果相同。

Public Declare Function EnableWindow Lib "user32.dll" (ByVal hWnd As Long, ByVal fEnable As Long) As Long
Public Declare Function IsWindowEnabled Lib "user32" (ByVal hWnd As Long) As Boolean

Sub test()
    Dim b As Boolean, h As Long

    h = FindWindow("xlmain", Application.Caption)

    Do
        EnableWindow h, True
        b = IsWindowEnabled(h)
    Loop Until b = True

End Sub

1 个答案:

答案 0 :(得分:0)

这是一篇非常有趣的文章,我认为这是你问题的关键:

http://blogs.msdn.com/b/oldnewthing/archive/2004/12/22/329884.aspx

它基本上说,不同的编码语言以不同的方式代表bool。

在幕后,bool实际上是一个数值变量。

在vba中,False的值表示为( - 1)

如果你这样做,你可以测试一下:

Public sub TestBool
   dim b as boolean
   b = 1
   msgbox cint(b)  '->> the result will be -1, not 1
End sub

如上所示,在“b = 1”行中,vba执行从1到-1的秘密转换。 但是,我的赌注是,当你将IsWindowEnabled声明为布尔值时,因为 这是外部代码,vba不会为你做“繁重的工作”,并且确实如此 不要进行上述转换(我猜 IsWindowEnabled 用C语言编写其中bool表示为1 )。

所以,在行中:

Loop Until b = True

实际发生的是:

Loop until 1 = -1

您可以通过在“循环直到”之前添加以下行来测试:

msgbox clng(b) & " " & clng(True)

有一些解决方案:

  1. 将IsWindowEnabled声明为Long(我认为这是最佳解决方案):

    Public Declare Function IsWindowEnabled Lib“user32”(ByVal hWnd As Long)As Long

  2. 将b声明为变体(它起作用,截至目前,不确定原因):

    Dim b

  3. -EDIT(30.3.15) - 这是一个小分子来证明这件事:

    私有声明函数IsWindowEnabled Lib“user32”(ByVal hWnd As Long)As Boolean

    Private Sub Demo_API_true_in_VBA()
        Dim b As Boolean
        Dim b2 As Boolean
    
        b = 1
        Debug.Print "b = 1 :  " & "Clng(b)=" & CLng(b) & "  b=" & b
        'result- b = 1 :  Clng(b)=-1  b=True
    
        b = -1
        Debug.Print "b = -1:  " & "Clng(b)=" & CLng(b) & "  b=" & b
        'result- b = -1:  Clng(b)=-1  b=True
    
        Debug.Print
    
        b2 = IsWindowEnabled(Application.hWnd)
        Debug.Print "b2 = IsWindowEnabled() :  " & "Clng(b2)=" & CLng(b2) & "  b2=" & b2
        'result- b2 = IsWindowEnabled() :  Clng(b2)=1  b2=True
        ' NOTE HERE THAT b2 equels to 1, not to  -1 !!!
    
        Debug.Print
    
        Debug.Print "b = " & b & " ; " & "b2 = " & b2  ' both will **appear** as True
        'result- b = True ; b2 = True
    
        Debug.Print
    
        ' However, the result of the comparison here will be False !!!
        ' because vba actually does a numerical comparison, and 1 <> -1 .
        Debug.Print "Is b = b2 ?  " & CStr(b = b2)   
        'result- Is b = b2 ?  False
    End Sub