我制作了一个记录的宏,然后更改了本地设置(在我的例子中是小数点分隔符)。在宏的末尾,它将恢复设置。
如果出现错误,我会让程序使用'on error'语句恢复本地设置。 (该程序的简化示例如下)
到目前为止,我没有遇到任何问题;但是,由于我现在计划将该计划转移给我的同事,我真的希望不要干涉他们并覆盖他们自己的本地设置。
On error
语句在这里是否足够安全并确保设置已恢复?
是否存在程序可能遇到On error
无法重定向到错误处理程序的错误的情况?
PS:我已经知道我可以使用String = Replace(Number, ",", ".")
转换我的所有数字但由于某些原因我无法承担宏的所有许多变量。
示例代码:
Private Declare Function GetUserDefaultLCID% Lib "kernel32" ()
Private Declare Function GetLocaleInfoA Lib "kernel32" (ByVal Locale As Long, ByVal LCType As Long, ByVal lpLCData As String, ByVal cchData As Long) As Long
Private Declare Function SetLocaleInfoA Lib "kernel32" (ByVal Locale As Long, ByVal LCType As Long, ByVal lpLCData As String) As Boolean
Sub test()
' what to do on error
On Error GoTo ErrorHandler:
' define a number (Your local settings are set up to
Dim MyNumber As Single
MyNumber = 0.03
MsgBox ("Number is 0,03 ->" & MyNumber)
' record the settings in the variable LocalSettingsDecimal
Dim LocalSettingsDecimal As String
Dim Buffer As String
Buffer = String(256, 0)
Dim le As Integer
le = GetLocaleInfoA(GetUserDefaultLCID(), 14, Buffer, Len(Buffer))
LocalSettingsDecimal = Left(Buffer, le - 1)
' force decimal settings to '.'
Call SetLocaleInfoA(GetUserDefaultLCID(), 14, ".")
' Now is the program body
MsgBox ("Number is now 0.03 ->" & MyNumber)
' an unfortunate error:
MyNumber = "aa"
Call SetLocaleInfoA(GetUserDefaultLCID(), 14, LocalSettingsDecimal)
MsgBox ("Number should be back 0,03 ->" & MyNumber)
Exit Sub
ErrorHandler:
Call SetLocaleInfoA(GetUserDefaultLCID(), 14, LocalSettingsDecimal)
MsgBox ("There was an error but it's ok, it should be back to 0,03 ->" & MyNumber)
End Sub
答案 0 :(得分:3)
VBA代码有很多种方法可以被中断,有些甚至不会涉及一个聪明的用户,它会在MsgBox
上破坏并点击 Stop 按钮:如果主机崩溃的话与您的代码完全无关(一些KB更新会浮现在脑海中),在程序执行过程中,您的错误处理程序将不会被跳入,并且您无法阻止它。
请勿篡改用户的本地设置。修改你的代码。
我已经知道我可以使用
转换我的所有号码String = Replace(Number, ",", ".")
您的代码将数字视为字符串,反之亦然。如果数字来自工作表中的单元格,则可以将其读入Double
,而无需考虑用户的小数分隔符。
Dim myNumber As Double
With ActiveSheet
If IsNumeric(.Range("A1").Value) And Not IsError(.Range("A1").Value) Then myNumber = CDbl(.Range("A1").Value)
'myNumber contains a valid numeric value
End With
如果数字来自您制作的UserForm上的文本框,并且您允许用户在代码要求为点时输入逗号,那么您需要修复数据输入代码并添加一些输入验证防止这种情况一种方法是处理接收用户输入的KeyPress
控件的TextBox
事件 - 并“吞下”任何无效的键:
Private Sub txtInput_KeyPress(ByVal keyAscii As MSForms.ReturnInteger)
If Not IsValidKeyAscii(keyAscii, txtInput.Value) Then keyAscii = 0
End Sub
Private Function IsValidKeyAscii(ByVal keyAscii As Integer, ByVal value As String) As Boolean
'returns true if specified keyAscii is a number, or if it's a dot and value doesn't already contain one
IsValidKeyAscii = (keyAscii = vbKeyDot And InStr(1, value, Chr$(vbKeyDot)) = 0) Or (keyAscii >= vbKey0 And keyAscii <= vbKey9)
End Function
如果数字来自InputBox
,您将无法阻止用户输入他们想要的内容,但您仍然可以验证输入并防止错误输入进一步传播到您的代码中。
Private Function PromptForNumber() As Double
Dim isValid As Boolean
Dim userInput As String
Do
userInput = InputBox("Enter a decimal number:")
isValid = IsNumeric(userInput) And InStr(userInput, ",") = 0
If Not isValid Then MsgBox "Value '" & userInput & "' is not numeric. Please make sure to use [en-US] decimal separator."
While Not isValid
PromptForNumber = CDbl(userInput)
End Function
没有理由搞乱用户的控制面板设置。
答案 1 :(得分:1)
如果在代码中的任何地方遇到End
命令,那么这将影响您的计划。
看一下下面的例子。如果A
调用B
然后没有问题,则会处理错误,当控件返回A
时,处理程序仍将执行您的区域设置重置。但取消注释C
的调用并再次运行代码。执行只是停止,控制永远不会返回A
,因此不会执行重置。
因此,您的方案是将工作簿发送给您的同事,然后他们添加一些使用End
命令的逻辑,无论出于何种原因。
Option Explicit
Sub A()
On Error GoTo ErrHandler
Dim foo As Long
'call B
B
' call C - uncomment to see impact
'C
ErrHandler:
Debug.Print "Error occurred in A"
Debug.Print "Fixing locale stuff..."
End Sub
Sub B()
On Error GoTo ErrHandler
Dim foo As Long
'cause an error
foo = "bar"
ErrHandler:
Debug.Print "Error occurred in B"
Debug.Print Err.Description
End Sub
Sub C()
On Error GoTo ErrHandler
Dim foo As Long
'cause an error
foo = "bar"
ErrHandler:
Debug.Print "Error occurred in C"
Debug.Print Err.Description
End
End Sub