Visual Basic Tutorial

This tutorial will build a small Visual Basic application in stages. The example here was built using Visual Basic version 6 on a 1024x768 display. At the completion of each stage the application can be run to verify proper functioning. In its finished form, the application will provide simple editing of point attributes. The final application will look like this:


The complete code for the application at each step can be found in the online help file under Tutorial Code.

In the discussion that follows, PI-SDK objects, which are in fact interfaces, are referred to as "objects" for simplicity.

Step 1:

In the first step, the application will retrieve the list of Known Servers, fill a combo box, and the default server will be selected.

  1. Start Visual Basic and from the File menu choose New. From the dialog presented select Standard Exe and press the OK button.
  2. Select the displayed form and drag the bottom right handle until the form is about 4-1/2" (11.4 cm) wide by 4" (10.2 cm) tall. Set the Caption property of the form to "Point Edit"
  3. From the toolbox, select the label control and insert a label at the top left. Set the Caption property of the label to "Server:"
  4. From the toolbox, select the combo box control and starting just under the label at the left hand side drag a rectangle about 2" (5 cm) by 2-1/2" (6-1/2 cm) to define the control. At this point the form should look like this:



  1. From the Project menu, select the References item. In the dialog presented, scroll down until you see the item for the PISDK 1.1 Type Library and check the checkbox next to it.  Also check the item PISDK Common 1.0 Type Library then click OK. If you don't see the PISDK entries it probably indicates a failure during installation. See the troubleshooting section for more information.
  2. Double-click on the form background to bring up the code window. Your cursor should be located just below the declaration of the Form_Load subroutine. Move the cursor to the top of the file and enter

Option Explicit

Dim srv as Server

Dim pt As PIPoint

This tells Visual Basic that all variables must be declared and declares two variables with global scope, srv and pt.

  1. Move the cursor back to just under the Form_Load subroutine and type:

Dim cur As Integer

Dim dflt As Integer

cur = 0

dflt = 0

For Each srv In Servers

Combo1.AddItem srv.Name

If srv.Name = Servers.DefaultServer.Name Then

dflt = cur

End If

cur = cur + 1


Combo1.ListIndex = dflt

Set srv = Servers(Combo1.Text)

Here we are declaring two integers, cur and dflt, and initializing them both to 0. As we iterate through the Servers collection, cur keeps track of the index of the current server. When we find the default server, dflt is set to its index.

The For Each loop that follows is a standard method for looping through most of the PI-SDK collections. (Even large collections, like PIPoints, support this syntax, however, iterating through all points on a PI Server is generally a bad idea for performance reasons). The For Each statement here loads the variable srv with a server from the Servers collection each time through the loop.

Inside the loop we call the combo box's AddItem method, passing it the Name property of the Server object in srv. In the If statement we compare this name to the name of the system's default server. The expression Servers.DefaultServer.Name gets the default server name in two steps; the Servers collection's DefaultServer property gives us a Server object for the default server, then we get that object's Name property. When we find a name that matches the name of the default server we save the index in our combo box in dflt. Regardless of the outcome of the comparison we increment the cur variable so it holds the index of the next item to be added to the combo box.

After exiting the loop we tell the combo box to set its selected member to the default server by setting its ListIndex property to our saved dflt variable. As a side effect, this makes the selected server's name visible in the combo box's Text property.

Finally we set our global Server variable srv to the current server selected in our combo box. This is done using the Servers.Item property, which is the default property of the collection so we do not need to specify its name. We pass the Item property the name of the server we want, which we find in the combo box's Text property as described above.

  1. We want to update our global server variable whenever the user changes the server selection so we add code for the Click event of the combo box. In the code window open the combo box at the top left of the window and select "Combo1." Then open the combo box at the top right of the window and select "Click." This will enter the subroutine definition in the code window. To add the implementation, we copy the last line of the Form_Load routine into Combo1_Click

Set srv = Servers(Combo1.Text)

Save the project. At this point you should be able to run the program and see your form with a combo box with the default server selected. When you drop the combo box you should see the other servers in your Known Servers Table.

Note that if you have just installed the PI-SDK you may only have a single server in your Known Servers Table. You can add additional servers with the Servers.Add method. If you would like to add another server to see the combo box work, even if you only have one PI Server to access, you can add the same server with a different local name. To do this, temporarily add a line at the beginning of your Form_Load routine similar to the following:

Servers.Add "tempServer", "UID=piadmin;path=localhost;port=5450", "PI3", False

The first argument is the local name you want for this server, the second argument is a connection string which specifies the default user (UID), the network path to the server (in this case a server on the local box was used), and the port on the server where PI is listening (PI3 Servers typically use 5450 and PI2 Servers use 545). The third argument indicates the type of server (currently only "PI3" and "PI2" are supported. Finally, the last argument says don't bother checking the serverID right now, wait until the first connection.

To add a server to the Known Servers Table, run your application once with this line in place. If no errors are reported you should see the new server in the combo box. Stop the program and comment out the Servers.Add line so it doesn't get executed again.

Step 2:

In this step we will add retrieval of a PIPoint by tag name. We will fetch the point attributes for the point and display their names in a list box.

  1. If the project from Step1 is not already open, open it now.
  2. Go to the form view and select the CommandButton from the toolbox. Drag the cursor to define a button starting about ½" (1.3 cm) under the combo box. Leave enough room to add a button above this one but below the combo box. Set the Caption property of the button to Retrieve.
  3. From the toolbox select the TextBox icon. Drag the cursor to define a text box about 2" (5 cm) wide just to the right of the Retrieve button just created. Set the Textbox's Text property to an empty string.
  4. From the toolbox select the Label icon and drag to create a label about 1" (2-1/2 cm) long just above the text box created above. Set the Caption property of the label to Tag Name:.
  5. Select the Line icon from the toolbox and drag a line across the form just under the button and text box created above. This is only a visual separator so the results are separated from the request. Set the line's BorderWidth property to 2.
  6. Select the ListBox control from the toolbox. Drag the cursor to define a list box on the left side of the form just under the line created above. Make the list box about 1-3/4" (4-1/2 cm) square. The ListBox should have a Multi-Select property of 0, the default. At this point your form should look like this:



  1. In the form, double-click on the Retrieve button to go to the code window and start entering code for the Command1_Click event. Add the following code:


If Text1.Text = "" Then

MsgBox "Please enter a tagname"

Exit Sub

End If

Set pt = srv.PIPoints(Text1.Text)

Dim ptatr As PointAttribute


For Each ptatr In pt.PointAttributes

List1.AddItem ptatr.Name


Exit Sub


MsgBox Err.Description

The first line above and the last three are for standard error trapping. If any statement after the On Error GoTo HANDLER statement raises an error (this could be a VB problem or a PI-SDK error), execution is transferred to the statement just after the HANDLER: label. In this case, our handler displays a message box with the error and then the routine ends. If no errors are encountered, the statements execute sequentially until the Exit Sub statement is reached at which time the routine ends.

After the On Error statement, the next four lines check to make sure some text has been entered for the tag name by examining the Text property of the Text1 text box. Once we are sure we have some text we attempt to retrieve a PIPoint object for the tag into our global pt variable. In the line

Set pt = srv.PIPoints(Text1.Text)

we use the Server object that has been set in our srv global variable, either during the Form_Load or because the user clicked on a different server in our combo box. We ask for the PIPoints property of this Server and then call the Item property (again we are counting on it being the default property), passing it the text property of our TextBox for the tag name. If there is no such point, the call will fail and we will be sent to the error handler. We could change the error handling to inspect the error raised and give appropriate messages, but to keep it simple we will rely on the PI-SDK returning a reasonable message.

With the PIPoint object successfully stored in pt, we then declare a PointAttribute variable for use in our iteration. We empty out the list box from the last time attributes were retrieved using the list box's Clear method. Next, we iterate through the PIPoint object's PointAttributes collection property using the same For Each construct that we earlier used to iterate through the Known Servers table. As we loop through each attribute we retrieve the Name property and add it to our list box.

  1. Save the project. At this point when you run the program you should be able to select a server, type in a tag name and click Retrieve. The names of the point attributes for the tag should be displayed in the list box.

If the default user for your server has no password, the application should perform correctly. However, if your default user requires a password, the application will not be able to open the server to retrieve point information. In the next step, we will solve this problem.

Step 3:

In this step, we will add a login button that calls the Connections.Login method to connect to the specified server. This method (supplied by the PI-SDK Dialogs) attempts to login to a PI Server using a specified user name and password. If this fails, it then presents a login dialog to allow the user to supply a user name and password.

In step 4 we are going to use this application to modify point attributes. To be successful in this endeavor we must be able to login to the server with a user name that has adequate permission to edit the entered tag. In this example, we will be connecting as the default user for the selected server. If this user does not have sufficient privilege to change point attributes you may want to change the default user. If the default user is already password protected, you will have an opportunity to change to a different user because the Login dialog will be displayed at runtime. For a discussion of users and establishing editing rights for points on the server consult the PI Server documentation. (Note: the PI-SDK does not support editing points on PI on OpenVMS servers).

  1. If the project from Step2 is not already open, open it now.
  2. Select the References entry from the Project Menu. Scroll down until you find the reference labeled PI-SDK Dialogs, check the box, and click OK. Select the Object Browser entry from the View Menu. You can now select PISDKDlg from the dropdown and browse the methods for the Connections object. In particular look at the Login method, as this is the method we will be calling. Close the Object Browser window.
  3. From the toolbox select the CommandButton icon and drag the cursor to create a button under the combo box and above the button labeled Retrieve. Set the caption of this button to "Login."
  4. Double-click on the button to go to the code window in the implementation of the Click event for the CommandButton. Enter the following code in this event:

Dim Cxn As New PISDKDlg.Connections

Dim s As PISDK.Server

On Error Resume Next

Set s = Cxn.Login(srv, , , True)

If Err.Number <> 0 Then

MsgBox Err.Description


If s.Connected Then

MsgBox "Successfully connected to " & s.Name 

End If

End If

As you saw in the Object Browser, the Login method takes four parameters, all optional. The first is a reference to a PI Server object, the second specifies the user name, the third specifies the password, and the fourth specifies how to handle an existing login that was made using different login parameters.

We set the first parameter using the name from our global server object, srv, which we set during Form_Load and updated when the combo box was used.

A common usage is to call the Login method for a particular server using the default user name and no password, and this is how we call it in this example. This means that the second and third parameters we leave blank in order to use the defaults. If the default user account is password protected, the login dialog will pop up and allow the user to enter a new user name (if needed) and a password; otherwise we will silently establish a connection.

A PI Server can only be logged in to one user account at a time. By specifying True for the fourth parameter in the Login method we are saying if a connection has already been established using different parameters, the Login method should log out and then log in using the new parameters. If we had specified False for the fourth parameter, then instead of terminating the existing connection, the Login method would have raised an error in the global Err object indicating we were trying to login to a Server we were already logged into.

Note that it is possible for the Login method to complete with no errors and still not establish a connection. This occurs when the user clicks the Cancel button on the Login dialog. If a connection is made, it returns a reference to a PI Server object for the connected server. If a connection is not made because of an error, the reference will be set to Nothing. So the best way to determine if the login was successful is to check that the returned server (s) is valid and connected (s.Connected = true).

  1. Save the project. Run the application and try the Login button. If the default user account for the selected server is not password protected, you should see the success message pop up. If it is password protected, the login dialog should pop up and allow you to login using any user name and password valid on the selected PI Server. To password protect the user account with the password "newpassword" you can insert the following line of code just prior to calling the Login method:


srv.DefaultUser.SetPassword "", "newpassword"

You should comment this line out after the first time it executes.

Step 4:

In step 4 we will add display and editing of individual point attributes.

  1. If the project from Step3 is not already open, open it now.
  2. Select the Label control from the toolbox and drag the cursor to insert a label under the separator line we added in Step 2 and to the right of the list box of attributes. Set the caption of this label to read "Attribute Name:."
  3. Insert another Label control underneath the one just inserted. Make the label about 2" (5.1 cm) wide by ½" (1.3 cm) high. Set the caption to an empty string.
  4. Insert a third Label control just underneath the previous one and set its Caption property to "Value:."
  5. Select the TextBox control from the toolbox and drag to create a text box about 2" (5 cm) wide just under the previous label - Value. Set the Text property to an empty string.
  6. Finally select the CommandButton control from the toolbox and drag the cursor to create a button in the bottom right of the form about 1-1/4" (3.2 cm) wide. Set the button's Caption property to read "Update." At this point your form should look like the picture displayed at the beginning of the tutorial.
  7. Double-click on the list box to go to the code window and begin editing the code for the List1 Click event. Enter the following code:

Label4.Caption = List1.Text

Text2.Text = CStr(pt.PointAttributes(List1.Text).Value)

Here we are setting the label control caption for the attribute name to hold the same text as the selected member of the list box. We then set our text box contents to the value of this attribute. We do this by accessing our PIPoint object stored in pt when Retrieve was click. We access the PIPoint'sPointAttributes collection calling its default property "Item" and passing it the text from the list box. This will return the PointAttribute object of that name. We pass the Value property of that PointAttribute object which is a variant to the CStr() function for turning the contents of the variant to a string for display.

  1. In the form view double-click on the button now labeled Update to go to the code window and begin editing the code for the click event of that button. Enter the following code:

Dim ptatr As PointAttribute

If pt Is Nothing Then

MsgBox "Please retrieve attributes for a tag first."

Exit Sub

End If

If Label4.Caption = "" Then

MsgBox "Please select an attribute to modify"

Exit Sub

End If

Set ptatr = pt.PointAttributes(Label4.Caption)

pt.PointAttributes.ReadOnly = False

ptatr.Value = Text2.Text

pt.PointAttributes.ReadOnly = True

MsgBox "Modification succeeded"

Exit Sub


MsgBox Err.Description

The first line above and the last 3 are part of the error trapping discussed in Step 2. We then dimension a variable to hold a reference to a PointAttribute object for use later. The first If statement checks that we have already successfully retrieved a reference to a PIPoint into our pt variable so we don't try to access it before it has been set. This variable is set when the user retrieves point attributes. If this hasn't been done yet we prompt the user and exit the routine. The second If statement checks that the user has selected some attribute to edit. Here we are checking the Caption property of the label, set when the user clicks in the list box. Again if we have no selection we warn the user and exit the routine.

We now set the PointAttribute variable, ptatr, we dimensioned earlier by accessing the PointAttributes collection of the PIPoint stored in pt. We call the default Item property for the collection passing the name of the attribute as stored in our label caption when the user clicked on the attribute.

Next we set the ReadOnly property of the PIPoint's PointAttributes collection to False. This is required to successfully change an attribute value on the server as a safety to avoid inadvertent modifications. Note two lines later we set the property back to True again, resetting our safety. In between we do the actual modification, by setting the Value property of the PointAttribute object to the new value. Here we set it to the Text property of the text box. Behind the scenes, the PI-SDK coerces the data type of the value from a String as retrieved from the text box to the type required for the PointAttribute. If the coercion fails, an error is raised.

Finally, we put up a message indicating that the value has been successfully changed. This is appropriate because any errors that might have occurred up to this point would have sent us to the handler: label, bypassing this message box.

At this point the application is complete. Save the project and test the application.

You can probably think of enhancements that could make this application more useful in different contexts, or easier to understand and use. One current problem is that if the user changes the server, the tag name and point attributes still reflect a tag on the previous server. You could blank out these entries when the server was selected or perhaps automatically look up the current tag name on the new server. As it stands, with only a few lines of code we have built a GUI point attribute editor.

Enabling Operational Intelligence