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

C# Discussion :

Appel d'une DLL C# avec Delphi 7.


Sujet :

C#

  1. #1
    Expert confirmé
    Avatar de popo
    Homme Profil pro
    Analyste programmeur Delphi / C#
    Inscrit en
    Mars 2005
    Messages
    2 674
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Analyste programmeur Delphi / C#
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2005
    Messages : 2 674
    Points : 5 259
    Points
    5 259
    Par défaut Appel d'une DLL C# avec Delphi 7.
    Bonjour,

    Je ne sais pas trop s'il faut que je poste ce message sur le forum Delphi ou celui de C# alors je le mets ici car le code Delphi est standard et fonctionne pour d'autres DLL.

    Ne trouvant pas de librairie en Delphi pour convertir du RTF en HTML, j'ai essayer d'appeler une librairie C# depuis un programme Delphi.
    Cette librairie peut être téléchargée à l'adresse suivante : https://code.msdn.microsoft.com/wind...F-and-aaa02a6e

    Pour ne pas modifier cette librairie j'ai créé une petite DLL qui l'appelle et sur laquelle j'ai ouvert l'interop.
    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
    using MarkupConverter;
    using System;
    using System.Globalization;
    using System.IO;
    using System.Runtime.InteropServices;
     
    namespace XXX.YYY.Services.Converter
    {
        public interface IComMarkupConverter
        {
            String RtfToHtml(String rtfText);
        }
     
        [Guid("708F0B54-3BD1-428E-8905-FE79383B37FF")]
        [ComVisible(true)]
        public class MarkupConverterService : IComMarkupConverter
        {
            /// <summary>
            /// Constructeur par défaut
            /// </summary>
            public MarkupConverterService() { }
     
            /// <summary>
            /// Méthode de conversion d'un contenu RTF vers du HTML
            /// </summary>
            /// <param name="rtfText">Contenu RTF</param>
            /// <returns>Contenu HTML</returns>
            public String RtfToHtml(String rtfText)
            {
                Log("Entering RtfToHtml()");
                Log("RTF Content :" + Environment.NewLine + rtfText);
     
                Log("Creating converter...");
                IMarkupConverter converter = new MarkupConverter.MarkupConverter();
                Log("Converter successfully created");
     
                String result = String.Empty;
                try
                {
                    Log("Calling RTF to HTML conversion method...");
                    result = converter.ConvertRtfToHtml(rtfText);
                    Log("Method return this HTML content :" + Environment.NewLine + result);
                }
                catch (Exception ex)
                {
                    String message = "Method return an exception :" + Environment.NewLine
                        + "Exception message : " + Environment.NewLine
                        + ex.Message + Environment.NewLine
                        + "Exception stack trace : " + Environment.NewLine
                        + ex.StackTrace;
                    Log(message);
                }
     
                return result;
            }
     
            /* CA 1822 :
             * Mark members as static */
            static void Log(String log)
            {
                String logFileName = Path.Combine(Path.GetTempPath(), @"Converter\LogConverter.txt");
                if (File.Exists(logFileName)) File.AppendAllText(logFileName, String.Format(CultureInfo.InvariantCulture, "{0} => {1}",
                    DateTime.Now.ToLongTimeString(), log) + Environment.NewLine);
            }
        }
    }
    Si ça peut servir, j'ai ajouté un log (bien dégueulasse) pour tracer ce qui se passe et le résultat est le suivant :
    15:59:06 => Entering RtfToHtml()
    15:59:06 => RTF Content :
    {\rtf1\ansi\ansicpg1252\deff0\deflang1036{\fonttbl{\f0\fnil\fcharset0 Calibri;}}{\colortbl ;\red255\green0\blue0;}{\*\generator Msftedit 5.41.21.2510;}\viewkind4\uc1\pard\sl240\slmult1\lang12\f0\fs22 Bonjour,\par Test en \cf1 couleur\cf0 , en \b gras\b0 , et en \i italique \i0 sur une m\'eame ligne.\par }
    15:59:06 => Creating converter...
    15:59:06 => Converter successfully created
    15:59:06 => Calling RTF to HTML conversion method...
    15:59:06 => Method return an exception :
    Exception message :
    Overflow or underflow in the arithmetic operation.
    Exception stack trace :
    at System.Windows.Thickness.op_Equality(Thickness t1, Thickness t2)
    at System.Windows.Thickness.Equals(Object obj)
    at System.Object.Equals(Object objA, Object objB)
    at System.Windows.DependencyObject.UpdateEffectiveValue(EntryIndex entryIndex, DependencyProperty dp, PropertyMetadata metadata, EffectiveValueEntry oldEntry, EffectiveValueEntry& newEntry, Boolean coerceWithDeferredReference, Boolean coerceWithCurrentValue, OperationType operationType)
    at System.Windows.StyleHelper.ApplyStyleOrTemplateValue(FrameworkObject fo, DependencyProperty dp)
    at System.Windows.StyleHelper.InvalidateContainerDependents(DependencyObject container, FrugalStructList`1& exclusionContainerDependents, FrugalStructList`1& oldContainerDependents, FrugalStructList`1& newContainerDependents)
    at System.Windows.StyleHelper.DoThemeStyleInvalidations(FrameworkElement fe, FrameworkContentElement fce, Style oldThemeStyle, Style newThemeStyle, Style style)
    at System.Windows.StyleHelper.UpdateThemeStyleCache(FrameworkElement fe, FrameworkContentElement fce, Style oldThemeStyle, Style newThemeStyle, Style& themeStyleCache)
    at System.Windows.FrameworkContentElement.OnThemeStyleChanged(DependencyObject d, Object oldValue, Object newValue)
    at System.Windows.StyleHelper.GetThemeStyle(FrameworkElement fe, FrameworkContentElement fce)
    at System.Windows.FrameworkContentElement.UpdateThemeStyleProperty()
    at System.Windows.FrameworkContentElement.OnInitialized(EventArgs e)
    at System.Windows.FrameworkContentElement.TryFireInitialized()
    at System.Windows.FrameworkContentElement.ChangeLogicalParent(DependencyObject newParent)
    at System.Windows.FrameworkContentElement.AddLogicalChild(Object child)
    at System.Windows.LogicalTreeHelper.AddLogicalChild(DependencyObject parent, Object child)
    at System.Windows.Documents.TextContainer.InsertElementInternal(TextPointer startPosition, TextPointer endPosition, TextElement element)
    at System.Windows.Documents.TextElement.RepositionWithContent(TextPointer textPosition)
    at System.Windows.Documents.TextElementCollection`1.Add(TextElementType item)
    at System.Windows.Controls.RichTextBox..ctor(FlowDocument document)
    at System.Windows.Controls.RichTextBox..ctor()
    at MarkupConverter.RtfToHtmlConverter.ConvertRtfToXaml(String rtfText)
    at MarkupConverter.RtfToHtmlConverter.ConvertRtfToHtml(String rtfText)
    at MarkupConverter.MarkupConverter.ConvertRtfToHtml(String rtfText)
    at XXX.YYY.Services.Converter.MarkupConverterService.RtfToHtml(String rtfText) in c:\Users\ABCDEFGH\Documents\Visual Studio 2013\Projects\Converter\MarkupConverterService.cs:line 66
    Le même RTF (disponible sur la troisième ligne du log précédent) dans une application Windows Form en C# fonctionne avec uniquement ce code.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    IMarkupConverter converter = new MarkupConverter.MarkupConverter();
    return converter.ConvertRtfToHtml(rtfText);
    J'ai pensé au fait que le type String n'est pas le même et que ça pouvait poser problème.
    Cependant, en regardant le log généré, la chaîne à l'air de parfaitement passer.

    J'ai d'ailleurs une autre DLL C# appelée depuis Delphi avec une chaîne en paramètre et qui fonctionne parfaitement.

    Cette DLL est inscrit dans la base de registre avec la ligne de commande suivante :
    Code DOS : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    C:\Windows\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe "C:\Users\ABCDEFGH\Documents\Visual Studio 2013\Projects\Converter\bin\D
    ebug\XXX.YYY.Services.Converter.dll"

    Si ça peut aider voici le code Delphi appelant :
    Code Delphi : 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
    function ExistComObject(Const Identifier : String) : Boolean;
      function ExistGUID(GuidIdentifier : TGUID) : Boolean;
      var ComObject : IUnknown;
      begin
        Result := Succeeded(CoCreateInstance(GuidIdentifier, nil, CLSCTX_INPROC_SERVER or
          CLSCTX_LOCAL_SERVER, IUnknown, ComObject));
      end;
     
    var Guid : TGUID;
    begin
      Result := False;
      FillChar(Guid,SizeOf(TGUID), #0);
      if Succeeded(CLSIDFromProgID(PWideChar(WideString(Identifier)), GUID)) then
        Result:=ExistGUID(GUID);
    end;
     
    procedure TTestForm.RtfToHtmlButtonClick(Sender: TObject);
    var ConverterOleVariant : Variant;
        RtfText, HtmlText : String;
    begin
      RtfText := Rtf.Text;
      if (ExistComObject('XXX.YYY.Services.Converter.MarkupConverterService')) then
      begin
        RtfText := StringReplace(RtfText,#$D#$A,'',[rfReplaceAll]);
        try
          ConverterOleVariant := CreateOleObject('XXX.YYY.Services.Converter.MarkupConverterService');
          HtmlText := ConverterOleVariant.RtfToHtml(RtfText);
          ConverterOleVariant := Unassigned;
          Html.Text := HtmlText;
        except
          on E : Exception do
          begin
            ShowMessage(E.Message);
          end;
        end;
      end;
    end;

  2. #2
    Expert confirmé

    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Septembre 2006
    Messages
    3 580
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Chef de projet NTIC
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Septembre 2006
    Messages : 3 580
    Points : 5 195
    Points
    5 195
    Par défaut
    si tu t'y connais en C#, tu as aussi l'option simple de faire un petit Exe en .Net qui fait la conversion et pour lequel tu l'appelles en passant
    en argument le nom du fichier à convertir..

    Ca me parait "simple" à faire ça (voir plus simple que de faire un wrapper, etc...)
    The Monz, Toulouse
    Expertise dans la logistique et le développement pour
    plateforme .Net (Windows, Windows CE, Android)

  3. #3
    Expert confirmé
    Avatar de popo
    Homme Profil pro
    Analyste programmeur Delphi / C#
    Inscrit en
    Mars 2005
    Messages
    2 674
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Analyste programmeur Delphi / C#
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2005
    Messages : 2 674
    Points : 5 259
    Points
    5 259
    Par défaut
    C'est justement la solution que je voulais éviter.
    L'écriture sur disque est souvent hasardeuse (je pense notamment aux droits sur les fichiers ou sur les dossier, à l'UAC).

    Par contre l'idée de faire un exécutable n'est pas si mauvaise mais passer un contenu RTF sous forme de chaîne directement à un exécutable (ou même à une DLL) et renvoyer un contenu HTML par ce même biais me semble risqué. J'ai peur qu'à un moment l'une des chaînes soit tronquée.

    Je pourrais éventuellement passer par la base de données avec une simple table contenant un GUID pour identifier la demande de conversion, pourquoi pas un code pour gérer quelle conversion je veux réaliser (si les besoins évoluent), et deux champs en texte long. Mais n'est ce pas trop lourd pour ce que je veux faire ?

  4. #4
    Expert confirmé

    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Septembre 2006
    Messages
    3 580
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Chef de projet NTIC
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Septembre 2006
    Messages : 3 580
    Points : 5 195
    Points
    5 195
    Par défaut
    bah après, s'est juste de la communication entre 2 applications...

    Tu peux aussi utiliser les "pipe" de communication pour dialoguer entre les 2 applis aussi... (ou socket, etc...)

    L'intérêt d'éviter le Wrapper est de ne pas avoir à le mettre à jour si le besoin arrive...

    Ne connaissant pas Delphi, je ne pourrais pas trop en dire plus !
    The Monz, Toulouse
    Expertise dans la logistique et le développement pour
    plateforme .Net (Windows, Windows CE, Android)

  5. #5
    Expert confirmé
    Avatar de popo
    Homme Profil pro
    Analyste programmeur Delphi / C#
    Inscrit en
    Mars 2005
    Messages
    2 674
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Analyste programmeur Delphi / C#
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2005
    Messages : 2 674
    Points : 5 259
    Points
    5 259
    Par défaut
    Pour des raisons pas toujours très claires là où je travaille, la construction, la signature et la distribution d'une DLL liée à une application est beaucoup plus simple que pour une autre application. En plus, lorsqu'on discute avec l'offre, il sont assez récalcitrant à l'idée d'avoir à expliquer au clients qu'on a crée un EXE à la place d'une DLL (on peut les comprendre dans une certaines mesure).

    Bon, tout ça pour dire que remplacer ce qui devait être une DLL par un exécutable n'est pas du tout du goût de l'offre et qu'il m'ont demandé de trouver une autre solution.

    En débuguant dans Visual Studio avec l'option "Start external program", je me suis aperçu que la création du RichTextBox (voir la stack trace du premier message) ne passait jamais la première fois mais qu'après c'était bon.

    J'ai donc modifié la librairie d'origine pour mettre une verrue dont je ne suis pas fier mais qui a le mérite de fonctionner.
    J'ai retenté l'opération une trentaine de fois pour m'en assurer.

    J'ai remplacé cette ligne :
    Code C# : Sélectionner tout - Visualiser dans une fenêtre à part
    var richTextBox = new RichTextBox();

    Par ce code
    Code C# : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    RichTextBox richTextBox;
    try { richTextBox = new RichTextBox(); }
    catch { richTextBox = new RichTextBox(); }

    A moins que quelqu'un m'indique une solution plus propre et qui me permettrait de garder le principe de l'appel à une DLL, je passe en résolu.
    Je précise également que si quelqu'un connait une librairie Delphi gratuite et efficace pour le faire, je suis également preneur.

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

Discussions similaires

  1. Réponses: 0
    Dernier message: 18/03/2015, 10h23
  2. Utiliser une dll C# avec delphi
    Par Gruick dans le forum Débuter
    Réponses: 8
    Dernier message: 19/06/2008, 10h23
  3. Chargement d'une dll C++ avec Delphi
    Par rudi0 dans le forum Langage
    Réponses: 6
    Dernier message: 26/08/2007, 19h15
  4. Réponses: 1
    Dernier message: 11/04/2007, 11h45
  5. Erreur lors de l'appel d'une DLL créée avec Visual
    Par WELCOMSMAIL dans le forum C++Builder
    Réponses: 6
    Dernier message: 06/09/2006, 15h53

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