Visual Basic and the HP e3000 Examples 
COM components are an excellent method to use to interface existing applications
to new applications.  This example shows how to control an existing terminal-based
using a COM component.  The resulting application can then be easily client/server
or Web enabled. 


  Home
  New
  Site Map
  VB Examples
    Visual Basic Example Intro
  
     ODBC Program Generator
        COM Client/Server and Web
        TurboIMAGE Calls from Win32
  Guest Book
  Email

Using an ActiveX Server-Side
Component with a Host-Based Application

The goal in this example is to take an arbitrary HP terminal-based application, add a Visual Basic Graphical User Interface (GUI) to it and make it accessible through a Web browser without changing even one line of application source code.  How is this possible?  We can do it using an ActiveX dll server component that manipulates the WRQ Reflection terminal emulator.

Figure 2.1 - Network View of Result

Figure 2.1 provides a network view of the results of our objective.  When we are done, the same application that is now accessible using a terminal emulator will be accessible both through the Web or a PC using a Visual Basic GUI client.  It is important to note that we need to add a middle tier server into our network to make this solution possible.  In this case we choose to use an NT server.  However, any Windows 9X, NT or Windows 2000 platform could be used.

Figure 2.2 - Software View of Result

Figure 2.2 shows how the solution we have in mind works from a software component point of  view.  It is important to note that absolutely nothing changes on the HP e3000.  For the client/server solution, we only need to add one copy of  Reflection to the NT server.  For the Web solution we also need IIS 4.0 or higher on the NT server.  That's it!

On the PC that will serve as the GUI client, we need the free VB runtime components.  On the PC that will serve as the Web browser, we only need a Web browser.  In a real-world implementation of this solution we'd only need one copy of Reflection to implement this solution and one login connection the the HP e3000!  In fact, if we work it right, we can have as many users as we want make use of it.  (This is a simple example and it has some limitations that would have to be overcome before it became truly multi-user.)  

HP 3000 Demo Application

A small VPlus application is used to implement our sample solution.  Its one screen is show in Figure 2.3.

Figure 2.3 - Demo VPlus Application

 

Implementing The Solution

Implementing the solution we have in mind will take several steps:

  • First, we let Reflection create most of a program to run the Reflection session by capturing a Visual Basic program while running the application.

  • Next, add the generated code to a new Visual Basic program that will logon the the HP 3000 do our work and logoff.

  • We then change the Visual Basic program to an ActiveX (COM) server dll component.

  • We then create a GUI client to test the COM component.

  • We then write an Active Server Page (ASP) module in Visual Basic Script to use the or COM component on the Web.  

  • Finally, we create an HTM page to invoke the ASP module.

 

Capture a Reflection Visual Basic Module

The easiest way to integrate Reflection commands into a Visual Basic program is to first record your actions in Reflection and save the file as a Visual Basic code module. Next, add the module to your Visual Basic project and make the modifications needed to integrate the Reflection commands into your Visual Basic program. The following procedure provides a step-by-step description of the process:


Record a Script in Reflection.

  1. Start with a "fresh" copy of Reflection. Do not start with a settings file (you may choose to load a settings file after you start recording, though, as described in step 3. The recorded material will contain the OLE commands that start Reflection (and load the settings file, if needed). If Reflection is already running, you can reset to default values and start fresh by closing any open connections, then choosing the Defaults command from the Setup menu.

  2. Choose the Start Recording command from the Reflection Script menu.

  3.  Perform the actions you want to record. This can include configuring your connection or loading a settings file.

  4.  When you're done recording, choose the Stop Recording command from the Script menu.

  5. In the Stop Recording dialog box, enter a name in the File Name text box and choose Visual Basic (*.bas) from the Save As Type list box.

  6. Choose Save to save your file as a Visual Basic code module.


Add the Script to Your Visual Basic Project.

  1. Start a new Standard.exe project file. 

  2. Choose Add File from Visual Basic's File menu, select the code module you created in Reflection, and choose OK.
    This adds the Visual Basic code module you recorded in Reflection to your Visual Basic project.

  3.  Choose Add File from Visual Basic's File menu, add  RWINAPI.TXT from the Reflection directory as a module, and choose OK.
    This adds the Reflection constant definitions to your Visual Basic project. Click here for more information about this file.

  4. Select the name of your Reflection code module from the Visual Basic Project window, then choose View Code.
    This opens the Visual Basic code module you recorded in Reflection. The procedure that Reflection recorded is listed as "Main" in the Procedure (or "Proc") list box. Since Visual Basic does not require a Main procedure, you should change the name of this procedure to something more descriptive. For example, if you recorded a logon script, you might change the Main procedure to "ReflectionSession."

Figure 2.2 - Captured Reflection Visual Basic Program

' Generated by the Reflection Script Recorder on 10-04-2000 17:48:22.14.
' Generated by Reflection for HP 6.00.
Option Explicit
Sub Main()
Dim Reflection As Object
Dim password1 As String

Const DIALOG_TITLE = "timeent"
Const NEVER_TIME_OUT = 0

Dim LF As String ' Chr$(rcLF) = Chr$(10) = Control-J
Dim CR As String ' Chr$(rcCR) = Chr$(13) = Control-M
Dim ESC As String ' Chr$(rcESC) = Chr$(27) = Control-[

LF = Chr$(rcLF)
CR = Chr$(rcCR)
ESC = Chr$(rcESC)

' Create a new instance of Reflection.
Set Reflection = CreateObject("Reflection1.Application")
' Use the statement below instead to attach to an existing instance of Reflection.
' Set Reflection = GetObject(, "Reflection1.Application")

' Normally the Reflection application will be visible while this script is running,
' and will remain open when this script terminates.
' Delete the following line if you want Reflection to be invisible and automatically closed.
Reflection.Visible = True

' Password was removed from this script for security.
password1 = ""
' Prompt for (what is assumed to be) a password.
password1 = Reflection.PasswordBox("ENTER ACCOUNT (XFORMIX) PASSWORD:", DIALOG_TITLE)
If password1 = "" Then Exit Sub

' Do not let Reflection process data communications between API calls.
Reflection.ProcessDatacomm = False

If Reflection.Connected = False Then
Reflection.ConnectionType = "BEST-NETWORK"
Reflection.ConnectionSettings = "Host class"
Reflection.ConnectionSettings = "DefaultNetwork VT-MGR"
End If
If Reflection.Connected = False Then
Reflection.Connect
End If

Reflection.StatusBar = "Waiting for Prompt: MPE/iX:"
Reflection.WaitForString "MPE/iX:", NEVER_TIME_OUT, rcAllowKeystrokes
Reflection.WaitForHostTrigger
Reflection.StatusBar = ""
Reflection.Transmit "hello mgr.xformix,rctest" & CR

Reflection.StatusBar = "Waiting for Prompt: ENTER ACCOUNT (XFORMIX) PASSWORD:"
Reflection.WaitForString LF & "ENTER ACCOUNT (XFORMIX) PASSWORD:", NEVER_TIME_OUT, rcAllowKeystrokes
Reflection.WaitForHostTrigger
Reflection.StatusBar = ""
Reflection.Transmit password1, rcDecodePassword
Reflection.Transmit CR

Reflection.StatusBar = "Waiting for Prompt: RCTEST.XFORMIX:"
Reflection.WaitForString LF & "RCTEST.XFORMIX: ", NEVER_TIME_OUT, rcAllowKeystrokes
Reflection.WaitForHostTrigger
Reflection.StatusBar = ""
Reflection.Transmit "timeentp" & CR

Reflection.StatusBar = "Waiting for Prompt: Sub Code :"
Reflection.WaitForString ESC & "b", NEVER_TIME_OUT, rcAllowKeystrokes
Reflection.WaitForHostTrigger
Reflection.StatusBar = ""
Reflection.Transmit "RJC"
' Press HpEnter (Simulate pressing the Enter key).
Reflection.TransmitTerminalKey rcHpEnterKey

Reflection.StatusBar = "Waiting for Prompt: Sub Code : R"
Reflection.WaitForString ESC & "b", NEVER_TIME_OUT, rcAllowKeystrokes
Reflection.WaitForHostTrigger
Reflection.StatusBar = ""
' Press F8, labeled as EXIT
Reflection.TransmitTerminalKey rcHpF8Key

Reflection.StatusBar = "Waiting for Prompt: RCTEST.XFORMIX:"
Reflection.WaitForString LF & "RCTEST.XFORMIX: ", NEVER_TIME_OUT, rcAllowKeystrokes
Reflection.WaitForHostTrigger
Reflection.StatusBar = ""
Reflection.Transmit "EXIT" & CR

Reflection.WaitForString LF & "<Your 'VT-MGR' connection has terminated>" & CR & LF & LF, NEVER_TIME_OUT, rcAllowKeystrokes
Reflection.CapsLock = False

' Resume normal data communications processing.
Reflection.ProcessDatacomm = True
End Sub
' Recording stopped at 17:50:20.07.

Notice that two lines at the top of the procedure have been included to dimension a variable as an OLE Automation object, and then to create an instance of the object for the specific Reflection product you're using. Other lines in the procedure that call Reflection methods and properties are prefixed with the name "Reflection" so they can reference the appropriate object.

Create a Visual Basic Project 
for the Generated Code

 

 

Figure 2.4 - Create a Visual Basic Project

 

 

Figure 2.5 - Add the Reflection Created Module

 

Figure 2.6 - Add the Reflection API module

 

Figure 2.7 - Module List from New Program

 

 

 

 

Figure 2.8 - Reference the Reflection Object in the Project

 

 

 

Edit one line of code from the generated application.

'Set Reflection = GetObject(, "Reflection1.Application")
Set Reflection = CreateObject("Reflection1.Application")

 

 

Figure 2.9 - Run the Generated Application from Visual Basic

 

At this point we have a Visual Basic program that runs a Reflection session.  We could add a graphical user interface to it and make it a more attractive application.  However, by changing it to an ActiveX (COM) component we gain many more benefits.  Some of those are the ability to share an instance of Reflection between multiple users, the ability to share a logon session on the HP e3000 and the ability to access the component over the Web.

Before making our program into a COM component, we will divide it's statements  into logical groupings.  The reasons for this partitioning will become more obvious when we create our ActiveX implementation.

 

Partition the Visual Basic Program
into Logical Subroutines

The generated Visual Basic program logically  performs at least 3 different functions; Logon, ProcessTimeRequest and Logoff.  We next partition the program statements into these three logical groupings and add a startup subroutine to invoke them.

 

Figure 2.10 - Partitioned Program

' Generated by the Reflection Script Recorder on 10-04-2000 17:48:22.14.
' Generated by Reflection for HP 6.00.
Option Explicit

Dim Reflection As Object
Dim password1 As String
Dim searchAcct As String 'Text we're going to look for, find
Dim searchText As String 'Text we're going to look for, find
Const DIALOG_TITLE = "timeent"
Const NEVER_TIME_OUT = 0

Dim LF As String ' Chr$(rcLF) = Chr$(10) = Control-J
Dim CR As String ' Chr$(rcCR) = Chr$(13) = Control-M
Dim ESC As String ' Chr$(rcESC) = Chr$(27) = Control-[

 

Sub Logon()
LF = Chr$(rcLF)
CR = Chr$(rcCR)
ESC = Chr$(rcESC)

' Create a new instance of Reflection.
Set Reflection = CreateObject("Reflection1.Application")
' Use the statement below instead to attach to an existing instance of Reflection.
' Set Reflection = GetObject(, "Reflection1.Application")

' Normally the Reflection application will be visible while this script is running,
' and will remain open when this script terminates.
' Delete the following line if you want Reflection to be invisible and automatically closed.
Reflection.Visible = True

' Password was removed from this script for security.
password1 = ""
' Prompt for (what is assumed to be) a password.
password1 = Reflection.PasswordBox("ENTER ACCOUNT (XFORMIX) PASSWORD:", DIALOG_TITLE)
If password1 = "" Then Exit Sub

' Do not let Reflection process data communications between API calls.
Reflection.ProcessDatacomm = False

If Reflection.Connected = False Then
Reflection.ConnectionType = "BEST-NETWORK"
Reflection.ConnectionSettings = "Host class"
Reflection.ConnectionSettings = "DefaultNetwork VT-MGR"
End If
If Reflection.Connected = False Then
Reflection.Connect
End If

Reflection.StatusBar = "Waiting for Prompt: MPE/iX:"
Reflection.WaitForString "MPE/iX:", NEVER_TIME_OUT, rcAllowKeystrokes
Reflection.WaitForHostTrigger
Reflection.StatusBar = ""
Reflection.Transmit "hello mgr.xformix,rctest" & CR

Reflection.StatusBar = "Waiting for Prompt: ENTER ACCOUNT (XFORMIX) PASSWORD:"
Reflection.WaitForString LF & "ENTER ACCOUNT (XFORMIX) PASSWORD:", NEVER_TIME_OUT, rcAllowKeystrokes
Reflection.WaitForHostTrigger
Reflection.StatusBar = ""
Reflection.Transmit password1, rcDecodePassword
Reflection.Transmit CR

Reflection.StatusBar = "Waiting for Prompt: RCTEST.XFORMIX:"
Reflection.WaitForString LF & "RCTEST.XFORMIX: ", NEVER_TIME_OUT, rcAllowKeystrokes
Reflection.WaitForHostTrigger
Reflection.StatusBar = ""
Reflection.Transmit "timeentp" & CR

Reflection.StatusBar = "Waiting for Prompt: Sub Code :"
Reflection.WaitForString ESC & "b", NEVER_TIME_OUT, rcAllowKeystrokes
Reflection.WaitForHostTrigger
Reflection.StatusBar = ""

' Add to make into a real program
Exit Sub
ErrorHandler:

' Check for properties er ror
If Err = 10000 Then
Reflection.MsgBox "This demonstration script was unable to modify one or more Reflection Properties", 48, "Logon Demo"
Exit Sub
End If
End Sub


' Recording stopped at 17:50:20.07.
Sub ProcessTimeRequest(searchAcct As String, returnCode As Integer, Result As String)
Reflection.Transmit "RJC"
' Press HpEnter (Simulate pressing the Enter key).
Reflection.TransmitTerminalKey rcHpEnterKey

Reflection.StatusBar = "Waiting for Prompt: Sub Code : R"
Reflection.WaitForString ESC & "b", NEVER_TIME_OUT, rcAllowKeystrokes
Reflection.WaitForHostTrigger
Reflection.StatusBar = ""
' Press F8, labeled as EXIT

End Sub


Sub Logoff()
Call ProcessTimeRequest("dummy query", 0, searchText) ' Added
' Press F8, labeled as EXIT
Reflection.TransmitTerminalKey rcHpF8Key
Reflection.StatusBar = "Waiting for Prompt: RCTEST.XFORMIX:"
Reflection.WaitForString LF & "RCTEST.XFORMIX: ", NEVER_TIME_OUT, rcAllowKeystrokes
Reflection.WaitForHostTrigger
Reflection.StatusBar = ""
Reflection.Transmit "EXIT" & CR

Reflection.WaitForString LF & "<Your 'VT-MGR' connection has terminated>" & CR & LF & LF, NEVER_TIME_OUT, rcAllowKeystrokes
Reflection.CapsLock = False

' Resume normal data communications processing.
Reflection.ProcessDatacomm = True

' Add to make into a real program and to terminate Reflection properly
Reflection.Quit
Set Reflection = Nothing
Exit Sub
ErrorHandler:

' Check for properties error
If Err = 10000 Then
Reflection.MsgBox "This demonstration script was unable to modify one or more Reflection Properties", 48, "Logon Demo"
Exit Sub
End If
End Sub

 

Creating a COM implementation of the program consists mainly of adding a Class module with the right properties and methods that invokes the module we already have.  It is really this new Class that will provide the required COM interface to the outside world.

Create an ActiveX COM DLL Server

 

Figure 2.11 - Create a Class

 

Figure 2.12 - Code Generate By The Class Builder

'local variable(s) to hold property value(s)
Private mvarQueryAccount As Variant 'local copy
Private mvarQReturnCode As Variant 'local copy
Private mvarQResult As Variant 'local copy
Public Sub QueryQServer()
End Sub

Public Sub StopQServer()
End Sub

Public Sub StartQServer()
End Sub

Public Property Let QResult(ByVal vData As Variant)
'used when assigning a value to the property, on the left side of an assignment.
'Syntax: X.QResult = 5
mvarQResult = vData
End Property


Public Property Set QResult(ByVal vData As Variant)
'used when assigning an Object to the property, on the left side of a Set statement.
'Syntax: Set x.QResult = Form1
Set mvarQResult = vData
End Property


Public Property Get QResult() As Variant
'used when retrieving value of a property, on the right side of an assignment.
'Syntax: Debug.Print X.QResult
If IsObject(mvarQResult) Then
Set QResult = mvarQResult
Else
QResult = mvarQResult
End If
End Property



Public Property Let QReturnCode(ByVal vData As Variant)
'used when assigning a value to the property, on the left side of an assignment.
'Syntax: X.QReturnCode = 5
mvarQReturnCode = vData
End Property


Public Property Set QReturnCode(ByVal vData As Variant)
'used when assigning an Object to the property, on the left side of a Set statement.
'Syntax: Set x.QReturnCode = Form1
Set mvarQReturnCode = vData
End Property


Public Property Get QReturnCode() As Variant
'used when retrieving value of a property, on the right side of an assignment.
'Syntax: Debug.Print X.QReturnCode
If IsObject(mvarQReturnCode) Then
Set QReturnCode = mvarQReturnCode
Else
QReturnCode = mvarQReturnCode
End If
End Property



Public Property Let QueryAccount(ByVal vData As Variant)
'used when assigning a value to the property, on the left side of an assignment.
'Syntax: X.QueryAccount = 5
mvarQueryAccount = vData
End Property


Public Property Set QueryAccount(ByVal vData As Variant)
'used when assigning an Object to the property, on the left side of a Set statement.
'Syntax: Set x.QueryAccount = Form1
Set mvarQueryAccount = vData
End Property


Public Property Get QueryAccount() As Variant
'used when retrieving value of a property, on the right side of an assignment.
'Syntax: Debug.Print X.QueryAccount
If IsObject(mvarQueryAccount) Then
Set QueryAccount = mvarQueryAccount
Else
QueryAccount = mvarQueryAccount
End If
End Property

Create a GUI Client To Use The ActiveX Server

 

Figure 2.13 - GUI Client Screen

 

Figure 2.14 - Gui Client Code

Option Explicit
Private ResultBuffer As String
Private QueryBuffer As String
Private returnCode As Integer
Dim CR As String 'Carriage return
Dim LF As String 'Linefeed

Dim TimeServer As New TimeEntProj.TimeQuery

Private Sub cmdQuery_Click()
TimeServer.QReturnCode = 0
TimeServer.QueryAccount = UCase(txtAccount)

If TimeServer.QueryAccount <> "" Then

TimeServer.QueryQServer
txtReturnCode = TimeServer.QReturnCode
If TimeServer.QReturnCode = 2 Then
txtAccount = TimeServer.QueryAccount
txtResult = TimeServer.QResult
Else
txtMessage = "Invalid Account -- Please Renter"
End If

Else
MsgBox "Please Enter Account Number"
End If

End Sub
Private Sub Form_Load()
txtReturnCode = 0
TimeServer.StartQServer
CR = Chr$(13)
LF = Chr$(10)
End Sub

Private Sub Form_Unload(Cancel As Integer)
Set TimeServer = Nothing
TimeServer.StopQServer
End Sub

Private Sub cmdStop_Click()
Unload Me
End Sub

Create an Active Server Page (ASP) Client To Use The ActiveX Server

Figure 2.15 - Active Server Page The Uses COM Object

<%@ LANGUAGE="VBSCRIPT" %> <% Response.Buffer = true Dim bOK, strErrorDesc, strResultBuffer

Set TimeServer = Server.CreateObject("TimeEntProj.TimeQuery") TimeServer.StartQServer TimeServer.QueryAccount = Request.Form("txtAccountNum") Response.Write "Account Number Entered: " & TimeServer.QueryAccount TimeServer.QResult = " " TimeServer.QReturnCode = 0

bOk = TimeServer.QueryQServer

If bOk = 0 Then strResultBuffer = TimeServer.QResult

If bOk <> 0 Then strErrorDesc =" Error"

TimeServer.StopQServer Set TimeServer = Nothing

%>

<html>

<head> <title>Results</title> </head>

<body bgcolor="#FFFFFF">

<p>Here is the result of the Query: </p>

<p><a href="<%=Request.Form("txtResultCode")%>"><%=Request.Form("txtResultCode")%></a></p>

<% If bOk = 0 Then %> <p><textarea rows="5" name="S1" cols="51"><%=strResultBuffer%></textarea></p> <p>It worked!</p> <% Else Response.Write strErrorDesc End If%>

</body> </html>

 

 

 
Figure 2.16 - HTML Form
<html>
<head>
<title>Testing Time Entry component</title>
</head>
<body bgcolor="#ffffff">
<form target="bottom" method="post" action=".\TimeQEnt.asp" name="frmTAX">
  <p> Please Enter Your Account Number Below:</p>
  <div align="left"><table border="0" cellpadding="0" cellspacing="5">
    <tr>
      <td align="right">   Account Number</td>
      <td><input name="txtAccountNum" size="31" value="" >
     </td>
    </tr>
    <tr>
      <td align="right" colspan="2"><div align="center"><center><p><input type="submit"
      value="Submit" name="B1"></p></center></div></td>
    </tr>
  </table>
  </div>
</form>
</body>
</html>

 

 

 

Figure 2.17 - HTML Entry Screen
Uses ASP Page

Installation and Configuration

This example distribution comes in as a single zip file.  It contains installation components for both the HP e3000 and the Windows computer.   

Prerequisites

  • Both the HP e3000 and the PC must be reachable by each other across a network.

  • The HP e3000 requires MPE/iX 5.5 or newer

  • The Windows 9x or NT computer requires Visual Basic 6 sp3 or newer.  It also requires IIS 4.0 or newer.

Install Programs on HP e3000 

Install Programs on NT Server 

Run setup.exe on the Windows computer. 

Getting something to work...

Compile and Execute the VB Sample Application

Finally, compile and execute the Visual Basic sample application.

 

 

download.gif (899 bytes) Download the source


Copyright (c) 1999 - 2000 Transformix Computer Corporation
Comments and suggestions to the Webmaster.