I have some VB6 code that needs to be migrated to VB.NET, and I wanted to inquire about this line of code, and see if there is a way to implement it in .NET
Error(Err.Number)
Keeps telling me that an Expression is expected.
If Err.Number = 53 Then
GoTo x
Else
Msg = " Error N. " & Err.Number & Chr(13) & Error(Err.Number)
MsgBox(Msg, 16, "Warning")
FileClose(1)
Exit Sub
End If
The VB6 documentation states:
The return value of the Error function corresponds to the Description
property of the Err object.
so instead of using Error(Err.Number) use Err.Description.
Related
I was wondering whether there is a smarter/more accurate method of debugging userform initializations in VBA that are called from a specific module.
Because when I write an erroneously piece of code in the Userform_initialisatize, I the error I receive states an error, but not where it occurs, the highlighted piece of code is simply call Userform_intitialize and I'm left guessing which piece of code in Sub Userform_intitialize contains the error.
So incrementally building a userform with test runs after every small addition of code work effectively to create a stable Userform initilisation code. Because I know what I changed since the last successful run, but it would save quite some time if I immediately know where the error occurs, especially in cases where trial runs consume a lot of time.
So are there ways to extract in which line the exact error occurs within a called Sub Userform_intitialize in vba Excel 2016?
As #A.S.H already mentioned the handler of Initialize event should remain private. Thats because the Initialize event itself is private so it is intended to be handled by the instances itself and not by anybody else.
So are there ways to extract in which line the exact error occurs within a called Sub Userform_intitialize in vba Excel 2016?
Regarding your question, yes it is still possible to extract the line number where the error occurred. But the lines needs to be part of the source code. Then the function VBA.Information.Erl can be used to get the line number. Example:
UserForm module
Option Explicit
Private Const MODULE_NAME As String = "MyUserForm."
Private Sub UserForm_Initialize()
On Error GoTo Error_In_UserForm_Initialize
1 Const procName As String = "UserForm_Initialize"
' Some code here
2 Dim d As Date
3 d = Now
4 MsgBox "Hi from my userform! 'Now' is '" & d & "'", vbInformation, "Info"
' Here error occures, max. value of Integer is 32.767
5 Dim i As Integer
6 i = 40000
7 Exit Sub
Error_In_UserForm_Initialize:
8 Dim errorDescription As String
9 With Err
10 errorDescription = "Error '" & .Number & "'" & _
" with description '" & .Description & "'" & _
" occured in procedure '" & MODULE_NAME & procName & "'" & _
IIf(Erl <> 0, " on line '" & CStr(Erl) & "'.", ".")
11 End With
12 MsgBox errorDescription, vbCritical, "Error"
End Sub
Some additional readings about Erl here or here.
I'm fixing the bellow error "datatable importsheet operation failed. Invalid file" using this way:
On error resume next
DataTable.ImportSheet Environment("STPFilePath"),Environment("TestScriptName"),"Action2"
If Err.Description = "The DataTable.ImportSheet operation failed. Invalid file." \n "Line (20): "DataTable.ImportSheet Environment("STPFilePath"),Environment("TestScriptName"),"Action2""." Then
list of instructions
end if
But I got this error:
The test run cannot continue due to a syntax error.
Expected 'Then'
Line (24): "If Err.Description = "The DataTable.ImportSheet operation failed. Invalid file." \n "Line (20): "DataTable.ImportSheet Environment("STPFilePath"),Environment("TestScriptName"),"Action2""." Then".
Everything looks right. Please any help ? where I'm wrong ?
I'm really struggling with what you are trying to do and your comments are not helping...
When using
On Error Resume Next
and you encounter an error while executing a statement the following things will happen;
The statement will be skipped and the script will move to the next statement and carry on execution.
The object Err will be populated with details of the error that caused the statement to be skipped.
The Err object is made up of a few key properties that describe the error that occurred;
Number - The Error Code of the error that was raised.
Source - The Source of the error that was raised, this can be 3rd party library, the VBScript Runtime etc.
Description - A free text description of the error.
If you want to check for error
The DataTable.ImportSheet operation failed. Invalid file.
when
DataTable.ImportSheet Environment("STPFilePath"),Environment("TestScriptName"),"Action2"
is executed you need to capture the Err.Number code that corresponds to that specific error.
Something like this;
On Error Resume Next
DataTable.ImportSheet Environment("STPFilePath"),Environment("TestScriptName"),"Action2"
'Check that an error occurs
If Err.Number <> 0 Then
'Identify specific error and deal with accordingly.
Select Case Err.Number
Case 20012 'Code for DataTable.ImportSheet operation failed
'List of instructions...
Case Else
'Unhandled error show to screen
MsgBox "Error: " & Err.Number & " (" & Err.Source & ") - " & Err.Description
End Select
'Finished handling the error
Call Err.Clear()
End If
What I find most confusing is the miss-information in this thread.
"I need the description and not the number and the problem is to use Err.Details and not Err.Description in my case. Now, it is working." - Ref
The Err object does not contain a property called Details unless this is something specific to QTP but so far I haven't been able to find anything with a quick Google Search. So how you can say "it is now working" is beyond me.
Basic rules:
Double Quotes (") are escaped by doubling ("")
No escapes like "\n" in VBScript string literals (concatenation (or replacement) needed)
The concatenation operator is &
Basic strategy: Simplify, Divide, and conquer:
>> s = "1" & vbCrLf & "-""pi""-"
>> t = "1" & vbCrLf & "-""pi""-"
>> WScript.Echo s
>> WScript.Echo t
>> If s = t Then
>> WScript.Echo "no surprise"
>> End If
>>
1
-"pi"-
1
-"pi"-
no surprise
>>
Added:
Applied to your string/error message:
's = "The DataTable.ImportSheet operation failed. Invalid file." \n "Line (20): "DataTable.ImportSheet Environment("STPFilePath"),Environment("TestScriptName"),"Action2""."
s = "1" & vbCrLf & "2: ""3(""4""),5(""6""),""7""."
WScript.Echo s
output:
cscript 39878005.vbs
1
2: "3("4"),5("6"),"7".
You are getting a syntax error because the double quotes in your if statement are not escaped.
I'm not sure what you are trying to do here and maybe using Err.Number makes more sense but if you want to avoid the syntax error then use this code:
If Err.Description = "The DataTable.ImportSheet operation failed. Invalid file."" \n ""Line (20): ""DataTable.ImportSheet Environment(""STPFilePath""),Environment(""TestScriptName""),""Action2""." Then
''' list of instructions
End If
Also, you cannot use \n if you want to compare 2 lines in if statement. Use CHR(13) or CHR(10) instead of \n. I.e.
If Err.Description = "The DataTable.ImportSheet operation failed. Invalid file."& CHR(13) &"Line (20): ""DataTable.ImportSheet Environment(""STPFilePath""),Environment(""TestScriptName""),""Action2""." Then
'''list of instructions
End If
Again: Using Err.Number will make more sense as any extra/missing space/newline in above If condition will fail the condition.
Try to Replace the Err.Description line with this
If Err.Description = "The DataTable.ImportSheet operation failed. Invalid file." & vbCrLf & "Line (20): DataTable.ImportSheet Environment(" & STPFilePath & "),Environment(" & TestScriptName & ")," & Action2 & "." Then
Good Luck.!
I am trying to create a high-quality ErrorHandler. I get run-time error 438:
Object doesn't support this property or method
Here's code:
Sub Function_asdf()
...
On Error GoTo ErrorHandler
...
ErrorHandler:
& vbNewLine & "Error" & Err.Number & Err.line & Err.Description
Like that, you're doing nothing. You're trying to start a chain of strings, but this starts with a join operator (&) which is not connecting to any "first" part, and even if it was it's neither assigned to a variable nor shown into a dialog box.
Start by showing that into a MsgBox :
MsgBox vbNewLine & "Error" & Err.Number & Err.line & Err.Description
or assigning it to a variable first:
Dim errMsg As String
errMsg = vbNewLine & "Error" & Err.Number & Err.line & Err.Description
and then printing it:
Debug.Print errMsg
or logging it into a cell
Range("A1") = errMsg
or in a MsgBox
MsgBox errMsg
... and don't forget to specify on which line you're raising the exception (here it's clear, but it's not always evident) cause it would be impossible for someone to debug without knowing in which point of your code the exception is thrown.
EDIT - I've finally run your code
So, I've run your code and the error is raised because the object Err (i.e. the exception thrown) does not have the property Line. It might have been deprecated, or just never existed.
If you wanted to return the line on which the error occurs, use the ERL property:
MsgBox vbNewLine & "Error" & Err.Number & Erl & Err.Description
I'm encountering an odd VBA subscript out of range error in this simple sub :
Sub writeTypes(ByVal rowNb As Long, ByVal colNb, ws As Worksheet)
On Error GoTo ErrorHandler_ObjMethod
Const METHOD_NAME = "writeTypes (CCase)"
With ws
If Not isArrayEmpty(pTypes) Then
For i = LBound(pTypes) To UBound(pTypes)
If pTypes(i) <> "" Then
.Cells(rowNb, colNb).Value = .Cells(rowNb, colNb).Value & pTypes(i) & ";"
ElseIf i = UBound(pTypes) Then
.Cells(rowNb, colNb).Value = Left(.Cells(rowNb, colNb).Value, Len(.Cells(rowNb, colNb).Value) - 1)
End If
Next i
Else: .Cells(rowNb, colNb).Value = "N/A"
End If
End With
ErrorHandler_ObjMethod:
If err.Number <> 0 Then
Workbooks(AA_RESOURCES_WB).Close SaveChanges:=True
MsgBox (METHOD_NAME & vbNewLine & err.Number & vbNewLine & err.description)
End
End If
End Sub
The calling line of this procedure is : pUnassignedCases(i).writeTypes j, 7, ws
(The variables passed as params are correct I made sure of that several times)
Here is what I already tried to do :
-To remove the "ByVal"s in the parameters
-To remove the first "If Not"
-To remove the "Elseif" block
The removals were done properly without any syntax/logic errors.
I also checked any used variables (including the array of string that is "pTypes") in any way possible. All things seem perfectly fine.
I also tried to incorporate this code directly into my other sub (that goes through an array of CCase objects with a For loop) rather than calling it through a CCase object procedure, and somehow it works for the firsts CCases objects and then forces the loop to go beyond the CCase array upper bound... I can't make any sense of this.
When I go through the code line by line, the error occurs at the "End sub" line. But when I remove the error handling it goes fine but somehow the error gets passed on somewhere else in the code that isn't in anyway related to this sub and was working perfectly before... Then if I simply remove any calling of this sub everything is working as it already was.
Plus even when the error occurs, my worksheet line is still well updated with "N/A" (as it's supposed too because none of my cases objects have types for now). It's like the sub is cursed. This is driving me crazy.
A few things I noticed:
I don't know if these will fix the issue you are experiencing but they may be of use:
Parameter ByVal colNb has no type.
I suspect the line ElseIf i = UBound(pTypes) Then is intended to strip off the trailing ";"
If this is the case, similar code, might be best placed outside the for loop.
Consider: Can the array pTypes have a value that is <> "" in the UBound index position. If so you may have a logic error.
If the cell has no value and Len(.Cells(rowNb, colNb).Value) - 1) is used it will raise an error when used as an argument to the left function. I think this will occur when the array contains only empty strings.
isArrayEmpty: I'm wondering what this function does. I assume it does what it says on the tin.
The above don't explain your issue, "err" being lower case is weird as stated in another answer. If Exit sub is before the error handler it would stop the if statement being evaluated when no error has occurred.
Harvey
Code demonstrating poor error handling.
Sub a3(optional RaiseAnError As Boolean = true)
On Error GoTo errhand
If RaiseAnError Then
Err.Raise 1, "", "Simulating code that might raise and error "
End If
MsgBox "Got to the end of your code"
errhand:
If Err.Number <> 0 Then
MsgBox "Err.Number = " & Err.Number
Err.Raise 2, "", "Simulating code ie workbook close that might raise and error "
MsgBox "ok"
End
End If
End Sub
Given a pre-configured ODBC System DSN, I'd like to write a function that gracefully tests that connection using VBA.
Private Function TestConnection(ByVal dsnName As String) As Boolean
' What goes here?? '
End Function
Edit: To clarify, the System DSNs are pointing to external SQL Server 2005 databases, with Windows NT authentication.
One approach I've tried is to send some random query to the target database and catch the error. If the query works, return true. If there's an error then return false. This works just fine but it feels...kludgy. Is there a more elegant way, especially one that doesn't rely on On Error Goto ?
Note: It's a legacy Access 2000 database I'm working on, so any solution can't have any Access 2007 or 2003 dependencies. I'd like to make it generic to VBA, but if there's a simple way in Access that's fine too.
Much obliged for any advice.
Dim cnn As ADODB.Connection
Dim canConnect as Boolean
Set cnn = New ADODB.Connection
cnn.Open "DSN HERE"
If cnn.State = adStateOpen Then
canConnect = True
cnn.Close
End If
Msgbox canConnect
EDIT: DSN Format could be "DSN=MyDSN;UID=myuser;PWD=myPwd;"
Look this for connection strings
I'm too late to give you a useful answer to your question, but I came here because I wanted to see if StaCkOverflow has a better answer than the code I'm currently using to test ADODB connections.
...It turns out that the answer is 'No', so I'll post the code for reference: someone else will find it useful.
Coding notes: this isn't a generic answer: it's a method from a class encapsulating the ADODB.Connection object, and it assumes the existence of object 'm_objConnect'.
TestConnection: a VBA Class method for publishing debugging information for an ADODB.Connection object
This prints out the connection string, the current status, a list of ADODB errors (if any) and a full listing of the onnection's named properties.
Public Sub TestConnection()
On Error GoTo ErrTest
Dim i As Integer
If m_objConnect Is Nothing Then
Debug.Print "Object 'm_objConnect' not instantiated."
Else
Debug.Print m_objConnect.ConnectionString
Debug.Print "Connection state = " & ObjectStateString(m_objConnect.State)
Debug.Print
If m_objConnect.Errors.Count > 0 Then
Debug.Print "ADODB ERRORS (" & m_objConnect.Errors.Count & "):"
For i = 0 To m_objConnect.Errors.Count
With m_objConnect.Errors(i)
Debug.Print vbTab & i & ":" _
& vbTab & .Source & " Error " & .Number & ": " _
& vbTab & .Description & " " _
& vbTab & "(SQL state = " & .SqlState & ")"
End With
Next i
End If
Debug.Print
Debug.Print "CONNECTION PROPERTIES (" & m_objConnect.Properties.Count & "):"
For i = 0 To m_objConnect.Properties.Count - 1
Debug.Print vbTab & i & ":" _
& vbTab & m_objConnect.Properties(i).Name & " = " _
& vbTab & m_objConnect.Properties(i).Value
Next i
End If
ExitTest:
Exit Sub
ErrTest:
Debug.Print "Error " & Err.Number & " raised by " & Err.Source & ": " & Err.Description
Resume Next
End Sub
Private Function ObjectStateString(ObjectState As ADODB.ObjectStateEnum) As String
Select Case ObjectState
Case ADODB.ObjectStateEnum.adStateClosed
ObjectStateString = "Closed"
Case ADODB.ObjectStateEnum.adStateConnecting
ObjectStateString = "Connecting"
Case ADODB.ObjectStateEnum.adStateExecuting
ObjectStateString = "Executing"
Case ADODB.ObjectStateEnum.adStateFetching
ObjectStateString = "Fetching"
Case ADODB.ObjectStateEnum.adStateOpen
ObjectStateString = "Open"
Case Else
ObjectStateString = "State " & CLng(ObjectState) & ": unknown state number"
End Select
End Function
Share and enjoy: and watch out for line-breaks, helpfully inserted where they will break the code by your browser (or by StackOverflow's formatting functions).
There no magic function that will test this without actually connecting and trying an operation.
If you feel bad about the random query part - you can query the system tables
For Access
SELECT TOP 1 NAME FROM MSysObjects
For SQL Server
SELECT TOP 1 NAME FROM sysobjects
If you merely have to test that the database server is actually available, this can be done, despite what is being said here that it cannot.
In that case, you can attempt to open a TCP connection to the specific server and port.
The default instance of SQL Server, for example, listens on TCP port 1433. Attempting a simple TCP connection in VBA will tell you if it succeeds or not. Only if that is successful I would query using the ODBC connection.
This is a lot more graceful and efficient. It would remove any "gross" error from your ODBC test code. However, as I said, it is only applicable if you need to test for the mere existence/availability of the database server instance.