2 votes

L'obtention d'une chaîne de caractères à partir du Personal Communications iSeries d'IBM en utilisant EHLLAPI en C# me permet d'obtenir la chaîne de caractères suivie d'un message d'erreur.

J'essaie d'automatiser un processus dans un émulateur as400 (IBM's Personal Communications iSeries) et pour ce faire, j'utilise du code (que je n'ai absolument pas volé de CodeProject ) qui utilise EHLLAPI pour se connecter à l'émulateur.

J'ai créé un Winforms pour implémenter le code avec quelques boutons et quelques zones de texte pour le tester. Voici la classe qui expose les méthodes de 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;
    }
}

Il s'agit de l'événement OnClick que j'utilise pour appeler la méthode sur mon formulaire :

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;
}

Voici un exemple de ce problème. Je devrais obtenir une chaîne de 2 caractères à partir de la position "30" du curseur :

Le message d'erreur que j'obtiens est "String Result" (résultat de la chaîne de caractères) The garbage I get on "String Result"

C'est la région de l'émulateur que j'étais censé obtenir, juste "Sy" : enter image description here

Cela fonctionne parfois, parfois non. J'ai essayé sur différentes parties de l'émulateur et le problème est le même. L'obtention de la position du curseur et l'envoi d'une chaîne de caractères fonctionnent bien, mais seulement lorsque j'essaie d'obtenir une chaîne de caractères de l'émulateur.

Je ne sais même pas où chercher des réponses, car ce code a été publié à l'origine en 2005.

2voto

ArminAH Points 89

J'ai trouvé le problème. Dans la méthode ReadScreen Je fais un StringBuilder qui attend 3000 caractères. Comme j'utilise out dans le paramètre de la méthode, j'ai affaire à une adresse mémoire au lieu de deux variables. Comme j'ai alloué de l'espace pour au moins 3000 caractères, lorsque la chaîne que je lis est petite, elle vient parfois avec des déchets de cet espace "inutilisé". Ce que j'ai fait, c'est modifier la taille attendue de la variable StringBuilder à la longueur de la chaîne que j'essaie de lire moins 1 (si c'était juste la longueur, j'obtiendrais toujours un caractère erroné). Voici le code :

public static UInt32 ReadScreen(int position, int len, out string txt)
{
    StringBuilder Data = new StringBuilder(len - 1); //This line was the problem.
    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;
}

Mon explication est peut-être erronée, car j'apprends encore le langage C# et le code date de 2005, mais cette modification a fonctionné pour moi. N'hésitez pas à me corriger si j'ai mal compris quelque chose ou si je me suis trompé.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X