Session Integrator is Microsoft's offering for screen
scraping. Among the many benefits provided by it, we can say that
simplicity is where its more powerful capability resides. With a few API
objects, you can achieve complex screen scraping scenarios by using SNA
or the TN3270 transport. To set it up, you should select the Session
Integrator option during the product install process. Then you configure
it by selecting the Enable the Session Integrator Feature option in the
configuration panel and adding a Windows service account.
The Session Integrator
feature targets LU0 and LU2 (3270) applications. The LU0 capabilities of
Session Integrator are richer than the LU2-provided ones since the
interface of the first makes available low-level access to the session
data stream. In the case of LU2, the Host Integration Server product
group has taken care of the complexities around the data stream
manipulation, allowing developers to build applications that interface
directly with the 3270 data stream. Table 1 shows the interfaces available for the developers to program with Session Integrator using LU2.
Table 1. Interfaces Available for the Developers to Program with Session Integrator Using LU2
.NET Interface | Remarks |
---|
SessionDisplay | Provides the connection interface for the SessionDisplay class |
ScreenPosition | Provides access to a position on the LU2 screen |
ScreenCursor | Provides access to the cursor on the screen |
ScreenPartialField | Provides access to a part of a screen field |
ScreenField | Provides access to a particular area of the LU2 screen including the data and attributes |
ScreenFieldCollection | Contains a collection of ScreenField classes |
ScreenPartialFieldCollection | Contains a collection of ScreenPartialField classes |
ScreenFieldAttributeData | Provides all of the attributes about the ScreenField data |
Here we will give a sample of
how to use Session Integrator with a Display LU (LU2). Because we
already have an IP-DLC Link Service configured for the example in this article , we will just need to add a new connection that will point to
the mainframe environment we need to access, which is under the control
of the SSCP (VTAM). The sessions used in these types of connections are
known as dependent sessions,
because they need the VTAM to arbitrate the LU-LU session startup. Once
you have the information available, then you will need to create the
objects in the SNA Manager. HIS 2009 Session Integrator does not support
5250/TN5250 screen scraping on IBM AS/400 systems.
From a development
perspective, you should add a reference to the microsoft.
hostintegration.sna.session.dll library available in the %snaroot%
directory from your .NET code to be able to use Session Integrator. From
a coding perspective, to create either an SNA session or a TN3270
session, you should use the SessionDisplay class. Once your application has opened a session, you can use the WaitForContent
method to wait for any string you need to read or capture to appear on
the screen. Remember to call your method to render the screen as many
times as you need to reflect your latest 3270 session data. As the
session data arrives to the terminal in the EBCDIC format, you should
use the ConvertEbcdicToUnicode method
to convert the EBCDIC strings to the Unicode format. In the Host
Integration Server SDK, you will find examples for LU0 and LU2.
For instance, in our
configuration, we have a connection called SYS13270, with a few display
LUs. All of our LUs are grouped in the LU pool called SYS1LU. The
following code example belongs to our Session Integrator application and
is used to create a 3270 session using the SNA and TN3270 transports.
In this case, we will use the SNA transport with a local LOGICALUNITNAME set to SYS1LU, and for the TN3270 transport we will use the name of the TN3270 server.
try
{
m_Handler = new SessionDisplay();
if (strTransport=="SNA")
{
m_Handler.Connect("TRANSPORT=SNA;LOGICALUNITNAME=" + LUSession);
}
else
{
SessionConnectionDisplay TNDisplay = new SessionConnectionDisplay();
TNDisplay.DeviceType = SDeviceType;
TNDisplay.Transport = SessionDisplayTransport.TN3270;
TNDisplay.TN3270Port = Convert.ToInt32(TN3270Port);
TNDisplay.TN3270Server = TN3270Server;
m_Handler.Connect(TNDisplay);
}
m_Handler.Connection.HostCodePage = 37;
FontFamily fontFamily = new FontFamily("Courier New");
m_FixedFont = new Font(fontFamily, 18, FontStyle.Regular, GraphicsUnit.Pixel);
ScreenText.Font = m_FixedFont;
DrawScreen();
m_Handler.WaitForContent("TERM NAME", 20000);
DrawScreen();
SessionStatusLabel.Text = "Currently in Session";
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
The following code example uses ConvertEbcdicToUnicode to convert the EBCDIC session data to the Unicode format recognized by Windows:
public String CurrentScreen()
{
...
ScreenData screenData = m_Handler.GetScreenData(1, 1, −1);
screen = HostStringConverter.ConvertEbcdicToUnicode(screenData.Data);
return screen;
}
The following code applies when
using the TN3270 transport and is used to present all the TN3270 devices
supported by Host Integration Server:
foreach(string item in Enum.GetNames(typeof(TNDeviceType)) )
{
cboDeviceTypes.DropDownStyle = ComboBoxStyle.DropDownList;
cboDeviceTypes.Items.Add(item);
cboDeviceTypes.SelectedItem = "IBM3278Model2E";
}}
The following code applies
when using the TN3270 transport and is used to capture the TN3270
device that the Session Integrator application will represent:
SIDemo.SDeviceType = (TNDeviceType)Enum.Parse(typeof(TNDeviceType),
cboDeviceTypes.SelectedItem.ToString(), true);
Figure 2 shows the list of TN3270 devices available for a TN3270 session.
Once the 3270 session is established (SNA or TN3270), to start working with the session stream, you have to use the SendKey
method to send commands to the 3270 stream. It is like working with a
3270 emulator. The only difference is that the keyboard commands are
performed by the Session Integrator application and not by the end user.
Figure 3 shows the main screen of the Session Integrator Demo application.
The following code example shows how to call a CICS region (CICSDEMO) from the current screen. The example also shows how to execute a CICS transaction (WBGB-GetBalance):
private void getBalanceToolStripMenuItem1_Click(object sender, EventArgs e)
{
createSessionToolStripMenuItem.Enabled = false;
m_Handler.SendKey("CICSDEMO@E");
DrawScreen();
m_Handler.WaitForSession(SessionDisplayWaitType.PLUSLU, 5000);
DrawScreen();
m_Handler.WaitForContent(@"CICS", 5000);
DrawScreen();
try
{
ClearScreenAndWait();
m_Handler.SendKey("WBGB@E");
DrawScreen();
m_Handler.WaitForContent("F6=Get Cust", 5000);
DrawScreen();
GetBalance GBAL = new GetBalance();
GBAL.ShowDialog();
Figure 4 shows how the screen for the transaction WBGB-GetBalance
looks. It also shows the Windows form that is displayed to capture the
name and account number required for the application session to return
the actual balance.
Right after the capture takes
place, an Enter is issued by the application to capture the response, as
shown in the following example:
m_Handler.CurrentField.Data = GBAL.txtName.Text;
m_Handler.MoveNextField(new
ScreenFieldAttributeData(ScreenFieldAttribute.Normal)).Data =
GBAL.txtAccountNumber.Text;
m_Handler.SendKey("@E");
DrawScreen();
The following code example shows how to capture the response from the 3270 stream. The example uses the ScreenPartialField method to access parts of the screen fields:
ScreenPartialFieldCollection fields = new ScreenPartialFieldCollection(3);
fields.Add(new ScreenPartialField("Customer name not found", 21, 2));
fields.Add(new ScreenPartialField("Name / account could not be found", 21, 2));
fields.Add(new ScreenPartialField(".", 5, 31));
int indexOfField = m_Handler.WaitForContent(fields, 5000); DrawScreen();
if (indexOfField == 0)
throw new ArgumentException("Customer Name incorrect", GBAL.txtName.Text);
if (indexOfField == 1)
throw new ArgumentException("Account Name incorrect", GBAL.txtAccountNumber.Text);
string amountString = m_Handler.GetField(5, 20)[2].Data;
MessageBox.Show("Account Balance: " + amountString.ToString(), "Balance");
DrawScreen();
}catch (Exception ex)
{
MessageBox.Show(ex.Message);
}}
Figure 5 shows that the response for the GetBalance transaction is presented in the screen and through the message box window.