7. Writing Methods' Code

Applies to TestComplete 15.69, last modified on November 13, 2024

Creation of object methods includes two steps:

  • Writing the methods code.

  • Adding information about methods to the description file.

On this step we will write the script code for the WMI object methods. On the next step we will add information about the methods to the description.xml file. For a summary on the methods, review the step 1.

Most of the WMI object methods that we are going to create will query WMI for various information using the SWbemServices.ExecQuery method. The rest of this topic provides the full code of the methods as well as the explanation of what this code does. You need to add this code to the wmiCode unit.

ConnectToComputer

This method connects to WMI on a computer using the specified user account. It is actually a wrapper over the ConnectToComputerInternal routine that we have created earlier, with added reporting to the playback indicator and the test log.

The code below also contains the helper GetComputerDisplayName function that is used to obtain the computer name for use in the indicator and log messages. This method simply returns the computer name stored in theComputerName variable, except when the local computer is specified by the dot string (".") -- in this case the method transforms it into the actual computer name.

VBScript

Const UMSG_ComputerConnected    = "A connection to the ""%s"" computer has been established successfully."
Const UMSG_UnableToConnect      = "Unable to connect to the ""%s"" computer."
Const USMG_WaitingForConnection = "Connecting to the ""%s"" computer..."

Sub ConnectToComputer(Computer, User, Password)
  ComputerName = Computer

  ' Attempt to connect to WMI on the specified computer
  On Error Resume Next
  Indicator.PushText(aqString.Format(USMG_WaitingForConnection, GetComputerDisplayName))
  ConnectToComputerInternal User, Password
  Indicator.PopText

  ' Check if connection was successful
  If Err.Number = 0 Then
    Log.Message(aqString.Format(UMSG_ComputerConnected, GetComputerDisplayName))
  Else
    Log.Error(aqString.Format(UMSG_UnableToConnect, GetComputerDisplayName))
  End If
End Sub

Function GetComputerDisplayName
  If ComputerName = CLocalComputer Then
    GetComputerDisplayName = Sys.HostName
  Else
    GetComputerDisplayName = ComputerName
  End If
End Function

WaitForComputer

This method waits until the connection to WMI on the specified remote computer is established. Like ConnectToComputer, this method is also a wrapper over the ConnectToComputerInternal routine. The method calls the ConnectToComputerInternal routine multiple times until the remote WMI connection is successfully established or the timeout period elapses. The method also reports its actions and results to the playback indicator and the test log.

VBScript

Const UMSG_ConnectionTimeout    = "Failed to connect to the ""%s"" computer during the timeout period."

Sub WaitForComputer(Computer, User, Password, Timeout)
  ComputerName = Computer

  ' Convert the timeout value from milliseconds to seconds (round to larger)
  Dim TimeoutSeconds
  TimeoutSeconds = Timeout \ 1000
  If Timeout Mod 1000 <> 0 Then
    TimeoutSeconds = TimeoutSeconds + 1
  End If

  ' Perform multiple attempts to connect to the specified computer during the timeout period
  On Error Resume Next
  Indicator.PushText(aqString.Format(USMG_WaitingForConnection, GetComputerDisplayName))
  Dim StartTime
  StartTime = Now
  Do
    Err.Clear
    ConnectToComputerInternal User, Password
  Loop While (Err.Number <> 0) And (DateDiff("s", StartTime, Now) < TimeoutSeconds)
  Indicator.PopText

  ' Check if connection succeeded
  If Err.Number = 0 Then
    Log.Message(aqString.Format(UMSG_ComputerConnected, GetComputerDisplayName))
  Else
    Log.Error(aqString.Format(UMSG_ConnectionTimeout, GetComputerDisplayName))
  End If
End Sub

RestartComputer

This method uses the Reboot method of the Win32_OperatingSystem WMI class to shut down and then restart the computer:

VBScript

Sub RestartComputer
  Dim OSColl, OSItem
  Set OSColl = WMIService.ExecQuery("SELECT * FROM Win32_OperatingSystem")

  For Each OSItem In OSColl
    OSItem.Reboot
  Next
End Sub

GetEnvironmentVariable

This method queries the Win32_Environment class instance corresponding to the environment variable with the specified name and retrieves the variable value. The Flags_RtnImmedFwdOnly flag value is used to improve the performance of the WMI queries.

VBScript

Const Flags_RtnImmedFwdOnly = &H30 ' The iFlags value for the SWbemServices.ExecQuery method

Function GetEnvironmentVariable(Name)
  Dim EnvVarColl, EnvVarItem

  ' Search for an environment variable with the specified name
  Set EnvVarColl = WMIService.ExecQuery _
    ("SELECT * FROM Win32_Environment WHERE Name='" & Name & "'", , Flags_RtnImmedFwdOnly)

  ' Get the variable's value
  For Each EnvVarItem In EnvVarColl
    GetEnvironmentVariable = EnvVarItem.VariableValue
    Exit For
  Next
End Function

PostEnvironmentVariableInfo

This method queries the Win32_Environment WMI class to retrieve all environment variables defined on the computer and then posts the obtained information to the test log:

VBScript

Sub PostEnvironmentVariableInfo
  Dim EnvVarColl, EnvVarItem
  Log.AppendFolder("Environment Variables")

  ' Obtain all environment variables
  Set EnvVarColl = WMIService.ExecQuery("SELECT * FROM Win32_Environment", , Flags_RtnImmedFwdOnly)

  ' Log the variables' properties
  For Each EnvVarItem In EnvVarColl
    Log.AppendFolder EnvVarItem.Name
    Log.Message "Value: "           & EnvVarItem.VariableValue
    Log.Message "User name: "       & EnvVarItem.UserName
    Log.Message "Description: "     & EnvVarItem.Description
    Log.Message "System variable: " & EnvVarItem.SystemVariable
    Log.PopLogFolder
  Next
  Log.PopLogFolder
End Sub

PostProcessorInfo

This method queries the Win32_Processor WMI class to obtain information about the computer’s CPUs and then posts this information to the test log:

VBScript

Sub PostProcessorInfo
  Dim ObjectsList, CurrentObject, ID
  Log.AppendFolder "Processors"

  ' Obtain all the processors
  Set ObjectsList = WMIService.ExecQuery("SELECT * FROM Win32_Processor", , Flags_RtnImmedFwdOnly)

  ' Log the processors' properties
  ID = 1
  For Each CurrentObject In ObjectsList
    Log.AppendFolder "Processor #" & ID
    Log.Message "Manufacturer: " & CurrentObject.Manufacturer
    Log.Message "Description: "  & CurrentObject.Description
    Log.Message "Frequency: "    & CurrentObject.CurrentClockSpeed
    Log.PopLogFolder
    ID = ID + 1
  Next
  Log.PopLogFolder
End Sub

PostDrivesInfo

This method queries the Win32_LogicalDisk WMI class to retrieve information about the computer’s hard drives and then posts the obtained information to the test log:

VBScript

Sub PostDrivesInfo
  Dim ObjectsList, CurrentObject
  Log.AppendFolder "Logical Disks"
  
  ' Obtain all the fixed hard drives
  Set ObjectsList = WMIService.ExecQuery("SELECT * FROM Win32_LogicalDisk WHERE MediaType=12", , Flags_RtnImmedFwdOnly)

  ' Log the hard drives' properties
  For Each CurrentObject In ObjectsList
    Log.AppendFolder CurrentObject.Name
    Log.Message "Label: "           & CurrentObject.VolumeName
    Log.Message "Size (MB): "       & CurrentObject.Size / 1024^2
    Log.Message "Free space (MB): " & CurrentObject.FreeSpace  / 1024^2
    Log.PopLogFolder
  Next
  Log.PopLogFolder
End Sub

PostInstalledAppsInfo

This method queries the Win32_Product WMI class to retrieve information about software installed on the computer and then posts the obtained information to the test log:

VBScript

Sub PostInstalledAppsInfo
  Dim ObjectsList, CurrentObject
  Log.AppendFolder "Installed Applications"

  ' Obtain all the installed products
  Set ObjectsList = WMIService.ExecQuery("SELECT * FROM Win32_Product", , Flags_RtnImmedFwdOnly)

  ' Log the products' properties
  For Each CurrentObject In ObjectsList
    Log.AppendFolder CurrentObject.Caption
    Log.Message "Vendor: "      & CurrentObject.Vendor
    Log.Message "Version: "     & CurrentObject.Version
    Log.Message "Description: " & CurrentObject.Description
    Log.Message "Location: "    & CurrentObject.InstallLocation
    Log.PopLogFolder
  Next
  Log.PopLogFolder
End Sub

PostEventsInfo

This method queries the Win32_NTLogEvent WMI class to retrieve records from the system event log and then posts the latest records to the test log. The number of the latest events to report is specified by the MaxEventCount variable:

VBScript

Sub PostEventsInfo
  Dim ObjectsList, CurrentObject, Count
  Log.AppendFolder("System Events")

  ' Retrieve entries from the system event log
  Set ObjectsList = WMIService.ExecQuery("SELECT * FROM Win32_NTLogEvent WHERE LogFile='System'", , Flags_RtnImmedFwdOnly)

  ' Log the latest MaxEventCount events
  Count = 1
  For Each CurrentObject in ObjectsList
    Log.AppendFolder(CurrentObject.SourceName)
    Log.Message "User: "     & CurrentObject.User
    Log.Message "Category: " & CurrentObject.CategoryString      
    Select Case CurrentObject.EventType
      Case 1
        Log.Error   "Message", CurrentObject.Message
      Case 2
        Log.Warning "Message", CurrentObject.Message
      Case 3
        Log.Message "Message", CurrentObject.Message
    End Select
    Log.PopLogFolder

    Count = Count + 1
    If Count > MaxEventCount Then
      Exit For
    End If
  Next
  Log.PopLogFolder
End Sub

CreateProcess

This method uses the Create method of the Win32_Process WMI class to launch a process specified by its command line and returns the process ID. If the method fails to create the specified process, it posts an error message to the test log:

VBScript

Const UMSG_ProcessWasCreated         = "The ""%s"" process has been created successfully."
Const UMSG_UnableToCreateProcess     = "Unable to create the ""%s"" process."
Const UMSG_ErrorWhileCreatingProcess = "An error occurred while creating the ""%s"" process. The error code is %u."

Function CreateProcess(CommandLine)
  Dim Process, InParams, OutParams
  Set Process = WMIService.Get("Win32_Process")

  ' Specify the command line to execute
  Set InParams = Process.Methods_("Create").InParameters.SpawnInstance_
  InParams.CommandLine = CommandLine

  ' Launch the process and get its ID
  Set OutParams = WMIService.ExecMethod("Win32_Process", "Create", InParams)
  CreateProcess = OutParams.ProcessId

  ' Check if the process was launched successfully
  If OutParams.ReturnValue = 0 Then
    Log.Message(aqString.Format(UMSG_ProcessWasCreated, CommandLine))
  ElseIf IsNull(OutParams.ReturnValue) Then
    Log.Error(aqString.Format(UMSG_UnableToCreate, CommandLine))
  Else
    Log.Error(aqString.Format(UMSG_ErrorWhileCreatingProcess, CommandLine, OutParams.ReturnValue))
  End If
End Function

ProcessExists

This method checks to see if the specified process is running on the computer by querying the Win32_Process class instance corresponding to the specified process name.

VBScript

Function ProcessExists(ProcessName)
  ProcessExists = False
  Dim ProcessColl, ProcessItem

  ' Search for a process with the specified name
  Set ProcessColl = WMIService.ExecQuery _
    ("SELECT * FROM Win32_Process WHERE Name='" & ProcessName & "'", , Flags_RtnImmedFwdOnly)

  ' Check if the found object is valid
  For Each ProcessItem In ProcessColl
    ProcessExists = Not IsNull(ProcessItem.ProcessId)
    Exit For
  Next
End Function

WaitForProcessExit

This method waits until the specified process is stopped. For this, it monitors the __InstanceDeletionEvent WMI event triggered by the Win32_Process class instance corresponding to the specified process. This event occurs when a WMI class instance is deleted; in our case - when the process is stopped. The method waits for the event to occur within the provided timeout and then reports the results -- whether or not the event occurred and thus the process has stopped. The polling interval (that is, the interval that defines how often the method checks for the event) is specified by the CPollInterval constant and is 100 ms by default.

VBScript

Const UMSG_ProcessNotFound    = "The ""%s"" process is not running."
Const UMSG_ProcessExited      = "The ""%s"" process has closed."
Const UMSG_ProcessHasntExited = "The ""%s"" process has not closed during the timeout period."

Const CPollInterval = 0.1 ' = 100 ms; Polling interval for event queries

Sub WaitForProcessExit(ProcessName, Timeout)
  ' Verify that the specified process is running
  If Not ProcessExists(ProcessName) Then
    Log.Message(aqString.Format(UMSG_ProcessNotFound, ProcessName))
    Exit Sub
  End If

  Dim EventSource, EventItem

  ' Subscribe to the process termination event
  Indicator.PushText(aqString.Format(UMSG_WaitingForProcessExit, ProcessName))
  Set EventSource = oWMIService.ExecNotificationQuery _
    ("SELECT * FROM __InstanceDeletionEvent WITHIN " & CPollInterval _
    & " WHERE TargetInstance ISA 'Win32_Process'" _
    & " AND TargetInstance.Name='" & ProcessName & "'")

  ' Wait for the process to exit during the timeout period
  On Error Resume Next
  Set EventItem = EventSource.NextEvent(Timeout)
  Set EventSource = Nothing
  Indicator.PopText

  ' Check if the process has exited
  If IsEmpty(EventItem) Then
    Log.Error(aqString.Format(UMSG_ProcessHasntExited, ProcessName))
  Else
    Log.Message(aqString.Format(UMSG_ProcessExited, ProcessName))
  End If
End Sub

GetServiceState

This method queries the Win32_Service class instance corresponding to the service with the specified name and returns the current state of this service:

VBScript

Function GetServiceState(ServiceName)
  Dim ServiceColl, ServiceItem

  ' Search for a service with the specified display name
  Set ServiceColl = WMIService.ExecQuery _
    ("SELECT * FROM Win32_Service WHERE DisplayName='" & ServiceName & "'", , Flags_RtnImmedFwdOnly)

  ' Get the state of the service
  For Each ServiceItem In ServiceColl
    GetServiceState = ServiceItem.State
    Exit For
  Next
End Function

WaitForServiceState

This method waits until the service state changes; the service name and target state specified via the method parameters. The method implementation is similar to that of the WaitForProcessExit. It subscribes to the __InstanceModificationEvent WMI event generated by the Win32_Service class instance corresponding to the specified service. This event occurs whenever a WMI class instance is modified; in our case - when the service’s State property obtains the specified value. The method waits for the event to occur within the provided timeout and then reports the results.

VBScript

Const UMSG_ServiceNotFound              = "The ""%s"" service is not registered."
Const UMSG_ServiceStateChanged          = "The state of the ""%s"" service has changed to ""%s""."
Const UMSG_ServiceStateTimeout          = "The state of the ""%s"" service has not changed to ""%s"" during the timeout period."
Const UMSG_WaitingForServiceStateChange = "Waiting until the state of the ""%s"" service changes..."

Sub WaitForServiceState(ServiceName, State, Timeout)
  ' Verify that the specified service is registered
  If IsEmpty(GetServiceState(ServiceName)) Then
    Log.Error(aqString.Format(UMSG_ServiceNotFound, ServiceName))
    Exit Sub
  End If

  Dim EventSource, EventItem

  ' Subscribe to the service state change event
  Indicator.PushText(aqString.Format(UMSG_WaitingForServiceStateChange, ServiceName))
  Set Events = WMIService.ExecNotificationQuery _
    ("SELECT * FROM __InstanceModificationEvent WITHIN " & CPollInterval _
    & " WHERE TargetInstance ISA 'Win32_Service'" _
    & " AND TargetInstance.DisplayName='" & ServiceName & "'" _
    & " AND TargetInstance.State='" & State & "'")

  ' Wait for the service state to change during the timeout period
  On Error Resume Next
  Set EventItem = Events.NextEvent(Timeout)
  Set Events = Nothing
  Indicator.PopText

  ' Check if the service state has changed
  If IsEmpty(EventItem) Then
    Log.Error(aqString.Format(UMSG_ServiceStateTimeout, ServiceName, State))
  Else
    Log.Message(aqString.Format(UMSG_ServiceStateChanged, ServiceName, CurrentState))
  End If
End Sub

Once you have added the methods’ code to the wmiCode unit, you can proceed to the following step where we will define these methods in the script extension’s description file.

Prev     Next

See Also

Creating Object Methods
Creating Runtime Objects - Basic Concepts
Creating Runtime Objects

Highlight search results