Aller vers Misoft.fr       Retour à la page précédente       Dernière mise à jour : 22/07/2016

CODE ?

L'environnement de développement utilisé : Windows 10, Visual Studio Community 2015.

De nombreux algorithmes sont inspirés de codes trouvés sur le web. Je les reformule à ma manière, et j'espère aussi les améliorer et les rendre réutilisables.

Les commentaires sont les bienvenus, d'autant que peu de développeurs ont eu l'occasion de tester ces codes !

Je souhaite garder le contrôle sur le contenu de cette page, donc pas de blog.

Envoyer les mails à info@misoft.fr

J'apporte ma contribution à l'amélioration de Visual Studio sur le site Visual Studio UserVoice, en Anglais.

Auteur : Laurent CHAMBARET

Au sommaire :

Langage XAML

Ajouter la fonctionnalité de zoom interactif de l'affichage

Un contrôle de type ScrollViewer permet à l'utilisateur d'effectuer un zoom de l'affichage.

Cette fonctionnalité a été testée dans le contexte XAML de cible WPF.

Dans l'exemple suivant, le contrôle avec zoom est la fenêtre complète.

Le ScrollViewer est ici horizontal, mais il pourrait tout aussi bien être vertical.

MainWindow.xaml

  <Window ... SizeChanged="Window_SizeChanged">
    <ScrollViewer HorizontalScrollBarVisibility="Auto">
      <Grid>
        <Grid.LayoutTransform>
          <ScaleTransform
            ScaleX="{Binding ElementName=uiSliderMain, Path=Value}"
            ScaleY="{Binding ElementName=uiSliderMain, Path=Value}" />
        </Grid.LayoutTransform>
        ...
      </Grid>
    </ScrollViewer>
  </Window>

Le code XAML ci-dessus suffit pour intégrer la fonctionnalité de zoom.

Lorsque la fenêtre est affichée pour la première fois ou lorsqu'elle est re-dimensionnée, il est utile de fixer un zoom par défaut. Le multiplicateur ZOOM doit être choisi. Il est différent d'une application à l'autre. Cela dépend de la largeur occupée par les contrôles actuellement ou plus tard dans le déroulement de l'application. Il est ainsi possible de choisir que le zoom initial occupe toute la largeur d'affichage, ou seulement une partie de la largeur.

Utiliser ActualWidth au lieu de Width, qui n'a pas encore sa nouvelle valeur dans l'événement lorsque la fenêtre est maximisée.

MainWindow.xaml.cs

  private const double ZOOM = 0.0011;
	 
  private void Window_SizeChanged(object sender, SizeChangedEventArgs e)
  {
    uiSliderMain.Value = (ActualWidth - 50) * ZOOM;
  }

Si un contrôle (ici oControl) doit occuper toute la hauteur de la fenêtre, par exemple, il faut annuler le multiplicateur de zoom.

Le MaxWidth permet que le contrôle reste entièrement visible, quitte à ce que le contrôle n'occupe pas toute la hauteur.

MainWindow.xaml.cs

  MainWindow oMainWindow = Application.Current.MainWindow as MainWindow;
  oControl.Height = (oMainWindow.Height - 60) / oMainWindow.uiSliderMain.Value;
  oControl.MaxWidth = (oMainWindow.Width - 60) / oMainWindow.uiSliderMain.Value;

Langage C#

Les classes peuvent être intégrées à un projet de type "Bibliothèque de classes", voire "Bibliothèque de classes (Portable)" quand cela est possible.

Les versions récentes du Framework .NET peuvent proposer des solutions similaires pour résoudre les problématiques abordées.

En premier sont présentées essentiellement des classes avec méthodes statiques, utilisables directement sans instanciation, puis des classes plus orientées objet.

Sérialisation XML d'un objet

Cette classe permet la sérialisation automatique d'une instance d'objet vers du code XML, et la dé-sérialisation automatique d'un code XML vers une nouvelle instance d'objet.

Pour obtenir la syntaxe XML, le plus simple est de d'abord instancier un objet exemple, le sérialiser en XML, puis enregistrer la chaîne de texte XML dans un fichier.

CXml.cs

  using System;
  using System.Collections.Generic;
  using System.IO;
  using System.Linq;
  using System.Text;
  using System.Xml;
  using System.Xml.Serialization;
  
  namespace Misoft.Library.Class
  {
    /// <summary>
    /// Sérialisation et dé-sérialisation au format XML.
    /// Le résultat de la sérialisation est précédé par les codes BOM du codage UTF8.
    /// </summary>
    public static class CXml
    {
      #region Methods static
  
      /// <summary>
      /// Donne la sérialisation en chaîne XML d'un objet.
      /// </summary>
      /// <param name="oObject">Objet</param>
      /// <param name="bIndent">Indique si le XML doit être indenté avec des caractères tabulation</param>
      /// <returns>Sérialisation XML</returns>
      public static string Serialize(object oObject, bool bIndent)
      {
        if (oObject == null)
          throw new ArgumentNullException();

        XmlWriterSettings oXWS = new XmlWriterSettings();
        oXWS.Encoding = Encoding.UTF8;
        oXWS.Indent = bIndent;
        oXWS.IndentChars = "\t";
        oXWS.NewLineChars = Environment.NewLine;
        oXWS.ConformanceLevel = ConformanceLevel.Document;
        // Pas de using. Le Stream sera fermé par le XmlWriter
        MemoryStream oMemoryStream = new MemoryStream();
        using (XmlWriter oXmlWriter = XmlWriter.Create(oMemoryStream, oXWS))
        {
          XmlSerializer oXmlSerializer = new XmlSerializer(oObject.GetType());
          oXmlSerializer.Serialize(oXmlWriter, oObject);
        }
        string sXML = Encoding.UTF8.GetString(oMemoryStream.ToArray());
        return sXML;
      }
  
      /// <summary>
      /// Donne l'objet désérialisé d'un chaîne XML.
      /// </summary>
      /// <typeparam name="T">Type de l'objet</typeparam>
      /// <param name="sXML">Sérialisation XML</param>
      /// <returns>Objet désérialisé</returns>
      public static T Deserialize(string sXML)
      {
        if (sXML == null)
          throw new ArgumentNullException();

        using (MemoryStream oMemoryStream = new MemoryStream(Encoding.UTF8.GetBytes(sXML)))
        {
          XmlSerializer oXmlSerializer = new XmlSerializer(typeof(T));
          T oObject = (T)oXmlSerializer.Deserialize(oMemoryStream);
          return oObject;
        }
      }
  
      #endregion Methods static
    }
  }

Exemple de sérialisation d'une instance d'objet oInstance :

  string sXML = CXml.Serialize(oInstance, true);

Pour obtenir les octets de la sérialisation en UTF8, précédés par les codes BOM (0xEF 0xBB 0xBF) :

  byte[] vBytes = Encoding.UTF8.GetBytes(sXML);

Exemple de dé-sérialisation d'une chaîne sXML vers un objet de classe CInstance :

  CInstance oInstance = CXml.Deserialize<CInstance>(sXML);

Sérialisation XML d'un Dictionary

Cette classe permet la sérialisation XML d'une instance de classe de type dictionnaire. En effet, la classe Dictionary n'est pas directement sérialisable.

Le principe est de déclarer l'objet dictionnaire de type CDictionary au lieu de Dictionary.

Les noms de tags XML choisis sont volontairement courts ("I", "K" et "V") afin de réduire la taille du XML produit.

La classe convient pour des clés et/ou valeurs de tout type objet. Si les clés et/ou valeurs sont des types simples (nombre, chaîne...), alors il est possible d'utiliser une sérialisation plus compacte (avec une autre classe à écrire), avec clé et/ou valeur en attribut XML du tag Item plutôt qu'en élément XML.

CDictionary.cs

  using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Text;
  using System.Xml;
  using System.Xml.Schema;
  using System.Xml.Serialization;
  
  namespace Misoft.Library.Class
  {
    /// <summary>
    /// Classe dictionnaire sérialisable.
    /// </summary>
    /// <typeparam name="TKey">Type d'une clé du dictionnaire</typeparam>
    /// <typeparam name="TValue">Type d'une valeur du dictionnaire</typeparam>
    public class CDictionary : Dictionary, IXmlSerializable
    {
      #region Constants

      /// <summary>
      /// Tag XML pour un élément.
      /// </summary>
      public const string TAG_ITEM = "I";

      /// <summary>
      /// Tag XML pour une clé.
      /// </summary>
      public const string TAG_KEY = "K";

      /// <summary>
      /// Tag XML pour une valeur.
      /// </summary>
      public const string TAG_VALUE = "V";

      #endregion Constants
      #region Interface IXmlSerializable
  
      /// <summary>
      /// Donne le schéma XML.
      /// </summary>
      /// <returns>Schéma XML</returns>
      public XmlSchema GetSchema()
      {
        // Recommandé au lieu de : throw new NotImplementedException();
        return null;
      }
  
      /// <summary>
      /// Ecrit les données dans un flux XML.
      /// </summary>
      /// <param name="oXmlWriter">Flux d'écriture XML</param>
      public void WriteXml(XmlWriter oXmlWriter)
      {
        if (oXmlWriter == null)
          throw new ArgumentNullException();

        XmlSerializer oXmlSerializerKey = new XmlSerializer(typeof(TKey));
        XmlSerializer oXmlSerializerValue = new XmlSerializer(typeof(TValue));
        foreach (TKey oTKey in this.Keys)
        {
          oXmlWriter.WriteStartElement(TAG_ITEM);
  
          oXmlWriter.WriteStartElement(TAG_KEY);
          oXmlSerializerKey.Serialize(oXmlWriter, oTKey);
          oXmlWriter.WriteEndElement();
  
          oXmlWriter.WriteStartElement(TAG_VALUE);
          TValue oTValue = this[oTKey];
          oXmlSerializerValue.Serialize(oXmlWriter, oTValue);
          oXmlWriter.WriteEndElement();
  
          oXmlWriter.WriteEndElement();
        }
      }
  
      /// <summary>
      /// Lit les données depuis un flux XML.
      /// </summary>
      /// <param name="oXmlReader">Flux de lecture XML</param>
      public void ReadXml(XmlReader oXmlReader)
      {
        if (oXmlReader == null)
          throw new ArgumentNullException();

        XmlSerializer oXmlSerializerKey = new XmlSerializer(typeof(TKey));
        XmlSerializer oXmlSerializerValue = new XmlSerializer(typeof(TValue));
        bool bWasEmpty = oXmlReader.IsEmptyElement;
        oXmlReader.Read();
        if (bWasEmpty)
          return;
        while (oXmlReader.NodeType != XmlNodeType.EndElement)
        {
          oXmlReader.ReadStartElement(TAG_ITEM);
  
          oXmlReader.ReadStartElement(TAG_KEY);
          TKey oTKey = (TKey)oXmlSerializerKey.Deserialize(oXmlReader);
          oXmlReader.ReadEndElement();
  
          oXmlReader.ReadStartElement(TAG_VALUE);
          TValue oTValue = (TValue)oXmlSerializerValue.Deserialize(oXmlReader);
          oXmlReader.ReadEndElement();
  
          oXmlReader.ReadEndElement();
          this.Add(oTKey, oTValue);
          oXmlReader.MoveToContent();
        }
        oXmlReader.ReadEndElement();
      }
  
      #endregion Interface IXmlSerializable
    }
  }

Exemple de sérialisation XML :

  CDictionary<int, string> v = new CDictionary<int, string>();
  v.Add(10, "aaa");
  v.Add(3, "ccc");
  string sXML = CXml.Serialize(v, true);

Le résultat de la sérialisation XML :

  <?xml version="1.0" encoding="utf-8" ?>
  <CDictionaryOfInt32String>
    <I>
      <K>
        <int>10</int>
      </K>
      <V>
        <string>aaa</string>
      </V>
    </I>
    <I>
      <K>
        <int>3</int>
      </K>
      <V>
        <string>ccc</string>
      </V>
    </I>
  </CDictionaryOfInt32String>

Exemple de dé-sérialisation XML :

  v = CXml.Deserialize<CDictionary<int, string>>(sXML);

Cryptage MD5

Cette classe permet le cryptage MD5 d'un texte. Le décryptage de celui-ci est théoriquement impossible, sauf pour les textes courts (mot de passe...).

CCryptoMD5.cs

  using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Security.Cryptography;
  using System.Text;

  namespace Misoft.Library.Class
  {
    /// <summary>
    /// Cryptographie MD5.
    /// </summary>
    public static class CCryptoMD5
    {
      #region Methods static

      /// <summary>
      /// Donne le cryptage MD5 d'un texte.
      /// Le décryptage de celui-ci est théoriquement impossible.
      /// </summary>
      /// <param name="sText">Texte à crypter</param>
      /// <returns>Texte crypté</returns>
      /// <remarks>
      /// L'utilisation type de cette méthode consiste à comparer le cryptage du mot de passe saisi par l'utilisateur pour le login,
      /// avec le cryptage du bon mot de passe, préalablement stocké.
      /// </remarks>
      public static string Encrypt(string sText)
      {
        if (sText == null)
          throw new ArgumentNullException();

        byte[] vBytesUncrypted = Encoding.ASCII.GetBytes(sText);
        MD5CryptoServiceProvider oMD5 = new MD5CryptoServiceProvider();
        byte[] vBytesHash = oMD5.ComputeHash(vBytesUncrypted);
        StringBuilder oSB = new StringBuilder();
        for (int c = 0; c < vBytesHash.Length; c++)
          oSB.AppendFormat("{0:x2}", vBytesHash[c]);
        string sTextCrypted = oSB.ToString();
        return sTextCrypted;
      }

      #endregion Methods static
    }
  }

Exemple de cryptage de texte :

  string sCrypt = CCryptoMD5.Encrypt("Texte à crypter");

Cryptage Rijndael

Cette classe permet le cryptage et le décryptage Rijndael d'un texte.

Le cryptage est symétrique : il permet le décryptage.

CCryptoRijndael.cs

  using System;
  using System.Collections.Generic;
  using System.IO;
  using System.Linq;
  using System.Security.Cryptography;
  using System.Text;

  namespace Misoft.Library.Class
  {
    /// <summary>
    /// Cryptographie Rijndael.
    /// </summary>
    public static class CCryptoRijndael
    {
      #region Constants

      /// <summary>
      /// Taille de clé de l'algorithme de cryptage.
      /// </summary>
      private const int KEY_SIZE = 256;

      #endregion Constants
      #region Methods static

      /// <summary>
      /// Donne un texte crypté.
      /// </summary>
      /// <param name="vKeyIV">Vecteur d'initialisation IV</param>
      /// <param name="sPassPhrase">Mot de passe de cryptage</param>
      /// <param name="sPlainText">Texte à crypter</param>
      /// <returns>Chaîne cryptée</returns>
      public static string Encrypt(byte[] vKeyIV, string sPassPhrase, string sPlainText)
      {
        if ((vKeyIV == null) || (sPassPhrase == null) || (sPlainText == null))
          throw new ArgumentNullException();

        byte[] vPlainTextBytes = Encoding.UTF8.GetBytes(sPlainText);
        using (PasswordDeriveBytes oPasswordDeriveBytes = new PasswordDeriveBytes(sPassPhrase, null))
        {
          byte[] vKeyBytes = oPasswordDeriveBytes.GetBytes(KEY_SIZE / 8);
          using (RijndaelManaged oRijndaelManaged = new RijndaelManaged())
          {
            oRijndaelManaged.Mode = CipherMode.CBC;
            using (ICryptoTransform oCryptoTransform = oRijndaelManaged.CreateEncryptor(vKeyBytes, vKeyIV))
            using (MemoryStream oMemoryStream = new MemoryStream())
            using (CryptoStream oCryptoStream = new CryptoStream(oMemoryStream, oCryptoTransform, CryptoStreamMode.Write))
            {
              oCryptoStream.Write(vPlainTextBytes, 0, vPlainTextBytes.Length);
              oCryptoStream.FlushFinalBlock();
              byte[] vCipherTextBytes = oMemoryStream.ToArray();
              return Convert.ToBase64String(vCipherTextBytes);
            }
          }
        }
      }

      /// <summary>
      /// Donne un texte décrypté.
      /// </summary>
      /// <param name="vKeyIV">Vecteur d'initialisation IV</param>
      /// <param name="sPassPhrase">Mot de passe de cryptage</param>
      /// <param name="sCipherText">Texte crypté</param>
      /// <returns>Texte décrypté</returns>
      public static string Decrypt(byte[] vKeyIV, string sPassPhrase, string sCipherText)
      {
        if ((vKeyIV == null) || (sPassPhrase == null) || (sCipherText == null))
          throw new ArgumentNullException();

        byte[] vCipherTextBytes = Convert.FromBase64String(sCipherText);
        using (PasswordDeriveBytes oPasswordDeriveBytes = new PasswordDeriveBytes(sPassPhrase, null))
        {
          byte[] vKeyBytes = oPasswordDeriveBytes.GetBytes(KEY_SIZE / 8);
          using (RijndaelManaged oRijndaelManaged = new RijndaelManaged())
          {
            oRijndaelManaged.Mode = CipherMode.CBC;
            using (ICryptoTransform oCryptoTransform = oRijndaelManaged.CreateDecryptor(vKeyBytes, vKeyIV))
            using (MemoryStream oMemoryStream = new MemoryStream(vCipherTextBytes))
            using (CryptoStream oCryptoStream = new CryptoStream(oMemoryStream, oCryptoTransform, CryptoStreamMode.Read))
            {
              byte[] vPlainTextBytes = new byte[vCipherTextBytes.Length];
              int iDecryptedByteCount = oCryptoStream.Read(vPlainTextBytes, 0, vPlainTextBytes.Length);
              return Encoding.UTF8.GetString(vPlainTextBytes, 0, iDecryptedByteCount);
            }
          }
        }
      }

      #endregion Methods static
    }
  }

Exemple de cryptage de texte :

  RijndaelManaged oRijndaelManaged = new RijndaelManaged();
  string sPlainText = "Texte à crypter";
  const string sPassPhrase = "Phrase clé";
  string sCrypt = CCryptoRijndael.Encrypt(sPlainText, oRijndaelManaged.IV, sPassPhrase);

Exemple de décryptage de texte :

  string sDecrypt = CCryptoRijndael.Decrypt(sCrypt, oRijndaelManaged.IV, sPassPhrase);

Adresse IP publique du serveur

Cette classe permet l'identification de l'adresse IP v4 publique du serveur. Un serveur peut avoir plusieurs adresses IP, mais une seule est vue depuis Internet.

On peut obtenir une adresse différente de celles obtenues via Dns.GetHostEntry(Dns.GetHostName()).AddressList qui sont des adresses valables sur le réseau local.

CPublicServerIP.cs

  using System;
  using System.Collections.Generic;
  using System.Diagnostics;
  using System.IO;
  using System.Linq;
  using System.Net;
  using System.Text;
  
  namespace Misoft.Library.Class
  {
    /// <summary>
    /// Identification de l'adresse IP v4 publique du serveur.
    /// </summary>
    public static class CPublicServerIP
    {
      #region Methods static
  
      /// <summary>
      /// Donne l'adresse IP v4 publique du serveur, ou null si erreur.
      /// </summary>
      /// <returns>Adresse IP</returns>
      public static string Get()
      {
        try
        {
          const string URL_CHECKIP = "http://checkip.dyndns.org/";
          string sDirection = "";
          WebRequest oWebRequest = WebRequest.Create(URL_CHECKIP);
          using (WebResponse oWebResponse = oWebRequest.GetResponse())
          using (StreamReader oStreamReader = new StreamReader(oWebResponse.GetResponseStream()))
          {
            sDirection = oStreamReader.ReadToEnd();
          }
  
          // Recherche de l'adresse IP dans le code HTML
          // En espérant que le format HTML de sortie ne change pas dans le futur !
          int iFirst = sDirection.IndexOf("Address: ");
          if (iFirst == -1)
            return null;
          iFirst += 9;
          int iLast = sDirection.LastIndexOf("</body>");
          if (iLast == -1)
            return null;
          if (iLast < iFirst)
            return null;
          sDirection = sDirection.Substring(iFirst, iLast - iFirst);
          return sDirection;
        }
        catch (Exception x)
        {
          Debug.WriteLine("CPublicServerIP.Get : " + x.GetType() + " : " + x.Message);
          return null;
        }
      }
  
      #endregion Methods static
    }
  }

Exemple d'appel :

  string sServerIP = CPublicServerIP.Get();

Synchronisation avec un serveur de temps sur Internet (NTP)

Cette classe permet d'obtenir une heure synchronisée avec un serveur de temps sur Internet (NTP).

Il y a une synchronisation initiale avec le serveur de temps. Ensuite, l'heure actuelle est obtenue via la méthode Now de la classe, qui ne fait pas appel au serveur de temps mais ajoute à l'heure du PC le décalage de temps constaté lors de la dernière synchronisation. Il est possible d'effectuer des synchronisations ultérieures.

L'algorithme de décodage NTP provient de stackoverflow.

CInternetTime.cs

  using System;
  using System.Collections.Generic;
  using System.Diagnostics;
  using System.Linq;
  using System.Net;
  using System.Net.Sockets;
  using System.Text;
  using System.Threading;
  
  namespace Misoft.Library.Class
  {
    /// <summary>
    /// Date/heure synchronisée avec un serveur de temps sur Internet (NTP).
    /// </summary>
    /// <see cref="http://stackoverflow.com/questions/1193955/how-to-query-an-ntp-server-using-c" />
    public static class CInternetTime
    {
      #region Properties
  
      /// <summary>
      /// Dernier écart de temps connu entre DateTime.Now et l'heure obtenue depuis un serveur de temps sur Internet (NTP), en millisecondes.
      /// </summary>
      public static double DateTimeNowGap { get; private set; }
  
      #endregion Properties
      #region Properties methods
  
      /// <summary>
      /// Donne la date/heure actuelle de ce serveur synchronisée avec un serveur de temps sur Internet (NTP).
      /// Attention : Si la propriété est appelée avant l'initialisation de DateTimeNowGap, alors le résultat est l'heure locale, non synchronisée.
      /// </summary>
      public static DateTime Now
      {
        get
        {
          return DateTime.Now.AddMilliseconds(DateTimeNowGap);
        }
      }
  
      #endregion Properties methods
      #region Methods static
  
      /// <summary>
      /// Obtient l'heure depuis un serveur de temps sur Internet (NTP) et met à jour DateTimeNowGap.
      /// En cas d'erreur, DateTimeNowGap n'est pas mis à jour.
      /// </summary>
      public static void Synchro()
      {
        try
        {
          // Serveurs NTP : "time.windows.com", "pool.ntp.org" ...
          const string NTP_SERVER = "time.windows.com";
  
          byte[] vNtpData = new byte[48];
          vNtpData[0] = 0x1B;  // LeapIndicator = 0 (no warning), VersionNum = 3 (IPv4 only), Mode = 3 (Client Mode)
  
          DateTime dNow;
          IPAddress[] vIPAddress = Dns.GetHostEntry(NTP_SERVER).AddressList;
          IPEndPoint oIPEndPoint = new IPEndPoint(vIPAddress[0], 123);
          using (Socket oSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp))
          {
            Timer oTimer = new Timer(new TimerCallback(NTPTimeTimeout), oSocket, 3000, Timeout.Infinite);
            oSocket.Connect(oIPEndPoint);
            oSocket.Send(vNtpData);
            oSocket.Receive(vNtpData);
            dNow = DateTime.UtcNow;
            oSocket.Close();
          }
  
          const byte iServerReplyTime = 40;  // Offset du champ "Transmit Timestamp"
          ulong iIntPart = SwapEndianness(BitConverter.ToUInt32(vNtpData, iServerReplyTime));
          ulong iFractPart = SwapEndianness(BitConverter.ToUInt32(vNtpData, iServerReplyTime + 4));
  
          ulong iMilliseconds = iIntPart * 1000 + iFractPart * 1000 / 0x100000000L;
          DateTime dDateTime = new DateTime(1900, 1, 1).AddMilliseconds(iMilliseconds);
  
          double rDateTimeNowGapNew = (dDateTime - dNow).TotalMilliseconds;
          if (Math.Abs(rDateTimeNowGapNew) > 10 * 60 * 60 * 1000)
            return;
          DateTimeNowGap = rDateTimeNowGapNew;
        }
        catch (Exception x)
        {
          Debug.WriteLine("CInternetTime.Synchro : " + x.GetType() + " : " + x.Message);
        }
      }

      /// <summary>
      /// TimerCallback de TimeOut pour la méthode d'appel NTP.
      /// </summary>
      /// <param name="oState">Socket</param>
      private static void NTPTimeTimeout(object oState)
      {
        try
        {
          Socket oSocket = oState as Socket;
          oSocket.Close();
          oSocket.Dispose();
        }
        catch (Exception x)
        {
          Debug.WriteLine("CInternetTime.NTPTimeTimeout : " + x.GetType() + " : " + x.Message);
        }
      }

      /// <summary>
      /// Convertit entre Big-endian et Little-endian.
      /// </summary>
      /// <param name="i">Valeur d'origine</param>
      /// <returns>Valeur convertie</returns>
      private static uint SwapEndianness(ulong i)
      {
        return (uint)(((i & 0x000000ff) << 24) +
                      ((i & 0x0000ff00) << 8) +
                      ((i & 0x00ff0000) >> 8) +
                      ((i & 0xff000000) >> 24));
      }

      #endregion Methods static
    }
  }

Exemple d'appel :

  CInternetTime.Synchro();

  // Ecart entre l'heure du PC et l'heure du serveur NTP
  double rInternetNowGap = CInternetTime.DateTimeNowGap;

  DateTime dInternetNow = CInternetTime.Now;

Classe WebClient avec TimeOut

Celle classe ajoute à la classe standard WebClient la possibilité de fixer le TimeOut des demandes.

CWebClient.cs

  using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Net;
  using System.Text;
  
  namespace Misoft.Library.Class
  {
    /// <summary>
    /// Fournit des méthodes communes pour l'envoi de données à une ressource identifiée
    /// par un URI ou pour la réception de données en provenance de cette ressource.
    /// Celle classe ajoute à la classe WebClient la possibilité de fixer le TimeOut des demandes.
    /// </summary>
    public class CWebClient : WebClient
    {
      #region Properties
  
      /// <summary>
      /// Délai d'expiration des demandes en millisecondes.
      /// </summary>
      public int TimeOut { get; set; }
  
      #endregion Properties
      #region Methods override
  
      /// <summary>
      /// Retourne un objet System.Net.WebRequest pour la ressource spécifiée.
      /// </summary>
      /// <param name="oUri">Uri qui identifie la ressource à demander</param>
      /// <returns>Nouvel objet System.Net.WebRequest pour la ressource spécifiée</returns>
      protected override WebRequest GetWebRequest(Uri oUri)
      {
        WebRequest oWebRequest = base.GetWebRequest(oUri);
        if (TimeOut != 0)
          oWebRequest.Timeout = TimeOut;
        return oWebRequest;
      }
  
      #endregion Methods override
    }
  }

Exemple d'appel :

  CWebClient oWebClient = new CWebClient();
  oWebClient.TimeOut = 3000;
  string sData = oWebClient.DownloadString("http://www.google.fr/");

Envoi de SMS via OVH Telecom

Celle classe permet l'envoi de SMS via OVH Telecom.

Il faut préalablement créer un compte OVH Telecom, acquérir des crédits SMS, puis configurer le compte (Login, Password, From). Pour la création des Tokens, utiliser Chrome, pas IE.

Il s'agit d'un simple appel d'URL, donc facilement adaptable dans tout langage.

Le protocole https crypte les données transférées ainsi que l'URL, donc le login/password est protégé.

Il existe une autre méthode d'envoi avec une API, plus complexe : Guide API OVH

CSMSByOVH.cs

  using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Net;
  using System.Text;
  using System.Web;
  
  namespace Misoft.Library.Class
  {
    /// <summary>
    /// Envoi de SMS via OVH Telecom.
    /// Pour la création des Tokens OVH Telecom, utiliser Chrome, pas IE !
    /// Il faut acquérir des crédits OVH Telecom pour l'envoi des SMS.
    /// Nécessite la référence "System.Web".
    /// </summary>
    public static class CSMSByOVH
    {
      #region Methods static
  
      /// <summary>
      /// Envoie un SMS à un CGI via le protocole HTTPS.
      /// Une Exception est générée si l'envoi a échoué.
      /// Configurer dans le site OVH Manager / Telecom / SMS les valeurs de Login, Password, From.
      /// </summary>
      /// <param name="sServiceName">Nom de service OVH</param>
      /// <param name="sLogin">Login OVH Telecom pour les SMS</param>
      /// <param name="sPassword">Mot de passe OVH Telecom pour les SMS</param>
      /// <param name="sFrom">Source d'envoi des SMS</param>
      /// <param name="sPhone">Numéro de téléphone au format international</param>
      /// <param name="sMessage">Message</param>
      /// <see cref="https://docs.ovh.com/display/public/CRSMSFAX/Envoyer+des+SMS+par+HTTPS"/>
      public static void SendWithCGI(string sServiceName, string sLogin, string sPassword, string sFrom, string sPhone, string sMessage)
      {
        string sTo = sPhone.Replace("+", "00");
        string sURL = string.Format("https://www.ovh.com/cgi-bin/sms/http2sms.cgi?" +
          "account={0}&login={1}&password={2}&from={3}&to={4}&message={5}&noStop=1",
          HttpUtility.UrlEncode(sServiceName), HttpUtility.UrlEncode(sLogin), HttpUtility.UrlEncode(sPassword),
          HttpUtility.UrlEncode(sFrom), HttpUtility.UrlEncode(sTo), HttpUtility.UrlEncode(sMessage));
        string sResult;
        using (WebClient oWebClient = new WebClient())
          sResult = oWebClient.DownloadString(sURL);
        if (sResult.StartsWith("KO"))
        {
          string sErr = sResult.Substring(3).Replace("\n", " ");
          throw new ApplicationException(sErr);
        }
      }
  
      #endregion Methods static
    }
  }

Exemple d'appel. Tous les paramètres doivent être personnalisés :

  CSMSByOVH.SendWithCGI("sms-........-1", "username", "password", "from", "+33123456789", "Message envoyé");