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.
In the first step, the application will retrieve the list of Known Servers, fill a combo box, and the default server will be selected.
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.
Dim cur As Integer
Dim dflt As Integer
cur = 0
dflt = 0
For Each srv In Servers
If srv.Name = Servers.DefaultServer.Name Then
dflt = cur
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.
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.
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.
On Error GoTo HANDLER
If Text1.Text = "" Then
MsgBox "Please enter a tagname"
Set pt = srv.PIPoints(Text1.Text)
Dim ptatr As PointAttribute
For Each ptatr In pt.PointAttributes
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.
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.
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).
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
If s.Connected Then
MsgBox "Successfully connected to " & s.Name
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).
srv.DefaultUser.SetPassword "", "newpassword"
You should comment this line out after the first time it executes.
In step 4 we will add display and editing of individual point attributes.
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.
Dim ptatr As PointAttribute
If pt Is Nothing Then
MsgBox "Please retrieve attributes for a tag first."
If Label4.Caption = "" Then
MsgBox "Please select an attribute to modify"
Set ptatr = pt.PointAttributes(Label4.Caption)
pt.PointAttributes.ReadOnly = False
ptatr.Value = Text2.Text
pt.PointAttributes.ReadOnly = True
MsgBox "Modification succeeded"
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.