Bonjour/Bonsoir à toutes et à tous !
Récemment, dans deux de mes projets personnels, j'ai eu besoin d'utiliser des APIs WinRT dans une application bureautique. Avec quelques manipulations, ça fonctionne, mais je me suis très vite rendu compte que l'on perdait alors la rétrocompatibilité de l'application avec Windows Vista et 7. Je vais donc donner une petite astuce toute bête et très rapide qui permet d'assurer la rétrocompatibilité.
Pour cela vous aurez besoin :
- D'un projet type Application Windows.
- Du SDK Windows 8 ou 8.1 selon les APIs que vous souhaitez utiliser.
- 125gr de beurre.
- Et 2 œufs.
Configuration du projet
Tout d'abord, vous aurez besoin du fichier "Windows.winmd", fournit par le SDK de Windows 8/8.1. Vous trouverez ce fichier à l'emplacement suivant : C:\Progam Files (x86)\Windows Kits\8.0 (ou 8.1)\References\CommonConfiguration\Neutral\Windows.winmd
.
Essayez d'ajouter ce fichier aux références de votre projet Application Windows, vous rencontrerez une erreur.
Résolvons le soucis : Déchargez votre projet dans Visual Studio, puis faîtes clic-droit sur le projet, Modifier le fichier de projet. Sous la ligne :
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
Ajoutez la ligne :
<TargetPlatformVersion>8.0</TargetPlatformVersion>
Rechargez le projet, puis essayez d'ajouter "Windows.winmd" aux références du projet; cette fois-ci, ça passe. Vous pouvez désormais utiliser les APIs WinRT dans un projet bureautique.
Le problème de compatibilité
C'est super de pouvoir utiliser les APIs WinRT, mais si on ne fait un petit peu attention, on perd bêtement la rétrocompatibilité du projet car ce fichier est exploitable exclusivement sous Windows 8 et 8.1, même avec une condition "Suis-je exécuté sous Windows 8?". Cette rétrocompatibilité est perdue au moment ou notre programme tente de charger Windows.winmd
en mémoire (rappelons que notre programme ne charge pas toutes les références à son démarrage).
Il y a UN unique point à retenir pour éviter de charger une référence avant d'en avoir réellement besoin : ne pas tenter par quelque moyen un accès à la Class contenant un membre susceptible de faire appel à cette fameuse référence.
Autrement dit : tant que vous n'instanciez pas ou n'appelez pas un membre statique d'une Class utilisant Windows.winmd
, celui-ci ne sera pas chargé, donc la rétrocompatibilité est assurée.
La solution
Du coup, vous l'aurez sûrement devinez, la solution est assez simple :
- Créez une Class "MyClassWinRT" qui sera chargé d'utiliser les APIs WinRT (de préférence non statique)
- Utilisez le code suivant, à l'extérieur de cette Class, pour tester si votre application tourne sous Windows 8 ou supérieur :
private bool RunningOnWindows8OrHigher()
{
return (Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Minor >= 2);
}
Voila, il ne reste plus qu'à exploiter la Class :
private void OkButton_Click(object sender, RoutedEventArgs e)
{
if (RunningOnWindows8OrHigher())
{
var winRt = new MyClassWinRT();
winRt.ShowToas(); // Une fonction qui affichera un ToastNotifcation par exemple.
}
else
{
// Afficher une InfoBulle
}
}
C'est tout 😁
Avec cette méthode, SoftwareZator 4.0 est capable, par exemple, de récupérer la liste des applications Windows Store installés, et la prochaine mise à jour de ClipboardZanager sera capable d'afficher des ToastNotifications tout en préservant la rétrocompatibilité avec Windows Vista et Windows 7.
Alternative
Une autre solution est possible, mais je l'apprécie beaucoup moins : chargez "Windows.winmd" au Runtime et utilisez les fonctions par réflexion. Ca vous évite de passer par une Class, mais le code devient beaucoup moins propre, voir dégueulasse ! A éviter donc :)