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 .NET Discussion :

Intégration DLL Win32


Sujet :

Delphi .NET

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Août 2008
    Messages
    20
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 20
    Points : 11
    Points
    11
    Par défaut Intégration DLL Win32
    Bonjour,
    je début en Delphi.NET, et j'aimerais réutilisé une DLL Win32 dans mon Application Fiche VCL pour Delphi.NET.
    J'ai lu l'aide ici, mais j'ai du mal à le mettre en pratique.
    Pour l'instant mon projet est vide :
    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
    unit Unit1;
     
    interface
     
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs;
     
    type
      TForm1 = class(TForm)
      private
        { Déclarations privées}
      public
        { Déclarations publiques}
      end;
     
    var
      Form1: TForm1;
     
    implementation
     
    {$R *.nfm}
     
    end.
    Quelqu'un pourrait-il me donner un exemple de code complet pour l'intégration d'une DLL, que je puisse voir à quel endroit et comment l'intégrer ?

    Merci d'avance

  2. #2
    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
    Regarde comment est fait l'unité Windows.pas, des appels de DLL il n'y a que ça dedans ... sinon la fonction recherche du forum ...
    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

  3. #3
    Rédacteur


    Profil pro
    Inscrit en
    Janvier 2003
    Messages
    7 171
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2003
    Messages : 7 171
    Points : 15 060
    Points
    15 060
    Billets dans le blog
    1
    Par défaut
    Salut,
    Citation Envoyé par Jognu Voir le message
    Bonjour,
    J'ai lu l'aide ici, mais j'ai du mal à le mettre en pratique.
    C'est à dire ?

  4. #4
    Membre à l'essai
    Profil pro
    Inscrit en
    Août 2008
    Messages
    20
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 20
    Points : 11
    Points
    11
    Par défaut
    En fait, je viens de voir que j'avais un fichier Interface.pas et types.pas fournis avec la dll.
    Du coup si je les inclus à mon projet je peux appeler les fonctions.
    Le seul problème c'est que vu qu'ils sont prévus pour Win32, je n'arrive pas à les compiler dans mon projet.

    J'ai deux erreurs :
    [Pascal Erreur] Interface.pas(70): E2410 Les variables pointeur, les paramètres ou les constantes non protégés sont autorisés uniquement dans une procédure non protégée
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    // procedure permettant de lier une procédure
    procedure DllGetProc(var PointeurProcedure: Pointer; const NomProcedure: string);
    Et deux :
    [Pascal Erreur] Interface.pas(163): E2089 Transtypage incorrect
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    DllHandle := LoadLibrary(PChar(nomDll));
    et :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    PointeurProcedure := GetProcAddress(DllHandle, PChar(NomProcedure));
    En réglant ces erreurs est-ce que je peux utiliser la dll sans passer par du VLI ?

    J'ai aussi essayé la deuxième méthode du lien, mais quand je créé mon interface, si ma fonction est :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    function TDLL_existe(const identifiant: TCodeUtilisateur): TAuthRetour;
    Il ne connaît pas TCodeUtilisateur et TAuthRetour.

    EDIT : si j'inclus types.pas à mon projet il les reconnaît. C'est la bonne méthode ?

  5. #5
    Rédacteur


    Profil pro
    Inscrit en
    Janvier 2003
    Messages
    7 171
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2003
    Messages : 7 171
    Points : 15 060
    Points
    15 060
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Jognu
    Le seul problème c'est que vu qu'ils sont prévus pour Win32, je n'arrive pas à les compiler dans mon projet.
    Le code dont tu disposes ne prend pas en charge la compilation sous les 2 plateformes. Il ne te présente que la partie publique des classes, enfin à prioris vu les nom des unités citées.
    Mieux vaut utiliser les appels P/Invoke.

    Citation Envoyé par Jognu
    Il ne connaît pas TCodeUtilisateur et TAuthRetour.
    Moi non plus
    Ces classes sont-elles déclarées qq part ?

    Si c'est possible joint ta DLL et ces fichiers .pas.

  6. #6
    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 Jognu Voir le message
    EDIT : si j'inclus types.pas à mon projet il les reconnaît. C'est la bonne méthode ?
    Bien sur, c'est comme les fichiers .h en C++, un fichier Header, contenant les structures utilisées comme paramètre des fonctions, ainsi que les proprototypes de ces mêmes fonctions, donc tes fichiers interfaces et types sont tes équivalents du Header C++,
    EDIT : Types.pas, c'est une unité de Delphi, j'espère que ton unité s'appelle autrement !

    par contre, dans ton Delphi.Net, faut que tu cherche comment déclarer un code "unsafe" comme on peut le faire en C#, P/Invoke (System.Runtime.InteropServices ) est l'une des méthodes pour que le GC ne foute pas le bazard dans les DLL Win32 que tu souhaites utiliser

    L'autre solution, est de faire en Delphi Win32, un ActiveX qui encaspule la DLL Win32 (tu peux ainsi utiliser sans effort interfaces.pas et types.pas, sans devoir te palucher la syntaxe à la con DLLImport .Net), tu redéfinis les fonctions que tu as besoin en SafeCall dans ton Interface de l'ActiveX, ainsi tu peux recenser dans la bibliothèque des assembly cet ActiveX, le GC n'y verra que du feu ! mais cela revient à faire la méthode VLI ...
    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

  7. #7
    Membre à l'essai
    Profil pro
    Inscrit en
    Août 2008
    Messages
    20
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 20
    Points : 11
    Points
    11
    Par défaut
    Citation Envoyé par ShaiLeTroll Voir le message
    Bien sur, c'est comme les fichiers .h en C++, un fichier Header, contenant les structures utilisées comme paramètre des fonctions, ainsi que les proprototypes de ces mêmes fonctions, donc tes fichiers interfaces et types sont tes équivalents du Header C++,
    EDIT : Types.pas, c'est une unité de Delphi, j'espère que ton unité s'appelle autrement !

    par contre, dans ton Delphi.Net, faut que tu cherche comment déclarer un code "unsafe" comme on peut le faire en C#, P/Invoke (System.Runtime.InteropServices ) est l'une des méthodes pour que le GC ne foute pas le bazard dans les DLL Win32 que tu souhaites utiliser

    L'autre solution, est de faire en Delphi Win32, un ActiveX qui encaspule la DLL Win32 (tu peux ainsi utiliser sans effort interfaces.pas et types.pas, sans devoir te palucher la syntaxe à la con DLLImport .Net), tu redéfinis les fonctions que tu as besoin en SafeCall dans ton Interface de l'ActiveX, ainsi tu peux recenser dans la bibliothèque des assembly cet ActiveX, le GC n'y verra que du feu ! mais cela revient à faire la méthode VLI ...
    D'accord, merci pour ces renseignements !
    Donc je vais inclure le fichier types, et je vais utiliser la méthode VLI pour faire ça. J'ai déjà commencé, je continue demain et je vous tiens au courant

    EDIT :
    alors, j'ai fait comme la méthode VLI dans la FAQ, mais ça ne fonctionne pas.
    Dans uses j'ai bien inclus Borland.Vcl.Win32 et mon .pas types (jusque là ça marche).
    Juste après les uses j'ai mis :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
      type
     IWin32DLLInt = interface
      function StrToCodeUtilisateur(const chaine: shortString): TCodeUtilisateur;
     end;
    Il reconnaît TCodeUtilisateur.

    Ensuite je teste à la création de ma form :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    procedure Tfenetre_principale.FormCreate(Sender: TObject);
    var MyDLL      : String;        // Nom complet de la DLL
        MyWin32DLL : IWin32DLLInt; // Interface contenant les fonctions exportées et non managées
         retour     : TCodeUtilisateur;
     
        begin
        MyDLL := ExtractFilePath(Application.ExeName) +'dll\Cnx.dll';
        ShowMessage(MyDLL);
     // Appel à travers l'interface
      if not SysUtils.Supports(MyDLL, IWin32DLLInt, MyWin32DLL)
      then ShowMessage('Ne peut charger Cnx.dll') // Erreur
      else retour := MyWin32DLL.StrToCodeUtilisateur('test');  // Appel de la fonction de la DLL non-managée
     
    end;
    Et quand je lance j'obtiens le message "Ne peut charger Cnx.dll".
    L'erreur est :
    La référence d'objet n'est pas définie à une instance d'un objet.
    Je dois me tromper quelque part, mais je ne vois pas où !

    EDIT 2:
    j'ai testé la méthode P/Invoke (puisque à priori elle marcherait aussi très bien pour ce que je veux faire).
    Ca me donne :
    La signature de la fonction :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    function NomUtilParCode(const identifiant: TCodeUtilisateur): ShortString;
    Dans mon code : (TCodeUtilisateur correspond en fait à un ShortString)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    [DllImport('Cnx.dll', CharSet = CharSet.Auto, EntryPoint = 'NomUtilParCode')]
    Function NomUtilParCode (const identifiant :string):string; external;
    Dans ma fonction :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    retour := NomAppParCode('test');
    A l'exécution j'obtiens aussi comme message d'erreur :
    La référence d'objet n'est pas définie à une instance d'un objet.
    Ca vient au moment du :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    retour := NomAppParCode('test');
    D'où peut venir cette erreur ?

    Merci

  8. #8
    Membre à l'essai
    Profil pro
    Inscrit en
    Août 2008
    Messages
    20
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 20
    Points : 11
    Points
    11
    Par défaut
    Je me permet de faire un double post, parce qu'à force d'éditer celui d'au-dessus on y comprend plus grand chose.

    J'ai tenté de faire un ActiveX en Win32 (dans un premier temps sans encapsuler la DLL).
    Est-ce normal que si je le compile je ne puisse pas l'importer dans mon projet .NET ? (il me fait la même erreur que si j'essaye d'importer la DLL Win32).
    Sinon j'ai cherché comment encapsuler la DLL, mais il n'y a malheureusement pas beaucoup de doc à ce sujet. Je dois importer la DLL dans l'activeX comme je le ferais pour un projet Win32 ?

  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
    As-tu fais un RegSrv32 de ton ActiveX avant de tenter de l'importer dans l'Assembly .NET ? As-tu bien mis un objet dedans avec une Interface ? (Nouvel ActiveX puis une fois le projet DLL créée, Nouvel Objet Automation, voir ICI, d'ailleurs, une idée saugrenue mais potentiellement jouable , pourrait-on ajouter un Nouvel Objet Automation directement dans la DLL Win32 ? faudrait essayer ça en rajoutant les 4 exports DllGetClassObject, DllCanUnloadNow, DllRegisterServer, DllUnregisterServer, je n'ai jamais tenté, mais pourquoi pas !)


    Sinon pour Encaspsuler la DLL, il faut refaire sous la forme d'une Interface tous les appels de fonctions de la DLL avec les conventions COM et SafeCall (attention au valeur retour de type interface, voir ICI, au début, je me suis fourvoyé, la solution étant à la fin, mais le cheminement est tout aussi important)

    Bon Boulot, tu as du travail, ...
    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 à l'essai
    Profil pro
    Inscrit en
    Août 2008
    Messages
    20
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 20
    Points : 11
    Points
    11
    Par défaut
    Citation Envoyé par ShaiLeTroll Voir le message
    As-tu fais un RegSrv32 de ton ActiveX avant de tenter de l'importer dans l'Assembly .NET ? As-tu bien mis un objet dedans avec une Interface ? (Nouvel ActiveX puis une fois le projet DLL créée, Nouvel Objet Automation, voir ICI, d'ailleurs, une idée saugrenue mais potentiellement jouable , pourrait-on ajouter un Nouvel Objet Automation directement dans la DLL Win32 ? faudrait essayer ça en rajoutant les 4 exports DllGetClassObject, DllCanUnloadNow, DllRegisterServer, DllUnregisterServer, je n'ai jamais tenté, mais pourquoi pas !)
    Merci pour tous ces renseignements !
    Je n'avais effectivement par créer d'objet Automation ni fait le regsvr32, maintenant ça marche.
    J'ai tenté d'ajouter l'objet automation dans la DLL Win32 pour tester ton idée.
    L'objet n'est pas proposé dans la palette d'outil, je l'ai donc créer dans le projet ActiveX.
    J'ai ensuite importer les deux fichier (un _TLB et le unit) dans mon projet DLL Win32 et j'ai rajouté les exports. Ça compile sans erreurs, en revanche quand je fais le regsvr32 j'obtiens des erreurs :
    L'exception Exception logicielle inconnue (0x0eedfade) s'est produite dans l'application à l'emplacement 0x7c812aeb
    puis
    Runtime error 217 at 00963131
    puis
    LoadLibrary("dllwin32.dll") a échoué - Une routine d'initialisation d'une libraire dynamique (DLL) a échoué.
    Si tu as une idée pour tenter de le faire marcher dis le moi j'essayerai.

    En attendant je pars sur la méthode "normal" !

    EDIT :
    Question bête :
    Je fais une interface dans mon activeX pour les appels de fonction, mais dans l'interface on place uniquement la signature de la fonction non ?
    Dans ce cas je dois aussi remettre le code de la fonction en-dessous ?

    Et dans mon projet, la bonne procédure et d'ajouter ma DLL aux références (et dans le uses) et ensuite de faire namespaceDeLaDLL.nomDeLaFonction ?

  11. #11
    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
    C'est juste une idée, Euh, tu as mis le_TLB, le .pas mais as-tu inclu en ressource le .TLB ! Mais bon je pense que c'est risqué de mettre les deux en un, j'essayerais au moins une fois pour voir ...

    Sinon, en général, je ne fais qu'un ActiveX qui encapsule mais ce dernier appel en fait la DLL (je livre les deux DLL ensemble) ... ainsi un seul code à maintenir pour le fonctionnel, il n'y a que la partie "Interface" qui doit être faite une seconde fois ...
    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 à l'essai
    Profil pro
    Inscrit en
    Août 2008
    Messages
    20
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 20
    Points : 11
    Points
    11
    Par défaut
    Non je n'ai pas inclus le .TLB en ressources.
    Qu'appelles-tu en ressources ?
    J'ai essayé de le mettre dans le même dossier avec le même nom que la DLL, mais ça ne marche pas mieux.

  13. #13
    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
    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
    Membre à l'essai
    Profil pro
    Inscrit en
    Août 2008
    Messages
    20
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 20
    Points : 11
    Points
    11
    Par défaut
    Ça fait toujours la même erreur.
    Ça doit pas être possible, ce serait trop beau si ça marcher !

    Pour l'autre méthode, dans mon ActiveX j'ai mon Unit :
    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
    unit Unit1;
     
    {$WARN SYMBOL_PLATFORM OFF}
     
    interface
     
    uses
      ComObj, ActiveX, CnxCtsActiveX_TLB, StdVcl;
     
    type
      TCnxC = class(TAutoObject, ICnxC)
      protected
     
      end;
     
    implementation
     
    uses ComServ;
     
    type
     IWinDLL = interface
      function StrToCodeUtilisateur(const chaine: shortString): TCodeUtilisateur; safecall;
     end;
     
    initialization
      TAutoObjectFactory.Create(ComServer, TCnxC, Class_CnxC,
        ciMultiInstance, tmApartment);
    end.
    C'est à cette endroit que je dois modifier les types ? Puisque TCodeUtilisateur il ne connaît pas ?

  15. #15
    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
    Encore une fois ce n'est pas magique, IWinDLL ça sort d'où ? ICnxC est-ce l'interface qui servira pour l'Assembly ?

    Evidemment, tu dois aussi redéclarer les types de la DLL en Interface pour que tout soit propre ...

    Exemple (tapé à la main, mais ça te donne une idée de tout ce qu'il faut avoir, lit bien car j'y ai mis quelques commentaires)

    Dans la DLL
    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
     
    library Shai_DLL;
     
    uses
      Shai_DLL_Exports in 'Shai_DLL_Exports.pas',
      ShaiTypes in 'Shai_DLL_Types.pas';
     
    {$R *.res}
     
    exports
      ShaiFunction;
     
     
    begin
     
    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
    21
    unit Shai_DLL_Exports;
     
    interface
     
    uses Windows, Shai_DLL_Types;
     
    function ShaiFunction(const lpParam: TParamStruct): TResultStruct; stdcall;
     
    implementation
     
    {* -----------------------------------------------------------------------------
    ShaiFunction fait quelque chose
    @param lpParam Pointeur sur Structure TParamStruct
    @return Structure TResultStruct - Resultat
    ------------------------------------------------------------------------------ }
    function ShaiFunction(const lpParam: TParamStruct): TResultStruct; stdcall;
    begin
      // Fait quelque chose avec lpParam pour donner un TResultStruct
    end;
     
    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
     
    unit Shai_DLL_Types;
     
    interface
     
    type
      TResultStruct = record
        ErrorCode: Integer; // long int
        Count: Cardinal;    // unsigned long int
        ID: Cardinal;       // unsigned long int
      end;
     
      PParamStruct = ^TParamStruct;
      TParamStruct = record
        lpChaine: PChar;
        lpDate: PSystemTime;
        lpEntier: Cardinal;
      end;
    Dans l'ActiveX
    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
     
    library Shai_DLL_COM;
     
    uses
      SysUtils,
      Classes,
      ComServ,
      Shai_DLL_COM_Impl in 'Shai_DLL_COM_Impl.pas' {Shai_DLL_COM_Impl: CoClass},
      Shai_DLL_COM_TLB in 'Shai_DLL_COM_TLB.pas'; // Généré automatiquement lorsque l'on manipule via l'Editeur de Bibliothèques de Type (dans le Menu Voir)
     
    {$R *.TLB}
     
    {$R *.res}
     
    exports
      DllGetClassObject,
      DllCanUnloadNow,
      DllRegisterServer,
      DllUnregisterServer;
     
    begin
     
    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
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
     
    unit Shai_DLL_COM_Impl;
     
    type
      TShai_DLL_COM_Impl = class(TAutoObject, IShai_DLL_COM)
      protected
        function ShaiFunction(const Param: IParamStruct): IResultStruct; safecall;
      end;
     
      TParamStruct_Impl = class(TAutoObject, IParamStruct)
        ... ben faut tout implémenté
     
      TResultStructImpl = class(TAutoObject, IResultStruct)
      private
        FData: TResultStruct; // Oui, la bonne vieille structure, l'interface n'est qu'une coquille autour !!!!
      protected
        function Get_Count: LongWord; safecall;
        function Get_ErrorCode: Integer; safecall;
        function Get_ID: LongWord; safecall;
      public
        constructor CreateWithInterface(const AResultStruct: IResultStruct);
        destructor Destroy; override;
      end;
     
     
    implementation
     
     
    function TShai_DLL_COM_Impl.ShaiFunction(const Param: IParamStruct): IResultStruct; 
    begin
      LoadLibrary('Shai_DLL.dll');
      @ptr := GetProcAdress('ShaiFunction');
      ptr(...); // faut s'amuser à tranformer les types COM ... ça en fait, j'ai fait tout un système pour qu'une interface soit capable de s'initialiser via un Record et inversement
     
      Result := ObjRes;
    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
    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
     
    unit Shai_DLL_COM_TLB;
     
    // le bla bla généré !!!
     
    // GUID
     
    type
     
    // *********************************************************************//
    // Déclaration Forward des types définis dans la bibliothèque de types    
    // *********************************************************************//
      IShai_DLL_COM = interface;
      IParamStruct = interface;
      IResultStruct = interface;
     
    // *********************************************************************//
    // Interface   : IShai_DLL_COM
    // Indicateurs : (...) Dual OleAutomation Dispatchable
    // GUID        : {GUID}
    // *********************************************************************//
      IShai_DLL_COM = interface(IDispatch)
        ['{GUID}']
        function ShaiFunction(const Param: IParamStruct): IResultStruct; safecall;
      end;
     
    // *********************************************************************//
    // Interface   : IResultStruct
    // Indicateurs : (...) Dual OleAutomation Dispatchable
    // GUID        : {GUID}
    // *********************************************************************//
      IResultStruct = interface(IDispatch)
        ['{GUID}']
        function Get_ErrorCode: Integer; safecall;
        function Get_Count: LongWord; safecall;
        function Get_ID: LongWord; safecall;
        property ErrorCode: Integer read Get_ErrorCode;
        property Count: LongWord read Get_Count;
        property ID: LongWord read Get_ID;
      end;
     
    // *********************************************************************//
    // Interface   : IParamStruct
    // Indicateurs : (...) Dual OleAutomation Dispatchable
    // GUID        : {GUID}
    // *********************************************************************//
      IParamStruct = interface(IDispatch)
        ['{GUID}']
        function Get_Chaine: WideString; safecall;
        procedure Set_Chaine(const Value: WideString); safecall;
        function Get_Date: TDateTime; safecall;
        procedure Set_Date(Value: TDateTime); safecall;
        procedure Get_Entier ...
        property Chaine: WideString read Get_Chaine write Set_Chaine;
        property Date: TDateTime read Get_Date write Set_Date;
        property Entier ...
      end;
     
    implementation
     
    uses ComObj;
     
    class function CoShai_DLL_COMImpl.Create: IShai_DLL_COM;
    begin
      Result := CreateComObject(CLASS_Shai_DLL_COMImpl) as IShai_DLL_COM;
    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

  16. #16
    Membre à l'essai
    Profil pro
    Inscrit en
    Août 2008
    Messages
    20
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 20
    Points : 11
    Points
    11
    Par défaut
    Merci pour les bouts de code, j'avais du mal dans ton topic car je bloquais à une étape que tu avais déjà passé quand tu as posté.
    Je vais testé tout ça.

    EDIT : bizarrement je n'ai pas accès aux fonctions LoadLibrary et GetProcAddress dans l'activeX avec les mêmes uses que toi, il faut que je rajoute Windows.

  17. #17
    Membre à l'essai
    Profil pro
    Inscrit en
    Août 2008
    Messages
    20
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 20
    Points : 11
    Points
    11
    Par défaut
    Voila, j'ai commencé par implémenter une seule fonction (toute simple), et mon ActiveX compile (c'est déjà pas mal).
    Par contre quand je l'importe dans mon projet .NET (en le rajoutant dans uses), je vois la class mais pas la fonction que j'ai rajouté
    Pourtant c'est structuré comme tu m'as montré.

  18. #18
    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
    Pour la partie .NET je ne peux pas t'aider, je ne connais pas, faire voir la déclaration généré dans le fichier _TLB ... tu es bien passé par l'Editeur de Bibliothèques de Type ?
    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

  19. #19
    Membre émérite
    Avatar de ALWEBER
    Homme Profil pro
    Expert Delphi
    Inscrit en
    Mars 2006
    Messages
    1 496
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 69
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Expert Delphi

    Informations forums :
    Inscription : Mars 2006
    Messages : 1 496
    Points : 2 762
    Points
    2 762
    Billets dans le blog
    10
    Par défaut
    Bonjour,
    Juste un petit mot en plus pour apporter mon grain de sel.
    Si je résume bien le but est d'avoir du code Win32 dans une appli DELPHI.NET.
    Je l'ai réalisé de deux manières : ActiveX pour créer une visu openGL sur Internet. CGI pour générer du PDF. J'ai repris une appli PowerPDF qui était en libre accès que j'ai
    retravaillé pour retirer toute la partie Forms.

  20. #20
    Membre à l'essai
    Profil pro
    Inscrit en
    Août 2008
    Messages
    20
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 20
    Points : 11
    Points
    11
    Par défaut
    Citation Envoyé par ShaiLeTroll Voir le message
    Pour la partie .NET je ne peux pas t'aider, je ne connais pas, faire voir la déclaration généré dans le fichier _TLB ... tu es bien passé par l'Editeur de Bibliothèques de Type ?
    Je n'était effectivement pas passé par l'éditeur, j'avais modifié le _TLB à la main, et je n'avais pas dû le faire très bien.

    Je viens de faire une fonction addition dans l'activeX qui renvoit juste l'addition de deux nombres (sans lien avec la DLL Win32, juste pour voir si j'arrive à l'appeler depuis mon application .NET, et ça marche). Je repars donc sur l'encapsulation.

    EDIT :
    Je tente d'implémenter une fonction toute simple de ma DLL, voici ce qu'il y a dans le code source de la DLL Win32 :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    function StrToCodeUtilisateur(const chaine: shortString): TCodeUtilisateur;
    begin
      result := chaine;
    end;
    Avec :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    TCodeUtilisateur = ShortString;
    Il y a 3 choses qui me posent problème :
    • il faut que je déclare le type TCodeUtilisateur dans mon _TLB, comment peut-on faire cela dans l'éditeur bibliothèque de types ?
    • Dans les paramètres pour la méthode il n'y pas de string ou de shortstring (j'avais vu que ça poser problème à Delphi), j'ai lu dans les tutos qu'en rajoutant ShareMem en premier dans les uses ça régler le problème. Je l'ai rajouté dans mon .dpr, mais ça ne change rien.
    • Lorsque je charge la libraire et que je fais ptr := GetProcAddress(dllInstance, 'StrToCodeUtilisateur'); il me fait une erreur avec ptr. Avec quel type de variable suis-je censé le déclarer ?


    Merci !
    Bonjour,
    Juste un petit mot en plus pour apporter mon grain de sel.
    Si je résume bien le but est d'avoir du code Win32 dans une appli DELPHI.NET.
    Je l'ai réalisé de deux manières : ActiveX pour créer une visu openGL sur Internet. CGI pour générer du PDF. J'ai repris une appli PowerPDF qui était en libre accès que j'ai
    retravaillé pour retirer toute la partie Forms.
    J'aimerais autant que possible éviter de retravailler le code Win32 pour le rendre compatible .NET, si vraiment je n'arrive pas l'ActiveX je réécrirais complètement la DLL en .NET.

Discussions similaires

  1. Comment charger une DLL win32 en C# de manière dynamique
    Par Jayceblaster dans le forum Windows Forms
    Réponses: 4
    Dernier message: 10/06/2009, 18h38
  2. comment utiliser une DLL win32 en C??
    Par Jayceblaster dans le forum C
    Réponses: 8
    Dernier message: 31/03/2006, 12h49
  3. HWND de MFC à une DLL Win32
    Par Taron31 dans le forum MFC
    Réponses: 5
    Dernier message: 16/03/2006, 06h53
  4. [VB6] création dll win32 et appel par un autre programme
    Par Tankian85 dans le forum VB 6 et antérieur
    Réponses: 1
    Dernier message: 10/03/2006, 08h21
  5. Comment créer une dll Win32 sous Delphi ?
    Par Mickey.jet dans le forum Langage
    Réponses: 8
    Dernier message: 16/06/2005, 15h38

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