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 :

DLL String Pourquoi ça marche sans BORLNDMM.DLL


Sujet :

Langage Delphi

  1. #1
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 550
    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 550
    Points : 25 120
    Points
    25 120
    Par défaut DLL String Pourquoi ça marche sans BORLNDMM.DLL
    Voici le code (fichier joints), je l'ai testé depuis la machine d'où je poste ce sujet, il n'y jamais eu delphi, il n'y a nulle par non plus BORLNDMM.DLL, et hop mystère contre toute indication suivante, cela fonction SANS soucis :

    Remarque importante concernant la gestion de mémoire de DLL : ShareMem doit
    être la première unité de la clause USES de votre bibliothèque ET de votre projet
    (sélectionnez Projet-Voir source) si votre DLL exporte des procédures ou des
    fonctions qui passent des chaînes en tant que paramètres ou résultats de fonction.
    Cela s'applique à toutes les chaînes passées de et vers votre DLL --même celles
    qui sont imbriquées dans des enregistrements et classes. ShareMem est l'unité
    d'interface pour le gestionnaire de mémoire partagée BORLNDMM.DLL, qui doit
    être déployé avec vos DLL. Pour éviter d'utiliser BORLNDMM.DLL, passez les
    informations de chaînes avec des paramètres PChar ou ShortString
    .
    Ayant nombre de sujet sur ce problème, et n'y ayant jamais été confronté malgré quelques DLL déjà déployé (souvent je fais du PChar par reflexe DLL), mais quand j'ai des formes et des string normal, je m'interroge ...

    Voici, le code d'appel, accompagnant les fichiers ... je pense que le passage en out/var/const des string doit tout changer, puisque cela revient à faire un passage de "PString = ^String;" et non une copie de string avec un passage de paramètre normal (qui rappelons fait une copie de la variable, et pour un objet, je crois que cela fait une copie du pointeur d'instance qui pointe sur l'objet mais cela ne duplique pas l'objet biensur, la duplication n'est valable que pour ordinales, string, array ...), je vais le tester sur la machine neutre dès que j'ai modifié le source sur mon poste de travail habituel (demain ...)

    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
    procedure TFrmTestDivers.WriteStringList(const FileName: string; const Strings: TStrings);
    var
      HandleDLL: HMODULE;
      _WriteStringList: procedure(const FileName: string; const Strings: TStrings); stdcall;
    begin
      HandleDLL := LoadLibrary('DLLTest.dll');
     
      if HandleDLL > 0 then
      begin
        try
          @_WriteStringList := GetProcAddress(HandleDLL, 'WriteStringList');
          if Assigned(@_WriteStringList) then
            _WriteStringList(FileName, Strings);
        finally
          FreeLibrary(HandleDLL);
        end;
      end;
    end;
     
    procedure TFrmTestDivers.BtnWriteStringListInFileClick(Sender: TObject);
    begin
      WriteStringList(EdDLLOutFileName.Text, MemoDLL.Lines);
    end;
     
    procedure TFrmTestDivers.GetDLLForm(out Form: TForm);
    var
      HandleDLL: HMODULE;
      _GetDLLForm: procedure(out Form: TForm); stdcall;
    begin
      HandleDLL := LoadLibrary('DLLTest.dll');
     
      if HandleDLL > 0 then
      begin
        @_GetDLLForm := GetProcAddress(HandleDLL, 'GetDLLForm');
        if Assigned(@_GetDLLForm) then
          _GetDLLForm(Form)
        else
          Form := nil;
        if Assigned(Form) then
        begin
          Form.OnClose := DLLFormClose;
          Form.Tag := HandleDLL;
          Form.Caption := Form.Caption + ' - ' + Application.ExeName;
        end;
      end;
    end;
     
    procedure TFrmTestDivers.FreeDLLForm(const Form: TForm);
    var
      _FreeDLLForm: procedure(const Form: TForm); stdcall;
    begin
      if Form.Tag > 0 then
      begin
        @_FreeDLLForm := GetProcAddress(Form.Tag, 'FreeDLLForm');
        if Assigned(@_FreeDLLForm) then
        begin
          _FreeDLLForm(Form);
          FreeLibrary(Form.Tag);
        end;
      end;
    end;
     
    procedure TFrmTestDivers.SetDLLFormMemo(const Form: TForm; const Lines: string);
    var
      _SetDLLFormMemo: procedure(const Form: TForm; const Lines: string); stdcall;
    begin
      if Form.Tag > 0 then
      begin
        @_SetDLLFormMemo := GetProcAddress(Form.Tag, 'SetDLLFormMemo');
        if Assigned(@_SetDLLFormMemo) then
          _SetDLLFormMemo(Form, Lines);
      end;
    end;
     
    procedure TFrmTestDivers.DLLFormClose(Sender: TObject; var Action: TCloseAction);
    begin
      Action := caHide;
    end;
     
    var
      Form: TForm;
     
    procedure TFrmTestDivers.BtnGetDLLFormClick(Sender: TObject);
    begin
      GetDLLForm(Form);
      Form.Show();
    end;
     
    procedure TFrmTestDivers.BtnFreeDLLFormClick(Sender: TObject);
    begin
      FreeDLLForm(Form);
    end;
     
    procedure TFrmTestDivers.BtnSetMemoDLLFormClick(Sender: TObject);
    begin
      SetDLLFormMemo(Form, MemoDLL.Lines.Text);
    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

  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 448
    Points
    28 448
    Par défaut
    Bon, j'ai reconstitué ton unité de test...ouf

    1) le OnClose fonctionne car il ne fait aucunement référence à Form, c'est juste une méthode avec un paramètre qui est modifié...mais si tu t'amusais à modifier une propriété de Form...badaboum !

    2) le FreeDLLForm plante chez moi sur la ligne FreeLibrary(Form.Tag)...voir ce que je viens de dire en 1

    3) SetDLLFormMemo, ici ça peut paraitre plus surprenant, mais en fait tout est ok. Form est une fiche créer par la DLL qui a tout à fait le droit de la manipuler comme bon lui semble...la chaine que tu envoie en paramètre n'est jamais modifiée par la DLL, là encore aucun soucis...mais essaie de modifier la chaine en retour et badaboum

    4) WriteStringList, c'est encore plus tordu, mais ça fonctionne toujours le DLL se content d'invoquer une méthode de la classe qui manipule une chaine en lecture seule...c'est on ne peux plus casse gueule, mais là encore ça fonctionne car la DLL et l'EXE ne se marchent pas sur les pieds

    en résumé, l'objet de ShareMem est de partager le même gestionnaire de mémoire entre la DLL et l'EXE, sans cela, un objet alloué dans l'un ne peux pas être MODIFIE par l'autre sous peine d'une exception.

    mais il est tout à fait acceptable de retourner une instance de classe de l'un vers l'autre...c'est ce que je fais régulièrement en déclarant différemment la même fonction côté DLL et côté EXE

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    // côté DLL :
    function GetObject:TMonObject; 
    begin
     Result:=TMonObject.Create;
    end;
     
    //côté EXE:
    function GetObject:THandle; external "madll.dll";
    et ce "Handle" est alors utilisé comme suis

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    //côté EXE:
    function DoSomething(TheObject:THandle):HResult; external "madll.dll";
     
    // côté DLL :
    function DoSomething(TheObject:TMonObject):HResult; 
    begin
     Result:=TheObject.DoSomething();
    end;
    Et la fonction indispensable dans ce cas de figure :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    // côté EXE
    procedure FreeObject(Handle:THandle); external "madll.dll"
     
    // côté DLL
     
    procedure FreeObject(TheObject:TMonObject);
    begin
     TheObject.Free;
    end;
    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 550
    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 550
    Points : 25 120
    Points
    25 120
    Par défaut
    Citation Envoyé par tothpaul
    1) le OnClose fonctionne car il ne fait aucunement référence à Form, c'est juste une méthode avec un paramètre qui est modifié...mais si tu t'amusais à modifier une propriété de Form...badaboum !
    Aucun problème directement depuis l'Exe

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    procedure TFrmTestDivers.BtnChangeTitleDirectClick(Sender: TObject);
    begin
      Form.Caption := EdDLLOutFileName.Text;
    end;
    Citation Envoyé par tothpaul
    2) le FreeDLLForm plante chez moi sur la ligne FreeLibrary(Form.Tag)...voir ce que je viens de dire en 1
    Idem aucun soucis, il me permet de stocker la DLL propriétaire de la Form, je n'aurais pas pu faire fonctionner mon programme (je suis en D6 Ent, les deux machines de test son en XP, l'une avec Delphi, l'autre fraichement formatée)
    Citation Envoyé par tothpaul
    3) SetDLLFormMemo, ici ça peut paraitre plus surprenant, mais en fait tout est ok. Form est une fiche créer par la DLL qui a tout à fait le droit de la manipuler comme bon lui semble...la chaine que tu envoie en paramètre n'est jamais modifiée par la DLL, là encore aucun soucis...mais essaie de modifier la chaine en retour et badaboum
    la chaine de SetDLLFormMemo est une Const, donc impossible de modifier la valeur, il est évident que dans le cas d'une modification, il faut utiliser un PChar alloué par l'Exe avec une longueur fixe, comme pour toute API, souvent le problème est de transmettre une chaine que l'on ne modifie pas et j'ai vu souvent ceci comme un problème, ... la phase de modification étant encore plus délicate, mais simple passage de paramètre en const (simule un pointeur), c'est une astuce à savoir ... même si pour le principe je préfère le PChar
    Citation Envoyé par tothpaul
    4) WriteStringList, c'est encore plus tordu, mais ça fonctionne toujours le DLL se content d'invoquer une méthode de la classe qui manipule une chaine en lecture seule...c'est on ne peux plus casse gueule, mais là encore ça fonctionne car la DLL et l'EXE ne se marchent pas sur les pieds
    Effectivement, tout est en param const (donc pointeur sur variable), ...
    Citation Envoyé par tothpaul
    en résumé, l'objet de ShareMem est de partager le même gestionnaire de mémoire entre la DLL et l'EXE, sans cela, un objet alloué dans l'un ne peux pas être MODIFIE par l'autre sous peine d'une exception.
    Pour quoi donc la Form est modifiable de mon côté alors ? C'est ce que je ne comprend pas, et c'est testé sur deux machines différentes, donc tu échange des objets mais tu ne les manipules que d'un seul coté ?
    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
    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 448
    Points
    28 448
    Par défaut
    Citation Envoyé par ShaiLeTroll
    Pour quoi donc la Form est modifiable de mon côté alors ? C'est ce que je ne comprend pas, et c'est testé sur deux machines différentes, donc tu échange des objets mais tu ne les manipules que d'un seul coté ?
    tout dépend de ce que tu fais, il faut bien voir que quand l'executation touche à la fiche de la DLL c'est le code de l'executation qui est exécuté, pas celui de la DLL...tant qu'il sagit d'accéder à un offset dans l'objet pour lire un Handle par exemple et soumettre à Windows ce paramètre y'a pas de soucis

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    procedure TControl.SetTextBuf(Buffer: PChar);
    begin
      Perform(WM_SETTEXT, 0, Longint(Buffer));
      Perform(CM_TEXTCHANGED, 0, 0);
    end;
    mais si tu commences à vouloir modifier les données internet de l'objet Delphi, c'est là que le gestionnaire de mémoire entre en jeu et que tu fais tout planter.

    Au hasard, l'ajoute d'un composant sur la fiche devrait te provoquer l'erreur puisqu'il modifie les listes internes Controls et Components.


    A noter aussi que FastMM utilise une autre technique pour partager le gestionnaire de mémoire, qui ne nécessite pas ShareMem
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  5. #5
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 550
    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 550
    Points : 25 120
    Points
    25 120
    Par défaut
    J'ai regardé FastShareMem et FastMM (en D5, car il permettait d'augmenter la performance avec un grand nombre de thread, et c'était pour remplacer le Memory Manager qu'avait fait le créateur du produit sur lequel nous devions travailler)

    Ensuite, Il n'est pas possible de créer un Bouton, puis que la Classe TButton de l'Exe et TButton de la DLL ne sont pas compatibles (surement un truc RTTI qui différe) , c'est pour cela qu'il faut faire un paquet d'execution (souvent rencontré dès le départ avec le TFont) ...

    simplement comme ceci

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    procedure TFrmTestDivers.BtnAddButtonToFormDirectClick(Sender: TObject);
    begin
      TButton.Create(Form).Parent := Form; 
    end;
    Mais on peut faire ceci dans la DLL

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    procedure NewButton(out Button: TButton); stdcall;
    begin
      Button := TButton.Create(nil);
    end;
    et dans l'Exe

    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
    procedure TFrmTestDivers.BtnAddButtonToFormClick(Sender: TObject);
    var
      Button: TButton;
      _NewButton: procedure(out Button: TButton); stdcall;
    begin
      if Form.Tag > 0 then
      begin
        @_NewButton := GetProcAddress(Form.Tag, 'NewButton');
        if Assigned(@_NewButton) then
        begin
          try
            _NewButton(Button);
            Form.InsertComponent(Button);
            Button.Parent := Form;
          except
            on E: Exception do ShowMessage(E.Message);
          end;
        end;
      end;
    end;
    Cela fonctionne parfaitement ...

    ou encore, plus vicieux, juste en récupérant la bonne classe (celle de la DLL différente de l'Exe)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    procedure GetButtonClass(out AClass: TWinControlClass); stdcall;
    begin
      AClass := TButton;
    end;
    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
     
    procedure TFrmTestDivers.BtnAddButtonToFormByClassClick(Sender: TObject);
    var
      AClass: TWinControlClass;
      _GetButtonClass: procedure(out AClass: TWinControlClass); stdcall;
    begin
      if Form.Tag > 0 then
      begin
        @_GetButtonClass := GetProcAddress(Form.Tag, 'GetButtonClass');
        if Assigned(@_GetButtonClass) then
        begin
          try
            _GetButtonClass(AClass);
            AClass.Create(Form).Parent := Form;
          except
            on E: Exception do ShowMessage(E.Message);
          end;
        end;
      end;
    end;
    Sinon, pourquoi Tag et Caption fonctionne chez moi et pas chez toi, c'est ce qui me pose le plus de problème ... la différence de comportement entre une machine et une autre ... mais sinon, si je fais ma DLL pour le projet prévu au bureau, il n'y a aura pas de manipulation de la Form en direct, voir même, l'application n'aura pas connaissance de la Form en tant qu'Objet mais comme toi, juste un Handle ... et si il y a du passage de chaine, ça sera du PChar
    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
    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 448
    Points
    28 448
    Par défaut
    Citation Envoyé par ShaiLeTroll
    Sinon, pourquoi Tag et Caption fonctionne chez moi et pas chez toi, c'est ce qui me pose le plus de problème ...
    Caption j'ai pas testé, mais ça fait appel à Windows, ce n'est pas une propriété de l'objet Delphi

    quand au Tag, si mon souvenir est bon, tu fais référence à une propriété d'un objet que tu viens de libérer...vu que Tag est juste un offset vers une adresse qui vient d'être libérée...ça peut fonctionner, mais c'est vraiment pas propre
    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 550
    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 550
    Points : 25 120
    Points
    25 120
    Par défaut
    Citation Envoyé par tothpaul
    quand au Tag, si mon souvenir est bon, tu fais référence à une propriété d'un objet que tu viens de libérer...vu que Tag est juste un offset vers une adresse qui vient d'être libérée...ça peut fonctionner, mais c'est vraiment pas propre
    Bien pour le FreeDLLForm, je vais modifier cela pour que FreeDLLForm renvoie le Handle de la DLL, effectivement c'est stupide ... cela fonctionne parce que c'est un integer, avec une méthode ou une string cela aurait planté sévère ...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    procedure TFrmTestDivers.FreeDLLForm(const Form: TForm);
    var
      _FreeDLLForm: function(const Form: TForm): Integer; stdcall;
    begin
      if Form.Tag > 0 then
      begin
        @_FreeDLLForm := GetProcAddress(Form.Tag, 'FreeDLLForm');
        if Assigned(@_FreeDLLForm) then
          FreeLibrary(_FreeDLLForm(Form));
      end;
    end;
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    function FreeDLLForm(const Form: TForm): Integer; stdcall;
    begin
      Result := Form.Tag;
      RemoveToFormManager(Form); // le Free est fait par Remove
    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
    Membre confirmé
    Avatar de gb_68
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2006
    Messages
    232
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Haut Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2006
    Messages : 232
    Points : 546
    Points
    546
    Par défaut
    Bonjour
    Voila un débat qui m'intéresse beaucoup

    En fait, ces histoires de ShareMem & Co ont de quoi laisser perplexe. Après pas mal de recherches voila ce que j'ai cru comprendre (si j'ai faux merci de remettre dans le droit chemin ) :
    • les Dll sont chargés dans l'espace mémoire du processus qui les requière (sauf cas exceptionnels de "Dll distantes" chargées dans un autre processus - chose possible avec COM(+?) je crois - ici hors sujet)
    • la mémoire est donc partagée et accessible par tous les modules (Dll chargées) et par tous les threads
    • l'utilisation de variables et d'objets travers les modules ne posent donc pas de problème, sauf lors de leurs allocations/désallocations/réallocations mémoire.
    • celles-ci se réalisent sans problèmes si elles sont effectués par la même Dll (Dll qui alloue x devra libérer x)
    • dans le cas contraire des problèmes se posent, problèmes dus à l'usage de gestionnaires de mémoire différents
      Pourquoi des gestionnaires différents ?
      • j'ai lu que cela permettrait de gérer un gestionnaire spéciale pour des Dll souvent chargées/déchargées (?) et ainsi de gérer leurs éventuelles fuites mémoires.
      • je pense aussi que comme les Dll peuvent être utilisées par tous les langages, ceux-ci peuvent avoir des gestionnaires mémoires spéciaux (langage fonctionnel avec gc ?)
      • sûrement d'autres ... si quelqu'un les connait ...
    • certains types font des allocations/désallocations/réallocations de manière "discrète" (les tableau dynamiques et notamment les strings), donc cela peut poser des problèmes


    Je crois bien que vous utilisez des versions antérieures de Delphi, mais l'info est intéressante : Delphi 2006 propose un nouveau gestionnaire de mémoire
    http://dn.codegear.com/article/33416
    ainsi qu'une unité SimpleShareMem.pas que l'on peut substituer à ShareMem (ne nécessitant pas BORLNDMM.DLL) dont voici le code (licence MPL 1.1)
    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
    { *********************************************************************** }
    {                                                                         }
    {  Borland Delphi Memory Manager                                          }
    {                                                                         }
    {  Copyright (c) 2005 Borland Software Corporation                        }
    {                                                                         }
    {  Portions created by Pierre le Riche are                                }
    {   Copyright (c) Pierre le Riche / Professional Software Development     }
    {                                                                         }
    {  Acknowledgement: With special thanks to the Fastcode community and     }
    {   supporters for their valuable input and feedback.                     }
    {                                                                         }
    {                                                                         }
    { *********************************************************************** }
     
    (* ***** BEGIN LICENSE BLOCK *****
     * Version: MPL 1.1
     *
     * This memory manager implementation is subject to the
     * Mozilla Public License Version 1.1 (the "License"); you may
     * not use this file except in compliance with the License.
     * You may obtain a copy of the License at http://www.mozilla.org/MPL/
     *
     * Software distributed under the License is distributed on an "AS IS" basis,
     * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
     * for the specific language governing rights and limitations under the
     * License.
     *
     * ***** END LICENSE BLOCK ***** *)
     
    unit SimpleShareMem;
     
    interface
     
    implementation
     
    initialization
      {Try to use a shared memory manager. If one is not available, start sharing
       the current one.}
      If not AttemptToUseSharedMemoryManager then
        ShareMemoryManager
     
    end.
    AttemptToUseSharedMemoryManager et ShareMemoryManager sont dans getmem.inc (aussi MPL 1.1) alors peut être importables dans les anciens Delphi.

    Voila, si j'ai dis des bêtises , n'hésitez pas !

    p.s. SimpleShareMem testé, .... ça fonctionne !!!!

  9. #9
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 550
    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 550
    Points : 25 120
    Points
    25 120
    Par défaut
    Je déterre ce vieux sujet, toujours String et DLL !

    Dans le développement de plusieurs DLL, l'allocation des Chaines est effectué par la DLL surtout lorsque ces chaines sont les membres d'un record (évidemment, il est nécessaire depuis le programme d'appeler la fonction de récupération de la structure avec un try..finally avec une fonction de release)

    comme

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    StructSearc := Search(Params): TStructSearch;
    try
     ..
    finally
      CloseSearch(StructSearc);
    end;
    TStructSearch contient différents éléments, des entiers, des PChar, des tableaux dynamiques de PChar ...

    c'est sur le modèle FindFirst\FindClose finalement !

    j'ai donc ces fonctions en interne pour recopier mes String Pascal en PChar en Delphi 7 (vous m'excusez pour le + 1 )

    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
    procedure AffectString(var P: PAnsiChar; const S: AnsiString);
    var
      LenS: Integer;
    begin
      FreeString(P); // On Réalloue un autre pointeur, donc on libère le précédent et on le met à nil
     
      if Value <> '' then // on considère '' comme nil
      begin
        LenS := Length(S);
        GetMem(P, LenS + 1); // Je reste maître de ma mémoire !
        CopyMemory(P, @S[1], LenS);
        PByte(Integer(P) + LenS)^ := 0;
      end;
    end;
     
    procedure FreeString(var P: PChar);
    begin
      if Assigned(P) then
        FreeMem(P);
     
      P := nil;
    end;
    J'ai fait des objets COM encapsulant des DLL (pour un partenaire ne connaissant que le .NET) et donc j'ai aussi les versions WideString

    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
    procedure FreeWideString(var P: PWideChar);
    begin
      if Assigned(P) then
        FreeMem(P);
     
      P := nil;
    end;
     
    procedure AffectWideString(var P: PWideChar; const S: WideString);
    var
      LenP: Integer;
    begin
      FreeWideString(P); // On Réalloue un autre pointeur, donc on libère le précédent et on le met à nil
     
      if Value <> '' then // on considère '' comme nil
      begin
        LenP := Length(S) * SizeOf(WideChar); // Wide !!!
        GetMem(P, LenP + SizeOf(WideChar)); // Je reste maître de ma mémoire de la chaine, y compris le zéro terminal !
        CopyMemory(P, @S[1], LenP);
        PWord(Integer(P) + LenP)^ := 0; // Zéro Terminal
      end;
    end;
    Les Chaines passées en paramètres sont à 95% des variables locales, donc une fois la fonction terminée, elles sont libérés, c'est pour cela que je veux une véritable COPIE de la chaine dans un PChar et pas juste un transtypage comme on le fait souvent pour l'appel d'API car de toute façon la zone mémoire est toujours valable durant l'appel ... mais dans mon cas, la chaine d'origine peut disparaitre ...

    Confirmez vous déjà que l'on peut remplacer le CopyMemory par StrPLCopy
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
        CopyMemory(P, @S[1], LenS);
        PByte(Integer(P) + LenS)^ := 0;
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    StrPLCopy(P, S, Count);
    Je voulais savoir déjà, existe qu'il existe un StrPLCopy pour Wide ?

    Je voulais savoir si je suis parano et qu'il existe un moyen plus simple pour copier une chaine pascal vers un PChar sans que celui-ci soit dépendant de la chaine d'origine (compteur de ref et autre bidule)
    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
    Expert confirmé

    Profil pro
    Leader Technique
    Inscrit en
    Juin 2005
    Messages
    1 756
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France, Rhône (Rhône Alpes)

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

    Informations forums :
    Inscription : Juin 2005
    Messages : 1 756
    Points : 4 173
    Points
    4 173
    Par défaut
    Les règles concernant les string Delphi et les DLL ne s'appliquent pas de la même façon pour les WideString.

    Le type widestring n'est pas seulement une chaîne unicode, c'est aussi une entité conçue pour être compatible BSTR.
    C'est la raison pour laquelle il n'y a pas de comptage de référence sur les WideStrings, et détail non négligeable : Elles ne sont pas allouées sur le gestionnaire de mémoire standard de Delphi mais sur le gestionnaire de mémoire COM (IMAlloc, CoGetMalloc).
    La particularité de ce dernier c'est qu'il est partagé. C'est déjà une sorte de ShareMem à lui tout seul.
    Ainsi une DLL peut très bien allouer une chaîne de caractères qui sera finallement libérée par une autre, ou même par l'application qui l'utilise.

    Pour tes assembly .NET qui appellent la DLL, je pense que tu dois pouvoir te contenter de déclarer des paramètres de type Widestring, puis au moment de la déclaration de la fonction dans .NET, demander le marshaling en BSTR pour le paramètre (qui doit d'ailleurs être celui par défaut, déclare simplement le paramètre en string).

    Jette un coup d'oeil à :
    http://msdn.microsoft.com/en-us/libr...stringsanchor5

  11. #11
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 550
    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 550
    Points : 25 120
    Points
    25 120
    Par défaut
    Merci Franck SORIANO, mais je conserve des prototypes de fonctions compatible avec le C\C++, disons que je préfère clairement utiliser des PWideChar (LPWSTR) que des WideString (BSTR) ... tout simplement parce LPWSTR est nettement plus utilisé dans les API Windows ...

    Par contre, je connaissais vaguement le principe d'allocation des WideString, je savais qu'elles étaient spéciales puisque compatible COM (j'ai aussi cherché un peu dans l'unité ActiveX et SysAllocString), et j'avais discuté avec Reisubar de la différence UnicodeString de Delphi 2009 avec compteur de Ref, ... et les WideString géré bcp simplement directement dans Windows.

    Pour les Assembly.NET, je leur fourni un objet COM encapsulant la DLL, donc je passe des WideString effectivement, ce n'était d'ailleurs pas mon problème ... et les records sont gérés par des interfaces (je fais une copie des PChar vers des String, et je libère au plus vite celle de la DLL, tout en conservant la copie dans l'objet COM)

    Au final, tu ne réponds à aucune de mes questions :
    - StrPLCopy en Version Wide
    - Copie de String vers PChar ou WideString vers PWideChar sans devoir faire soi même les GetMem\CopyMemory ...
    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

  12. #12
    Membre chevronné
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    1 486
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Mai 2004
    Messages : 1 486
    Points : 2 082
    Points
    2 082
    Par défaut
    Bonjour,

    Je voulais savoir si vous auriez trouvé une réponse à ces questions. Aujourd'hui obligé d'utiliser une classe réalisée sous delphi 7 en .NET qui utilise du WideString à tout va, je n'ai pas trouvé une seule fonction capable de s'occuper de la copie en mémoire pour ces strings.

    J'avoue patauger un peu pour le moment mais un wrapper objet COM contenant une copie par valeur des strings Delphi semble être la seule solution.

  13. #13
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 550
    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 550
    Points : 25 120
    Points
    25 120
    Par défaut
    Quelle est vraiement ta problématique ?
    en plus Delphi 7 en .NET ça me choque, 2007 non ?

    Ouvre plutôt une autre discussion, ma question est plus rhétorique que pratique, je n'avais pas de problème mais je me posais la question sur le mot clé const et le type string avec les DLL ...

    moi j'ai tellement l'habitude mapper des DLL avec PChar par des ActiveX en WideString, j'adore pondre des trucs tordus pour gérer ce genre de chose ...
    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

  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 448
    Points
    28 448
    Par défaut
    j'imagine qu'il veux utiliser sous .Net un ActiveX réalisé avec Delphi 7
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  15. #15
    Membre chevronné
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    1 486
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Mai 2004
    Messages : 1 486
    Points : 2 082
    Points
    2 082
    Par défaut
    Exact. Désolé pour le petit HS. J'avais déjà créé une discussion dans Managé/Natif pour mon problème qui n'a pas déchaîné les foules.

Discussions similaires

  1. Réponses: 5
    Dernier message: 04/01/2008, 09h55
  2. Débutant Borlndmm.dll requises
    Par ducelier dans le forum C++Builder
    Réponses: 14
    Dernier message: 12/10/2006, 16h26
  3. DLL borlndmm.dll et cc3270mt.dll requises
    Par Nebelmann dans le forum C++Builder
    Réponses: 13
    Dernier message: 26/06/2006, 13h47
  4. DLL BORLNDMM.DLL
    Par masseur dans le forum C++Builder
    Réponses: 1
    Dernier message: 10/05/2005, 12h57
  5. [Execution] qtintf70.dll Mais pourquoi?
    Par Pedro dans le forum EDI
    Réponses: 4
    Dernier message: 03/06/2004, 13h23

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