<!-- Softwell WinCC VBScript 20-Part Tutorial · Blog 06 · updated 2026-08-29 --> Sub, Function, ByVal & ByRef in WinCC VBScript
Blog 06 · WinCC VBScript Tutorial · SQF Running Project

Sub, Function, ByVal & ByRef in WinCC VBScript

Move from long copy-paste scripts to structured programming. Build reusable SQF procedures and functions that validate process conditions, normalize SQL values and make the final database logger easier to test.

WinCC VBScript · Beginner to Project Level
Sub, Function, ByVal & ByRef in WinCC VBScript

Follow the chapters in sequence; every tutorial reuses the same SQF furnace project.

Running project: SQF_DB.dbo.tblEvent · SQF_No · ChargeNo · Event_From · Event_To · Temp_Set/Temp_Act · Cp_Set/Cp_Act · Oil_Set/Oil_Act · Jacket_Set/Jacket_Act · Fan_Status
View all 20 tutorial chapters

Blog 06 Learning Goal

Series: WinCC VBScript 20-Part TutorialRunning DB: SQF_DB.dbo.tblEventDifficulty: Beginner → Intermediate

Outcome

Create reusable Subs and Functions, explain return values, choose ByVal vs ByRef, use Exit statements, and refactor repeated SQF logic into small procedures.

Easy Testing Method: Every main code example on this page is followed by a copy-ready InputBox + MsgBox test. Use the dialog version first to understand the result, then move to the original WinCC/SQL code. Database writes and equipment commands are previewed or simulated unless the original example is already intended as a lab action.
Project context: Every example is connected to SQF_DB.dbo.tblEvent. The final script reads WinCC tags, validates/converts values, creates an ADO connection, inserts one row and writes SQL_Status back to WinCC.

1. SUB Procedure

A Sub performs an action and does not return a value.

Sub ShowSQFStatus()
    HMIRuntime.Trace "SQF status check started" & vbCrLf
End Sub

Easy TestEasy Test 1 — InputBox + MsgBox

Self-contained procedure test; no PLC or SQL Server is required.

Sub ShowSQFValue(ByVal NameText, ByVal ValueText)
    MsgBox NameText & " = " & ValueText, vbInformation, "Sub Quick Test"
End Sub

Dim TempAct
TempAct = InputBox("Enter Temp_Act", "Easy Test 1 — InputBox + MsgBox", "825.5")
Call ShowSQFValue("Temp_Act", TempAct)

2. CALL

Use Call to explicitly invoke a Sub. It is optional in many VBScript cases, but useful for beginners because it makes the action obvious.

Call ShowSQFStatus()

Easy TestEasy Test 2 — InputBox + MsgBox

Self-contained procedure test; no PLC or SQL Server is required.

Sub ShowSQFValue(ByVal NameText, ByVal ValueText)
    MsgBox NameText & " = " & ValueText, vbInformation, "Sub Quick Test"
End Sub

Dim TempAct
TempAct = InputBox("Enter Temp_Act", "Easy Test 2 — InputBox + MsgBox", "825.5")
Call ShowSQFValue("Temp_Act", TempAct)

3. Parameters

Procedures become reusable when values are passed in instead of hard-coded.

Sub TraceProcessValue(ByVal Name, ByVal Value)
    HMIRuntime.Trace Name & " = " & CStr(Value) & vbCrLf
End Sub

Call TraceProcessValue("Temp_Act", TempAct)

Easy TestEasy Test 3 — InputBox + MsgBox

Self-contained procedure test; no PLC or SQL Server is required.

Sub ShowSQFValue(ByVal NameText, ByVal ValueText)
    MsgBox NameText & " = " & ValueText, vbInformation, "Sub Quick Test"
End Sub

Dim TempAct
TempAct = InputBox("Enter Temp_Act", "Easy Test 3 — InputBox + MsgBox", "825.5")
Call ShowSQFValue("Temp_Act", TempAct)

4. FUNCTION and Return Value

A Function returns a value by assigning to its own name.

Function CheckTemperature(ByVal TempSet, ByVal TempAct)
    If TempAct >= TempSet Then
        CheckTemperature = True
    Else
        CheckTemperature = False
    End If
End Function

Easy TestEasy Test 4 — InputBox + MsgBox

A self-contained function test using the same setpoint/actual-value pattern as the SQF project.

Function TestIsOK(ByVal SetValue, ByVal ActualValue)
    TestIsOK = (ActualValue >= SetValue)
End Function

Dim SP, PV
SP = CDbl(InputBox("Enter Setpoint", "Easy Test 4 — InputBox + MsgBox", "850"))
PV = CDbl(InputBox("Enter Actual Value", "Easy Test 4 — InputBox + MsgBox", "825"))

MsgBox "Setpoint = " & SP & vbCrLf & _
       "Actual = " & PV & vbCrLf & _
       "Function Result = " & TestIsOK(SP, PV), _
       vbInformation, "Function Quick Test"

5. Use a Function in IF Logic

Functions make a large decision easier to read.

If CheckTemperature(TempSet, TempAct) Then
    EventTo = "TEMPERATURE ACHIEVED"
Else
    EventTo = "TEMPERATURE NOT ACHIEVED"
End If

Easy TestEasy Test 5 — InputBox + MsgBox

Change the InputBox values to force different IF/ELSE outcomes.

Dim TempSet, TempAct, FanInput, FanStatus, ResultText
TempSet = CDbl(InputBox("Enter Temp_Set", "Easy Test 5 — InputBox + MsgBox", "850"))
TempAct = CDbl(InputBox("Enter Temp_Act", "Easy Test 5 — InputBox + MsgBox", "825"))
FanInput = InputBox("Fan_Status: enter 1 for RUNNING, 0 for STOPPED", "Easy Test 5 — InputBox + MsgBox", "1")
FanStatus = (FanInput = "1")

If TempAct >= TempSet And FanStatus Then
    ResultText = "TEMPERATURE READY + FAN RUNNING"
ElseIf TempAct >= TempSet Then
    ResultText = "TEMPERATURE READY, FAN STOPPED"
Else
    ResultText = "TEMPERATURE BELOW SETPOINT"
End If

MsgBox ResultText & vbCrLf & _
       "Temp_Set = " & TempSet & vbCrLf & _
       "Temp_Act = " & TempAct, vbInformation, "Condition Quick Test"

6. ByVal

ByVal passes a copy. Changes inside the procedure do not change the caller variable.

Sub TestByVal(ByVal Value)
    Value = Value + 10
End Sub

TempSet = 850
Call TestByVal(TempSet)
' TempSet remains 850

Easy TestEasy Test 6 — InputBox + MsgBox

Self-contained procedure test; no PLC or SQL Server is required.

Sub ShowSQFValue(ByVal NameText, ByVal ValueText)
    MsgBox NameText & " = " & ValueText, vbInformation, "Sub Quick Test"
End Sub

Dim TempAct
TempAct = InputBox("Enter Temp_Act", "Easy Test 6 — InputBox + MsgBox", "825.5")
Call ShowSQFValue("Temp_Act", TempAct)

7. ByRef

ByRef allows the procedure to change the caller variable. Use it deliberately.

Sub NormalizeFan(ByRef FanStatus)
    If FanStatus Then
        FanStatus = 1
    Else
        FanStatus = 0
    End If
End Sub

Call NormalizeFan(FanStatus)

Easy TestEasy Test 7 — InputBox + MsgBox

Self-contained procedure test; no PLC or SQL Server is required.

Sub ShowSQFValue(ByVal NameText, ByVal ValueText)
    MsgBox NameText & " = " & ValueText, vbInformation, "Sub Quick Test"
End Sub

Dim TempAct
TempAct = InputBox("Enter Temp_Act", "Easy Test 7 — InputBox + MsgBox", "825.5")
Call ShowSQFValue("Temp_Act", TempAct)
Training preference: start with ByVal because it reduces unintended side effects. Use ByRef only when the procedure is intentionally expected to modify the caller variable.

8. Exit Sub

Guard clauses make validation readable and prevent the remainder of a procedure from running.

Sub ValidateCharge(ByVal Charge)
    If Trim(CStr(Charge)) = "" Then
        MsgBox "Charge Number required"
        Exit Sub
    End If

    HMIRuntime.Trace "Charge valid" & vbCrLf
End Sub

Easy TestEasy Test 8 — InputBox + MsgBox

Self-contained procedure test; no PLC or SQL Server is required.

Sub ShowSQFValue(ByVal NameText, ByVal ValueText)
    MsgBox NameText & " = " & ValueText, vbInformation, "Sub Quick Test"
End Sub

Dim TempAct
TempAct = InputBox("Enter Temp_Act", "Easy Test 8 — InputBox + MsgBox", "825.5")
Call ShowSQFValue("Temp_Act", TempAct)

9. Exit Function

Exit Function ends a Function early after assigning the result.

Function IsValidTemp(ByVal Value)
    IsValidTemp = False

    If Not IsNumeric(Value) Then Exit Function
    If CDbl(Value) < 0 Then Exit Function
    If CDbl(Value) > 1000 Then Exit Function

    IsValidTemp = True
End Function

Easy TestEasy Test 9 — InputBox + MsgBox

A self-contained function test using the same setpoint/actual-value pattern as the SQF project.

Function TestIsOK(ByVal SetValue, ByVal ActualValue)
    TestIsOK = (ActualValue >= SetValue)
End Function

Dim SP, PV
SP = CDbl(InputBox("Enter Setpoint", "Easy Test 9 — InputBox + MsgBox", "850"))
PV = CDbl(InputBox("Enter Actual Value", "Easy Test 9 — InputBox + MsgBox", "825"))

MsgBox "Setpoint = " & SP & vbCrLf & _
       "Actual = " & PV & vbCrLf & _
       "Function Result = " & TestIsOK(SP, PV), _
       vbInformation, "Function Quick Test"

10. Reusable SQF Helper Functions

The final project becomes much clearer when formatting and validation are isolated.

Function SqlSafeText(ByVal Value)
    SqlSafeText = Replace(CStr(Value), "'", "''")
End Function

Function SqlNumber(ByVal Value)
    SqlNumber = Replace(CStr(Value), ",", ".")
End Function

Function BuildTimeText()
    BuildTimeText = Right("0" & Hour(Now), 2) & ":" & _
                    Right("0" & Minute(Now), 2) & ":" & _
                    Right("0" & Second(Now), 2)
End Function

Easy TestEasy Test 10 — InputBox + MsgBox

Shows the exact timestamp formatting used later in tblEvent.TM.

Dim LabelText, TM
LabelText = InputBox("Enter a label for this timestamp", "Easy Test 10 — InputBox + MsgBox", "SQF Event")
TM = Right("0" & Hour(Now), 2) & ":" & _
     Right("0" & Minute(Now), 2) & ":" & _
     Right("0" & Second(Now), 2)
MsgBox LabelText & vbCrLf & _
       "Date/Time = " & Now & vbCrLf & _
       "TM = " & TM, vbInformation, "Date/Time Quick Test"

11. Participant Exercises

Complete these before HMIRuntime tag programming.

Create CheckTemperature().
Create CheckProcessReady() using four actual/setpoint pairs.
Create SqlSafeText().
Create BuildTimeText().
Demonstrate ByVal without changing caller data.
Demonstrate ByRef by normalizing FanStatus to 0/1.

SQF Running Project Lab · Blog 06

Refactor SQF validation into reusable functions

Function CheckProcessReady(ByVal TempSet, ByVal TempAct, _
                           ByVal CpSet, ByVal CpAct, _
                           ByVal OilSet, ByVal OilAct, _
                           ByVal JacketSet, ByVal JacketAct, _
                           ByVal FanStatus)
    CheckProcessReady = (TempAct >= TempSet) And _
                        (CpAct >= CpSet) And _
                        (OilAct >= OilSet) And _
                        (JacketAct >= JacketSet) And _
                        CBool(FanStatus)
End Function

Easy TestEasy Test 11 — InputBox + MsgBox

A self-contained function test using the same setpoint/actual-value pattern as the SQF project.

Function TestIsOK(ByVal SetValue, ByVal ActualValue)
    TestIsOK = (ActualValue >= SetValue)
End Function

Dim SP, PV
SP = CDbl(InputBox("Enter Setpoint", "Easy Test 11 — InputBox + MsgBox", "850"))
PV = CDbl(InputBox("Enter Actual Value", "Easy Test 11 — InputBox + MsgBox", "825"))

MsgBox "Setpoint = " & SP & vbCrLf & _
       "Actual = " & PV & vbCrLf & _
       "Function Result = " & TestIsOK(SP, PV), _
       vbInformation, "Function Quick Test"
By Blog 06, participants should stop repeating large condition blocks and begin creating reusable, testable helpers.

Trainer Checkpoint

Participant should explain this chapter without copying the final program.

FAQs

Why does this tutorial use SQF_DB.dbo.tblEvent?

One stable industrial dataset lets participants learn VBScript progressively without changing examples in every chapter.

Should participants memorize the complete SQL logger now?

No. Learn the current chapter first. The complete WinCC-to-SQL program is assembled in later chapters.

Are HMIRuntime and ADODB VBScript keywords?

No. They are runtime/COM objects used by VBScript. The language keywords control how the script is structured.

Continue the WinCC VBScript 20-Part Tutorial

Use the same SQF process variables in the next chapter.

Next: Blog 07
Verified learning pathway

Discuss WinCC VB Scripting Training

Explore practical WinCC VBS, SCADA, SQL reporting and industrial automation training options.

Content reviewed: 28 August 2026

☎ Call WhatsApp ✉ Email Enquire Now