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

API, COM et SDKs Delphi Discussion :

ActiveX appelé par Javascript


Sujet :

API, COM et SDKs Delphi

  1. #1
    Membre confirmé
    Inscrit en
    Novembre 2006
    Messages
    147
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 147
    Par défaut ActiveX appelé par Javascript
    Bonjour,


    J'utilise un programme qui répétitivement (disons 10 fois par seconde) exécute le code javascript suivant:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    var proc = new ActiveXObject("xxxx.yyyy");
    return proc.Calculate(gxptTarget, gxptOutput, gxptParams, gxptModelInfo);
    Où xxxx.yyyy est un activeX censé exposé la méthode Calculate qui est de la forme (donnée en VB par le constructeur du prog en question):

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    Public Function Calculate(ByRef gxptTarget As Variant, _
                              ByRef gxptOutput As Variant, _
                              ByRef gxptParams As Variant, _
                              ByRef gxptModelInfo As Variant) _  As Variant
    Je voudrais, en outre, pouvoir disposer des données envoyées par le prog (tous les variants envoyés sont des tableaux de réels) pour pouvoir les afficher dans Form1.chart sous Delphi.
    Non spécialiste, loin s'en faut, des objets com j'ai péniblement réussi dans un premier temps à créer une simple appli conventionnelle delphi (une simple et unique Form1) dans laquelle j'ai défini et exposé la méthode Calculate en créant un objet Automation et de fait, cela fonctionne (la procédure calcule est bien appelée et retourne des valeurs au prog). J'ai cependant un dernier problème: A chaque éxécution de :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    var proc = new ActiveXObject("xxxx.yyyy");
    L'ActiveX est créé, Calculate est donc appelée coté delphi grâce au serveur automation et une fenêtre Form1 et créée (et d'ailleurs détruite à la fin puisqu'elles ne s'accumulent pas: il n'y a toujours qu'un seule Form1 vivante,
    ce qui semblerait indiquer l'activeX est détruit par le prog à chaque appel).

    Comment faire en sorte que Form1 ne soit créée qu'au premier appel de calculate ? cela se définit-il au niveau du javascript (vérifier que l'objet existe pour ne pas le récréer si oui) ou au niveau Delphi ? Ou est-ce tout simplement impossible ?

    Quelqu'un a-t-il une idée ?

    Cordialement

    Eric BEAUMARD

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

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 962
    Par défaut
    var Proc doit simplement être défini en variable globale au script et non à l'intérieur de la fonction.

  3. #3
    Membre confirmé
    Inscrit en
    Novembre 2006
    Messages
    147
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 147
    Par défaut
    Citation Envoyé par Andnotor Voir le message
    var Proc doit simplement être défini en variable globale au script et non à l'intérieur de la fonction.
    S'agissant de ce script je n'ai accès, dans le logiciel en question, qui est un exe,
    qu'à une fenêtre dans laquelle je peux taper mon script. Le logiciel appelle
    répétitivement le script en question et retourne à chaque fois à l'exe. Je ne vois pas comment maintenir un contexte (une var globale) dans ces conditions.
    Autrement dis, je ne peux écrire du javascript qu'à l'intérieur d'une fonction qui est appelé périodiquement par un exe duquel je ne controle rien et dont je n'ai pas non plus le source.

    Est-il impossible de maintenir un contexte au niveau de l'activeX ?
    (stocker des trucs quelque part en RAM par un exe qui servirait de tampon
    à l'activeX et qui dialoguerait avec lui et serait lui, permanent)

    Cordialement

    Eric

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

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 962
    Par défaut
    Un serveur automation contient un compteur d'accès. Si le compteur = 0 ET que l'application serveur a été lancée automatiquement à l'établissement d'une connexion, le serveur est arrêté.

    Si le serveur a été démarré manuellement, il n'est jamais arrêté.

    Dans ton cas, soit tu le lances au démarrage de Windows (en tâche de fond, fenêtre minimisée, etc), soit à travers ton script avant new ActiveXObject("xxxx.yyyy").

    Ce qui donnerait quelque chose comme ceci (Je n'ai pas testé):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    var oShell = new ActiveXObject("Shell.Application");
    oShell.ShellExecute("TonProg.exe", "", "", "open", 0);
     
    var proc = new ActiveXObject("xxxx.yyyy");
    return proc.Calculate(gxptTarget, gxptOutput, gxptParams, gxptModelInfo);
    Tu devras bien sûr t'assurer qu'une seule instance de ton prog est créé (Mutex)

  5. #5
    Membre confirmé
    Inscrit en
    Novembre 2006
    Messages
    147
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 147
    Par défaut
    Ce qui donnerait quelque chose comme ceci (Je n'ai pas testé):
    [CODE]var oShell = new ActiveXObject("Shell.Application");
    oShell.ShellExecute("TonProg.exe", "", "", "open", 0);
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    var proc = new ActiveXObject("xxxx.yyyy");
    return proc.Calculate(gxptTarget, gxptOutput, gxptParams, gxptModelInfo);
    Tu devras bien sûr t'assurer qu'une seule instance de ton prog est créé (Mutex)
    Bon, j'essaie de bien comprendre. J'aurais donc un TonProg.exe lancé
    par le script à chacune des ses exécutions. Je ne vois pas comment
    tester en Javascript l'existence de Tonprog.exe pour ne pas la lancer
    plusieurs fois. Donc, et ce n'est pas un pb, il suffirait peut-être de lancer
    TonProg.exe avant de lancer l'appli qui exécute le JavaScript.

    Tu dis donc qu'il n'est pas problématique de demander plusieurs création
    de l'activeX parce que le système gère la chose. Ok.

    Il faudra donc maintenant que j'arrive à envoyer des données
    de l'activeX vers TonProg.exe, et je ne veux pas passer pas un
    fichier. Alors comment faire ? TFileStream, zone RAM commune, etc. ?

    Qui a une idée ?

    Cordialement

    Eric

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

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 962
    Par défaut
    Je ne vois pas comment tester en Javascript l'existence de Tonprog.exe pour ne pas la lancer plusieurs fois. Donc, et ce n'est pas un pb, il suffirait peut-être de lancer TonProg.exe avant de lancer l'appli qui exécute le JavaScript.
    C'est exactement ce que je t'ai proposé. (Sinon une gestion par Mutex côté Delphi qui fait un Halt de la 2ème instance)

    Tu dis donc qu'il n'est pas problématique de demander plusieurs création de l'activeX parce que le système gère la chose.
    Parlons plutôt de connexion. La création est implicite si (et uniquement si) le serveur n'est pas encore lancé.

    Il faudra donc maintenant que j'arrive à envoyer des données de l'activeX vers TonProg.exe
    Du coup je ne comprend plus la finalité. Tu dis que tu as créé un serveur COM en Delphi dans lequel tu as exposé la procedure Calculate. Depuis cette procédure, tu peux afficher ce que tu veux.

  7. #7
    Membre confirmé
    Inscrit en
    Novembre 2006
    Messages
    147
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 147
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Du coup je ne comprend plus la finalité. :koi: Tu dis que tu as créé un serveur COM en Delphi dans lequel tu as exposé la procedure Calculate. Depuis cette procédure, tu peux afficher ce que tu veux.
    Oui. J'ai créé une ActiveForm et j'ai rajouté cette procédure (calculate) que
    j'ai exposé. Le pb est que chaque fois que la procédure est appelée
    par le javascript la form est réaffichée puisque tout l'activeX est recréé ...Et
    ce n'est pas jouable parce que détruire et récréer une fenêtre 20 fois
    par seconde ...

    C'est donc pour ça que j'ai pensé à créer un activeX non-visuel qui expose
    calculate d'un coté et la feuille de l'autre coté dans TonProg.exe.
    Il s'ensuit que dans cette hypothèse je dois être capable d'envoyer
    les données reçues dans calculate vers TonProg.exe.

    Ou bien je conserve l'activeForm mais comment empêcher les cycles
    de destruction-recréation de la form de l'activeForm à chaque instanciation
    de l'activeX?

    Il faudrait un espèce d'activeX persistant et doté d'une forme, qui résisterait
    à la destruction ordonnée par le javascript et qui exposerait calculate.

    Cordialement

    Eric

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

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 962
    Par défaut
    Ok.

    Alors ce que je te propose est de te passer de l'ActiveForm et de déléguer toute la tâche à TonProg.exe. En deux mots, de transformer TonProg.exe en serveur automation.

    C'est assez simple en Delphi:
    1. Crée un nouveau projet Delphi Application fiche VCL,
    2. Ajoute à ce projet un Objet automation,
    3. Donne un nom à la CoClass. Par ex. Automation ,
    4. Une bibliothèque de types est ajoutée à ton projet. Sur IAutomation, tu vas y ajouter ta méthode Calculate (Bouton avec la flèche verte) et éditer ses paramètres.
    5. Une fois terminé, presses le bouton Rafraîchir l'implementation.
    6. Tu as maintenant la même procédure Calculate que dans ton ActiveForm à laquelle tu vas ajouter le code d'affichage sur la fiche principale.


    Il ne reste plus qu'à recenser le serveur. Deux méthodes:
    1. Depuis Delphi, menu Executer > Recenser le serveur ActiveX,
    2. En ligne de commande TonProg.exe /RegServer.


    Du côté de l'autre exe, l'appel est identique:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    var proc = new ActiveXObject("TonProg.Automation");
    return proc.Calculate(gxptTarget, gxptOutput, gxptParams, gxptModelInfo);
    ...enfin on retombe sur les explications précédentes, le serveur va être démarré au moment de la connexion et arrêté lorsque la connexion est libérée. (A la sortie de la fonction du 1er exe, compteur = 0). Arranges-toi pour démarrer TonProg avant l'exe.

  9. #9
    Membre confirmé
    Inscrit en
    Novembre 2006
    Messages
    147
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 147
    Par défaut
    Ok je te remercie pour tes conseils, je vais essayer ça. J'y avais pensé mais
    avais abandonné l'idée parce que à priori ce qui se produisait pour l'activeForm
    devait se produire aussi pour un TonProg exposant Calculate (destruction/création incessante du TonProg.exe). Mais tu semble savoir que cela ne se produira pas et donc je vais essayer. Et l'idée se défend puisque
    TonProg.exe n'est pas instancié par la clause Initialize comme c'est le cas
    pour l'activeform.

    Cordialement.

    Eric.

  10. #10
    Membre confirmé
    Inscrit en
    Novembre 2006
    Messages
    147
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 147
    Par défaut
    Bon je viens d'essayer le truc et finallement ce que j'avais déjà
    vécu s'est reproduit (je l'avais oublié). J'ai créé une appli, ajouté
    un objet automation, renseigné les paramètres, et commandé
    le rafraichissement du source. Donc tout fonctionne et compile
    correctement. Mais ... Delphi, et c'est logique, ne propose pas
    de recenser le serveur (l'option est grisée) puisque pour lui
    c'est une appli "normale" (le fait d'avoir inséré un objet automation
    ne lui fait ni chaud ni froid) et maintenant je me souviens que j'avais
    déjà rencontré ce pb et que c'est cela aussi qui m'avait incité à
    ne pas retenter l'expérience.

    Donc j'ai essayé regserver32 mais lui me répond qu'il ne trouve pas le
    point d'entrée DllRegisterServer dans mon exe ...

    Voilà où j'en suis à la seconde où j'écris ces lignes.

    Cordialement

    Eric

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

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 962
    Par défaut
    DllRegisterServer n'est appelé que dans le cas d'un serveur in-process (une DLL). J'ai l'impression que tu as mélangé ton ancien code avec le nouveau.

    Commence par un projet simple. Crées simplement ton nouveau projet avec l'objet automation (Sans procédure) et essayes de l'enregistrer.

  12. #12
    Membre confirmé
    Inscrit en
    Novembre 2006
    Messages
    147
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 147
    Par défaut
    Citation Envoyé par Andnotor Voir le message
    DllRegisterServer n'est appelé que dans le cas d'un serveur in-process (une DLL). J'ai l'impression que tu as mélangé ton ancien code avec le nouveau.

    Commence par un projet simple. Crées simplement ton nouveau projet avec l'objet automation (Sans procédure) et essayes de l'enregistrer.
    Ce qui donne:

    0- Ouverture de Delphi.
    1- Nouvelle, application.
    2- Nouveau, autre, activeX, Objet automation, nom "essai"
    3- Pas de définition de fonction exposée.
    4- Compilation ok.


    Je rencontre exactement les mêmes pb que ceux décrits dans mon dernier
    message:

    1- Delphi ne me propose pas de recenser l'objet automation.
    2- Regserver32 me dit que la DllRegisterServer n'est pas exposée par mon exe.


    Voilà les fichiers du projet:

    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
    program PessaiAutomationDansExe;
     
    uses
      Forms,
      Unit1 in 'Unit1.pas' {Form1},
      PessaiAutomationDansExe_TLB in 'PessaiAutomationDansExe_TLB.pas',
      Unit2 in 'Unit2.pas' {Essai: CoClass};
     
    {$R *.TLB}
     
    {$R *.res}
     
    begin
      Application.Initialize;
      Application.CreateForm(TForm1, Form1);
      Application.Run;
    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
     
    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 *.dfm}
     
    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
    unit Unit2;
     
    {$WARN SYMBOL_PLATFORM OFF}
     
    interface
     
    uses
      ComObj, ActiveX, AxCtrls, Classes, PessaiAutomationDansExe_TLB, StdVcl;
     
    type
      TEssai = class(TAutoObject, IConnectionPointContainer, IEssai)
      private
        { Déclarations privées }
        FConnectionPoints: TConnectionPoints;
        FConnectionPoint: TConnectionPoint;
        FEvents: IEssaiEvents;
        { Remarque : FEvents gère un collecteur d'événement *unique*. Pour accéder à plusieurs collecteurs
          d'événements, utilisez FConnectionPoint.SinkList et parcourez la liste de collecteurs. }
      public
        procedure Initialize; override;
      protected
        { Déclarations protégées }
        property ConnectionPoints: TConnectionPoints read FConnectionPoints
          implements IConnectionPointContainer;
        procedure EventSinkChanged(const EventSink: IUnknown); override;
      end;
     
    implementation
     
    uses ComServ;
     
    procedure TEssai.EventSinkChanged(const EventSink: IUnknown);
    begin
      FEvents := EventSink as IEssaiEvents;
    end;
     
    procedure TEssai.Initialize;
    begin
      inherited Initialize;
      FConnectionPoints := TConnectionPoints.Create(Self);
      if AutoFactory.EventTypeInfo <> nil then
        FConnectionPoint := FConnectionPoints.CreateConnectionPoint(
          AutoFactory.EventIID, ckSingle, EventConnect)
      else FConnectionPoint := nil;
    end;
     
     
    initialization
      TAutoObjectFactory.Create(ComServer, TEssai, Class_Essai,
        ciMultiInstance, tmApartment);
    end.

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

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 962
    Par défaut
    Désolé, tout semble correct. Je ne vois pas

  14. #14
    Membre confirmé
    Inscrit en
    Novembre 2006
    Messages
    147
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 147
    Par défaut
    Citation Envoyé par Andnotor Voir le message
    Désolé, tout semble correct. Je ne vois pas
    Moi non plus. En même temps la réaction de Delphi me semble normale. Cette
    application est un exe standart et de ce fait il ne me donne pas accès au recensement de l'objet automation. J'ai vu un menu concernant les objets com sous Delphi. En l'explorant j'ai cru comprendre qu'on pouvait intégrer un objet COM à une application standart (un.exe). Mais bon, ce n'est pas très clair.

    Peut-on créer un exe qui expose un objet automation recensé et accessible par comme tel par le système et les autres applications ?

    Je n'en sais rien. Toute aide sera la bienvenue ...

    Cordialement

    Eric BEAUMARD

Discussions similaires

  1. Réponses: 2
    Dernier message: 17/03/2009, 21h06
  2. appeler une action par javaScript
    Par khaledirb7 dans le forum Struts 1
    Réponses: 3
    Dernier message: 14/08/2007, 22h57
  3. Appel de controle ActiveX personnalise depuis javascript
    Par ay1@duclert.org dans le forum Windows
    Réponses: 1
    Dernier message: 23/05/2007, 16h55
  4. Appel Méthode 4D par Javascript
    Par mxh77 dans le forum 4D
    Réponses: 2
    Dernier message: 02/10/2006, 15h48

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