I'm trying to automate a process in an as400 emulator (IBM's Personal Communications iSeries) and in order to do so, I'm using some code (that I totally did not steal from CodeProject) which uses EHLLAPI to connect to the emulator.
I created a Winforms to implement the code with some buttons and some textboxes to test it. Here's the class to expose the methods from EHLLAPI:
public class EhllapiFunc //Class used to import the DLL.
{
[DllImport("PCSHLL32.dll")]
public static extern UInt32 hllapi(out UInt32 Func, StringBuilder Data, out UInt32 Length, out UInt32 RetC);
}
class EhllapiWrapper
{
/*These are the constants used to as function codes that are sent as parameters to the function in the DLL.
There are a lot more constants but these are the only ones used for the moment*/
const UInt32 HA_CONNECT_PS = 1; /* 000 Connect PS*/
const UInt32 HA_DISCONNECT_PS = 2; /* 000 Disconnect PS*/
const UInt32 HA_COPY_PS_TO_STR = 8; /* 000 Copy PS to String*/
/*EHLLAPI return codes. There are a lot more. I'll leave just some of them as I'm not getting any return codes in my issue*/
const UInt32
HARC_SUCCESS = 0; /* 000 Good return code.*/
const UInt32
HARC99_INVALID_INP = 0; /* 000 Incorrect input*/
const UInt32
HARC_INVALID_PS = 1; /* 000 Invalid PS, Not*/
const UInt32
HARC_BAD_PARM = 2; /* 000 Bad parameter, or*/
//Method to connect to the emulator.
public static UInt32 Connect(string sessionID)
{
StringBuilder Data = new StringBuilder(4);
Data.Append(sessionID);
UInt32 rc = 0;
UInt32 f = HA_CONNECT_PS;
UInt32 l = 4;
return EhllapiFunc.hllapi(out f, Data, out l, out rc);
}
//Method to disconnect.
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);
}
/*This is the method where I'm having the problem.*/
public static UInt32 ReadScreen(int position, int len, out string txt)
{
StringBuilder Data = new StringBuilder(3000);
UInt32 rc = (UInt32)position;
UInt32 f = HA_COPY_PS_TO_STR;
UInt32 l = (UInt32)len;
UInt32 r = EhllapiFunc.hllapi(out f, Data, out l, out rc);
txt = Data.ToString();
return r;
}
}
This is the OnClick event I use to call the method on my form:
private void bReadString_Click(object sender, EventArgs e)
{
//I tried cleaning the TextBox where the outputed string is sent before calling the method.
tbReadOut.Text = "";
string s;
//I send the position and string length entered on the form to the method and then "s" is modified inside the method "ReadScreen".
EhllapiWrapper.ReadScreen(Convert.ToInt32(tbReadPos.Text), Convert.ToInt32(tbReadLen.Text), out s);
tbReadOut.Text = s;
}
Here's an example of the issue. I should be getting a string of the size of 2 characters from the cursor position "30":
The garbage I get is on "String Result"

This is the region from the emulator I was supposed to get, just "Sy":

This sometimes works and sometimes it doesn't. I tried on different parts of the emulator and the issue is the same. Getting the cursor position and sending a string work fine, it is just when I'm trying to get a string from the emulator.
I don't even know where to look for answers as this code was originally posted in 2005.
I found the problem. Inside the method
ReadScreenI make aStringBuilderthat expects 3000 characters. As I'm usingoutin the parameter of the method, I'm dealing with one memory address instead of just two variables. As I allocated space for at least 3000 characters, when the string I read is small, sometimes it comes with garbage from that "unused" space. What I did was change the expected size of theStringBuilderto the length of the string I'm trying to read minus 1 (if it was just the length I will still get one garbage character). Here's the code:My explanation might be wrong, as I'm still learning C# and the code was originally from 2005, but this modification worked for me. Feel free to correct me if I misunderstood something or if I got something wrong.