Click here to Skip to main content
Click here to Skip to main content

Using EHLLAPI in C#

By , 17 Feb 2005
 

Using EHLLAPI from C#

EHLLAPI (Extended High Level Language Application Programming Interface) is a standard library to build interfaces to AS400 applications. It's distributed with all major emulation vendors (RUMBA, IBM Client Access, ...), and it's installed automatically as DLL.

This article will explain how to interact with AS/400 applications using the library distributed with IBM Client Access emulator: PCSHLL32.DLL. If you use a different emulation software, you can apply the concepts exposed in this article with some minor modifications.

EHLLAPI Concept

In a lot of companies, data integration is not so simple because a lot of programs are very old and databases are not well structured. Even if data can be accessed using ODBC drivers, the real problem is the knowledge of data structures and integration: which tables I must change to insert a new product code? Where are all the data of a customer (in which tables)? These and a lot of other questions have a simple answer: ask to users and learn the commands they type on the screen to insert or read information. You translate the problem: it's not important to know the logic to manipulate data, what's important is to know the "video" command the users type.

The interface used to interact with AS/400 is called "screen scraping": it's based on the fact that emulator software use a char interface to interact with AS/400 programs. Using this interface, you can read from and write to emulation screens. This really simple mechanism reveals all its power if inserted in a high level window program.

DLL Exported Function

PCSHLL32.DLL includes just a function named HLLAPI that receives a parameter (function code): by changing the value of this parameter, we can perform all the operations. There are almost one hundred functions available in the DLL and declared as const inside code. In my experience, I used just five of these functions:

  • HA_CONNECT_PS: connect to a client session (every session is identified by an ID: "A", "B", and so on).
  • HA_DISCONNECT_PS: disconnect from a client session.
  • HA_SET_CURSOR: set the cursor in the absolute position (rows * 80 (or 132) + cols).
  • HA_SENDKEY: send a string to a client session.
  • HA_COPY_PS_TO_STR: read from video.
  • HA_WAIT: wait for session deblocking.

To import the DLL function, I used this code:

public class EhllapiFunc
{
    [DllImport("PCSHLL32.dll")]
    public static extern UInt32 hllapi(out UInt32 Func, 
      StringBuilder Data, out UInt32 Length, out UInt32 RetC);
}

This class contains just a static function referrer to the PCSHLL32 function. This function return 0 if all is OK, otherwise it returns an error code (see inside the code). Parameters are declared without statement because they are used in two directions (to send and receive value). Depending on the Func parameter, Data, Length and RetC parameters have different meanings.

Inside Class Code

I created a class named EhllapiWrapper. This class exposes five static methods. The structure of these methods is very simple: initialize parameter, call HLLAPI function exposed by the EhllapiFunc class, and return value:

public static UInt32 Connect(string sessionID) 
{ 
 StringBuilder Data = new StringBuilder(4);
 //Data will contain the ID code of Session

 Data.Append(sessionID);
 UInt32 rc=0;
 UInt32 f=HA_CONNECT_PS; //function code
 UInt32 l=4; //lenght of data parameter
 return  EhllapiFunc.hllapi(out f, Data, out l, out rc);
 //return error code
}
public static UInt32 Disconnect(string sessionID) 
{
 StringBuilder Data = new StringBuilder(4); 
 Data.Append(sessionID);
 UInt32 rc=0;
 UInt32 f=HA_DISCONNECT_PS;
 UInt32 l=4;
return  EhllapiFunc.hllapi(out f, Data, out l, out rc);
}
public static UInt32 SetCursorPos(int p)
{
 StringBuilder Data = new StringBuilder(0);
 //no Data parameter is required

 UInt32 rc=(UInt32) p;
 //rc parameter contains the curson position

 UInt32 f=HA_SET_CURSOR;
 UInt32 l=0;
 return EhllapiFunc.hllapi(out f, Data, out l, out rc);
}
public static UInt32 GetCursorPos(out int p)
{
 StringBuilder Data = new StringBuilder(0);
 UInt32 rc=0;
 UInt32 f=HA_QUERY_CURSOR_LOC;
 UInt32 l=0; //return position
 UInt32 r = EhllapiFunc.hllapi(out f, Data, out l, out rc);
 p = (int)l;
 return r;
}
public static UInt32 SendStr(string cmd)
{
 StringBuilder Data = new StringBuilder(cmd.Length);
 //Data has the length of cmd string

 Data.Append(cmd);
 UInt32 rc=0;
 UInt32 f=HA_SENDKEY;
 UInt32 l=(UInt32)cmd.Length;
 //l parameter contain the length of cmd string

 return  EhllapiFunc.hllapi(out f, Data, out l, out rc);
}

public static UInt32 ReadScreen(int position, int len, out string txt)
{
 StringBuilder Data = new StringBuilder(3000);
 //Initialization to a MAX char 
 //(> maximum number of char in a screen session)

 UInt32 rc=(UInt32)position;
 //set initial position to start reading from

 UInt32 f=HA_COPY_PS_TO_STR;
 UInt32 l=(UInt32)len;
 //set the number of chars that 
 //function will read from position

 UInt32 r = EhllapiFunc.hllapi(out f, Data, out l, out rc);
 txt=Data.ToString(); //result
 return r;
}
public static UInt32 Wait()
//just wait for execution of a command on session
{
 StringBuilder Data = new StringBuilder(0);
 UInt32 rc=0;
 UInt32 f=HA_WAIT ;
 UInt32 l=0;
 UInt32 r = EhllapiFunc.hllapi(out f, Data, out l, out rc);
 return r;
}

Using EhllapiWrapper Class

A typical use of the wrapper class is this one:

  1. Connect to session.
  2. Set cursor position.
  3. Send string.
  4. Read screen.
  5. Disconnect.

Some Notes

Session ID for Client Access emulator is a char where "A" identifies the first session opened, "B" the second one, and so on. You can send a special key to the session using a particular syntax (see the comment section inside Wrapper class code). For example, ENTER corresponds to @E, F1 key to @1, and so on.

Demo Code

Demo code includes a simple form containing five buttons (one for every method). I used a different color to identify functions and parameters. Form has TopMost = true, so it remains visible when you interact with session. So start a Client Access session, specify ID (typically "A" if it's the first session started), and push Connect. A message box is displayed with return code.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Luca Bertoncini
Web Developer
Italy Italy
Member
I'm a Delphi programmer since the 1.0 version.
My acual interest concern all modern language and development tools.
I'm a runner (3H:12M) to Pisa Marathon in 2002.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionDebug v Release IssuememberGrandizer Coen22 Mar '07 - 13:04 
Hello,
 
This article was a savior for me, Thank you! Without it I would have to assume the end-user would be on a certain screen to sendkeys to it. With this, I can determine if they are on the appropriate screen and warn them at least if they are not.
 
My problem is that it works 100% great in Debug mode. I get back the screen scraped value. When in Release mode, I get error code 10 (unavailable or similar, don't have the file in front of me, but the number is correct) every time I try to do a Connect.
 
Do you have Any suggestions on why it would work in Debug but give me a connection error in Release? Confused | :confused:
 
Would using the Wait method inside the Connect method right after the sending of the HA_CONNECT_PS function do anything?

 
TIA,
Kevin
AnswerRe: Debug v Release Issuememberbertonciniluca22 Mar '07 - 21:45 
- Check if session ID is rigth
- You cannot connect two times to the same session without Disconnect first.
- The correct sequence is:
1. Connect
2..... Commands to the session
3. Disconnect
 
Let me know.
ciao
QuestionRe: Debug v Release IssuememberGrandizer Coen23 Mar '07 - 2:29 
I adjusted my code a bit so no matter what the result of the connection, it will always disconnect. Below is the method that I put within the main class as in your article. I have tried it encapsulated this this as well as above and both work 100% of the time in Debug but never (always getting error code 10 = HARC_UNSUPPORTED) when in Release mode. I have verified the Session ID and is a single "A" in my testing.
 
Ugh, this is part of programming that I hate. When things should work but are not.
 
Here is my method - I put Message boxes for now to see what is being returned.
 
public static string ScrapeScreen(string sSessionID, int iPosition, int iLength, out UInt32 iReturnCode) {
string sScreenText = "";
 
try {
iReturnCode = Connect(sSessionID);
MessageBox.Show("Connection: " + iReturnCode.ToString());
if(iReturnCode == HARC_SUCCESS) {
iReturnCode = ReadScreen(iPosition, iLength, out sScreenText);
MessageBox.Show("ReadScreen: " + iReturnCode.ToString());
} // if we successfully connected to the session
} catch(Exception e) {
// Some error occurred - check the iReturnCode
} finally {
// Need to do this no matter what
iReturnCode = Disconnect(sSessionID);
MessageBox.Show("Disconnect: " + iReturnCode.ToString());
} // try-catch-finally
 
return sScreenText;
}
 
Any thoughts?
QuestionIs there new way to handle mainframe in C#?memberli_robert15 Mar '07 - 8:40 
We are using EHLLAPI in VB6 to do two-way communications.
 
Do you know if there's some new ways to handle mainframe in .NET, such as through Web Services, Message Queue, or integration through BizTalk server?
 
Thanks

AnswerRe: Is there new way to handle mainframe in C#?memberLuca Bertoncini15 Mar '07 - 9:07 
The role of EHLLAPI is to "bypass" the application logic knowledge by using screen transactions.
I think you can encapsulate EHLLAPI code in a Web Service just to call function via this technology. The problem concerns the control over transaction.
ciao
GeneralRemote controlmemberRogerFoxDogs26 Jan '07 - 13:45 
I am developing a distributed automation application, part of which includes controlling the AS/400 iSeries for Windows emulator with code that uses the EHLLAPI libs. I have written the code to write to and read from the emulator running on the same PC. Now I need to separate them onto different boxes. Is there a way that I can communicate with the emulator over the network? The only place that makes sense is in the HLDConnectPS structure but that doesn't look like it will do the trick.
 
Is EHLLAPI up to the task? If not, is there an alternative?
 
Thanks,
John
AnswerRe: Remote controlmemberLuca Bertoncini26 Jan '07 - 20:43 
Best way to solve you problem is to create a centralized FIFO. Every time a users must write on as/400 screen a new record (with all important data) is inserted in FIFO. Central PC read from FIFO and produce the output to AS/400.
It's an asynchronous way to solve the problem. I don't know if this is your case.
Let me know.
 
ciao
Luca
GeneralDllNotFoundExceptionmemberSwenni19 Jun '06 - 6:06 
Luca,
I also like that code. It compiles without any mistakes. But as soon as I push a button I get this error:
 
An unhandled exception of type 'System.DllNotFoundException' occurred in clsEHLLAPI.dll
 
Additional information: Unable to load DLL 'PCSHLL32.dll': The specified module could not be found. (Exception from HRESULT: 0x8007007E)
 
I tryed everything to tell the system where to find this dll,- nothing worked. Did you not telling something?
 
Thank you
 
Swen
GeneralRe: DllNotFoundExceptionmemberLuca Bertoncini29 Jul '06 - 7:33 
Have you installed client Access on your PC?
Try to copy the dll in the program's directory.
 
ciao
GeneralRe: DllNotFoundExceptionmembergavin.morris16 Mar '07 - 0:46 
I got the same error, Did this work as a fix??? I have copied the dll to many dirs to get this to work including system32, still no joy Frown | :-(
 
All help gratefully received

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web02 | 2.6.130523.1 | Last Updated 17 Feb 2005
Article Copyright 2005 by Luca Bertoncini
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid