Obtenir le nom de l'appareil sur lequel un programme Delphi s'exécute.

On s'en servait peu dans le cas de logiciels classiques, mais dès qu'on commence à permettre aux utilisateurs de se connecter depuis de multiples endroits et sur de nombreux appareils il peut être bon de connaître le nom des machines qu'ils utilisent pour le leur afficher quelque part.

Dropbox, Google, Facebook, Apple et Twitter s'en servent afin de sécuriser les accès à leurs sites. Ils préviennent les utilisateurs et leur permettent d'interdire l'accès depuis un appareil ou un autre. Bien entendu le nom de l'appareil ne suffit pas pour sécuriser quoi que ce soit : il faut aussi d'autres critères comme l'IP de connexion, l'adresse MAC de l'appareil et d'autres éléments qui peuvent être difficilement duplicables.

Quand on s'attèle à cette tâche, la problématique que l'on a est de savoir où piocher les informations que l'on désire obtenir, et bien entendu elles dépendent de la plateforme d'exécution de notre application.

Pour gérer ce genre de choses, Embarcadero intègre des services de plateformes dans Firemonkey. Ce sont des classes ou des interfaces servant d'intermédiaires avec le matériel ou les fonctions logicielles disponibles ou pas sur la cible d'exécution. Elles permettent avec un même appel d'accéder aux API des différents appareils ou signalent que celles-ci ne sont pas disponibles.

Parmi ces services de plateforme, c'est dans IFMXDeviceService qu'on s'attendrait à trouver une fonction ou une propriété nous donnant le nom de l'appareil sur lequel on exécute le programme. Manque de bol ça n'y est pas et c'est un peu normal : le nom de l'ordinateur, du smartphone, de la tablette ou d'une manière générale du "device" n'est pas une composante absolue de chaque système d'exploitation. Nous allons donc devoir ruser et nous adapter.

Récupérer le nom de l'ordinateur sous Windows

Sous Microsoft Windows il n'est pas très compliqué de récupérer le nom de l'appareil. On considère que c'est le nom NETBIOS configuré lors de l'installation du système d'exploitation ou changé par l'administrateur du système. Ce nom est stocké dans la base de registres mais on peut aussi l'obtenir par l'API Windows avec la fonction getComputerName() ou getComputerNameEx().

Microsoft a bien fait les choses car depuis Windows XP nous avons également une variable d'environnement qui contient ce nom : COMPUTERNAME. Sous Delphi il suffit donc de lire sa valeur et si par malchance elle n'est pas renseignée on peut se rabattre sur l'autre variable d'environnement liée au réseau : HOSTNAME.

  Result := GetEnvironmentVariable('COMPUTERNAME');
  if ('' = Result) then
    Result := GetEnvironmentVariable('HOSTNAME');

Ne pas oublier d'importer l'unité System.SysUtils qui fournit GetEnvironmentVariable().

Ces informations fonctionnent sous Firemonkey mais également avec la VCL puisqu'elles sont directement liées à l'OS.

Récupérer le nom de l'ordinateur sous macOS

Le framework Foundation de macOS fournit tout ce qu'il faut pour obtenir des informations sur l'ordinateur sur lequel tourne un programme. Pour accéder à ses informations il faut commencer par utiliser les deux unités suivantes :

uses Macapi.Foundation, Macapi.helpers;

Macapi.Foundation contient le mapage de la librairie fournie par Apple.
Macapi.Helpers contient des méthodes pratiques notamment pour convertir les types Objective-C / Swift en types Delphi et permettre leur utilisation dans nos programmes.

La classe qui contient le nom de l'ordinateur se nomme NSHost. On crée donc une variable permettant d'y accéder.

var
  hote: NSHost;

Puis on appelle simplement la fonction fournie par Apple.

  hote := tnshost.Create;
  Result := NSStrToStr(hote.localizedName);

Pas de libération de la classe dans notre cas, c'est juste un accès aux API du système d'exploitation. Delphi s'occupe de tout.

Récupérer le nom de l'ordinateur sous Android

Pour Android la complexité ne vient pas du code mais de la multitude de possibilités. Les appareils sous Android n'ont en effet pas de nom et par conséquent il n'est pas possible de l'obtenir... Nous devons donc chercher à différents emplacements en fonction de la version d'Android et du matériel.

Afin d'accéder aux API utiles du système il faut commencer par utiliser trois unités fournies avec Delphi.

uses Androidapi.JNI.Os, Androidapi.JNI.Provider, Androidapi.helpers;

Androidapi.helpers comme pour sa copine sous macOS permet notamment de convertir des types liés à Android vers ou depuis des types Delphi.
Androidapi.JNI.Os et Androidapi.JNI.Provider décrivent un certain nombre de classes liées aux différentes versions d'Android. Elles contiennent les accès aux zones de stockages de paramètres mais aussi aux informations matérielles.

Comme Android ne fournit pas de vrai nom pour ses appareils, on pioche à plusieurs endroits.

En Java on aurait tendance à récupérer le nom de l'hôte à partir de son IP. Le hic, c'est que tous les appareils sous Android n'ont pas forcément de connexion réseau et que par conséquent on obtient la plupart du temps une IP locale et "LOCALHOST" comme nom d'appareil. Vous en conviendrez : ça n'aide pas beaucoup dans ce qu'on veut faire.

Il est donc de coutume de commencer par le nom attaché à la connexion Bluetooth. Il sert en général pour le partage d'infos et est le plus à jour quand il est disponible. Certains appareils sous Android n'ont pas de Bluetooth et par conséquent ça ne donne aucune réponse.

  Result := JStringToString(TJSettings_Secure.JavaClass.getString
    (TAndroidHelper.ContentResolver, StringToJString('bluetooth_name')));

Sur des versions récentes certains constructeurs comme Amazon ont décidé de donner un nom à leurs périphériques. Il est tantôt renseigné en dur par le fabricant, soit disponible en saisie dans les paramètres. Bien entendu il n'est pas disponible partout, on ne doit donc pas s'en contenter.

  Result := JStringToString(TJSettings_Global.JavaClass.getString
    (TAndroidHelper.ContentResolver, StringToJString('device_name')));

Il y a probablement d'autres paramètres susceptibles de contenir un nom exploitable de l'appareil, comme le nom de son réseau WIFI s'il est configuré et en émet un. Consultez la documentation de votre appareil s'il est spécial et les API personnalisées par son fabricant à défaut de trouver votre bonheur dans les informations fournies par Google directement dans la documentation d'Android.

A défaut de nom "utilisateur" on peut quand même récupérer un nom plus technique, mis en dur par le fabricant dans la distribution Android préinstallée. Pour cela il suffit d'interroger les informations de la classe android.os.Build.

  Result := JStringToString(tjbuild.JavaClass.model);

Là encore, si le MODEL n'est pas renseigné, on a une petite chance de trouver quelque chose dans DISPLAY.

  Result := JStringToString(tjbuild.JavaClass.DISPLAY);

Je vous propose d'en rester à 4 niveaux de recherche en prenant le premier qui ait un contenu. Ca donne donc ça.

  Result := JStringToString(TJSettings_Secure.JavaClass.getString
    (TAndroidHelper.ContentResolver, StringToJString('bluetooth_name')));
  if ('' = Result) then
    Result := JStringToString(TJSettings_Global.JavaClass.getString
      (TAndroidHelper.ContentResolver, StringToJString('device_name')));
  if ('' = Result) then
    Result := JStringToString(tjbuild.JavaClass.model);
  if ('' = Result) then
    Result := JStringToString(tjbuild.JavaClass.DISPLAY);

Bien entendu vous êtes libre de chercher d'autres sources de nom pour vos appareils... et n'hésitez pas à partager vos trouvailles avec moi pour que je les ajoute éventuellement ici.

Récupérer le nom du smartphone (iPhone) ou de la tablette (iPad) sous iOS

Pour iOS, c'est aussi simple que pour macOS : pour ça Apple fait bien les choses. On peut utiliser la classe UIDevice qui contient des informations sur le matériel (batterie, capteurs, nom de l'appareil, version et nom de l'OS).

Cette classe n'étant pas importée en standard dans les unitées proposées par Embarcadero, j'ai pompé celle que Daniele Teti fournit avec les sources de son excellent livre Delphi Cookbook (2nd edition). Il explique au chapitre 8 comment accéder aux API Java de Android et aux API Objective-C de iOS lorsqu'elles ne sont pas intégrées en standard à Firemonkey. Ce qui sert pour les API des systèmes d'exploitation vous permettra également d'accéder à toutes les librairies open source, privées ou commerciales écrites dans ces deux langages.
A elles seules ces pages justifient amplement l'acquisition et la lecture du livre. Livre par ailleurs intéressant du début à la fin et bourré d'exemples utilisables tels quels dans vos programmes.

Pour utiliser la classe UIDevice, on doit ajouter le code suivant à notre programme.

uses
  iOSapi.CocoaTypes, iOSapi.Foundation, Macapi.ObjectiveC, Macapi.helpers;

type
  UIDeviceClass = interface(NSObjectClass)
    ['{A2DCE998-BF3A-4AB0-9B8D-4182B341C9DF}']
    function currentDevice: Pointer; cdecl;
  end;

  UIDevice = interface(NSObject)
    ['{70BB371D-314A-4BA9-912E-2EF72EB0F558}']
    function name: NSString; cdecl;
  end;

  TUIDevice = class(TOCGenericImport<UIDeviceClass, UIDevice>)
  end;

Dans l'unité disponible avec l'exemple j'ai conservé des fonctions qui ne sont pas utiles dans le cas qui nous occupe mais peut-être vous seront-elles utiles pour d'autres choses.

Pour accéder aux méthodes fournies par cette classe, comme pour macOS on doit passer par une variable à déclarer dans le programme

var
  hote: UIDevice;

puis à utiliser tout simplement.

  hote := TUIDevice.Create;
  Result := NSStrToStr(hote.name);

Et voilà. C'est tout simple une fois qu'on a accès aux informations du système. Le plus dur étant fait par la classe générique TOCGenericImport et le compilateur de Delphi.

Récupérer le nom de l'ordinateur sous Linux

Sous Linux il suffit de récupérer le nom de l'hôte par appel de la commande hostname. Sur certaines versions du système cette information est également stockée dans la variable d'environnement du même nom.

  Result := GetEnvironmentVariable('HOSTNAME');

N'ayant pas pu faire de test pour le moment afin de vérifier sur différentes distributions que tout passe correctement, je me contenterai donc de vous suggérer la lecture de la variable d'environnement en attendant mieux. Je ferai les tests dès que possible et modifierai cet article et l'unité correspondante dans la boite à outils du blog.

Et maintenant testons

Pour vous éviter de recoller les morceaux je vous propose un programme de test avec l'unité regroupant tout ça. Il est librement téléchargeable sur GitHub avec les autres exemples du blog.

Il vous suffit de le télécharger et l'exécuter sur la plateforme que vous voulez. Vous pouvez bien entendu utiliser ces bouts de code dans vos logiciels.


Mug Toucan DX dans la baie de RioMug Pascal case in Alexandrie