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 :

Ecriture en mémoire partagée Delphi10


Sujet :

Langage Delphi

  1. #1
    Membre du Club
    Inscrit en
    Novembre 2004
    Messages
    84
    Détails du profil
    Informations forums :
    Inscription : Novembre 2004
    Messages : 84
    Points : 42
    Points
    42
    Par défaut Ecriture en mémoire partagée Delphi10
    Bonjour,
    J'ai une procédure d'écriture en mémoire partagée qui fonctionne très bien sous Delphi7 mais ne fonctionne pas sous Delphi10.
    Il s'agit d'écrire en mémoire partagée une chaine de quelques caractères.
    Avec Delphi10, je n'écris que le premier caractère de la chaine ! Pourquoi ? Je ne sais pas.
    Je pense qu'il s'agit d'un problème entre String et AnsiString ou Char et AnsiChar ou de longueur de chaine mais je ne vois pas où.
    Je vous soumets la procédure D7 :

    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
    procedure TForm1.WriteInSharedMemory(const lpLine:string);
    var
       lpData: Pointer; //pointeur sur la mémoire partagée
    begin
       //on prend possession du mutex pour écrire et empêcher les autres d'écrire
       waitForSingleObject(hMutex,3000); //on attend 3 sec maximum
       lpData:=MapViewOfFile(hSharedMemory,FILE_MAP_WRITE,0,0,SizeOf(Char)*Length(lpLine)+4);
       if lpData=nil then
       begin
          PanelLastError.caption:='Echec d''écriture en mémoire partagée';
          exit;
       end;
       //on écrit la longueur de la chaine dans les 32 premiers bits de la mémoire partagée
       Integer(lpData^):=SizeOf(Char)*Length(lpLine);
       //on écrit la chaine
       CopyMemory(Pointer(Integer(lpData)+4),PChar(lpLine),SizeOf(Char)*Length(lpLine));
       //on signale qu'on finit d'écrire
       UnMapViewOfFile(lpData);
       //on signale l'évènement aux autres applis
       PulseEvent(HEvent);
       //on libère le Mutex pour que les autres puissent écrire
       ReleaseMutex(hMutex);
    end;
    Si quelqu'un peut me corriger ça pour que ça marche avec D10, je l'en remercie par avance pour l'aide
    Gab

  2. #2
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 709
    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 709
    Points : 25 592
    Points
    25 592
    Par défaut



    Pense que la mémoire D7 est écrite et lue avec une chaine ANSI alors que D10 va utiliser une chaine UNICODE
    Si les deux sont en 32 bits, ça peut fonctionner (je en crois pas que l'on puisse avoir de la mémoire partagée en 32/64) mais D7 pourra confondre un caractère Zéro qui est juste la paire dans l'unicode comme une fin prématurée

    Il te faut donc veiller en D10 de convertir en ANSI (ou UTF8) pour fournir des char sur un octet, D7 pourra lire aussi du ANSI ou UTF8
    Tu peux aussi utiliser un WideString (alloué sur le COM) qui est en UNICODE qui existe en D7 qui permettra à D7 de recevoir des chaines venant de D10

    Quoi qu'il arrive, tu devras avoir des versions de code différentes pour l'un et l'autre, la façon d'encoder en UTF8 n'est pas la même en D7 et D10

  3. #3
    Membre du Club
    Inscrit en
    Novembre 2004
    Messages
    84
    Détails du profil
    Informations forums :
    Inscription : Novembre 2004
    Messages : 84
    Points : 42
    Points
    42
    Par défaut
    Merci pour la réponse. En effet, après conversion en AnsiString de la chaine à écrire, je récupère bien la totalité de la chaine dans la mémoire partagée.
    Par contre, maintenant c'est la partie lecture de la mémoire partagée qu'il faut je reprenne. Je récupère des caractères chinois au lien de récupérer des caractères locaux ! La portabilité de D7 à D10 n'est pas toujours évidente ...
    Merci encore.
    Gab

  4. #4
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 831
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 831
    Points : 13 579
    Points
    13 579
    Par défaut
    Attention aussi à la gestion du mutex qui devrait être incluse dans un bloc try..finally. Ici il ne sera jamais libéré si MapViewOfFile échoue et si les autres theads ont le même TimeOut ça ne fera que retarder la lecture/écriture de 3s... sans verrouillage.

  5. #5
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 709
    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 709
    Points : 25 592
    Points
    25 592
    Par défaut
    A mon avis, le mieux c'est de passer en UTF8, ce n'est pas le plus rapide mais le moins génant

    D7 c'est AnsiToUtf8 et Utf8ToAnsi et le type de chaine UTF8String
    D10 c'est TEncoding.UTF8 GetBytes et GetString, du String et du TBytes

    Au lieu d'échanger du AnsiChar, tu échange du Byte, c'est plus explicite

    D'ailleurs, j'aurais tendance à utiliser un packed record pour échanger les données pour être plus carré

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    TDataString = packed record
      Len: Integer;
      Memory: Pointer;
      CharSet: Byte; // 0 Ansi, 1 UTF8, 2 Unicode
    end;
    Et dans le cas, tu peux ainsi envoyer et recevoir différents type de chaine, tu auras couvert toutes les situations
    Typiquement,
    Delphi 7 envoie du Ansi, c'est D10 qui assume la conversion
    Delphi 10 envoie de l'Unicode, c'est D7 qui assume la conversion


    Si tu fournisse le code pour produire les handles, je peux bien t'écrire une version D10 fonctionnelle que je devrais pouvoir rendre compatible D7 (sans pouvoir la tester, je l'ai plus)

  6. #6
    Membre du Club
    Inscrit en
    Novembre 2004
    Messages
    84
    Détails du profil
    Informations forums :
    Inscription : Novembre 2004
    Messages : 84
    Points : 42
    Points
    42
    Par défaut
    Merci pour tout. J'ai aussi repris la procédure de lecture de la mémoire partagée. Même topo qu'avec l'écriture : micmac entre ansi et unicode (et sizeof(char) en plus..) Bon pour pour l'instant ça re-partage correctement entre applis D7 et applis D10. ça me saoule un peu tout ça ...

  7. #7
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 831
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 831
    Points : 13 579
    Points
    13 579
    Par défaut
    Puisque tu veux rester compatible D7, pourquoi ne pas simplement passer par un type ShortString en D10 ?

    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
    hSharedMemory := CreateFileMapping(INVALID_HANDLE_VALUE, nil, PAGE_READWRITE, 0, SizeOf(ShortString), nil);
     
    procedure Write(const Value :string);
    var
      Data :PShortString;
    begin
      WaitForSingleObject(hMutex, INFINITE);
     
      try
        Data := MapViewOfFile(hSharedMemory, FILE_MAP_WRITE, 0, 0, SizeOf(ShortString));
     
        if not Assigned(Data) then
          RaiseLastOSError;
     
        Data^ := Value;
        UnMapViewOfFile(Data);
     
      finally
        ReleaseMutex(hMutex);
      end;
    end;
     
    function Read :string;
    var
      Data :PShortString;
    begin
      WaitForSingleObject(hMutex, INFINITE);
     
      try
        Data := MapViewOfFile(hSharedMemory, FILE_MAP_READ, 0, 0, SizeOf(ShortString));
     
        if not Assigned(Data) then 
          RaiseLastOSError;
     
        Result := Data^;
        UnMapViewOfFile(Data);
     
      finally
        ReleaseMutex(hMutex);
      end;
    end;

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 17
    Dernier message: 02/02/2006, 13h03
  2. Mémoire swap et mémoire partagée
    Par Invité dans le forum Administration système
    Réponses: 6
    Dernier message: 16/12/2005, 17h39
  3. création d'objet en mémoire partagé
    Par BigNic dans le forum C++
    Réponses: 6
    Dernier message: 28/11/2005, 19h41
  4. Ecriture en mémoire
    Par trax44 dans le forum Assembleur
    Réponses: 2
    Dernier message: 25/10/2005, 15h07
  5. [CR][paradox] mémoire partagée disponible insuffisante !
    Par AGT dans le forum SAP Crystal Reports
    Réponses: 2
    Dernier message: 24/03/2004, 15h27

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