195 lines
6.0 KiB
QBasic
195 lines
6.0 KiB
QBasic
![]() |
Attribute VB_Name = "DevTools"
|
||
|
'================ Developer Tools =============
|
||
|
' Shared module version: 20220811
|
||
|
' Depends on: ex_WinAPI
|
||
|
' Required reference: Scripting, VBIDE
|
||
|
Option Private Module
|
||
|
Option Explicit
|
||
|
|
||
|
Private Const TEST_SUITE_MASK = "s_*"
|
||
|
Private Const TEST_NAME_MASK = "t_*"
|
||
|
Private Const COMPILATION_DELAY As Long = 250 ' ms
|
||
|
|
||
|
Public Function CompileVBProject(target As VBIDE.VBProject) As Boolean
|
||
|
Const CONTROL_ID_COMPILE = 578
|
||
|
Const MSGBOX_CLASS_ID As String = "#32770"
|
||
|
Const MSGBOX_NAME As String = "Microsoft Visual Basic for Applications"
|
||
|
Const WINDOW_MESSAGE_CLOSE As Long = &H10
|
||
|
|
||
|
target.VBE.MainWindow.Visible = True
|
||
|
With target.VBComponents(1).CodeModule
|
||
|
Call .CodePane.Show
|
||
|
Call .InsertLines(1, "123")
|
||
|
Call .DeleteLines(1, 1)
|
||
|
End With
|
||
|
|
||
|
Dim btnCompile As CommandBarControl: Set btnCompile = target.VBE.CommandBars.FindControl(ID:=CONTROL_ID_COMPILE)
|
||
|
If Not btnCompile.Enabled Then
|
||
|
CompileVBProject = False
|
||
|
Exit Function
|
||
|
End If
|
||
|
|
||
|
Call btnCompile.Execute
|
||
|
|
||
|
Call Sleep(COMPILATION_DELAY)
|
||
|
|
||
|
Dim nHwnd&: nHwnd = FindWindow(MSGBOX_CLASS_ID, MSGBOX_NAME)
|
||
|
CompileVBProject = nHwnd = 0
|
||
|
If Not CompileVBProject Then _
|
||
|
Call PostMessage(nHwnd, WINDOW_MESSAGE_CLOSE, 0&, 0&)
|
||
|
End Function
|
||
|
|
||
|
Public Function UpdateVersionStamp(target As VBIDE.VBProject, sVersion$) As Boolean
|
||
|
UpdateVersionStamp = False
|
||
|
|
||
|
On Error Resume Next
|
||
|
Dim iModule As VBComponent: Set iModule = target.VBComponents("Main")
|
||
|
If iModule Is Nothing Then _
|
||
|
Exit Function
|
||
|
|
||
|
Dim iCode As CodeModule: Set iCode = iModule.CodeModule
|
||
|
|
||
|
Dim nLineStart&: nLineStart = 1
|
||
|
Dim nLineEnd&: nLineEnd = iCode.CountOfLines
|
||
|
|
||
|
Dim nColumnStart&: nColumnStart = 1
|
||
|
Dim nColumnEnd&: nColumnEnd = 255
|
||
|
|
||
|
If Not iCode.Find("Public Const PRODUCT_VERSION", nLineStart, nColumnStart, nLineEnd, nColumnEnd) Then _
|
||
|
Exit Function
|
||
|
Call iCode.ReplaceLine(nLineEnd, "Public Const PRODUCT_VERSION = """ & sVersion & """")
|
||
|
|
||
|
UpdateVersionStamp = True
|
||
|
End Function
|
||
|
|
||
|
Public Function PrepareSkeletonFor(target As Object)
|
||
|
On Error Resume Next
|
||
|
Call target.Application.Run("'" & target.Name & "'" & "!Dev_PrepareSkeleton")
|
||
|
End Function
|
||
|
|
||
|
Public Function ExtractProperties(sLines() As String, ByRef nCurrent&, ByRef oSink As Scripting.Dictionary)
|
||
|
ExtractProperties = False
|
||
|
|
||
|
Do While nCurrent <= UBound(sLines, 1)
|
||
|
Dim sLine$: sLine = sLines(nCurrent)
|
||
|
nCurrent = nCurrent + 1
|
||
|
If sLine Like "%%*" Then _
|
||
|
Exit Do
|
||
|
|
||
|
Dim nSeparator&: nSeparator = VBA.InStr(1, sLine, "=")
|
||
|
If nSeparator = 0 Then _
|
||
|
GoTo NEXT_LINE
|
||
|
If VBA.Left(sLine, 1) = "#" Then _
|
||
|
GoTo NEXT_LINE
|
||
|
|
||
|
Dim sKey$: sKey = VBA.Trim(VBA.Left(sLine, nSeparator - 1))
|
||
|
Dim sValue$: sValue = VBA.Trim(Right(sLine, VBA.Len(sLine) - nSeparator))
|
||
|
If oSink.Exists(sKey) Then _
|
||
|
Exit Function
|
||
|
Call oSink.Add(sKey, sValue)
|
||
|
NEXT_LINE:
|
||
|
Loop
|
||
|
|
||
|
ExtractProperties = True
|
||
|
End Function
|
||
|
|
||
|
Public Function Dev_CountPublicAPI(target As VBIDE.CodeModule) As Long
|
||
|
Dim nLine&
|
||
|
For nLine = 1 To target.CountOfLines Step 1
|
||
|
If InStr(1, target.Lines(nLine, 1), "Public") <> 0 Then _
|
||
|
Dev_CountPublicAPI = Dev_CountPublicAPI + 1
|
||
|
Next nLine
|
||
|
End Function
|
||
|
|
||
|
Public Function Dev_ScanFunctions(target As VBIDE.CodeModule) As Collection ' of CDS_InfoFunction
|
||
|
Dim cResult As New Collection
|
||
|
|
||
|
Dim currentFunc As CDS_InfoFunction
|
||
|
Dim lastFunc As New CDS_InfoFunction
|
||
|
Dim nLine&
|
||
|
For nLine = 1 To target.CountOfLines Step 1
|
||
|
Set currentFunc = ExtractProcedure(target, nLine)
|
||
|
If lastFunc.name_ <> currentFunc.name_ And currentFunc.name_ <> vbNullString Then
|
||
|
currentFunc.isPublic_ = IsPublicFunc(target, currentFunc)
|
||
|
Call cResult.Add(currentFunc)
|
||
|
End If
|
||
|
Set lastFunc = currentFunc
|
||
|
Next nLine
|
||
|
|
||
|
Set Dev_ScanFunctions = cResult
|
||
|
End Function
|
||
|
|
||
|
Public Function Dev_ScanTests(target As VBIDE.VBProject, ByRef cTestsDB As Scripting.Dictionary) As Long
|
||
|
Dim nCount&: nCount = 0
|
||
|
Dim aComponent As VBIDE.VBComponent
|
||
|
Dim iComponents As VBIDE.VBComponents: Set iComponents = target.VBComponents
|
||
|
Dim tests As Collection
|
||
|
For Each aComponent In iComponents
|
||
|
If aComponent.Type <> vbext_ct_ClassModule Then _
|
||
|
GoTo NEXT_COMPONENT
|
||
|
If Not aComponent.Name Like TEST_SUITE_MASK Then _
|
||
|
GoTo NEXT_COMPONENT
|
||
|
|
||
|
Set tests = New Collection
|
||
|
Dim funcs As Collection: Set funcs = Dev_ScanFunctions(aComponent.CodeModule)
|
||
|
Dim aFunc As CDS_InfoFunction
|
||
|
For Each aFunc In funcs
|
||
|
If aFunc.name_ Like TEST_NAME_MASK And aFunc.isPublic_ Then _
|
||
|
Call tests.Add(aFunc.name_)
|
||
|
Next aFunc
|
||
|
|
||
|
If tests.Count > 0 Then
|
||
|
Call cTestsDB.Add(aComponent.Name, tests)
|
||
|
nCount = nCount + tests.Count
|
||
|
End If
|
||
|
NEXT_COMPONENT:
|
||
|
Next aComponent
|
||
|
|
||
|
Set iComponents = Nothing
|
||
|
Set aComponent = Nothing
|
||
|
|
||
|
Dev_ScanTests = nCount
|
||
|
End Function
|
||
|
|
||
|
Public Function Dev_RemoveDebugCode(target As VBIDE.VBProject)
|
||
|
Dim selectedComps As New Collection
|
||
|
Dim aComponent As VBIDE.VBComponent
|
||
|
For Each aComponent In target.VBComponents
|
||
|
If Dev_IsTestingModule(aComponent.Name) Then _
|
||
|
Call selectedComps.Add(aComponent)
|
||
|
Next aComponent
|
||
|
|
||
|
For Each aComponent In selectedComps
|
||
|
Call target.VBComponents.Remove(aComponent)
|
||
|
Next aComponent
|
||
|
End Function
|
||
|
|
||
|
Public Function Dev_IsTestingModule(sName$) As Boolean
|
||
|
Dev_IsTestingModule = True
|
||
|
|
||
|
If sName Like TEST_SUITE_MASK Then _
|
||
|
Exit Function
|
||
|
If sName Like "DevHelper*" Then _
|
||
|
Exit Function
|
||
|
If sName Like "DevTester*" Then _
|
||
|
Exit Function
|
||
|
If sName Like "DevTesterUI*" Then _
|
||
|
Exit Function
|
||
|
If sName Like "API_MockInteraction*" Then _
|
||
|
Exit Function
|
||
|
|
||
|
Dev_IsTestingModule = False
|
||
|
End Function
|
||
|
|
||
|
' =====
|
||
|
Private Function ExtractProcedure(target As VBIDE.CodeModule, nLine&) As CDS_InfoFunction
|
||
|
Set ExtractProcedure = New CDS_InfoFunction
|
||
|
ExtractProcedure.name_ = target.ProcOfLine(nLine, ExtractProcedure.type_)
|
||
|
End Function
|
||
|
|
||
|
Private Function IsPublicFunc(target As VBIDE.CodeModule, func As CDS_InfoFunction) As Boolean
|
||
|
Dim nStart&: nStart = target.ProcBodyLine(func.name_, func.type_)
|
||
|
Dim sTxt$: sTxt = target.Lines(nStart, 1)
|
||
|
IsPublicFunc = InStr(1, sTxt, "Private") = 0
|
||
|
End Function
|