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

Web & réseau Delphi Discussion :

TIdHttp et IOHandler XE7 VCL


Sujet :

Web & réseau Delphi

  1. #1
    Membre émérite

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2007
    Messages
    3 388
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2007
    Messages : 3 388
    Points : 2 999
    Points
    2 999
    Par défaut TIdHttp et IOHandler XE7 VCL
    Bonjour

    Pas doué en prog web moi !
    Je veux juste récupérer un fichier Jours fériés

    Je voulais utiliser basiquement un TIDHttp et je trouve plein d'exemple sur le net dans le genre :
    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
     
    procedure DownloadHTTP(const AUrl : string; out DestStream: TStream);
    begin
      with TIdHTTP.Create(Application) do
      try
        try
          Get(AUrl, DestStream);
        except
          on e: Exception do
            MessageDlg(Format('Erreur : %s',[e.Message]), mtInformation, [mbOK], 0);
        end;
      finally
        Free;
      end;
    end;
    Problème : à chaque appel je reçois le message :

    ---------------------------
    Notification des exceptions du débogueur
    ---------------------------
    Le projet Project2.exe a déclenché la classe d'exception EIdIOHandlerPropInvalid avec le message 'Valeur IOHandler non valide'.
    ---------------------------
    Arrêter Continuer Aide
    ---------------------------
    Nulle part dans les exemples que je trouve il n'est question de IOHandler (même si j'ai bien le composant correspondant sur la palette delphi.

    Pourquoi un truc aussi simple me pose-t-il des problèmes ??

  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
    Si c'est pour le HTTPS et dans ce cas, les exemples sont très nombreux
    Cela implique de fournir libeay32.dll et ssleay32.dll

    C'est d'ailleurs la première chose que Google répond pour "delphi TIdHttp et IOHandler" -> Sécurisation des connexions réseau Indy

    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
     
     
     
    procedure TFrmMain.Button1Click(Sender: TObject);
     
      function IsHTTPS(const AUrl : string): Boolean;
      begin
        with TIdURI.Create(AUrl) do
        try
          Result := SameText(Protocol, 'HTTPS');
        finally
          Free;
        end;
      end;
     
      // Surtout pas out pour AReponseContent !!!
      procedure DownloadHTTP(const AUrl: string; AReponseContent: TStream; const ExpectedContentType: string = '');
      begin
        with TIdHTTP.Create(nil) do // aucune raison de mettre Application ici !
        try
          if IsHTTPS(AUrl) then
          begin
            IOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(nil); // ici nil pourrait être l'objet TIdHTTP mais avec la syntaxe with c'est pas compatible
            TIdSSLIOHandlerSocketOpenSSL(IOHandler).SSLOptions.Method := sslvSSLv23; // la valeur sslvSSLv23 laisse au server le choix du protocole, on ne s'en occupe pas
          end;
          try
            Get(AUrl, AReponseContent);
            if ResponseCode <> 200 then
              raise Exception.CreateFmt('[%d] %s', [ResponseCode, ResponseText]);
     
            if ExpectedContentType <> '' then
              if not SameText(Response.ContentType, ExpectedContentType) then
                raise Exception.CreateFmt('Invalid Response Content Type : %s', [Response.ContentType]);
     
          except
            on e: Exception do
              MessageDlg(Format('Erreur : %s',[e.Message]), mtInformation, [mbOK], 0);
          end;
        finally
          IOHandler.Free;
          Free;
        end;
      end;
     
    var
      JSONStream: TStringStream;
      ResponseJSON: TJSONObject;
      Pair: TJSONPair;
    begin
      JSONStream := TStringStream.Create('', TEncoding.UTF8);
      try
        DownloadHTTP('https://calendrier.api.gouv.fr/jours-feries/metropole.json', JSONStream, 'application/json');
     
        ResponseJSON := TJSONObject.ParseJSONValue(JSONStream.DataString) as TJSONObject; // UTF8 !
        try
          for Pair in ResponseJSON do
             ValueListEditor1.Values[Pair.JsonString.Value] := Pair.JsonValue.Value;
        finally
          ResponseJSON.Free();
        end;
      finally[ATTACH=CONFIG]651713[/ATTACH]
        JSONStream.Free();
      end;


    Si ce n'est pas pour du HTTPS, il faudrait nous donner plus d'information
    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
    Membre émérite

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2007
    Messages
    3 388
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2007
    Messages : 3 388
    Points : 2 999
    Points
    2 999
    Par défaut
    Il y en a beaucoup mais avec TIdSSLIOHandlerSocketOpenSSL , je n'en n'ai pas trouvé.

    Ton aide est toujours précieuse mais nouvelle erreur :

    ---------------------------
    Project2
    ---------------------------
    Erreur lors de la connexion avec SSL.

    error:1409442E:SSL routines:SSL3_READ_BYTES:tlsv1 alert protocol version.
    ---------------------------
    OK
    ---------------------------

    J'ai trouvé l'URL sur https://www.data.gouv.fr/fr/datasets...1df4822526c1c/

    Il y a lien vers la doc de l'API JSON mais je pensais pouvoir télécharger le fichier directement puisqu'on y arrive depuis un navigateur.

  4. #4
    Membre émérite

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2007
    Messages
    3 388
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2007
    Messages : 3 388
    Points : 2 999
    Points
    2 999

  5. #5
    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
    Avec le code fourni ci-dessus, cela fonctionne parfaitement avec les DLL que j'ai 1.0.2.11 (1.0.2k)

    Nom : Sans titre.png
Affichages : 118
Taille : 20,3 Ko

    C'est pour cela que j'évite OpenSSL, je préfère laisse Windows le faire, je reviens avec une version sans OpenSSL et sa chiasse de version
    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
    Membre émérite

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2007
    Messages
    3 388
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2007
    Messages : 3 388
    Points : 2 999
    Points
    2 999
    Par défaut
    dans c:\windows\system32 j'ai la version 1.0.2.21 qui est plus récente. Est-ce que ça ne devrait pas fonctionner ?

    J'ai copié les 2 dll dans le répertoire du projet et cette fois ça passe.

    Mais l'encodage est incorrect. Exemple : Lundi de Pentecôte

  7. #7
    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
    Tu as bien repris le code fourni ci-dessus ?
    L'important étant TEncoding.UTF8 dans le constructeur du TStringStream

    On laisse Windows et WinInet gére le HTTPS et ça sans le problème de Handshake bien connu avec OpenSSL
    Pas besoin des deux DLL avec le code ci-dessus mais c'est un poil plus brut comme code, il est robuste, j'utilise une variante depuis des années, il est en PROD depuis 2017 et je ne suis plus dans la boite concernée, donc plus de maintenance de ma part.

    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
     
    procedure TFrmMain.Button1Click(Sender: TObject);
     
     
      procedure GetInternetFile(const AServerName: string; const AURL: string; AStream: TStream; const ExpectedContentType: string = '');
      type
        TAcceptTypes = packed array[0..1] of LPWSTR;
      const
        BufferSize = 1024;
        ACCEPT_TYPES: TAcceptTypes = (PChar('text/*'), nil); // PCTSTR rgpszAcceptTypes[] = {_T(“text/*”), NULL};
      var
        hSession, hHTTP, hReq : HINTERNET;
        Accept: TAcceptTypes;
        Buffer: array[1..BufferSize] of Byte;
        BufferLen: DWORD;
        sAppName: string;
      begin
        AStream.Size := 0;
        sAppName := ExtractFileName(Application.ExeName);
     
        Accept := ACCEPT_TYPES;
        if ExpectedContentType <> '' then
          Accept[0] := PChar(ExpectedContentType);
     
        // Winapi.WinInet !!!
        hSession := InternetOpen(PChar(sAppName), INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);
        try
          hHTTP := InternetConnect(hSession, PChar(AServerName), INTERNET_DEFAULT_HTTP_PORT, nil, nil, INTERNET_SERVICE_HTTP, 0, 1);
          try
            hReq := HttpOpenRequest(hHTTP, PChar('GET'), PChar(AURL), nil, nil, @accept, 0, 1);
            try
              if HttpSendRequest(hReq, nil, 0, nil, 0) then
              begin
                BufferLen := 0;
                repeat
                  if InternetReadFile(hReq, @Buffer, BufferSize, BufferLen) then
                    AStream.WriteBuffer(Buffer, BufferLen);
     
                until BufferLen = 0;
              end
              else
                raise Exception.Create('HttpOpenRequest failed. ' + SysErrorMessage(GetLastError));
            finally
              InternetCloseHandle(hReq);
            end;
          finally
            InternetCloseHandle(hHTTP);
          end;
        finally
          InternetCloseHandle(hSession);
        end;
      end;
     
    var
      JSONStream: TStringStream;
      ResponseJSON: TJSONObject;
      Pair: TJSONPair;
    begin
      JSONStream := TStringStream.Create('', TEncoding.UTF8);
      try
        GetInternetFile('calendrier.api.gouv.fr', '/jours-feries/metropole.json', JSONStream, 'application/json');
     
        ResponseJSON := TJSONObject.ParseJSONValue(JSONStream.DataString) as TJSONObject; // UTF8 !
        try
          for Pair in ResponseJSON do
             ValueListEditor1.Values[Pair.JsonString.Value] := Pair.JsonValue.Value;
        finally
          ResponseJSON.Free();
        end;
      finally
        JSONStream.Free();
      end;
    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 émérite

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2007
    Messages
    3 388
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2007
    Messages : 3 388
    Points : 2 999
    Points
    2 999
    Par défaut
    Ton dernier code avec Wininet fonctionne parfaitement.

    Merci encore ...

  9. #9
    Membre émérite

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2007
    Messages
    3 388
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2007
    Messages : 3 388
    Points : 2 999
    Points
    2 999
    Par défaut
    Citation Envoyé par ShaiLeTroll Voir le message
    Tu as bien repris le code fourni ci-dessus ?
    L'important étant TEncoding.UTF8 dans le constructeur du TStringStream
    En fait, j'avais fait ça mais je me rends compte que le TMemoryStream ne prend l'encodage

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    var
      St: TMemoryStream;
    begin
     
      St := TMemoryStream.Create;
      DownloadHTTP(Format(API, [Zones[6]]), TStream(St));
      St.Seek(0, TSeekOrigin.soBeginning);
      Memo1.Lines.LoadFromStream(St);
      St.Free;
    Je vais modifier et comme ça j'aurai 2 façons de le faire.

  10. #10
    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
    Si il fonctionne, autant prendre celui-là car sans dépendance

    En Delphi 11, je t'aurais conseillé TRESTClient et TRESTRequest,
    Je l'utilise aussi en D10 mais j'ai des soucis de Certificat HTTPS, D10 ne propage pas le OnNeedCertificate des ses couches basses de IPPeerClient, le comble, j'ai du repassé à du TIdHTTP pour ce WebService (interne)


    EDIT : n'utilise pas out pour échanger des objets comme TStream, c'est déjà un échange par référence implicite.

    Utilise un TBytesStream, c'est idéal pour gérer le fonctions du TEncoding ensuite :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    TEncoding.UTF8.GetString(BytesStream.Bytes);
    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

  11. #11
    Membre émérite

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2007
    Messages
    3 388
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2007
    Messages : 3 388
    Points : 2 999
    Points
    2 999
    Par défaut
    c'est vrai que les dépendances sont toujours problématiques. Autant s'en défaire quand on peut

  12. #12
    Membre émérite

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2007
    Messages
    3 388
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2007
    Messages : 3 388
    Points : 2 999
    Points
    2 999
    Par défaut
    Résultat avec ton code :

    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
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
     
    unit UnitJoursFeries;
     
    interface
     
    uses
      Winapi.Windows, Winapi.Messages, Wininet, System.Math,
      System.SysUtils, System.Variants, System.Classes, System.JSON, Vcl.Graphics,
      Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, IdBaseComponent,
      IdComponent, IdTCPConnection, IdTCPClient, IdHTTP, IdIOHandler, IdURI,
      IdIOHandlerStream, IPPeerClient, Data.Bind.Components, Data.Bind.ObjectScope,
      REST.Client, IdIOHandlerSocket, IdIOHandlerStack, IdSSL, IdSSLOpenSSL,
      Vcl.Grids, Vcl.ValEdit, System.DateUtils;
     
      type
        TOnGetJourFerie = reference to procedure(Nom: string; Jour: TDate);
     
    procedure GetJourFeries(OnGetJourFerie: TOnGetJourFerie; AnneeDebut, AnneeFin: Integer);
    procedure GetJourFeriesAvecSSL(OnGetJourFerie: TOnGetJourFerie);
     
    implementation
     
    const
      API = 'https://calendrier.api.gouv.fr/jours-feries/%s.json';
      Zones: array [0 .. 12] of string = (
        'alsace-moselle', 'guadeloupe', 'guyane', 'la-reunion', 'martinique',
        'mayotte', 'metropole', 'nouvelle-caledonie', 'polynesie-francaise',
        'saint-barthelemy', 'saint-martin', 'saint-pierre-et-miquelon', 'wallis-et-futuna');
     
     
    {$REGION 'AVEC dépendance à OpenSSL'}
     
    /// <summary>
    ///   Nécessite libeay32.dll et ssleay32.dll version 1.0.2.11 ou plus
    /// </summary>
    procedure DownloadHTTP(const AUrl: string; out DestStream: TStream);
     
      function IsHTTPS(const AUrl: string): Boolean;
      begin
        with TIdURI.Create(AUrl) do
          try
            Result := SameText(Protocol, 'HTTPS');
          finally
            Free;
          end;
      end;
     
    begin
      with TIdHTTP.Create(Application) do
        try
          if IsHTTPS(AUrl) then
          begin
            IOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
            TIdSSLIOHandlerSocketOpenSSL(IOHandler).SSLOptions.Method := sslvSSLv23;
            // la valeur sslvSSLv23 laisse au server le choix du protocole, on ne s'en occupe pas
          end;
          try
            Get(AUrl, DestStream);
          except
            on e: Exception do
              MessageDlg(Format('Erreur : %s', [e.Message]), mtInformation, [mbOK], 0);
          end;
        finally
          IOHandler.Free;
          Free;
        end;
    end;
     
    procedure GetJourFeriesAvecSSL(OnGetJourFerie: TOnGetJourFerie);
    begin
     
    end;
     
    {$ENDREGION 'AVEC dépendance à OpenSSL'}
     
    {$REGION 'SANS dépendance à OpenSSL'}
     
    procedure GetInternetFile(const AServerName: string; const AUrl: string; AStream: TStream;
      const ExpectedContentType: string = '');
    type
      TAcceptTypes = packed array [0 .. 1] of LPWSTR;
    const
      BufferSize                 = 1024;
      ACCEPT_TYPES: TAcceptTypes = (PChar('text/*'), nil); // PCTSTR rgpszAcceptTypes[] = {_T(?text/*?), NULL};
    var
      hSession, hHTTP, hReq: HINTERNET;
      Accept               : TAcceptTypes;
      Buffer               : array [1 .. BufferSize] of Byte;
      BufferLen            : DWORD;
      sAppName             : string;
    begin
      AStream.Size := 0;
      sAppName     := ExtractFileName(Application.ExeName);
     
      Accept := ACCEPT_TYPES;
      if ExpectedContentType <> '' then
        Accept[0] := PChar(ExpectedContentType);
     
      // Winapi.WinInet !!!
      hSession := InternetOpen(PChar(sAppName), INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);
      try
        hHTTP := InternetConnect(hSession, PChar(AServerName), INTERNET_DEFAULT_HTTP_PORT, nil, nil,
          INTERNET_SERVICE_HTTP, 0, 1);
        try
          hReq := HttpOpenRequest(hHTTP, PChar('GET'), PChar(AUrl), nil, nil, @Accept, 0, 1);
          try
            if HttpSendRequest(hReq, nil, 0, nil, 0) then
            begin
              BufferLen := 0;
              repeat
                if InternetReadFile(hReq, @Buffer, BufferSize, BufferLen) then
                  AStream.WriteBuffer(Buffer, BufferLen);
     
              until BufferLen = 0;
            end
            else
              raise Exception.Create('HttpOpenRequest failed. ' + SysErrorMessage(GetLastError));
          finally
            InternetCloseHandle(hReq);
          end;
        finally
          InternetCloseHandle(hHTTP);
        end;
      finally
        InternetCloseHandle(hSession);
      end;
    end;
     
    procedure GetJourFeries(OnGetJourFerie: TOnGetJourFerie; AnneeDebut, AnneeFin: Integer);
    var
      JSONStream  : TStringStream;
      ResponseJSON: TJSONObject;
      Pair        : TJSONPair;
      DateStr     : string;
      Dts         : TArray<string>;
      DateDte     : TDate;
      Annee       : Word;
    begin
      JSONStream := TStringStream.Create('', TEncoding.UTF8);
      try
        GetInternetFile('calendrier.api.gouv.fr', '/jours-feries/metropole.json', JSONStream, 'application/json');
     
        ResponseJSON := TJSONObject.ParseJSONValue(JSONStream.DataString) as TJSONObject; // UTF8 !
        try
          for Pair in ResponseJSON do
          begin
            DateStr := Pair.JsonString.Value;
            Dts := DateStr.Split(['-']);
            Annee := Dts[0].ToInteger;
            if InRange(Annee, AnneeDebut, AnneeFin) then
            begin
              DateDte := System.DateUtils.EncodeDateTime(Annee, Dts[1].ToInteger, Dts[2].ToInteger, 0, 0, 0, 0);
              OnGetJourFerie(Pair.JsonValue.Value, DateDte);
            end;
          end;
        finally
          ResponseJSON.Free();
        end;
      finally
        JSONStream.Free();
      end;
    end;
     
    {$ENDREGION 'SANS dépendance à OpenSSL'}
     
    end.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
      UnitJoursFeries.GetJourFeries(
        procedure(Nom: string; Dt: TDate)
        begin
          Memo3.Lines.Add(Nom + #9#9 + DateToStr(Dt));
        end,
        2022, 2025
      );

  13. #13
    Modérateur
    Avatar de tourlourou
    Homme Profil pro
    Biologiste ; Progr(amateur)
    Inscrit en
    Mars 2005
    Messages
    3 858
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Biologiste ; Progr(amateur)

    Informations forums :
    Inscription : Mars 2005
    Messages : 3 858
    Points : 11 301
    Points
    11 301
    Billets dans le blog
    6
    Par défaut
    Bonjour,
    Le second site est beaucoup plus complet. Quant au premier, interroger un site pour ces dates peut être remplacé par un simple code local :
    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
    const
      // dates JJMM ou jours après Dimanche de Pâques
      FeriesDates: array[1..11] of integer = (0101, +1, 0105, 0805, +39, +50, 1407, 1508, 0111, 1111, 2512);
      FeriesNames: array[1..11] of string = ( 'J. de l''An' , 'Pâques' , 'Travail' ,  'Victoire' ,
                                               'Ascension' , 'Pentecôte' , 'Nationale' , 'Assomption' ,
                                                'Toussaint' , 'Armistice' , 'Noël' );
     
    var
      DatesFeries: array[1..11] of TDateTime;
     
    // https://delphi.developpez.com/faq/?page=Dates-particulieres
    function Paques(Annee : integer): TDateTime;
    var
      Y,G,C,X,Z,D,E,N,P,J,M: integer;
    begin 
      {Algorithme valable pour les dates comprises entre 1583 et 4099} 
      Y := Annee; 
      G := (Y mod 19) + 1; 
      C := Trunc((Y/100)) + 1; 
      X := Trunc(3 * C / 4) - 12; 
      Z := Trunc(((8 * C) + 5) / 25) - 5; 
      D := Trunc(((5 * Y) / 4) - X - 10); 
      E := ((11 * G)+ 20 + Z - X) mod 30; 
      if ((E = 25) and (G > 11)) or (E = 24) then 
        E := E + 1;
      N := 44 - E; 
      if N < 21 then
        N := N + 30; 
      P := N + 7 - ((D + N) mod 7); 
      if P > 31 then 
        J := P - 31 
      else 
        J := P; 
      if J = P then 
        M := 3 
      else 
        M := 4;
      Result := EncodeDate(Annee, M, J);
    end;
     
    begin
      // détermination des fériés
      DimancheDePaques := Paques(Year);
      for i := 1 to 11 do begin
        if FeriesDates[i] < 100 then
          DatesFeries[i] := DimancheDePaques + FeriesDates[i]
        else begin
          Month := FeriesDates[i] mod 100;
          Day   := FeriesDates[i] div 100;
          DatesFeries[i] := EncodeDate(Year, Month, Day);
        end;
      end;
    end;
    Delphi 5 Pro - Delphi 11.3 Alexandria Community Edition - CodeTyphon 6.90 sous Windows 10 ; CT 6.40 sous Ubuntu 18.04 (VM)
    . Ignorer la FAQ Delphi et les Cours et Tutoriels Delphi nuit gravement à notre code !

  14. #14
    Membre émérite

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2007
    Messages
    3 388
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2007
    Messages : 3 388
    Points : 2 999
    Points
    2 999
    Par défaut
    C'est vrai mais je trouve que récupérer la liste officielle est une solution toujours "à jour".

    Mais je vais conserver ta fonction en cas de connexion internent impossible.

    Merci à toi.

  15. #15
    Membre émérite

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2007
    Messages
    3 388
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2007
    Messages : 3 388
    Points : 2 999
    Points
    2 999
    Par défaut
    @ShaiLeTroll

    En Delphi 11, je t'aurais conseillé TRESTClient et TRESTRequest,
    Dans XE7, j'ai aussi le TRestClient.

    Pour apprendre comment faire ça avec ce composant, tu aurais un exemple stp ?


    ...

    J'aime toujours autant la doc Delphi

    Embarcadero Technologies ne possède pas d'informations supplémentaires pour le moment. Veuillez nous aider à documenter cette rubrique en utilisant la page Discussion !

    Récupérée de « http://localhost/Libraries/XE7/f/ind...g&oldid=545363 »

  16. #16
    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 tourlourou Voir le message
    Bonjour,
    Le second site est beaucoup plus complet. Quant au premier, interroger un site pour ces dates peut être remplacé par un simple code local :
    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
    const
      // dates JJMM ou jours après Dimanche de Pâques
      FeriesDates: array[1..11] of integer = (0101, +1, 0105, 0805, +39, +50, 1407, 1508, 0111, 1111, 2512);
      FeriesNames: array[1..11] of string = ( 'J. de l''An' , 'Pâques' , 'Travail' ,  'Victoire' ,
                                               'Ascension' , 'Pentecôte' , 'Nationale' , 'Assomption' ,
                                                'Toussaint' , 'Armistice' , 'Noël' );
     
    var
      DatesFeries: array[1..11] of TDateTime;
     
    // https://delphi.developpez.com/faq/?page=Dates-particulieres
    function Paques(Annee : integer): TDateTime;
    var
      Y,G,C,X,Z,D,E,N,P,J,M: integer;
    begin 
      {Algorithme valable pour les dates comprises entre 1583 et 4099} 
      Y := Annee; 
      G := (Y mod 19) + 1; 
      C := Trunc((Y/100)) + 1; 
      X := Trunc(3 * C / 4) - 12; 
      Z := Trunc(((8 * C) + 5) / 25) - 5; 
      D := Trunc(((5 * Y) / 4) - X - 10); 
      E := ((11 * G)+ 20 + Z - X) mod 30; 
      if ((E = 25) and (G > 11)) or (E = 24) then 
        E := E + 1;
      N := 44 - E; 
      if N < 21 then
        N := N + 30; 
      P := N + 7 - ((D + N) mod 7); 
      if P > 31 then 
        J := P - 31 
      else 
        J := P; 
      if J = P then 
        M := 3 
      else 
        M := 4;
      Result := EncodeDate(Annee, M, J);
    end;
     
    begin
      // détermination des fériés
      DimancheDePaques := Paques(Year);
      for i := 1 to 11 do begin
        if FeriesDates[i] < 100 then
          DatesFeries[i] := DimancheDePaques + FeriesDates[i]
        else begin
          Month := FeriesDates[i] mod 100;
          Day   := FeriesDates[i] div 100;
          DatesFeries[i] := EncodeDate(Year, Month, Day);
        end;
      end;
    end;

    Je reconnais partiellement l'algorithme que j'utilise, je note des différences sur le code mais qui donne exactement le même résultat sur la plage 1583 et 4099
    EDIT
    J'utilise la méthode purement mathématique Butcher-Meeus
    Et le code de tourlourou, c'est la méthode Oudin adaptée par Claus Tøndering qui a ajouté des instructions conditionnelles évitant certains calculs prévisibles donc plus rapide.

    L'objectif dans mon cas était tout autre !
    Calcul de la date de fête des mères qui ne peut être en collision avec la Pentecôte (basé sur Pâques)
    Voici le code isolé dans une Démo

    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
    unit Unit1;
     
    interface
     
    uses
      Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
      Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
     
    type
      TForm1 = class(TForm)
        Button1: TButton;
        Memo1: TMemo;
        procedure Button1Click(Sender: TObject);
      private
        { Déclarations privées }
      public
        { Déclarations publiques }
      end;
     
    var
      Form1: TForm1;
     
    implementation
     
    {$R *.dfm}
     
    uses System.DateUtils, System.Math;
     
    function GetPaques(Year: Word; AMonday: Boolean = False): TDate;
    var
      MetonRemainder, MetonCorrection: Word;
      Century, RankYear, Secular, LeapRemainder, LeapYear, LeapYearDelta: Word;
      ProemptosisCycle, Proemptosis, Epactae, SundayLetter: Word;
      Day, Month: Word;
    begin
      {Algorithme Butcher-Meeus valable pour les dates à partir de 1583}
     
      MetonRemainder := Year mod 19; // Année % 19 = n - cycle de Méton
      DivMod(Year, 100, Century, RankYear); // Année %/ 100 => c & u - centaine et rang de l'année
      DivMod(Century, 4, Secular, LeapRemainder); // c %/ 4 => s & t - siècle séculaire bissextile
      DivMod(RankYear, 4, LeapYear, LeapYearDelta); // u %/ => b & d - année bissextile et année commune
     
      ProemptosisCycle := (Century + 8) div 25; // (c + 8) / 25 = p - cycle de proemptose
      Proemptosis := (Century - ProemptosisCycle + 1) div 3; // (c - p + 1) / 3 = q - proemptose
      Epactae := (19 * MetonRemainder + Century - Secular - Proemptosis + 15) mod 30; // (19 n + c - s - q + 15) % 30 = e - épacte
     
      SundayLetter := (2 * LeapRemainder + 2 * LeapYear - Epactae - LeapYearDelta + 32) mod 7; // (2 t + 2 b - e - d + 32 L) % 7 - lettre dominicale
      MetonCorrection := (MetonRemainder + 11 * Epactae + 22 * SundayLetter) div 451; // (n + 11 e + 22 L) / 451 = h - correction
     
      DivMod(Epactae + SundayLetter - 7 * MetonCorrection + 114, 31, Month, Day); // (e + L - 7 h + 114) %/ 31 => m & j
     
      // Si m = 3, le dimanche de Pâques est le (j + 1) mars
      // Si m = 4, le dimanche de Pâques est le (j + 1) avril
      Result := EncodeDate(Year, Month, Day + 1);
     
      if AMonday then
        Result := IncDay(Result, 1);
    end;
     
     
    function GetPentecote(Year: Word; AMonday: Boolean = False): TDate;
    begin
      // Dimanche de Paques + 7 Semaines
      Result := IncDay(GetPaques(Year, AMonday), 7 * 7);
    end;
     
    function GetFeteDesMeres(Year: Word): TDate;
    begin
      // Date au dernier dimanche de mai
      Result := EndOfAMonth(Year, MonthMay);
      while DayOfTheWeek(Result) <> DaySunday do
        Result := IncDay(Result, -1);
     
      // sauf si cette date coïncide avec celle de la Pentecôte, auquel cas elle est repoussée au premier dimanche de juin
      if DaysBetween(Result, GetPentecote(Year, False)) = 0 then
        Result := IncWeek(Result, 1);
    end;
     
     
    procedure TForm1.Button1Click(Sender: TObject);
    var
      I: Integer;
    begin
      for I := 2015 to 2045 do
        Memo1.Lines.Add(IntToStr(I) + ': ' + FormatDateTime('YYYY-MM-DD', GetFeteDesMeres(I)));
    end;
     
    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

  17. #17
    Membre émérite

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2007
    Messages
    3 388
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2007
    Messages : 3 388
    Points : 2 999
    Points
    2 999
    Par défaut
    Merci pour la fête des mères

    J'en profite pour demander si vous avez le même problème que moi dans Firefox quand je visualise le code dans une fenêtre à part :

    Nom : 2024-03-07_105637.jpg
Affichages : 64
Taille : 67,7 Ko

  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
    HS: "Visualiser dans une fenêtre à part" affiche de la même façon sur Chrome y compris même le titre "Code post? sur le forum" ...

    On devrait sortir ça dans un sujet "bug charset 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

  19. #19
    Modérateur
    Avatar de tourlourou
    Homme Profil pro
    Biologiste ; Progr(amateur)
    Inscrit en
    Mars 2005
    Messages
    3 858
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Biologiste ; Progr(amateur)

    Informations forums :
    Inscription : Mars 2005
    Messages : 3 858
    Points : 11 301
    Points
    11 301
    Billets dans le blog
    6
    Par défaut
    Signalé, merci
    Delphi 5 Pro - Delphi 11.3 Alexandria Community Edition - CodeTyphon 6.90 sous Windows 10 ; CT 6.40 sous Ubuntu 18.04 (VM)
    . Ignorer la FAQ Delphi et les Cours et Tutoriels Delphi nuit gravement à notre code !

  20. #20
    Membre émérite

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2007
    Messages
    3 388
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2007
    Messages : 3 388
    Points : 2 999
    Points
    2 999
    Par défaut
    En fait, si j'utilise Firefox, c'est parce que c'est le seul navigateur qui ne me pose de problème de clic sur les liens.
    Sur Chrome et Edge, sur le forum et plein d'autres sites, le clic sur un lien ne fonctionne pas.
    Je dois faire un ctrl clic pour ouvrir dans une autre fenêtre ou maj clic pour un autre onglet.
    Et sur le forum, le "visualiser dans une fenêtre à part" sur un autre onglet me réaffiche le fil en cours. Ce qui ne me sert à rien.
    Donc, je n'ai pas trop le choix :-(

    Maintenant, pourquoi ce comportement sur les autres navigateurs, aucune idée !
    Mais heureusement que j'ai Firefox sinon je serais bien embêté

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. [TIdHTTP] Récupérer code HTML
    Par daedric dans le forum Web & réseau
    Réponses: 1
    Dernier message: 26/04/2006, 10h02
  2. indy10 comment arrêter un tidhttp.post
    Par dvarrel dans le forum Web & réseau
    Réponses: 2
    Dernier message: 21/03/2006, 23h00
  3. TidHTTP et gestion d'un password incorrect
    Par Lio590 dans le forum Web & réseau
    Réponses: 2
    Dernier message: 16/10/2005, 22h10
  4. Petite question TIdHTTP
    Par tixu dans le forum Web & réseau
    Réponses: 7
    Dernier message: 29/10/2004, 16h25

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