我想我在Excel中偶然发现了一个bug --我真的很想和别人核实一下。
当打开工作簿并将打开的应用程序的Workbook.VBProject.HelpFile属性设置为ForceDisable时,读取.AutomationSecurity属性时会发生错误。在这种情况下,此string属性返回一个(可能)格式错误的Unicode字符串,而VBA则用问号显示该字符串。在它上运行StrConv(.,vbUnicode)使它再次可读,但它有时会以这种方式松开最后一个字符;这可能表明unicode字符串确实格式错误,因此VBA试图首先转换它,然后失败。
复制这种行为的步骤:
Dim a As Long)要使用的代码:
Const csFilePath As String = "<path to your test workbook>"
Sub TestSecurity(testType As String, secondExcel As Application, security As MsoAutomationSecurity)
Dim theWorkbook As Workbook
secondExcel.AutomationSecurity = security
Set theWorkbook = secondExcel.Workbooks.Open(csFilePath)
Call MsgBox(testType & " - helpfile: " & theWorkbook.VBProject.HelpFile)
Call MsgBox(testType & " - helpfile converted: " & StrConv(theWorkbook.VBProject.HelpFile, vbUnicode))
Call MsgBox(testType & " - description: " & theWorkbook.VBProject.Description)
Call theWorkbook.Close(False)
End Sub
Sub Test()
Dim secondExcel As Excel.Application
Set secondExcel = New Excel.Application
Dim oldSecurity As MsoAutomationSecurity
oldSecurity = secondExcel.AutomationSecurity
Call TestSecurity("enabled macros", secondExcel, msoAutomationSecurityLow)
Call TestSecurity("disabled macros", secondExcel, msoAutomationSecurityForceDisable)
secondExcel.AutomationSecurity = oldSecurity
Call secondExcel.Quit
Set secondExcel = Nothing
End Sub结论:在Excel 2010工作时:
这可能比这更奇怪,因为我发誓我曾经在VBE GUI中看到过问号--当我看到这样一个项目的属性时,会弹出这个版本,尽管我现在无法复制它。
我意识到这是一种边缘情况
还有其他人也可以测试这一点来验证我的Excel安装是否没有软管吗?最好也用另一个Excel版本,看看这是否有区别?
希望这不会像我在这里的其他帖子那样成为一种卷尾草:)也许“Tumblewide生成器”可能是一个很好的徽章.
更新
我已经扩展了属性列表,以测试我还可以找到什么,以及所有VBProject的属性(BuildFileName、Description、Filename、HelpContextID、HelpFile、Mode、Name、Protection和Type),只有.HelpFile有一个问题,就是在宏关闭时会损坏。
更新2
将示例代码移植到Word 2010并运行完全相同的行为--当禁用宏时,.HelpFile属性的格式是错误的。似乎负责这一工作的代码是Office范围的,可能在共享的VBA库模块中(正如预期的那样)。
更新3
刚刚在Excel 2007和2003上测试了它,并且都包含了这个bug。我还没有安装Excel来测试它,但我可以肯定地说,这个问题已经有很长的历史了:)
发布于 2016-06-29 09:25:26
我已经处理了所讨论的字符串的底层二进制表示,并发现.HelpFile字符串属性确实返回格式错误的字符串。
.HelpFile属性返回的BSTR表示( VB(A)字符串的水下二进制表示)列出了字符串前面的4个字节的字符串大小,但是下面的内容填充了ASCII表示,而不是VBA所期望的Unicode (UTF16)表示。
解析返回的BSTR内容,并自行决定在某些情况下最有可能使用哪种格式来解决此问题。不幸的是,这里也有另一个问题:它只适用于等长字符串.奇数长度字符串得到他们的最后一个字符切分,他们的BSTR大小报告一个短,而ASCII表示只是不包括最后一个字符也.在这种情况下,无法完全恢复字符串。
下面的代码是问题中的示例代码。与原始示例代码一样,使用说明也适用于它。RecoverString函数执行所需的魔术来恢复字符串;) DumpMem返回传递给它的字符串的50字节内存转储;使用这个函数查看内存是如何为传入的字符串准确地布局的。
Const csFilePath As String = "<path to your test workbook>"
Private Declare Sub CopyMemoryByte Lib "kernel32" Alias "RtlMoveMemory" (ByRef Destination As Byte, ByVal Source As Long, ByVal Length As Integer)
Private Declare Sub CopyMemoryWord Lib "kernel32" Alias "RtlMoveMemory" (ByRef Destination As Integer, ByVal Source As Long, ByVal Length As Integer)
Private Declare Sub CopyMemoryDWord Lib "kernel32" Alias "RtlMoveMemory" (ByRef Destination As Long, ByVal Source As Long, ByVal Length As Integer)
Function DumpMem(text As String) As String
Dim textAddress As LongPtr
textAddress = StrPtr(text)
Dim dump As String
Dim offset As Long
For offset = -4 To 50
Dim nextByte As Byte
Call CopyMemoryByte(nextByte, textAddress + offset, 1)
dump = dump & Right("00" & Hex(nextByte), 2) & " "
Next
DumpMem = dump
End Function
Function RecoverString(text As String) As String
Dim textAddress As LongPtr
textAddress = StrPtr(text)
If textAddress <> 0 Then
Dim textSize As Long
Call CopyMemoryDWord(textSize, textAddress - 4, 4)
Dim recovered As String
Dim foundNulls As Boolean
foundNulls = False
Dim offset As Long
For offset = 0 To textSize - 1
Dim nextByte As Byte
Call CopyMemoryByte(nextByte, textAddress + offset, 1)
recovered = recovered & Chr(CLng(nextByte) + IIf(nextByte < 0, &H80, 0))
If nextByte = 0 Then
foundNulls = True
End If
Next
Dim isNotUnicode As Boolean
isNotUnicode = isNotUnicode Mod 2 = 1
If foundNulls And Not isNotUnicode Then
recovered = ""
For offset = 0 To textSize - 1 Step 2
Dim nextWord As Integer
Call CopyMemoryWord(nextWord, textAddress + offset, 2)
recovered = recovered & ChrW(CLng(nextWord) + IIf(nextWord < 0, &H8000, 0))
Next
End If
End If
RecoverString = recovered
End Function
Sub TestSecurity(testType As String, secondExcel As Application, security As MsoAutomationSecurity)
Dim theWorkbook As Workbook
secondExcel.AutomationSecurity = security
Set theWorkbook = secondExcel.Workbooks.Open(csFilePath)
Call MsgBox(testType & " - helpfile: " & theWorkbook.VBProject.HelpFile & " - " & RecoverString(theWorkbook.VBProject.HelpFile))
Call MsgBox(testType & " - description: " & theWorkbook.VBProject.Description & " - " & RecoverString(theWorkbook.VBProject.Description))
Call theWorkbook.Close(False)
End Sub
Sub Test()
Dim secondExcel As Excel.Application
Set secondExcel = New Excel.Application
Dim oldSecurity As MsoAutomationSecurity
oldSecurity = secondExcel.AutomationSecurity
Call TestSecurity("disabled macros", secondExcel, msoAutomationSecurityForceDisable)
Call TestSecurity("enabled macros", secondExcel, msoAutomationSecurityLow)
secondExcel.AutomationSecurity = oldSecurity
Call secondExcel.Quit
Set secondExcel = Nothing
End Subhttps://stackoverflow.com/questions/38080516
复制相似问题