IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage Delphi Discussion :

Utilisation fonction dll et violation d'accès. Conflit d'intérêt et besoin Synchronize ?


Sujet :

Langage Delphi

  1. #1
    Nouveau membre du Club
    Inscrit en
    Mars 2010
    Messages
    35
    Détails du profil
    Informations forums :
    Inscription : Mars 2010
    Messages : 35
    Points : 32
    Points
    32
    Par défaut Utilisation fonction dll et violation d'accès. Conflit d'intérêt et besoin Synchronize ?
    Bonjour,

    J'ai un projet Delphi qui permet de faire fonctionner une application web dans IIS avec Isapi et je rencontre le fameux "Violation d'accès..." à certains moments que je n'arrive pas à expliquer et qui fait tomber toute l'application et qui nécessite un redémarrage du service IIS. C'est plutot ennuyeux... Une aide serait la bienvenue. Je vous explique dans les grandes lignes et s'il manque des informations, n'hésitez pas...

    J'ai une fiche TWebModulePrincipal qui possède des procédures qui se déclenche à l'exécution d'une url du navigateur, en l'occurrence ici la procédure WebModulePrincipalWebActionPortailAction qui se déclenche à l'appel de "http://...../portail/..." et dont voici le code

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    procedure TWebModulePrincipal.WebModulePrincipalWebActionPortailAction(
      Sender: TObject; Request: TWebRequest; Response: TWebResponse;
      var Handled: Boolean);
    var
      CurrentSession: TIsapiSession;
      ParamServeur, ParamPort, ParamFileJMS, MessageJMS, aHTML, Erreur: String;
      Params: TObRunParams;
      aConnexionAS400: TConnexionAS400;
      PServeurJMS, PPort, PFileJMS, PFonctionAppelee,
      PModeCommunication, PSociete, PLibelleSociete, PPersonne, PLogin, PNom, PPrenom, PProfilWindows, PPoste, PLibellePoste, PGestionHabilitations,
      PFicheGRC, PIdentifiantFicheGRC,
      PParametre13, PParametre14, PParametre15, PParametre16, PParametre17, PParametre18, PParametre19, PParametre20,
      PErreur: PChar;
    begin
      Erreur := '';
      ParamServeur := Request.QueryFields.Values['serveur'];
      ParamPort := Request.QueryFields.Values['port'];
      ParamFileJMS := Request.QueryFields.Values['filejms'];
      WriteMsgLog(g_LogFile, 'Communication ' +ParamFileJMS+ ' : GRC appelée depuis portail sur serveur ' +ParamServeur+ ':' +ParamPort);
      if ((ParamServeur <> '') and (ParamPort <> '') and (ParamFileJMS <> '')) then begin
        try
          try
            // Récupération des informations de connexion dans un message crée par le portail de la file JMS
            PModeCommunication := PChar('FileJMS');
            PServeurJMS := PChar(ParamServeur);
            PPort := PChar(ParamPort);
            PFileJMS := PChar(ParamFileJMS);
            PFonctionAppelee := StrAlloc(10);
            PSociete  := StrAlloc(60);
            PLibelleSociete  := StrAlloc(60);
            PPersonne  := StrAlloc(60);
            PLogin  := StrAlloc(60);
            PNom  := StrAlloc(60);
            PPrenom  := StrAlloc(60);
            PProfilWindows  := StrAlloc(60);
            PPoste  := StrAlloc(60);
            PLibellePoste  := StrAlloc(60);
            PGestionHabilitations  := StrAlloc(5);
            PFicheGRC  := StrAlloc(60);
            PIdentifiantFicheGRC  := StrAlloc(60);
            PParametre13  := StrAlloc(60);
            PParametre14  := StrAlloc(60);
            PParametre15  := StrAlloc(60);
            PParametre16  := StrAlloc(60);
            PParametre17  := StrAlloc(60);
            PParametre18  := StrAlloc(60);
            PParametre19  := StrAlloc(60);
            PParametre20  := StrAlloc(60);
            PErreur := StrAlloc(256);
            ReceptionMsg(PModeCommunication, PFileJMS, PServeurJMS, PPort, PFonctionAppelee,
                            PSociete, PLibelleSociete, PPersonne, PLogin, PNom, PPrenom, PProfilWindows, PPoste, PLibellePoste, PGestionHabilitations,
                            PFicheGRC, PIdentifiantFicheGRC,
                            PParametre13, PParametre14, PParametre15, PParametre16, PParametre17, PParametre18, PParametre19, PParametre20,
                            PErreur);
            Erreur := PErreur;
            WriteMsgLog(g_LogFile, 'Communication ' +ParamFileJMS+ ' : ReceptionMsg ' +PLogin+ ';' +PPersonne+ ';' +PNom+ ';' +PPrenom+ ';' +PProfilWindows+ ';' +PSociete+ ';' +PLibelleSociete+ ';' +PPoste+ ';' +PLibellePoste);
            if Erreur = '' then begin
              if string(PPersonne) <> '' then begin
                // On teste que le retour renvoi bien un message,
                try
                  CurrentSession := GetSession(Request);
                except
                  on e: ESessionNotFound do begin
                    WriteMsgLog(g_LogFile, 'Communication ' +ParamFileJMS+ ' : Session non trouvée');
                    // S'il l'utilsateur n'a pas encore de session d'ouverte dans la GRC, on la crée avec les informations reçues du portail
                    CurrentSession := CreateWebSession;
                    WriteMsgLog(g_LogFile, 'Communication ' +ParamFileJMS+ ' : Création session ' +IntToStr(CurrentSession.IdSession)+ ' pour ' +PLogin);
                  end;
                end;
                CurrentSession.UserAutorise := True;
                CurrentSession.Gvperg := StrToInt(PPersonne);
                CurrentSession.Login := PLogin;
                CurrentSession.GvpergNom := PNom;
                CurrentSession.GvpergPrenom := PPrenom;
                CurrentSession.GvpeProfilWindows := PProfilWindows;
                CurrentSession.GVSTRG := StrToInt(PSociete);
                CurrentSession.GVSTRGLibelle := PLibelleSociete;
                CurrentSession.GVHORG := StrToInt(PPoste);
                CurrentSession.GVHORGLibelle := PLibellePoste;
                CurrentSession.RemoteAddr := Request.RemoteAddr;
                CurrentSession.ServeurJMS := ParamServeur;
                CurrentSession.PortJMS := ParamPort;
                CurrentSession.NomFileJMS := ParamFileJMS;
                CurrentSession.GestionHabilitations := PGestionHabilitations;
                WriteMsgLog(g_LogFile, 'Communication ' +ParamFileJMS+ ' : Maj infos session ' +IntToStr(CurrentSession.IdSession)+ ' pour ' +PLogin+ ';' +PPersonne+ ';' +PNom+ ';' +PPrenom+ ';' +PProfilWindows+ ';' +PSociete+ ';' +PLibelleSociete+ ';' +PPoste+ ';' +PLibellePoste);
                if PFicheGRC <> '' then begin
                  if PFicheGRC = 'client' then begin
                    WriteMsgLog(g_LogFile, 'Communication ' +ParamFileJMS+ ' : Appel fiche client pour session ' +IntToStr(CurrentSession.IdSession)+ ' et id ' +PIdentifiantFicheGRC);
                    Response.SendRedirect('accesdirect?action=clientgeneral&lvmerg=' +PIdentifiantFicheGRC+ '&IdSession=' + IntToStr(CurrentSession.IdSession));
                    Exit;
                  end else begin
                    if PFicheGRC = 'patrimoine' then begin
                      WriteMsgLog(g_LogFile, 'Communication ' +ParamFileJMS+ ' : Appel fiche patrimoine pour session ' +IntToStr(CurrentSession.IdSession)+ ' et id ' +PIdentifiantFicheGRC);
                      Response.SendRedirect('accesdirect?action=patrimoinegeneral&evnprg=' +PIdentifiantFicheGRC+ '&IdSession=' + IntToStr(CurrentSession.IdSession));
                      Exit;
                    end else begin
                      WriteMsgLog(g_LogFile, 'Communication ' +ParamFileJMS+ ' : Appel fiche ' +PFicheGRC+ ' pour session ' +IntToStr(CurrentSession.IdSession)+ ' incorrecte');
                      aHTML := 'La fiche GRC [' +PFicheGRC+ '] n est pas prise en charge depuis le portail Aravis<br>';
                    end;
                  end;
                end else begin
                  WriteMsgLog(g_LogFile, 'Communication ' +ParamFileJMS+ ' : Redirection identification terminée pour session ' +IntToStr(CurrentSession.IdSession)+ ' et profil ' +PNom);
                  Response.SendRedirect('accesdirect?action=identificationterminee&gvho=' +IntToStr(CurrentSession.GVHORG)+ '&IdSession=' + IntToStr(CurrentSession.IdSession));
                  Exit;
                  end;
              end else begin
                WriteMsgLog(g_LogFile, 'Communication ' +ParamFileJMS+ ' : Le message lu est probablement vide (voir pour puger activemq)');
                aHTML := 'Erreur lors de la recherche des informations de connexion dans la file JMS [' +ParamFileJMS+ '] sur le serveur ActiveMQ [' +ParamServeur+ ':' +ParamPort+ ']<br>';
                aHTML := aHTML + 'Veuillez fermer toutes vos fenetres GRC puis relancer la GRC depuis le portail<br>';
                aHTML := aHTML + '<br>' + Erreur + '<br>';
              end;
            end else begin
              WriteMsgLog(g_LogFile, 'Communication ' +ParamFileJMS+ ' : Erreur lecture message JMS ' +Erreur);
              aHTML := 'Erreur lors de la recherche des informations de connexion dans la file JMS [' +ParamFileJMS+ '] sur le serveur ActiveMQ [' +ParamServeur+ ':' +ParamPort+ ']<br>';
              aHTML := aHTML + 'Veuillez fermer toutes vos fenetres GRC puis relancer la GRC depuis le portail<br>';
              aHTML := aHTML + '<br>' + Erreur + '<br>';
            end;
          except
            on e: Exception do begin
              WriteMsgLog(g_LogFile, 'Communication ' +ParamFileJMS+ ' : Exception ' +e.Message);
              TraiteException(e, aHTML);
            end;
          end;
        finally
          StrDispose(PFonctionAppelee);
          StrDispose(PSociete);
          StrDispose(PLibelleSociete);
          StrDispose(PPersonne);
          StrDispose(PLogin);
          StrDispose(PNom);
          StrDispose(PPrenom);
          StrDispose(PProfilWindows);
          StrDispose(PPoste);
          StrDispose(PLibellePoste);
          StrDispose(PGestionHabilitations);
          StrDispose(PFicheGRC);
          StrDispose(PIdentifiantFicheGRC);
          StrDispose(PParametre13);
          StrDispose(PParametre14);
          StrDispose(PParametre15);
          StrDispose(PParametre16);
          StrDispose(PParametre17);
          StrDispose(PParametre18);
          StrDispose(PParametre19);
          StrDispose(PParametre20);
          StrDispose(PErreur);
          //WriteMsgLog(g_LogFile, 'Communication liberation memoire');
          SendHTMLResponse(Response, aHTML);
        end;
      end else begin
        aHTML := 'Erreur dans l url transmise du portail<br>';
        SendHTMLResponse(Response, aHTML);
      end;
    end;
    D'après mes logs, le problème de violation d'accès semble se lever lorsque ce code est appelé vraiment simultanément (deux onglets du navigateur avec l'url ".../portail" qui se rafraichissent symultanément visiblement), je présume "vraiment simultanément" car toujours d'après les logs la plupart du temps ça passe... D'où ma question : Y a t il besoin d'un synchronize ou autre chose du genre et pourquoi ?

    Petite précision la procédure ReceptionMsg est une procédure développée par mes soins dans un autre projet et exécutée dans une dll et déclarée comme suit dans le projet :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    procedure ReceptionMsg(PModeCommunication, PNomFileJms, PServeur, PPort, PFonctionAppelee,
      PParametre1, PParametre2, PParametre3, PParametre4, PParametre5, PParametre6, PParametre7, PParametre8, PParametre9, PParametre10,
      PParametre11, PParametre12, PParametre13, PParametre14, PParametre15, PParametre16, PParametre17, PParametre18, PParametre19, PParametre20,
      PErreur: PAnsiChar); stdcall; external 'Acgwebutils_d.dll';
    Y aurait il un lien car je me demande si la violation d'accès ne se lèvent pas au moment de cet appel ?


    D'avance merci pour votre aide.

  2. #2
    Expert éminent sénior
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    Novembre 2002
    Messages
    8 964
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Freelance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Points : 28 430
    Points
    28 430
    Par défaut
    je ne sais pas, mais je trouve horrible ces StrAlloc !

    si tu ne veux pas exploser la pile en déclarant tout cela en statique, tu peux au moins les regrouper dans un Record que tu alloues en une seule fois

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
     
    type
      TData = record
          FonctionAppelee : array[0..9] of Char;
          Societe,
          LibelleSociete,
          Personne,
          Login,
          Nom,
          Prenom,
          ProfilWindows,
          Poste,
          LibellePoste,
          FicheGRC,
          IdentifiantFicheGRC,
          Parametre13,
          Parametre14,
          Parametre15,
          Parametre16,
          Parametre17,
          Parametre18,
          Parametre19,
          Parametre20  : array[0..59] of Char;
          GestionHabilitations : array[0..59] of Char;
          Erreur: array[0..255] of Char;
      end;
    var
      Data: ^TData;
    begin
      New(Data);
      try
    ...
      finally
        Dispose(Data);
      end;
    end;
    ensuite la violation d'accès c'est généralement la lecture ou l'écriture dans un pointeur invalide...il faut donc identifier les lignes concernées et regarder la valeur des variables à cet endroit
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  3. #3
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 452
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 452
    Points : 24 863
    Points
    24 863
    Par défaut
    Citation Envoyé par 3Fred9 Voir le message
    ... D'où ma question : Y a t il besoin d'un synchronize ou autre chose du genre et pourquoi ?
    Vérifier effectivement si les requêtes sont lancées dans plusieurs Threads
    La DLL pourrait ainsi gérer un THREAD_ATTACH\DETACH pour isoler peut-être des objets communs comme par exemple la Base de données.
    Synchronize c'est un peu la technique du pauvre, mieux vaut profiter des Threads et utiliser des objets pour chacun, éventuellement quelques Sections Critiques si l'on utilise des objets partagés.

    PChar et PAnsiChar mélangé, c'est en D7 ?

    D'ailleurs WriteMsgLog plusieurs threads pourraient modifier le fichier en même temps, tu pourrais voir donc des logs enchevêtrés.
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  4. #4
    Nouveau membre du Club
    Inscrit en
    Mars 2010
    Messages
    35
    Détails du profil
    Informations forums :
    Inscription : Mars 2010
    Messages : 35
    Points : 32
    Points
    32
    Par défaut
    je ne sais pas, mais je trouve horrible ces StrAlloc !
    C'est bien le nombre que tu trouves horrible ?
    Je vais faire évoluer mon code comme tu me le conseille ce qui est en effet plus "élégant"

    si tu ne veux pas exploser la pile en déclarant tout cela en statique
    Désolé, qu'entends tu par là ? Pourrais tu m'expliquer stp ?

    ensuite la violation d'accès c'est généralement la lecture ou l'écriture dans un pointeur invalide...
    En effet... et du coup (ah le retour de vacances...) en relisant le message exact "Violation d'accès à l'adresse 02435E62 dans le module 'Acgwebutils_d.dll'. Lecture de l'adresse 000204B0" celui ci se produit en fait dans la procedure de la dll ReceptionMsg dont je transmets du coup le code :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    procedure ReceptionMsg(PModeCommunication, PNomFile, PServeur, PPort, PFonctionAppelee,
      PParametre1, PParametre2, PParametre3, PParametre4, PParametre5, PParametre6, PParametre7, PParametre8, PParametre9, PParametre10,
      PParametre11, PParametre12, PParametre13, PParametre14, PParametre15, PParametre16, PParametre17, PParametre18, PParametre19, PParametre20,
      PErreur: PAnsiChar); stdcall;
    var
      Serveur, NomFile, ModeCommunication, FonctionAppelee,
      Parametre1, Parametre2, Parametre3, Parametre4, Parametre5, Parametre6, Parametre7, Parametre8, Parametre9, Parametre10,
      Parametre11, Parametre12, Parametre13, Parametre14, Parametre15, Parametre16, Parametre17, Parametre18, Parametre19, Parametre20,
      Msg, Erreur: String;
      Port: Integer;
      ListeParametres: TStringList;
    begin
      ModeCommunication := String(PModeCommunication);
      NomFile := String(PNomFile);
      Serveur := String(PServeur);
      Port := StrToInt(String(PPort));
      Erreur := '';
      FonctionAppelee := '';
      Parametre1 := '';
      Parametre2 := '';
      Parametre3 := '';
      Parametre4 := '';
      Parametre5 := '';
      Parametre6 := '';
      Parametre7 := '';
      Parametre8 := '';
      Parametre9 := '';
      Parametre10 := '';
      Parametre11 := '';
      Parametre12 := '';
      Parametre13 := '';
      Parametre14 := '';
      Parametre15 := '';
      Parametre16 := '';
      Parametre17 := '';
      Parametre18 := '';
      Parametre19 := '';
      Parametre20 := '';
     
      if ModeCommunication = 'FileJMS' then
        // Communication par file JMS
        Msg := LectureMessageJMS(Serveur, Port, NomFile)
      else
        if ModeCommunication = 'Fichier' then
          // Communication par message contenu dans un fichier
          Msg := LectureMessageTexte(NomFile)
        else
          Msg := 'ERREUR (Acgwebutils) : Le mode de communication [' +ModeCommunication+ '] n est pas prise en charge';
      if LeftStr(Msg, 6) = 'ERREUR' then
        Erreur := Msg
      else begin
        ListeParametres := TStringList.Create;
        ListeParametres.Delimiter := ';';
        ListeParametres.StrictDelimiter := True;
        ListeParametres.DelimitedText := Msg;
        if ListeParametres.Count >= 1 then begin
          FonctionAppelee := ListeParametres.Strings[0];
          if ListeParametres.Count >= 2 then begin
            Parametre1 := ListeParametres.Strings[1];
            if ListeParametres.Count >= 3 then begin
              Parametre2 := ListeParametres.Strings[2];
              if ListeParametres.Count >= 4 then begin
                Parametre3 := ListeParametres.Strings[3];
                 if ListeParametres.Count >= 5 then begin
                   Parametre4 := ListeParametres.Strings[4];
                   if ListeParametres.Count >= 6 then begin
                     Parametre5 := ListeParametres.Strings[5];
                     if ListeParametres.Count >= 7 then begin
                       Parametre6 := ListeParametres.Strings[6];
                       if ListeParametres.Count >= 8 then begin
                         Parametre7 := ListeParametres.Strings[7];
                         if ListeParametres.Count >= 9 then begin
                           Parametre8 := ListeParametres.Strings[8];
                           if ListeParametres.Count >= 10 then begin
                             Parametre9 := ListeParametres.Strings[9];
                             if ListeParametres.Count >= 11 then begin
                               Parametre10 := ListeParametres.Strings[10];
                               if ListeParametres.Count >= 12 then begin
                                 Parametre11 := ListeParametres.Strings[11];
                                 if ListeParametres.Count >= 13 then begin
                                   Parametre12 := ListeParametres.Strings[12];
                                   if ListeParametres.Count >= 14 then begin
                                     Parametre13 := ListeParametres.Strings[13];
                                     if ListeParametres.Count >= 15 then begin
                                       Parametre14 := ListeParametres.Strings[14];
                                       if ListeParametres.Count >= 16 then begin
                                         Parametre15 := ListeParametres.Strings[15];
                                         if ListeParametres.Count >= 17 then begin
                                           Parametre16 := ListeParametres.Strings[16];
                                           if ListeParametres.Count >= 18 then begin
                                             Parametre17 := ListeParametres.Strings[17];
                                             if ListeParametres.Count >= 19 then begin
                                               Parametre18 := ListeParametres.Strings[18];
                                               if ListeParametres.Count >= 20 then begin
                                                 Parametre19 := ListeParametres.Strings[19];
                                                 if ListeParametres.Count >= 21 then begin
                                                   Parametre20 := ListeParametres.Strings[20];
        end; end; end; end; end; end; end; end; end; end; end; end; end; end; end; end; end; end; end; end; end;
      end;
      StrPCopy(PFonctionAppelee, LeftStr(AnsiString(FonctionAppelee), 10));
      StrPCopy(PParametre1, LeftStr(AnsiString(Parametre1), 60));
      StrPCopy(PParametre2, LeftStr(AnsiString(Parametre2), 60));
      StrPCopy(PParametre3, LeftStr(AnsiString(Parametre3), 60));
      StrPCopy(PParametre4, LeftStr(AnsiString(Parametre4), 60));
      StrPCopy(PParametre5, LeftStr(AnsiString(Parametre5), 60));
      StrPCopy(PParametre6, LeftStr(AnsiString(Parametre6), 60));
      StrPCopy(PParametre7, LeftStr(AnsiString(Parametre7), 60));
      StrPCopy(PParametre8, LeftStr(AnsiString(Parametre8), 60));
      StrPCopy(PParametre9, LeftStr(AnsiString(Parametre9), 60));
      StrPCopy(PParametre10, LeftStr(AnsiString(Parametre10), 60));
      StrPCopy(PParametre11, LeftStr(AnsiString(Parametre11), 60));
      StrPCopy(PParametre12, LeftStr(AnsiString(Parametre12), 60));
      StrPCopy(PParametre13, LeftStr(AnsiString(Parametre13), 60));
      StrPCopy(PParametre14, LeftStr(AnsiString(Parametre14), 60));
      StrPCopy(PParametre15, LeftStr(AnsiString(Parametre15), 60));
      StrPCopy(PParametre16, LeftStr(AnsiString(Parametre16), 60));
      StrPCopy(PParametre17, LeftStr(AnsiString(Parametre17), 60));
      StrPCopy(PParametre18, LeftStr(AnsiString(Parametre18), 60));
      StrPCopy(PParametre19, LeftStr(AnsiString(Parametre19), 60));
      StrPCopy(PParametre20, LeftStr(AnsiString(Parametre20), 60));
      StrPCopy(PErreur, LeftStr(AnsiString(Erreur), 256));
    end;
     
    function LectureMessageJMS(Serveur: String; Port: Integer; NomFileJMS: String): String;
    var
      StompClient: IStompClient;
      StompFrame: IStompFrame;
    begin
      Screen.Cursor := crDefault;// crArrow;
      try
        try
          StompClient := StompUtils.NewStomp(Serveur, Port);
          if (StompClient <> nil) then begin
            StompClient.Subscribe(NomFileJms);
            if (StompClient <> nil) then begin
              if StompClient.Receive(StompFrame, 2000) then begin
                if (Assigned(StompFrame)) then begin
                  Result := StompFrame.GetBody;
                end else
                  Result := '';
              end else
                Result := 'ERREUR_RecuperationMsgJms (Acgwebutils) : Impossible de récupérer le message';
            end else
              Result := 'ERREUR_RecuperationMsgJms (Acgwebutils) : Perte de connexion';
          end else
            Result := 'ERREUR_RecuperationMsgJms (Acgwebutils) : Impossible d établir une connexion sur le serveur Active MQ [' +Serveur+ ':' +IntToStr(Port)+ ']';
        except
          on E: Exception do begin
            Result := 'ERREUR_RecuperationMsgJms (Acgwebutils) ' +Result+ ' : Erreur réception message sur le serveur Active MQ [' +Serveur+ ':' +IntToStr(Port)+ '] : ' + E.ClassName + sLineBreak + E.Message;
          end;
        end;
      finally
        StompClient.Disconnect;
        StompClient := nil;
        StompFrame := nil;
        Screen.Cursor := crArrow;//crDefault;
      end;
    end;
    il faut donc identifier les lignes concernées et regarder la valeur des variables à cet endroit
    Aurais tu des méthodes pour faire cela à part faire évoluer les logs stp ? Car cela ne se produit qu'en prod bien évidemment sinon cela aurait été trop facile...


    Vérifier effectivement si les requêtes sont lancées dans plusieurs Threads
    Tu parles des requêtes du navigateur sur le serveur hébergeant IIS ? Ouaouh !! Comment vérifier ça ?

    La DLL pourrait ainsi gérer un THREAD_ATTACH\DETACH pour isoler peut-être des objets communs comme par exemple la Base de données.
    Synchronize c'est un peu la technique du pauvre, mieux vaut profiter des Threads et utiliser des objets pour chacun, éventuellement quelques Sections Critiques si l'on utilise des objets partagés.
    Chaud... Pas tout compris... désolé...

    PChar et PAnsiChar mélangé, c'est en D7 ?
    Oui le projet est en Delphi 2007 et le projet de la dll est en Delphi XE 2

    Merci

  5. #5
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 452
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 452
    Points : 24 863
    Points
    24 863
    Par défaut
    Cela pique un peu les PParametre20

    un PAnsiChar c'est par exemple ABC#0
    Pour passer plusieurs paramètres et un nombre variable, la pratique Win32 c'est ABC#0DEF#0GHI#0#0, chaque chaine séparé par le #0 et la fin du tableau par un #0 supplémentaire, et quand je parle de #0, je parle d'un seul caractère binaire de valeur 0.
    Avec une TStringList.DelimitedText faudra voir si l'on peut indiquer #0 comme Delimiter même si je travaillerais plutôt avec un TStringDynArray et je ferais une petite classe de Sérialisation TDLLAnsiCharDynArray qui fait le boulot de conversion.
    Surtout que passer de ABC,DEF,GHI à ABC#0DEF#0GHI#0#0 par un StringReplace ça semble bien plus simple que tout ce code de TStringList


    Screen.Cursor dans un Thread d'une application ISAPI ... déjà c'est étrange
    StompUtils est-il une unité ThreadSafe, je vois du IStompClient et IStompFrame, interface,
    est-ce du code interne ?
    est-ce une autre DLL maison exposant des interfaces ?
    est-ce du COM ? ce type de DLL gère aussi différent mode de partage mémoire, cf Multithreaded Apartments
    Car selon le mode en fait, le risque c'est que IStompClient soit le même partagé
    Si COM, les chaines sont surement des BSTR soit des WideString, lorsque je faisais mes DLL, j'utilisais souvent du PWideChar géré par des WideString, cela simplifie la gestion mémoire des chaines, c'est une sorte de ShareMem mais géré par Windows et non par Delphi.
    Est-ce composant ?

    Point d’entrée DllMain, DLL_THREAD_ATTACH une notion a maitrisé lors de l'utilisation d'une DLL en Multi-Thread
    Tu peux créer des objets et allouer des espaces mémoire pour le thread
    A noter que le DLL_PROCESS_ATTACH n'existe pas en Delphi, il faut considérer le DPR comme étant son équivalent voir DLLProc pour capturer le DLL_PROCESS_ATTACH\DETACH

    je te conseille de démarrer la DLL dans MainThread de ton projet, et ainsi les requêtes provoqueront une DLL_THREAD_ATTACH
    Après faut aussi étudier si il y a une gestion de Pool de Thread, c'est à dire que pour éviter trop de thread, les requêtes sont séquentialisées dans un groupe de thread.

    En gros, tu as plein de problématique lié à la programmation Serveur.
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  6. #6
    Membre expert
    Avatar de pprem
    Homme Profil pro
    MVP Embarcadero - formateur&développeur Delphi, PHP et JS
    Inscrit en
    Juin 2013
    Messages
    1 876
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loiret (Centre)

    Informations professionnelles :
    Activité : MVP Embarcadero - formateur&développeur Delphi, PHP et JS
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Juin 2013
    Messages : 1 876
    Points : 3 611
    Points
    3 611
    Par défaut
    Citation Envoyé par 3Fred9 Voir le message
    Tu parles des requêtes du navigateur sur le serveur hébergeant IIS ? Ouaouh !! Comment vérifier ça ?
    La réponse est dans la question. IIS exécute bien tout sous forme de threads. Il faut donc s'assurer que ce qu'on fait soit compatible.

    Et s'il y a accès à une base de données il faut gérer une connexion par thread ou dans le cas de FireDAC passer par le manager de connexion sur lequel le premier thread doit référencer un alias qui devra ensuite être utilisé par les autres connexions.

  7. #7
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 452
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 452
    Points : 24 863
    Points
    24 863
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     StompClient.Disconnect;
    Je serais paranoiaque

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    function LectureMessageJMS(Serveur: String; Port: Integer; NomFileJMS: String): String;
    var
      StompClient: IStompClient;
      StompFrame: IStompFrame;
    begin
      StompClient := nil;
      StompFrame := nil;
     
      if MainThreadID = GetCurrentThreadId() then
        Screen.Cursor := crDefault;// crArrow;
      try   
        try
          StompClient := StompUtils.NewStomp(Serveur, Port);
          try
            if (StompClient <> nil) then begin
              StompClient.Subscribe(NomFileJms);
              if (StompClient <> nil) then begin
                if StompClient.Receive(StompFrame, 2000) then begin
                  if (Assigned(StompFrame)) then begin
                    Result := StompFrame.GetBody;
                  end else
                    Result := '';
                end else
                  Result := 'ERREUR_RecuperationMsgJms (Acgwebutils) : Impossible de récupérer le message';
              end else
                Result := 'ERREUR_RecuperationMsgJms (Acgwebutils) : Perte de connexion';
            end else
              Result := 'ERREUR_RecuperationMsgJms (Acgwebutils) : Impossible d établir une connexion sur le serveur Active MQ [' +Serveur+ ':' +IntToStr(Port)+ ']';
          finally
            if (StompClient <> nil) then
              StompClient.Disconnect;
            StompClient := nil;
            StompFrame := nil;
         end;
       except
          on E: Exception do begin
            Result := 'ERREUR_RecuperationMsgJms (Acgwebutils) ' +Result+ ' : Erreur réception message sur le serveur Active MQ [' +Serveur+ ':' +IntToStr(Port)+ '] : ' + E.ClassName + sLineBreak + E.Message;
          end;
        end;
      finally
        if MainThreadID = GetCurrentThreadId() then
          Screen.Cursor := crArrow;//crDefault;
      end;
    end;
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  8. #8
    Nouveau membre du Club
    Inscrit en
    Mars 2010
    Messages
    35
    Détails du profil
    Informations forums :
    Inscription : Mars 2010
    Messages : 35
    Points : 32
    Points
    32
    Par défaut
    Citation Envoyé par ShaiLeTroll Voir le message
    Cela pique un peu les PParametre20

    un PAnsiChar c'est par exemple ABC#0
    Pour passer plusieurs paramètres et un nombre variable, la pratique Win32 c'est ABC#0DEF#0GHI#0#0, chaque chaine séparé par le #0 et la fin du tableau par un #0 supplémentaire, et quand je parle de #0, je parle d'un seul caractère binaire de valeur 0.
    Avec une TStringList.DelimitedText faudra voir si l'on peut indiquer #0 comme Delimiter même si je travaillerais plutôt avec un TStringDynArray et je ferais une petite classe de Sérialisation TDLLAnsiCharDynArray qui fait le boulot de conversion.
    Surtout que passer de ABC,DEF,GHI à ABC#0DEF#0GHI#0#0 par un StringReplace ça semble bien plus simple que tout ce code de TStringList
    Ouais c'est pas top mais cette procédure est aussi appelée depuis des fonctions développées avec un outils qui gère pas un nombre variable de paramètres... Mais je vais en effet essayer de faire évoluer mon code comme tu l'évoques. Merci.

    Citation Envoyé par ShaiLeTroll Voir le message
    Screen.Cursor dans un Thread d'une application ISAPI ... déjà c'est étrange
    Cette procédure est également appelée depuis un logiciel avec fenêtre windows, c'est pour cela.

    Citation Envoyé par ShaiLeTroll Voir le message
    StompUtils est-il une unité ThreadSafe, je vois du IStompClient et IStompFrame, interface,
    est-ce du code interne ?
    est-ce une autre DLL maison exposant des interfaces ?
    est-ce du COM ? ce type de DLL gère aussi différent mode de partage mémoire, cf Multithreaded Apartments
    Car selon le mode en fait, le risque c'est que IStompClient soit le même partagé
    Si COM, les chaines sont surement des BSTR soit des WideString, lorsque je faisais mes DLL, j'utilisais souvent du PWideChar géré par des WideString, cela simplifie la gestion mémoire des chaines, c'est une sorte de ShareMem mais géré par Windows et non par Delphi.
    Est-ce composant ?
    Oui c'est exactement ce composant, j'ai intégré cette unité StompClient.pas dans le même projet que la fonction ReceptionMsg qui génère la dll.


    Citation Envoyé par ShaiLeTroll Voir le message
    Point d’entrée DllMain, DLL_THREAD_ATTACH une notion a maitrisé lors de l'utilisation d'une DLL en Multi-Thread
    Tu peux créer des objets et allouer des espaces mémoire pour le thread
    A noter que le DLL_PROCESS_ATTACH n'existe pas en Delphi, il faut considérer le DPR comme étant son équivalent voir DLLProc pour capturer le DLL_PROCESS_ATTACH\DETACH

    je te conseille de démarrer la DLL dans MainThread de ton projet, et ainsi les requêtes provoqueront une DLL_THREAD_ATTACH
    Après faut aussi étudier si il y a une gestion de Pool de Thread, c'est à dire que pour éviter trop de thread, les requêtes sont séquentialisées dans un groupe de thread.

    En gros, tu as plein de problématique lié à la programmation Serveur.
    Je vais étudier tout ça... En effet plein...

  9. #9
    Nouveau membre du Club
    Inscrit en
    Mars 2010
    Messages
    35
    Détails du profil
    Informations forums :
    Inscription : Mars 2010
    Messages : 35
    Points : 32
    Points
    32
    Par défaut
    Citation Envoyé par ShaiLeTroll Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     StompClient.Disconnect;
    Je serais paranoiaque
    Concernant simplement le Disconnect ? Où c'est le Disconnect qui te ferais rajouté le code suivant ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
      if MainThreadID = GetCurrentThreadId() then
        Screen.Cursor := crDefault;// crArrow;

  10. #10
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 452
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 452
    Points : 24 863
    Points
    24 863
    Par défaut
    Aucun rapport entre ces blocs,
    c'est votre code initial qui laisse penser que NewStomp peut retourner nil donc le Disconnect dans le try finally pourrait provoquer une Violation Acces sur 00000000


    En fait, voici un code bien mieux écrit pour la gestion de la libération des interfaces même si en fait, cela n'est pas obligatoire, à la fin de fonction cela se fait implicitement mais j'ai déjà vu des interfaces mal codés qui ne supportaient pas certains ordres de libération, comme par exemple libérer le parent avant l'enfant.
    Et ces interfaces sont peut-être tout simplement non thread-safe, une section critique a ajouter peut-être au niveau du Receive ou même sur tout le LectureMessageJMS
    Il faut instancier la SectionCritique dans le Main de la DLL, soit le DPR, je recommande de faire un objet Singleton qui héberge les ressources communes au différents Threads, peut-être que le partie StompUtils pourrait être dans un thread dédié, traité séquentiellement sur une FIFO qui serait une autre approche de protection des appels, plus de concurrence ainsi mais forcement une rétention plus longue de la requête HTTP.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    function LectureMessageJMS(const Serveur: String; Port: Integer; const NomFileJMS: String): String;
    var
      StompClient: IStompClient;
      StompFrame: IStompFrame;
    begin
      Result := '';
     
      if MainThreadID = GetCurrentThreadId() then
        Screen.Cursor := crDefault;// crArrow;
      try   
        try
          StompClient := StompUtils.NewStomp(Serveur, Port);
          if StompClient <> nil then 
          begin
            try
              StompClient.Subscribe(NomFileJms);
     
              if StompClient.Receive(StompFrame, 2000) then 
              begin
                if StompFrame <> nil then 
                begin
                  try
                    Result := StompFrame.GetBody();
                  finally
                    StompFrame := nil;
                  end;
                end 
                else
                  Result := 'ERREUR_RecuperationMsgJms (Acgwebutils) : Impossible de récupérer le message';
              end 
              else
                Result := 'ERREUR_RecuperationMsgJms (Acgwebutils) : Perte de connexion';
            finally
              StompClient.Disconnect();
              StompClient := nil;
            end;
          end 
          else
            Result := 'ERREUR_RecuperationMsgJms (Acgwebutils) : Impossible d établir une connexion sur le serveur Active MQ [' +Serveur+ ':' +IntToStr(Port)+ ']';
       except
          on E: Exception do begin
            Result := 'ERREUR_RecuperationMsgJms (Acgwebutils) ' +Result+ ' : Erreur réception message sur le serveur Active MQ [' +Serveur+ ':' +IntToStr(Port)+ '] : ' + E.ClassName + sLineBreak + E.Message;
          end;
        end;
      finally
        if MainThreadID = GetCurrentThreadId() then
          Screen.Cursor := crArrow;//crDefault;
      end;
    end;


    Et pour le Screen.Cursor, c'est inutile en Thread voir instable dans une DLL ISAPI n'ayant pas d'interopérabilité avec le bureau avec un IIS lancé en Service
    J'ai justement ajouté le test pour que cela fonctionne dans l'application en supposant un appel dans le MAinThread et dans un thread secondaire pour la version IIS
    Bon j'aurais mis cela dans le programme appelant plutôt que la DLL mais chacun ses choix.
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

Discussions similaires

  1. Violation d'accès après appel d'une fonction DLL
    Par colorid dans le forum Langage
    Réponses: 9
    Dernier message: 12/06/2013, 12h15
  2. BCB 6 / Violation d'accès après utilisation d'une DLL
    Par a_lincoln54 dans le forum C++Builder
    Réponses: 1
    Dernier message: 28/04/2008, 14h15
  3. Violation d'accès du module msado15.dll
    Par kobe dans le forum Bases de données
    Réponses: 4
    Dernier message: 19/08/2005, 10h57
  4. Réponses: 6
    Dernier message: 24/02/2005, 09h44
  5. Utilisation fonction définie dans un .Dll
    Par jeab. dans le forum Windows
    Réponses: 5
    Dernier message: 23/03/2004, 16h23

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo