문제

I'd like to know how to get the line number of a line in vbscript programmaticly either at the point of the code like __LINE__ or more ideally a way to get the line number of where the current function was called like python's stack module so I can write a reusable debugging function(and the file the code is located in) and no I don't want to know how to turn on line numbers in my editor.

Also I'd like to now any similar useful information that can be extracted such as calling function, variable type as string, etc.

도움이 되었습니까?

해결책

Unfortunatly that doesn't work the way like in Ruby and Python. The next best thing i worked out is putting a call to a errorhandling function everywhere where things could go wrong. The numbers in the parameter of this function are adapted each time i execute a macro in my editor (i use textpad, the \i is autonumbering in a Regular Expression). If your editor doesn't support this you could write a script that does this. So when an error occurs, it is logged with the number the errorhandling function was called and you can easily find it back in the source by looking for #number#.

This is usable for both asp and vbs but for vbs there is an easier way. Some editors like textpad or sublimle text let you execute a vbs script, show the output in a tab and if an error is produced let you double click the line with the errormessage which opens the script at that line. This is also done by a regular expression. Let me know if you need the one for textpad.

on error resume next
'initialize constants DEBUGLEVEL and LOGFILE
'initialize strHostName

'some code
oConn.execute(sql)

if not LogError("#1#") then
  'do the things if successfull, otherwise log error with number
end if

'again some code
if not LogError("#2#") then
  'do the things if successfull, otherwise log error with number
end if

'the debug and log functions
function LogError(errornumber)
  'LogError\(\"#[0-9]+#\"\) replace by LogError("#\i#")
  if err.number <> 0 then
    call debug("<name of script>/Logerror","","","Errornumber:" _
      & errornumber & " " & err.number & " " & err.description & " " _
      & err.source)
    LogError = True
    err.clear
    errors = errors+1
  else
    LogError = False
  end if
end function

function Debug (pagina, lijn, varnaam, varinhoud)
  if DEBUGLEVEL > 0 then
    const forReading = 1, forWriting = 2, forAppending = 8, CreateFile = True
    dim fs,f, var, strHostName
    set fs=CreateObject("Scripting.FileSystemObject")
    strHostName    = fs.GetFileName(WScript.FullName)
    if fs.FileExists(LOGFILE) then
      set f=fs.OpenTextFile(LOGFILE, forAppending)
    else
      set f=fs.OpenTextFile(LOGFILE, forWriting,true)
    end if
    var = now & " " & pagina & ":" & lijn & ":" & varnaam & ":" & varinhoud
    f.WriteLine var
    if LCase(strHostName) = "cscript.exe" then 'debugging
      if DEBUGLEVEL > 1 then
        wscript.echo var
      end if
    end if
    f.Close
    set f=Nothing
    set fs=Nothing
  end if
  debug = true
end function

다른 팁

VBScript doesn't expose that information, so you can't access it programmatically from within the script (edge cases notwithstanding). You're going to need a debugger for extracting this kind of information. Or you could have another script interpret the first one and keep track of line numbers (like this). I wouldn't recommend the latter for any kind of production environment, though.

As long as it's happening outside of a function, the following works.

Automatic error-handling is turned off at the start of the script by On Error Resume Next, so that the script doesn't just exit before you can do anything. BUT, you can then turn error-handling back on using On Error GoTo 0 and Raise an exception yourself. That will output the line number in addition to any of your debugging messages.

For example:

On Error Resume Next
server = WScript.Arguments(0)
If Err.Number <> 0 Then
    WScript.Echo("Need to pass in an argument!")
    On Error GoTo 0
    Err.Raise(1)
End if

If you run this without any arguments, you get the following output:

Need to pass in an argument!
C:\script.vbs(6, 5) Microsoft VBScript runtime error: Unknown runtime error

The "6" refers to the line number where the exception was raised.

This way you can print custom output, and also you'll know what line the error happened at.

Yes!

There is a way to get the exact error line number, but it's HUGLY, as we are talking about an ancient programming tool....

And yes, it is worth it, especially if your code is going to run in front of many users. That way you can get past isolating and reproducing the bug, right to solving it.

Take a close look at the last variable "Erl" in the line of code below. It is an undocumented global variable the VB script processor holds.

Dim sErrorMsg as String
sErrorMsg = Err.Description & "(" & Err.Number & ")" & vbNewLine & "Source: " & Err.Source & vbNewLine & "At line number: " & Erl

In order to get anything from that global "Erl" variable you need to (manually)** set its value at the beginning of each line of code as shown below. Beware, you set the line number, if you forget to set the number for a specific line, Erl will report the last set value. See the division by zero error line, it reports the line number set above because I did not set a line number value at the beginning of the line that caused the error.

I have not figured out the inbuilt call stack, though I know there is one. Please let me know if you figure that one out, for now I use a module level variable to build the stack.

More tips at the very end, below this code sample

Sub WhatEverSub ()
2        Const iColIdxPageNbr As Integer = 2
3        Const iColIdxDefinition As Integer = 3

5        Dim oDoc_Source As Document
6        Dim oDoc_Target As Document



10        Dim oTable As Table
11        Dim oRange As Range
12        Dim n As Long
13        Dim strAllFound As String
14        Dim Title As String
15        Dim Msg As String

        On Error GoTo PrepErrorHandler
            Dim xyz As Long
            xyz = Rnd(3) / 0
16
17        Title = "Evil Finder - This program is about doing something important for the world"
18
19        'Show msg - stop if user does not click Yes
20        Msg = "This macro finds all evil things consisting of 2 or more " & _
            "uppercase letters and extracts the hex representation to a table " & _
            "in a new document." & vbNewLine & vbNewLine & _
            "Do you want to continue?"

21        If MsgBox(Msg, vbYesNo + vbQuestion, Title) <> vbYes Then
22            Exit Sub
23        End If

(... whatever code ...)

820        Application.ScreenUpdating = True
830        If n = 1 Then
840            Msg = "No evil things were found. Need to find better detection tool"
850            oDoc_Target.Close savechanges:=wdDoNotSaveChanges
860        Else
870            Msg = "Finished extracting " & n - 1 & " evil thing(s) to a new document."
880        End If

PrepErrorResumeLine:
890        MsgBox Msg, vbOKOnly, Title

        'Clean up
1000        Set oRange = Nothing
1010        Set oDoc_Source = Nothing
1020        Set oDoc_Target = Nothing
1030        Set oTable = Nothing

Exit Sub

PrepErrorHandler:
        Msg = Err.Description & "(" & Err.Number & ")" & vbNewLine & "Source: " & Err.Source & vbNewLine & "At line number: " & Erl
        Resume PrepErrorResumeLine
End Sub

**Some more tips: 1) As for setting the error line number values manually, I wrote a utility (more than a decade ago) to automate the addition or removal or renumbering of all lines in a module by working directly on the VB project files (or standalone .vbs files), but the below will take care of the basic, with a few manual adjustsments remaining...

Set up VB code line #s using MS Excel a) paste code in column C b) set column A's first cell value to 10, and second to 20 and drag copy down to auto increment until you reach the last line/row of code in column B c) in column B paste in the following formula and drag copy down =A1 & REPT(" ", 8 - LEN(A1)) d) copy columns B and C back into the VB code pane et voila!

Strip out the line numbers to do major edits using Word Paste the code in, Hit CTRL + H and make sure wildcards is checked (click the "more" button) Fill in the following settings FIND [^13][0-9 ]{4} REPLACE ^p Done!

2) number each line in increments of 10 at least so you can wedge in a few lines at the last minute without having to renumber each line below your change

3) On Error Resume Next is evil and will cost you a lot of debugging hours! At least 90% of the time, one should use a specific handler, or nothing. If you do not already know how to recover from an error, do not use RESUME NEXT to silence it, instead, log all the details (using Erl) and learn from the run time logs and use GoTo 0 'Zero, not the letter O to let the rest of the errors bubble up the call stack.

On Error GoTo MyErrorHandlerSection
(... write your risky code here ...)
On Error GoTo 0
'the line immediately above disables all error handling in the current function, if any error happens, it will be passed to the calling function

Nothing prevents you from adding another handling section in the same function if you have another chunk of risky code using

On Error GoTo MySecondErrorHandlerSection
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top