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

Delphi Discussion :

erreur stdCall DLL


Sujet :

Delphi

  1. #1
    Membre du Club

    Inscrit en
    Novembre 2008
    Messages
    69
    Détails du profil
    Informations forums :
    Inscription : Novembre 2008
    Messages : 69
    Points : 62
    Points
    62
    Billets dans le blog
    1
    Par défaut erreur stdCall DLL
    Bonjour,
    je rouvre la discussion car il s'agit d'un problème apparenté.
    Depuis douze ans je fais tourner des serveurs qui appellent sans problème plusieurs centaines de milliers de fois par jour une DLL au travers d'un stdCall.
    Or sur un ordinateur plus récent, ces serveurs plantent. J'ai essayé sur un autre ordinateur récent : même problème. (violation d'accès)
    Je dispose de Delphi 10.2 pour examiner le problème. Mais en mode debug de l'EDI le serveur marche parfaitement. Il n'y a qu'en compilé que le problème se produit. J'ai essayé le mode administrateur sans succès.
    en explorant un peu le code j'en suis arrivé à la conclusion que c'était l'appel à la DLL qui provoquait l'erreur. J'ai alors supprimé le StdCall : l'erreur disparait mais les résultats sont erronés.
    Il semblerait bien que ce soit lié aux ordinateurs récents...
    quelqu'un a une idée ?

  2. #2
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 043
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 67
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 043
    Points : 40 957
    Points
    40 957
    Billets dans le blog
    62
    Par défaut
    Citation Envoyé par GerardJ Voir le message
    quelqu'un a une idée ?
    Un problème de nombre de Bits 32/64 ?
    MVP Embarcadero
    Delphi installés : D3,D7,D2010,XE4,XE7,D10 (Rio, Sidney), D11 (Alexandria), D12 (Athènes)
    SGBD : Firebird 2.5, 3, SQLite
    générateurs États : FastReport, Rave, QuickReport
    OS : Window Vista, Windows 10, Windows 11, Ubuntu, Androïd

  3. #3
    Membre du Club

    Inscrit en
    Novembre 2008
    Messages
    69
    Détails du profil
    Informations forums :
    Inscription : Novembre 2008
    Messages : 69
    Points : 62
    Points
    62
    Billets dans le blog
    1
    Par défaut
    les ordinateurs sur lesquels ça fonctionne sont tous des 64 bits avec des cores I7 de 4ème génération. Un windows 10 famille (après upgrade) et l'autre W7 pro
    Celui sur lequel il y a des problèmes est aussi 64 bits core I7 de 7ème génération. W10 famille

  4. #4
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 459
    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 459
    Points : 24 873
    Points
    24 873
    Par défaut
    En même temps, en 64bits, il n'y a plus de convention d'appel spécifique, il n'y a plus qu'une seule convention le __fastcall
    Tout ça c'est valable pour les programmes 32Bits qui doivent effectivement conservé le register/pascal en interne et le stdcall/safecall pour l'extérieur
    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

  5. #5
    Membre du Club

    Inscrit en
    Novembre 2008
    Messages
    69
    Détails du profil
    Informations forums :
    Inscription : Novembre 2008
    Messages : 69
    Points : 62
    Points
    62
    Billets dans le blog
    1
    Par défaut
    Merci pour vos informations mais ceci n'éclaire pas encore ma lanterne...
    Suite à ton dernier post j'ai essayé de remplacer stdcall par safecall : toujours le même problème. Fastcall n'est pas reconnu par le compilateur.
    La question est pourquoi un programme qui tourne depuis longtemps sur des machines 64 bits cesse de tourner sur des machines plus récentes avec le même type de CPU ?
    Pourquoi le programme tourne sur ces machines plus récentes en mode debug de l'EDI Delphi 10.2 mais pas en compilé ?

    Mon problème est critique : mon site tourne actuellement sur les machines anciennes et si l'une d'elles tombe en panne, je n'ai pas de solution pour continuer...
    Un ami m'a dit qu'intel avait introduit une sécurité supplémentaire dans ses puces : serait-ce là le problème ?

  6. #6
    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 445
    Points
    28 445
    Par défaut
    alors petits rappels

    1) une appli 32 bits, tourne en 32 bits, même sur une OS 64bits (une application 64Bits ne peut pas tourner sur un OS 32bits)

    2) les applis 32 bit ne sont pas compatibles avec les DLL 64bits et vice versa

    3) la convention d'appel ce n'est pas une option qu'on peut changer comme on veux, ce doit être cohérent entre l'appelant et l'appelé, suivant le choix qui est fait, les paramètres sont passés de droite à gauche ou de gauche à droite, via des registres ou sur la pile, en laissant l'appelant nettoyer la pile ou en le faisant après l'appel...donc, sauf cas rares (procédure sans paramètre ou avec un seul paramètre qui passe dans un registre), on ne peux pas mettre n'importe quoi comme convention d'appel, il faut absolument choisir la bonne option. De Delphi à Delphi, il suffit de mettre la même option des deux côtés, de Delphi vers un autre langage, c'est généralement stdcall qui est utilisé sous Windows...mais pas toujours. safecall est utilisé pour remplacer une fonction retournant un HRESULT dans le cadre des appels COM (ActiveX).

    4) la convention d'appel ne change pas en fonction du processeur.

    je recommande l'usage de madExcept pour débuguer les violations d'accès ou fuites de mémoire, c'est un produit excellent ! Il ne permet pas de tout identifier mais pointe souvent dans la bonne direction.
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  7. #7
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 459
    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 459
    Points : 24 873
    Points
    24 873
    Par défaut
    Surtout que l'on ne sait rien du problème, GerardJ tu as ajouté ta question de ce vieux sujet de Steff2 ce qui est surement inapproprié, il aurait été préférable de créer ton propre sujet avec plus d'information comme le prototype de la fonction, des détails sur l'appelant et l'appelé, le contexte de compilation (32 ou 64), alignement mémoire, le gestionnaire de mémoire utilisé, j'ai pu constater des différences de comportement majeur dont la VA qui survient avec l'un et pas avec l'autre, la présence de thread, le type de VA avec les adresses permettant de savoir si c'est lié à un pointeur nil ou une utilisation d'un pointeur non valide ...


    Citation Envoyé par Paul TOTH Voir le message
    4) la convention d'appel ne change pas en fonction du processeur.
    je compléterais cette mention comme ceci

    4) la convention d'appel ne change pas en fonction du processeur mais en fonction de l'architecture cible du programme et de l'émulation disponible

    Soit pour un programme VCL pour Windows dont l'architecture est 32 Bits (y compris un 32Bits émulé sur WoW64) : cdecl, stdcall, fastcall, register et pascal
    et pour un programme VCL pour Windows dont l'architecture est 64 Bits : x64
    (et encore MSVC++ propose en plus __vectorcall pour ces deux architectures x86 et x86-64 supportées par Windows
    ni nous n'évoquerons pas les spécificités UNIX ou les processeurs ARM avec FMX et tout ça )
    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
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 043
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 67
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 043
    Points : 40 957
    Points
    40 957
    Billets dans le blog
    62
    Par défaut
    Citation Envoyé par ShaiLeTroll Voir le message
    Surtout que l'on ne sait rien du problème, GerardJ tu as ajouté ta question de ce vieux sujet de Steff2 ce qui est surement inapproprié, il aurait été préférable de créer ton propre sujet
    Voilà qui est fait
    MVP Embarcadero
    Delphi installés : D3,D7,D2010,XE4,XE7,D10 (Rio, Sidney), D11 (Alexandria), D12 (Athènes)
    SGBD : Firebird 2.5, 3, SQLite
    générateurs États : FastReport, Rave, QuickReport
    OS : Window Vista, Windows 10, Windows 11, Ubuntu, Androïd

  9. #9
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 459
    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 459
    Points : 24 873
    Points
    24 873
    Par défaut
    Citation Envoyé par SergioMaster Voir le message
    Voilà qui est fait
    Merci d'avoir divisé le sujet en deux, GerardJ tu as maintenant l'occasion de mieux d'écrire ton problème et son contexte
    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

  10. #10
    Membre du Club

    Inscrit en
    Novembre 2008
    Messages
    69
    Détails du profil
    Informations forums :
    Inscription : Novembre 2008
    Messages : 69
    Points : 62
    Points
    62
    Billets dans le blog
    1
    Par défaut
    Merci d'avoir séparé le sujet : je n'ai pas trouvé comment ouvrir une nouvelle discussion !
    Je décris donc mieux mon problème.
    Il y a douze ans j'ai créé un site sur lequel on peut jouer au bridge gratuitement avec et contre le programme de bridge Wbridge5 d'Yves Costel. Ce programme a été de nombreuses fois champion du monde. J'ai entre 800 et 1000 joueurs par jour, avec 20% d'anglophones. Chaque jour on peut jouer sur ce site bridgez.net deux tournois avec classement. Le site comporte un très grand nombre de serveurs : deux qui fournissent les tournois et les classements, tournois qui peuvent être joués sur le programme directement ceci ne tournant alors que sous Windows. Il y a neuf ans, nous avons ajouté la possibilité de jouer "on the Cloud" c'est-à-dire à partir d'un navigateur, ce qui ouvrait la porte à d'autre OS, aux tablettes, aux Mac, à Linux...
    Pour cela il a fallu créer un nouveau serveur qui déroule la partie de bridge, mais qui ne fait qu'appliquer les règles : il ne sait pas quelle décision il faut prendre en fonction de la situation. Ces décisions sont produites par le programme de Bridge d'Yves au travers de sa DLL wbtot_wb.dll. Les programmes de bridge sont très gourmands en temps CPU : ils peuvent utiliser le CPU à plein temps pendant 30s; C'est rare mais ça arrive. Pour permettre à de nombreux joueurs de jouer en même temps j'ai créé une ferme de serveurs DLL que le programme qui déroule la partie appelle pour savoir ce qu'il faut jouer. Actuellement il y a 20 serveurs DLL, mais au départ il y en avait 26 répartis sur des ordinateurs en réseau. Mais mes ordinateurs qui tournent 24/24 7/7 finissent par tomber en panne d'où la nécessité de les remplacer. Mais sur le dernier ordinateur acheté les serveurs DLL plantent systématiquement.
    Les programmes ont été écrits avec Delphi 7 mais sur le dernier ordinateur j'y ai installé Delphi 10.2.
    Chaque joueur crée un thread sur chacun des serveurs. lorsqu'il se logue, ses conventions sont envoyées à tous les serveurs DLL auxquels il se connecte en permanence. Les liaisons sont TCP/IP.
    Le serveur DLL reçoit donc des requêtes qui contiennent les données dans un enregistrement (record). Ce record est envoyé à la DLL par l'intermédiaire d'un pointeur (premier paramètre d'appel de la DLL), ainsi qu'un pointeur sur les conventions (second paramètre) et un un troisième paramètre un indice entier qui dit à la dLL le type d'opération qu'elle doit exécuter.
    Dans un premier temps pour essayer de résoudre le problème, j'ai utilisé Delphi 10.2 donc sur l'ordinateur qui pose le problème et là en mode débug de l'EDI pas de problème : le serveur tourne normalement. En prenant l'application ainsi produite celle-ci plante toujours : le comportement n'est pas le même dans les deux modes.
    Pour essayer de mieux cerner le problème j'ai commencé à mettre des messages qui me permettaient de tracer le déroulement du programme du serveur : a priori l'appel à la DLL se terminait correctement mais le serveur plantait toujours en violation d'accès. J'ai essayé le mode administrateur sans succès. J'ai donc fini par supprimer l'appel de la DLL en simulant une réponse probable : le serveur ne plantait plus et pouvait être appelé plusieurs fois.
    c'est là que j'ai commencé à m'intéresser au stdcall. Si je supprime le stdcall, le serveur ne plante plus mais les résultats sont incorrects et provoquent des problèmes sur l'autre serveur qui à fait la demande.
    la procédure d'appel est
    procedure wb_dll(H:pTjeu;C:ptconv;I_eval:integer);stdcall; external 'wbtot_wb.dll';
    J'utilise bien sûr madexcept mais il ne m’apporte aucune aide dans ce cas.
    Merci de votre aide.
    PS : J'ai décrit le problème à Barnsten qui est le distributeur d'embarcadero : il devrait me fournir une réponse que j'attends toujours.

  11. #11
    Expert confirmé Avatar de sergio_is_back
    Homme Profil pro
    Responsable informatique, développeur tout-terrain
    Inscrit en
    Juin 2004
    Messages
    1 084
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Responsable informatique, développeur tout-terrain
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Juin 2004
    Messages : 1 084
    Points : 5 604
    Points
    5 604
    Par défaut
    Citation Envoyé par GerardJ Voir le message
    Les programmes ont été écrits avec Delphi 7 mais sur le dernier ordinateur j'y ai installé Delphi 10.2.
    Intéressant problème :

    - Le problème ne vient pas de stdcall de toutes façon, comme l'a dit Paul TOTH le processeur ne change les conventions d'appel
    - Tu dis que tu utilise une DLL que tu n'a pas développé toi-même : a t-elle été développée avec Visual C++ ?

    Je dis ça car si elle a été développé en Visual C++ il te faut le runtime correspondant sur le PC en question, le Microsoft Redistribuable Package correspondant à la version avec laquelle la DLL a été écrite
    Le mieux est d'examiner les dépendances de la DLL que tu utilises
    Tu peux utiliser Dependency Walker pour ça ici : https://www.dependencywalker.com/

    En effet une DLL peut nécessiter la présence d'une autre... Et donc au final le plantage n'est pas toujours où l'on croit
    En tout cas c'est une piste à explorer

  12. #12
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 459
    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 459
    Points : 24 873
    Points
    24 873
    Par défaut
    Citation Envoyé par GerardJ Voir le message
    ...
    Les programmes ont été écrits avec Delphi 7 mais sur le dernier ordinateur j'y ai installé Delphi 10.2.
    ...j'ai utilisé Delphi 10.2 donc sur l'ordinateur qui pose le problème et là en mode débug de l'EDI pas de problème : le serveur tourne normalement. En prenant l'application ainsi produite celle-ci plante toujours : le comportement n'est pas le même dans les deux modes.
    J'ignore le code mais D7 à D10.2, le gestionnaire de mémoire change
    D7 c'est le MM interne ou BorlandMM via la DLL borlndmm.dll pour le partage ShareMem, mais cela peut-être un FastMM4 si il a été installé (ou un autre MM comme NexusMM ou BucketMM ...)
    D10.2 c'est FastMM4 (pas tout à fait la dernière FastMM4) ... et je ne parle pas du FastMM5 en option qui adore le multi-CPU

    Rien que là déjà, la gestion VA peut totalement être différent, la gestion par block de FastMM pouvant masquer quelques VA que l'on aurait avec l'ancien MM mais sa performance à mieux gérer la Parallélisation des threads augmente le risque d'accès à de la mémoire partagée mais non protégée

    l'Unicode ?
    la conversion du code a surement été faite entre le type PChar vers PAnsiChar pour toutes les fonctions de la DLL 'wbtot_wb.dll' ?
    C'est que passer d'un 1 octet par Char à 2 octets par Char puisque que D7 mappait implicitement un PChar comme un PAnsiChar mais que D10.2 lui mappe un PChar comme un PWideCar implicitement, une différence majeure que l'on repère vite avec le nombre de Warning à la compilation

    Et tout ça c'est un programme Serveur "Chaque joueur crée un thread sur chacun des serveurs" et là entre le mode Debug en Pas à Pas et le mode Release à fond les ballons, il y a une très grosse différence d'exécution, en Debug plein de risques d'accès concurrentiel au même bloc de mémoire sont éliminés et la VA sont quasi nul alors qu'un Release si l'on n'a pas gérer Section Critique, Verrou Lecture-Ecriture, des Sémaphores et tout autre mécanisme de synchronisation pour l'utilisation de la mémoire, cela peut vite explosé, la gestion de la mémoire des threads en D7 et D10 a carrément évolué.
    D'ailleurs, le MM de D10 est 100 fois plus rapide que D7 pour certaines allocations comme les tableaux, les chaines massivement réalloués, cette différence de performance peut donc influer sur la rapidité d'exécution de chaque thread et donc peu augmenter le risque d'accès à des zones de mémoire non protégées d'un thread à l'autre.

    Citation Envoyé par GerardJ Voir le message
    Mais mes ordinateurs qui tournent 24/24 7/7 finissent par tomber en panne d'où la nécessité de les remplacer. Mais sur le dernier ordinateur acheté les serveurs DLL plantent systématiquement.
    Les anciens ordinateurs n'étaient ils pas des mono CPU, donc les threads ne sont pas paralléliser réellement mais ordonnancer chacun leur tour.
    Les nouveaux ordinateurs sont par contre des Multi-Core, Multi-Threading donc le risque d'avoir 4, 8 voire 16 threads fonctionner réellement en simultané est élevé et l'on en revient au SK, MREWS et EVENT entre Thread

    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
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    //------------------------------------------------------------------------------
    (*                SoLuTions is an Versatile Library for Delphi                 -
     *                                                                             -
     *  Copyright "SLT Solutions", (©2006)                                         -
     *  contributeur : ShaiLeTroll (2011) - Gestion de TSimpleRWSync               -
     *  contributeur : ShaiLeTroll (2012) - Renommage Fichier et Correction XE2    -
     *  contributeur : ShaiLeTroll (2012) - Documentation Insight                  -
     *                                                                             -
     *                                                                             -
     * Ce logiciel est un programme informatique servant à aider les développeurs  -
     * Delphi avec une bibliothèque polyvalente, adaptable et fragmentable.        -
     *                                                                             -
     * Ce logiciel est régi par la licence CeCILL-C soumise au droit français et   -
     * respectant les principes de diffusion des logiciels libres. Vous pouvez     -
     * utiliser, modifier et/ou redistribuer ce programme sous les conditions      -
     * de la licence CeCILL-C telle que diffusée par le CEA, le CNRS et l'INRIA    -
     * sur le site "http://www.cecill.info".                                       -
     *                                                                             -
     * En contrepartie de l'accessibilité au code source et des droits de copie,   -
     * de modification et de redistribution accordés par cette licence, il n'est   -
     * offert aux utilisateurs qu'une garantie limitée.  Pour les mêmes raisons,   -
     * seule une responsabilité restreinte pèse sur l'auteur du programme,  le     -
     * titulaire des droits patrimoniaux et les concédants successifs.             -
     *                                                                             -
     * A cet égard  l'attention de l'utilisateur est attirée sur les risques       -
     * associés au chargement,  à l'utilisation,  à la modification et/ou au       -
     * développement et à la reproduction du logiciel par l'utilisateur étant      -
     * donné sa spécificité de logiciel libre, qui peut le rendre complexe à       -
     * manipuler et qui le réserve donc à des développeurs et des professionnels   -
     * avertis possédant  des  connaissances  informatiques approfondies.  Les     -
     * utilisateurs sont donc invités à charger  et  tester  l'adéquation  du      -
     * logiciel à leurs besoins dans des conditions permettant d'assurer la        -
     * sécurité de leurs systèmes et ou de leurs données et, plus généralement,    -
     * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité.          -
     *                                                                             -
     * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez      -
     * pris connaissance de la licence CeCILL-C, et que vous en avez accepté les   -
     * termes.                                                                     -
     *                                                                             -
     *----------------------------------------------------------------------------*)
    unit SLT.Common.ThreadUtils;
     
    interface
     
    {*$DEFINE DEBUG_SLT_RWS*}
     
    uses System.SysUtils, System.SyncObjs;
     
    type
      /// <summary>Encapsulation de différent Synchronizer de thread pour gérer les blocages en vue de protèger la mémoire lors d'accès simultané</summary>
      TSLTReadWriteSynchronizer = class sealed(TInterfacedObject, System.SysUtils.IReadWriteSync)
      public
        // Types Publiques
        type
          TLockType = (rwsltCritical, rwsltSimple, rwsltMREW);
     
      private
        // Membres Privés
        FLockType: TLockType;
        FCriticalSync: TCriticalSection;
     
        FReadWriteSyncIntf: IReadWriteSync;
        FName: string;
     
      private
        // Types Privés
        type
          TLockProc = procedure() of object;
          TLockFunc = function(): Boolean of object;
      private
        // Pointeurs de procédure actifs selon le type de Lock choisi
        FBeginReadProc: TLockProc;
        FEndReadProc: TLockProc;
        FBeginWriteProc: TLockFunc;
        FEndWriteProc: TLockProc;
     
        // Méthodes Privées
        procedure BeginReadByIntf();
        procedure EndReadByIntf();
        function BeginWriteByIntf(): Boolean;
        procedure EndWriteByIntf();
     
        procedure BeginReadByCS();
        procedure EndReadByCS();
        function BeginWriteByCS(): Boolean;
        procedure EndWriteByCS();
     
        {$IFDEF DEBUG_SLT_RWS}
        procedure OutputDebugRWS(const Msg: string); inline;
        {$ENDIF DEBUG_SLT_RWS}
     
      public
        // Constructeurs Publiques
        constructor Create(ALockType: TLockType = rwsltCritical); overload;
        constructor Create(const ALockName: string; ALockType: TLockType = rwsltCritical); overload;
        destructor Destroy(); override;
     
        // Méthodes - Implémentation de IReadWriteSync
        procedure BeginRead();
        procedure EndRead();
        function BeginWrite(): Boolean;
        procedure EndWrite();
     
        // Méthodes
        procedure Acquire();
        procedure Release();
     
        // Propriétés Publiques
        /// <summary>Nom du Synchronizer conçu pour aider au débogage</summary>
        property Name: string read FName;
        /// <summary>Indique le type d'implémentation interne de Lock du Synchronizer</summary>
        property LockType: TLockType read FLockType;
      end;
     
    implementation
     
    {$IFDEF DEBUG_SLT_RWS}
    {$IFDEF MSWINDOWS}
    uses
      Winapi.Windows,
      SLT.Common.Tracing;
    {$ENDIF MSWINDOWS}
    {$ENDIF DEBUG_SLT_RWS}
     
     
     
    const
      RWS_ASSERT_CHECK_LOCK_TYPE = 'Invalid %s.TLockType Value : %d'; // Do not localize
     
    { TSLTReadWriteSynchronizer }
     
    //------------------------------------------------------------------------------
    procedure TSLTReadWriteSynchronizer.Acquire();
    begin
      // Acquire est considéré comme un accès exclusif !
      BeginWrite();
    end;
     
    //------------------------------------------------------------------------------
    procedure TSLTReadWriteSynchronizer.BeginRead;
    begin
      {$IFDEF DEBUG_SLT_RWS}OutputDebugRWS('BEGIN READ ENTER');{$ENDIF DEBUG_SLT_RWS}
      FBeginReadProc();
      {$IFDEF DEBUG_SLT_RWS}OutputDebugRWS('BEGIN READ EXIT');{$ENDIF DEBUG_SLT_RWS}
    end;
     
    //------------------------------------------------------------------------------
    procedure TSLTReadWriteSynchronizer.BeginReadByCS();
    begin
      FCriticalSync.Acquire();
    end;
     
    //------------------------------------------------------------------------------
    procedure TSLTReadWriteSynchronizer.BeginReadByIntf();
    begin
      FReadWriteSyncIntf.BeginRead();
    end;
     
    //------------------------------------------------------------------------------
    function TSLTReadWriteSynchronizer.BeginWrite(): Boolean;
    begin
      {$IFDEF DEBUG_SLT_RWS}OutputDebugRWS('BEGIN WRITE ENTER');{$ENDIF DEBUG_SLT_RWS}
      Result := FBeginWriteProc();
      {$IFDEF DEBUG_SLT_RWS}OutputDebugRWS('BEGIN WRITE EXIT');{$ENDIF DEBUG_SLT_RWS}
    end;
     
    //------------------------------------------------------------------------------
    function TSLTReadWriteSynchronizer.BeginWriteByCS(): Boolean;
    begin
      FCriticalSync.Acquire();
      Result := True;
    end;
     
    //------------------------------------------------------------------------------
    function TSLTReadWriteSynchronizer.BeginWriteByIntf(): Boolean;
    begin
      Result := FReadWriteSyncIntf.BeginWrite();
    end;
     
    //------------------------------------------------------------------------------
    constructor TSLTReadWriteSynchronizer.Create(const ALockName: string; ALockType: TLockType);
    begin
      Create(ALockType);
     
      FName := ALockName;
    end;
     
    //------------------------------------------------------------------------------
    constructor TSLTReadWriteSynchronizer.Create(ALockType: TLockType);
    begin
      inherited Create();
     
      FLockType := ALockType;
      case FLockType of
        rwsltCritical:
          FCriticalSync := TCriticalSection.Create();
     
        rwsltSimple:
          FReadWriteSyncIntf := TSimpleRWSync.Create();
     
        rwsltMREW:
          FReadWriteSyncIntf := TMultiReadExclusiveWriteSynchronizer.Create();
      else
        raise EArgumentOutOfRangeException.CreateFmt(RWS_ASSERT_CHECK_LOCK_TYPE, [ClassName(), Ord(FLockType)]);
      end;
     
      if Assigned(FCriticalSync) then
      begin
        FBeginReadProc := BeginReadByCS;
        FEndReadProc := EndReadByCS;
        FBeginWriteProc := BeginWriteByCS;
        FEndWriteProc := EndWriteByCS;
      end
      else
      begin
        FBeginReadProc := BeginReadByIntf;
        FEndReadProc := EndReadByIntf;
        FBeginWriteProc := BeginWriteByIntf;
        FEndWriteProc := EndWriteByIntf;
      end;
    end;
     
    //------------------------------------------------------------------------------
    destructor TSLTReadWriteSynchronizer.Destroy();
    begin
      FreeAndNil(FCriticalSync);
     
      inherited Destroy();
    end;
     
    //------------------------------------------------------------------------------
    procedure TSLTReadWriteSynchronizer.EndRead();
    begin
      {$IFDEF DEBUG_SLT_RWS}OutputDebugRWS('END READ ENTER');{$ENDIF DEBUG_SLT_RWS}
      FEndReadProc();
      {$IFDEF DEBUG_SLT_RWS}OutputDebugRWS('END READ EXIT');{$ENDIF DEBUG_SLT_RWS}
    end;
     
    //------------------------------------------------------------------------------
    procedure TSLTReadWriteSynchronizer.EndReadByCS();
    begin
      FCriticalSync.Release();
    end;
     
    //------------------------------------------------------------------------------
    procedure TSLTReadWriteSynchronizer.EndReadByIntf();
    begin
      FReadWriteSyncIntf.EndRead();
    end;
     
    //------------------------------------------------------------------------------
    procedure TSLTReadWriteSynchronizer.EndWrite();
    begin
      {$IFDEF DEBUG_SLT_RWS}OutputDebugRWS('END WRITE ENTER');{$ENDIF DEBUG_SLT_RWS}
      FEndWriteProc();
      {$IFDEF DEBUG_SLT_RWS}OutputDebugRWS('END WRITE EXIT');{$ENDIF DEBUG_SLT_RWS}
    end;
     
    //------------------------------------------------------------------------------
    procedure TSLTReadWriteSynchronizer.EndWriteByCS();
    begin
      FCriticalSync.Release();
    end;
     
    //------------------------------------------------------------------------------
    procedure TSLTReadWriteSynchronizer.EndWriteByIntf();
    begin
      FReadWriteSyncIntf.EndWrite();
    end;
     
    //------------------------------------------------------------------------------
    procedure TSLTReadWriteSynchronizer.Release();
    begin
      // Acquire est considéré comme une fin d'accès exclusif !
      EndWrite();
    end;
     
    //------------------------------------------------------------------------------
    {$IFDEF DEBUG_SLT_RWS}
    procedure TSLTReadWriteSynchronizer.OutputDebugRWS(const Msg: string);
    begin
      {$IFDEF MSWINDOWS}
      TSLTDebugLogger.OutputDebugString('[SLT.RWS]', Format('%0:s : %1:s - Thread ID %2:d', [Name, Msg, Winapi.Windows.GetCurrentThreadId()]), True);
      {$ELSE MSWINDOWS}
      {$MESSAGE WARN 'Implémentation de OutputDebugRWS uniquement Windows pour TSLTReadWriteSynchronizer (Utilisation de Winapi.Windows.GetCurrentThreadId'}
      {$ENDIF MSWINDOWS}
    end;
    {$ENDIF DEBUG_SLT_RWS}
     
    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

  13. #13
    Membre du Club

    Inscrit en
    Novembre 2008
    Messages
    69
    Détails du profil
    Informations forums :
    Inscription : Novembre 2008
    Messages : 69
    Points : 62
    Points
    62
    Billets dans le blog
    1
    Par défaut
    je pense que les réponses n'ont pas exactement pris en compte la situation.
    Tous les ordinateurs sont des core I7 quadricœur.
    Il n'y a pas de problème de thread :les essais que je fais sont avec un seul joueur donc avec un seul thread.
    Ce n'est pas non plus un problème de génération d'EDI : les programmes que j'ai faits l'ont été avec Delphi 7 et ils tournent sur les "anciens" ordinateurs pas sur les récents. Je n'ai utilisé Delphi 10.2 que pour essayer de cerner le problème posé sans changer le code initial.
    Il y a donc deux problèmes qui n'ont peut-être qu'une seule cause :
    1. le programme qui tourne sur les anciens ordinateurs ne tourne pas sur les nouveaux
    2. le programme qui tourne dans l'EDI ne tourne pas en compilé

  14. #14
    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 445
    Points
    28 445
    Par défaut
    une violation d'accès hors IDE vient en général du fait qu'en mode debug les variables non initialisées sont généralement à 0, alors qu'elles ont une valeur aléatoire hors IDE...du coup un "if ptr = nil then" va passer en debug, mais pas hors ide.

    pour pour ce genre de problèmes, outre madExcept, j'utilise une console
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    {$IFDEF DEBUG}{$DEFINE LOG}{$ENDIF}
    begin
      {$IFDEF LOG}AllocConsole;{$ENDIF} // ouverture d'une console
      ...
      {$IFDEF LOG}WriteLn('Jusqu''ici tout va bien');{$ENDIF}
      ...
      {$IFDEF LOG}WriteLn('avant appel proc');{$ENDIF}
      proc;
      {$IFDEF LOG}WriteLn('après appel proc');{$ENDIF}
    end;
    et j'ajoute ce genre de choses jusqu'à identifier où ça plante, et je rajoute des affichages de variable pour comprendre ce qu'il se passe.
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  15. #15
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 043
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 67
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 043
    Points : 40 957
    Points
    40 957
    Billets dans le blog
    62
    Par défaut
    Bonjour,

    Je suis d'accord sur un point, pour tester avec 10.2 il faut faire attention au fait qu'il s'agit d'une version unicode et donc faire attention au fait q'un Pchar est devenu un PWidechar et non resté un PAnsiChar.
    En prenant l'application ainsi produite celle-ci plante toujours : le comportement n'est pas le même dans les deux modes.
    la dll est placée où, dans le répertoire de l'application ou dans SYSWOW64 ?
    MVP Embarcadero
    Delphi installés : D3,D7,D2010,XE4,XE7,D10 (Rio, Sidney), D11 (Alexandria), D12 (Athènes)
    SGBD : Firebird 2.5, 3, SQLite
    générateurs États : FastReport, Rave, QuickReport
    OS : Window Vista, Windows 10, Windows 11, Ubuntu, Androïd

  16. #16
    Membre du Club

    Inscrit en
    Novembre 2008
    Messages
    69
    Détails du profil
    Informations forums :
    Inscription : Novembre 2008
    Messages : 69
    Points : 62
    Points
    62
    Billets dans le blog
    1
    Par défaut
    merci de ces conseils : j'ai vérifié qu'il n'y a pas de variables non initialisées si le serveur tourne correctement. Les seules variables sont les conventions qui sont envoyées lors de la connexion du joueur mais s'il y a un problème normalement cela doit déférer en conventions par défaut qui sont elles initialisées.
    Pour tracer où cela plante, j'ai utilisé la fenêtre d'affichage du serveur. J'ai pu vérifier le sous-programme qui invoque la DLL est encadré par un gestionnaire d'erreur. Ce sous-programme se termine normalement = pas d'erreur interrompant son exécution mais que cela se déroute quand même vers la gestion d'erreur. J'ai trouvé cela bizarre mais il y a peut être un problème de timing.
    La DLL est située dans le répertoire de l'application.

  17. #17
    Membre du Club

    Inscrit en
    Novembre 2008
    Messages
    69
    Détails du profil
    Informations forums :
    Inscription : Novembre 2008
    Messages : 69
    Points : 62
    Points
    62
    Billets dans le blog
    1
    Par défaut
    Je viens de faire un nouveau test : j'ai un ordinateur récent (2019) mais avec un processeur AMD Ryzen.
    Sur cet ordinateur ça marche !
    est-ce que cela ne proviendrait pas du CPU Intel ? On m'a dit qu'on y avait mis une protection supplémentaire....
    quelqu'un en sait-il plus à ce sujet ?

  18. #18
    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 445
    Points
    28 445
    Par défaut
    Citation Envoyé par GerardJ Voir le message
    Je viens de faire un nouveau test : j'ai un ordinateur récent (2019) mais avec un processeur AMD Ryzen.
    Sur cet ordinateur ça marche !
    est-ce que cela ne proviendrait pas du CPU Intel ? On m'a dit qu'on y avait mis une protection supplémentaire....
    quelqu'un en sait-il plus à ce sujet ?
    non, mais je n'ai toujours pas compris quelle est la nature de l'erreur...donc difficile de ce prononcer. Je doute que ce soit un pb de processeur.
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  19. #19
    Expert confirmé Avatar de sergio_is_back
    Homme Profil pro
    Responsable informatique, développeur tout-terrain
    Inscrit en
    Juin 2004
    Messages
    1 084
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Responsable informatique, développeur tout-terrain
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Juin 2004
    Messages : 1 084
    Points : 5 604
    Points
    5 604
    Par défaut
    Citation Envoyé par GerardJ Voir le message
    Je viens de faire un nouveau test : j'ai un ordinateur récent (2019) mais avec un processeur AMD Ryzen.
    Sur cet ordinateur ça marche !
    est-ce que cela ne proviendrait pas du CPU Intel ? On m'a dit qu'on y avait mis une protection supplémentaire....
    quelqu'un en sait-il plus à ce sujet ?
    Difficile de répondre comme l'a dit Paul au dessus.
    L'erreur évoquée est une violation d'accès ce qui signifie que le code Delphi (ou la DLL) tente d’accéder vers une zone mémoire non-allouée ou qui est allouée pour autre chose...
    Ce peut être du à un pointeur mal initialisé, un problème d'alignement mémoire, une dépendance manquante (je te l'ai expliqué au-dessus), etc...
    Un problème de synchronisation de threads peut aussi être envisagé, si je comprend bien :

    - En debug tu est mono thread et ça fonctionne
    - En exécution tu est multi-thread et ça plante

    Il est possible que le comportement de tes threads soit légèrement différent sur Intel et AMD mais on rentre dans quelque chose de très fin et personnellement je n'y crois que moyennement

  20. #20
    Membre du Club

    Inscrit en
    Novembre 2008
    Messages
    69
    Détails du profil
    Informations forums :
    Inscription : Novembre 2008
    Messages : 69
    Points : 62
    Points
    62
    Billets dans le blog
    1
    Par défaut
    difficile de croire que c'est une faute de programmation ; les serveurs sont nombreux sur différents ordinateurs et sont sollicités des milliers de fois par jour depuis 12 ans. Une faute de programmation n'aurait pas pu passer inaperçue donc peu probable et ne conduirait pas à une erreur systématique sur des ordinateurs récents. et quand je dis systématique j'ai fait d'innombrables essais qui plante tous.
    Ce n'est pas non plus une question multithread : non seulement je fais des essais avec un seul joueur donc un seul thread, mais en plus l'appli est conçue pour rejeter les demandes lorsqu'elle occupée.
    Il me semblait avoir décrit la nature de l'erreur : violation d'accès en écriture...
    Je commence à me demander si je vais trouver la raison et une solution sur ce forum.. à part remplacer mes vieux ordinateurs par des AMD.

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. erreur OCI.dll
    Par sidharta dans le forum Oracle
    Réponses: 3
    Dernier message: 23/12/2005, 17h10
  2. Erreur => LIBMYSQL.dll
    Par wolfjeremy dans le forum Outils
    Réponses: 2
    Dernier message: 22/12/2005, 15h39
  3. erreur avec dll sous winXP sp2 / IIS5.1
    Par totoche dans le forum ASP
    Réponses: 10
    Dernier message: 12/12/2005, 16h27
  4. Erreur compilation DLL dans Eelphi 6
    Par jakouz dans le forum Langage
    Réponses: 2
    Dernier message: 25/05/2005, 16h38
  5. [C#] Erreur mscoree.dll
    Par Damsou dans le forum Windows Forms
    Réponses: 12
    Dernier message: 20/01/2005, 11h56

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