-
Notifications
You must be signed in to change notification settings - Fork 6
/
Module1.bas
509 lines (374 loc) · 14.5 KB
/
Module1.bas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
Attribute VB_Name = "modSBApi"
Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (ByRef Destination As Any, Source As Any, ByVal length As Long)
Public Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
'get the currently executing line number
Public Declare Function GetCurrentDebugLine Lib "sb_engine" (ByVal hDebug As Long) As Long
'get a variables value from its name
Private Declare Function dbg_getVarVal Lib "sb_engine" (ByVal hDebug As Long, ByVal varName As String, ByRef lpBuf As Byte, ByRef bufSz As Long) As Long
'enumerate global and local variable names (uses vbstdOut callback)
Private Declare Sub dbg_EnumVars Lib "sb_engine" (ByVal hDebug As Long)
Private Declare Sub dbg_EnumAryVarsByName Lib "sb_engine" (ByVal hDebug As Long, ByVal varName As String)
Private Declare Sub dbg_EnumAryVarsByPointer Lib "sb_engine" (ByVal hDebug As Long, ByVal pVar As Long)
Private Declare Function dbg_VarTypeFromName Lib "sb_engine" (ByVal hDebug As Long, ByVal varName As String) As Long
Public Declare Function dbg_LineCount Lib "sb_engine" (ByVal hDebug As Long) As Long
'we may not need this we should track internally...
Private Declare Function dbg_isBpSet Lib "sb_engine" (ByVal hDebug As Long, ByVal lineNo As Long) As Long
Private Declare Sub dbg_EnumCallStack Lib "sb_engine" (ByVal hDebug As Long)
Private Declare Sub dbg_RunToLine Lib "sb_engine" (ByVal hDebug As Long, ByVal lineNo As Long)
Public Declare Sub SetDefaultDirs Lib "sb_engine" (ByVal incDir As String, ByVal modDir As String)
'scripts that use import directive internally turn into one long flat script file. for debugging
'we must dump them to file and then load them for display so line numbers line up..
Private Declare Sub dbg_WriteFlatSourceFile Lib "sb_engine" (ByVal hDebug As Long, ByVal fpath As String)
Private Declare Function dbg_SourceLineCount Lib "sb_engine" (ByVal hDebug As Long) As Long
'
'int __stdcall sbSetGlobalVariable(pSbProgram pProgram, int isLong, BSTR* bvarName, BSTR* bbuf){
Private Declare Function sbSetGlobalVariable Lib "sb_engine" (ByVal hProgram As Long, ByVal isLong As Long, ByVal strVarName As String, ByVal strValue As String) As Long
'int __stdcall dbg_SetLocalVariable(pDebuggerObject pDO, long index, int isLong, BSTR *bbuf)
Private Declare Function dbg_SetLocalVariable Lib "sb_engine" (ByVal hDebug As Long, ByVal Index As Long, ByVal isLong As Long, ByVal strValue As String) As Long
'VARIABLE __stdcall dbg_VariableFromName(pDebuggerObject pDO, char *pszName)
Private Declare Function dbg_VariableFromName Lib "sb_engine" (ByVal hDebug As Long, ByVal strName As String) As Long
'breaks at next instruction..
Public Declare Sub dbg_Break Lib "sb_engine" (ByVal hDebug As Long)
Public hProgram As Long
Public hDebugObject As Long 'handle to the current debug object - pDO
Public readyToReturn As Boolean
Public dbg_cmd As Debug_Commands
Public running As Boolean
Public variables As New Collection 'of CVariable
Public callStack As New Collection 'of CCallStack
Public flatFile As String
Public hadError As Boolean
Public shuttingDown As Boolean
Public includeDir As String, moduleDir As String
Global dlg As New CCmnDlg
Global Const LANG_US = &H409
Enum cb_type
cb_output = 0
cb_dbgout = 1
cb_debugger = 2
cb_engine = 3
cb_error = 4
cb_refreshUI = 5
End Enum
Enum sb_VarTypes
VTYPE_UNKNOWN = -1
VTYPE_LONG = 0
VTYPE_DOUBLE = 1
VTYPE_STRING = 2
VTYPE_ARRAY = 3
VTYPE_REF = 4
VTYPE_UNDEF = 5
End Enum
Enum Debug_Commands
dc_NotSet = 0
dc_Run = 1
dc_stepinto = 3
dc_StepOut = 4
dc_StepOver = 5
dc_RunToLine = 6
dc_Quit = 7
dc_Manual = 8
End Enum
Function VariableFromName(name As String) As Long
If Len(name) = 0 Then Exit Function
VariableFromName = dbg_VariableFromName(hDebugObject, name)
End Function
Function SetVariable(v As CVariable, ByVal Value As String) As Boolean
On Error Resume Next
Dim x As Long
Dim isNumeric As Long
Dim name As String
name = v.name
If InStr(name, "::") < 1 Then name = "main::" & name
If Left(Value, 2) = "0x" Then
x = CLng("&h" & Mid(Value, 3))
If Err.Number = 0 Then
Value = x
isNumeric = 1
End If
Else
x = CLng(Value)
If Err.Number = 0 Then isNumeric = 1
End If
If v.isGlobal Then
SetVariable = sbSetGlobalVariable(hProgram, isNumeric, name, Value)
Else
SetVariable = dbg_SetLocalVariable(hDebugObject, v.Index, isNumeric, Value)
End If
End Function
Function LoadFlatFile() As Boolean
Dim tmp As String
tmp = GetFreeFileName(Environ("temp"))
dbg_WriteFlatSourceFile hDebugObject, tmp
If FileExists(tmp) Then
frmMain.hasImports = True
frmMain.scivb.ReadOnly = False
LoadFlatFile = frmMain.scivb.LoadFile(tmp)
frmMain.scivb.ReadOnly = True
flatFile = tmp
End If
End Function
Public Sub RunToLine(lineNo As Long)
dbg_RunToLine hDebugObject, lineNo
DebuggerCmd dc_Manual
End Sub
Public Function EnumCallStack() As Collection
Set callStack = Nothing
dbg_EnumCallStack hDebugObject 'this goes into syncronous set of callbacks
Set EnumCallStack = callStack
End Function
Public Function VariableTypeToString(x As sb_VarTypes) As String
types = Array("LONG", "DOUBLE", "STRING", "ARRAY", "REF", "UNDEF")
If x < 0 Or x > 5 Then
VariableTypeToString = "???"
Else
VariableTypeToString = LCase(types(x))
End If
End Function
Public Function VariableType(varName As String) As String
Dim x As sb_VarTypes
x = dbg_VarTypeFromName(hDebugObject, varName)
VariableType = VariableTypeToString(x)
End Function
Public Sub DebuggerCmd(cmd As Debug_Commands)
Dim startPos As Long, endPos As Long
With frmMain
.scivb.DeleteMarker .lastEIP, 1 'remove the yellow arrow
.scivb.DeleteMarker .lastEIP, 3 'remove the yellow line backcolor
'force a refresh of the specified line or it might not catch it..
startPos = .scivb.PositionFromLine(.lastEIP)
endPos = .scivb.PositionFromLine(.lastEIP + 1)
.scivb.DirectSCI.Colourise startPos, endPos
End With
dbg_cmd = cmd
readyToReturn = True
End Sub
Public Function EnumArrayVariables(varNameOrPointer As Variant) As Collection
Set variables = Nothing
If TypeName(varNameOrPointer) = "String" Then
dbg_EnumAryVarsByName hDebugObject, CStr(varNameOrPointer)
Else
dbg_EnumAryVarsByPointer hDebugObject, CLng(varNameOrPointer) 'this goes into syncronous set of callbacks
End If
Set EnumArrayVariables = variables
End Function
Public Function EnumVariables() As Collection
Set variables = Nothing
dbg_EnumVars hDebugObject 'this goes into syncronous set of callbacks
Set EnumVariables = variables
End Function
Public Function GetVariableValue(varName As String) As String
Dim buf() As Byte
Dim sz As Long
Dim ret As Long
Dim i As Long
sz = 1024
ReDim buf(sz)
ret = dbg_getVarVal(hDebugObject, varName, buf(0), sz)
If ret = 0 Then
GetVariableValue = StrConv(buf, vbUnicode)
i = InStr(GetVariableValue, Chr(0))
If i > 1 Then
GetVariableValue = Left(GetVariableValue, i - 1)
End If
ElseIf ret = 1 Then
GetVariableValue = "[ > 1024 chars ]"
ElseIf ret = 2 Then
GetVariableValue = "[Variable not found]"
Else
GetVariableValue = "[Unknown return value: " & ret & "]"
End If
End Function
Public Function VbLineInput(ByVal buf As Long, ByVal sz As Long) As Long
Dim b() As Byte
Dim retVal As String
VbLineInput = 0 'return value default..
retVal = InputBox("Script is requesting input value:", "Script Basic Line Input")
If Len(retVal) = 0 Then Exit Function
If Len(retVal) < sz Then
retVal = retVal & Chr(0)
ReDim b(Len(retVal))
b() = StrConv(retVal, vbFromUnicode)
CopyMemory ByVal buf, b(0), Len(retVal)
VbLineInput = Len(retVal) - 1
Else
MsgBox "Sorry VbLineInput is limited to " & sz & " characters", vbInformation
End If
End Function
Public Function GetDebuggerCommand(ByVal buf As Long, ByVal sz As Long) As Long
Dim b() As Byte
Dim Source As String, curline As Long
dbg_cmd = dc_NotSet
'there are some lines we dont want to stop and show as execution to the user,
'such as declares and function starts
curline = GetCurrentDebugLine(hDebugObject)
If Not BreakPointExists(curline) Then
Source = LCase(frmMain.scivb.GetLineText(curline))
Source = Trim(Replace(Source, vbTab, Empty))
If InStr(Source, " ") > 1 Then
Source = Left(Source, InStr(Source, " ") - 1)
If Source = "declare" Or Source = "function" Then
dbg_cmd = dc_stepinto
End If
End If
End If
If dbg_cmd = dc_NotSet Then
frmMain.SyncUI
'we block here until the UI sets the readyToReturn = true
'this is not a CPU hog, and form remains responsive to user actions..
readyToReturn = False
While Not readyToReturn
DoEvents
Sleep 20
Wend
End If
GetDebuggerCommand = dbg_cmd 'now were enum based..
' If Len(dbg_cmd) < sz Then
' dbg_cmd = dbg_cmd & Chr(0)
' ReDim b(Len(dbg_cmd))
' b() = StrConv(dbg_cmd, vbFromUnicode)
' CopyMemory ByVal buf, b(0), Len(dbg_cmd)
' GetDebuggerCommand = Len(dbg_cmd)
' Else
' GetDebuggerCommand = 0
' MsgBox "Shouldnt happen!"
' End If
End Function
Public Sub HandleDebugMessage(msg As String)
Dim cmd() As String
Dim v As CVariable
Dim c As New cCallStack
Dim handled As Boolean
If Left(msg, 10) = "Call-Stack" Then
cmd = Split(msg, ":", 3)
ElseIf Left(msg, 14) = "Array-Variable" Then
cmd = Split(msg, ":", 5)
ElseIf Left(msg, 19) = "Local-Variable-Name" Then
cmd = Split(msg, ":", 3)
Else
cmd = Split(msg, ":", 2)
End If
Select Case cmd(0)
Case "DEBUGGER_INIT" 'DEBUGGER_INIT: hDebugObj
'reint structures here
hDebugObject = CLng(cmd(1))
If frmMain.scivb.DirectSCI.GetLineCount <> dbg_SourceLineCount(hDebugObject) Then LoadFlatFile
InitDebuggerBpx
handled = True
Case "Local-Variable-Name"
Set v = New CVariable
v.Index = CLng(cmd(1))
v.name = cmd(2)
v.Value = GetVariableValue(v.name)
v.varType = VariableType(v.name)
variables.Add v
handled = True
Case "Global-Variable-Name"
Set v = New CVariable
v.isGlobal = True
v.name = cmd(1)
v.Value = GetVariableValue(v.name)
v.varType = VariableType(v.name)
variables.Add v
handled = True
Case "Call-Stack"
Set c = New cCallStack
c.Index = callStack.count
c.lineNo = CLng(cmd(1))
c.func = cmd(2)
callStack.Add c
handled = True
Case "Array-Variable" '"Array-Variable:%d:%d:%d:%s", i, TYPE(v2), v2, buf);
Set v = New CVariable
v.Index = CLng(cmd(1))
v.varType = VariableTypeToString(CLng(cmd(2)))
v.pAryElement = cmd(3)
v.Value = cmd(4) 'if is array then aryPointer will be parsed from value..
variables.Add v
handled = True
Case "Current-Line":
handled = True 'we dont need these anymore..
'Line: %s\r\n
'Message: %s\r\n
'Value: %s\r\n
End Select
If Not handled Then
'frmMain.txtDebug = frmMain.txtDebug & msg
End If
End Sub
Public Sub vb_stdout(ByVal t As cb_type, ByVal lpMsg As Long, ByVal sz As Long)
Dim b() As Byte
Dim msg As String
If shuttingDown Then Exit Sub
If t = cb_refreshUI Then
frmMain.Refresh
DoEvents
Sleep 10
Exit Sub
End If
If lpMsg = 0 Or sz = 0 Then Exit Sub
ReDim b(sz)
CopyMemory b(0), ByVal lpMsg, sz
msg = StrConv(b, vbUnicode)
If Right(msg, 1) = Chr(0) Then msg = Left(msg, Len(msg) - 1)
Select Case t
Case cb_debugger: HandleDebugMessage msg
Case cb_engine: HandleEngineMessage msg
Case cb_error: ParseError msg
Case Else:
If t = cb_dbgout Then msg = "DBG> " & msg
With frmMain.txtOut
.Text = .Text & Replace(msg, vbLf, vbCrLf)
.Refresh
DoEvents
End With
End Select
End Sub
Private Sub ParseError(msg As String)
Dim a As Long, b As Long, fpath As String, lNo As Long, eText As String
'Debug.Print "Error: " & Now & " """ & msg & """"
On Error Resume Next
hadError = True
a = InStr(msg, "File:")
If a > 0 Then
a = a + 5
b = InStr(a, msg, vbLf)
If b > 0 Then
fpath = Trim(Mid(msg, a, b - a))
If InStr(fpath, "\") > 0 Then fpath = FileNameFromPath(fpath)
End If
End If
a = InStr(msg, "Line: ")
If a > 0 Then
a = a + 6
b = InStr(a, msg, " ")
If b > 0 Then
lNo = CLng(Mid(msg, a, b - a))
a = InStr(b, msg, vbLf)
If a > b Then
eText = Mid(msg, b, a - b)
End If
End If
End If
If Len(eText) = 0 Then eText = Replace(msg, vbLf, " ")
Dim li As ListItem
Set li = frmMain.lvErrors.ListItems.Add(, , lNo)
li.SubItems(1) = fpath
li.SubItems(2) = eText
End Sub
Private Sub HandleEngineMessage(msg As String)
On Error Resume Next
Dim tmp() As String
tmp = Split(msg, ":")
If tmp(0) = "ENGINE_PRECONFIG" Then
hProgram = CLng(tmp(1))
hadError = False
ElseIf tmp(0) = "ENGINE_DESTROY" Then
hProgram = 0
hDebugObject = 0
If Not hadError And FileExists(flatFile) Then
Kill flatFile
flatFile = Empty
End If
End If
End Sub