Appel d’une fonction C/C++ en Windows Phone

Introduction

Pour les besoins d’un client, j’ai récemment été confronté à l’exploitation d’une librairie C sur Windows Phone. N’étant pas moi même familier au développement natif C et C++, je me suis arraché les cheveux à vouloir effectuer des appels de méthodes C à partir d’un projet Windows Phone classique. Pour faciliter le travail de ceux qui seraient confronté à la même problématique, je vais partager avec vous mon expérience.

Nous allons donc voir comment procéder pour exécuter du code écrit en C ou en C++ à partir d’un Windows Phone.

Pour cela, nous allons rapidement faire la distinction entre code natif et code managé, présenter l’architecture Windows Phone pour mieux comprendre le cloisonnement des couches, présenter le projet de type Hybrid que nous allons utiliser et enfin détailler les étapes de la réalisation.

Code natif vs code managé

Tout d’abord, il faut faire la distinction entre code managé et code natif.

Le code natif est du code C ou C++ compilé pour les plateformes ARM ou x86.

Le code managé, c’est du code C# compilé en langage MSIL (Microsoft IntermediateLanguage). Contrairement au code natif, la mémoire est gérée grâce au Garbage collector.

Pour Windows Phone 8, la compilation s’effectue « sur le cloud », c’est à dire au moment de la publication, en code natif pour ARM.

A la différence de Windows Phone 7.x, Windows Phone 8 supporte Visual C++ 2012, c’est à dire la version complète de C++, qui est disponible sur desktop.  Les versions desktop et mobile utilisent le même compilateur et le même IDE. Cela signifie que les applications Windows Phone peuvent utiliser du code existant C et C++ développé pour d’autres plateformes, en complément de librairies tierces et middleware (compatibilité source).

Attention cependant, Windows Phone 8 supporte une partie limitée des APIs COM et Win32 disponibles sur desktop. Une liste complète est disponible ici: http://msdn.microsoft.com/en-us/library/windowsphone/develop/jj207198(v=vs.105).aspx.

Pour aller plus loin sur le sujet, n’hésitez pas à consulter le MSDN: http://msdn.microsoft.com/en-us/library/windowsphone/develop/jj681687(v=vs.105).aspx

Petit rappel d’architecture Windows Phonearchi

Projet Hybride

Visual Studio mets à notre disposition le template de projet de type Hybrid (Class Libraries / Components) + (XAML + C# / VB) ».

Une application hybride va permettre d’exploiter du code natif à partir de code managé.

Elle se compose de 2 projets différents : le premier étant un projet classique Windows Phone 8 (xaml/c#) pour la partie managée et le deuxième un projet Windows Phone Runtime Component.

Le projet Windows Phone Runtime Component est un projet C++ qui va jouer le rôle de couche intermédiaire, appelée « wrapper ». Ce wrapper permet de faire le lien entre projet Windows Phone classique et librairie native C.

La DLL C est liée au wrapper qui va ainsi pouvoir exploiter ses méthodes natives.

Le wrapper est ensuite référencé au sein du projet Windows Phone classique.

archi2

L’hybride en pratique

Pour exploiter une librairie C, il faut:

  • Utiliser un projet de type Windows Phone Runtime Component comme Wrapper entre l’application Windows Phone et la librairie native
  • Disposer des fichiers .lib et .h (dans le cas d’une liaison statique)
  • Disposer des fichiers .lib (points d’entrées uniquement) + .h et de la DLL (dans le cas d’une liaison dynamique)

Mise en pratique

L’ objectif de la démonstration est de démontrer la faisabilité d’exécution de code C à travers l’utilisation d’un Windows Phone.

Nous allons développer une application Windows Phone classique à partir de laquelle il nous sera possible d’appeler du code natif.

La mise en pratique va se découper en 3 phases distinctes:

  1. l’implémentation de la librairie C
  2. la création du Wrapper (projet de type Windows Phone Runtime Component)
  3. la création d’une application classique Windows Phone, écrite en C#

La librairie C

Créer un projet de type Windows Phone Empty Static Library
tuto1
Une fois le projet créé, un fichier PhoneLib.cpp est inséré par défaut. Modifiez l’extension du fichier en PhoneLib.c de sorte à forcer la compilation en langage C.
tuto2

Ces fichiers c et h vont constituer notre point d’entrée dans la DLL.

Le fichier .h va contenir la déclaration de la méthode externe destinée à être appelée depuis notre application Windows Phone.

Ajouter le code suivant dans le .h :

#ifdef __cplusplus
extern "C"
{
#endif

 __declspec(dllexport) wchar_t* DisplayHelloFromLib();

#ifdef __cplusplus
}
#endif
Le fichier .c va contenir l’implémentation de la méthode DisplayHelloFromLib.
Ajouter le code suivant dans le .c
#include "pch.h"
#include "PhoneLib.h"

__declspec(dllexport) wchar_t* DisplayHelloFromLib()
{
	wchar_t  *data = L"Hello from static C";
	return data;
}

Cette méthode DisplayHelloFromLib() est la fonction qui va être appelée à partir du Wrapper. Dans notre exemple, elle se contente de retourner une chaîne de caractère « Hello from static C ».

Le Wrapper

Création d’un projet Windows Phone Runtime Component
tuto3 tuto4

Avant d’appeler notre méthode C précédemment crée, il va falloir référencer la librairie au sein du Wrapper. Contrairement aux projets classique avec code managé, il ne suffit pas de faire un clique droit sur le projet et d’ajouter une référence au projet. Cette référence passe par un paramétrage du Wrapper.

En effet, il faut « Linker » la librairie (.lib) au Wrapper.

Dans les propriétés du Wrapper, renseignez le nom de la librairie à linker:

tuto5

Pour pouvoir exploiter cette librairie il faut renseignez le chemin d’accès à cette librairie:

Il faut ensuite indiquer le chemin d’accès au fichier .h contenant la définition de la méthode C:

tuto6

Maintenant que la librairie est linkée, il nous est possible d’appeler la méthode C.

Déclarez une nouvelle méthode C++ dans le fichier Wrapper.h du Wrapper:

extern "C"
{
#include "PhoneLib.h"
#include "PhoneDLL.h"
}

namespace Wrapper
{
    public ref class WindowsPhoneRuntimeComponent sealed
    {
	public:
		String^ CallMyStaticCProgram();
    }
}

Notez l’utilisation du mot clé extern pour l’include des .h. Ceci permet d’indiquer que les fichiers .h en question sont étrangers au Wrapper.

Implémentez ensuite la méthode C++ qui va effectuer l’appel à la méthode C:

String^ WindowsPhoneRuntimeComponent::CallMyStaticCProgram()
{
        wchar_t *w = DisplayHelloFromLib();
	StringReference sr(const_cast<wchar_t*>(w));
	return sr;
}

Notez l’appel à notre méthode DisplayHelloFromLib déclarée dans la librairie C.

L’application Windows Phone

Il ne nous reste plus qu’à créer un projet Windows Phone classique, en XAML/C#, dans lequel on référence le projet Wrapper.

Une fois la référence ajoutée, il nous est possible d’instancier notre classe WindowsPhoneRuntimeComponent déclarée dans le Wrapper et d’appeler ensuite la méthode C++ appelant elle-même la méthode C:

private void Button_Click(object sender, RoutedEventArgs e)
{
            var wrapper = new WindowsPhoneRuntimeComponent();
            Tb.Text = wrapper.CallMyStaticCProgram();
}

WP_20140218_001
Et voilà. L’application Windows Phone appelle le Wrapper qui se charge à son tour d’appeler la librairie C.

Note:
Avant de pouvoir exécuter ce code sur un device Windows Phone, pensez à modifier la plateforme cible en ARM :

arm

Note: Vous constaterez que j’ai réalisé cette démonstration à l’aide d’une librairie statique.
En effet, il est en théorie possible d’appeler une librairie dynamique (en utilisant une dll). Malheureusement, je n’y suis pas encore parvenu car j’ai systématiquement une erreur (au runtime) de type « FileNotFoundException » laissant imaginer qu’une référence est manquante lors de l’appel à la méthode C.

error

Il est important de distinguer statique de dynamique: une librairie statique va être linkée à un projet sous forme de « package » contenant toutes les dépendances nécessaires pour fonctionner.
La librairie dynamique, contrairement à la statique, se présente sous la forme d’une dll seule, qui, lors de l’exécution va résoudre dynamiquement ses dépendances.
Je poursuis mes recherches sur la librairie dynamique. Si vous avez déjà pratiqué ce genre d’appel à une librairie dynamique, je suis preneur🙂

Téléchargez les sources ici: http://1drv.ms/1bJBDzR

3 réflexions sur “Appel d’une fonction C/C++ en Windows Phone

  1. Mathieu dit :

    Dès le départ à la création de la Librairie Statique C, j’ai un problème lié au changement de l’extension du PhoneLib.cpp en .c. Il me retourne le message d’erreur suivant:
    « error C1853: Le fichier d’en-tête précompilé ‘Debug\PhoneLib.pch’ est issu d’une version antérieure du compilateur, ou l’en-tête précompilé est en C++ et vous l’utilisez en C (ou inversement) »

    J’ai résolu (ou bidouillé) le problème en laissant l’extension .cpp , ou alors en changeant l’extension de pch.cpp -> pch.c

    Ensuite, pour mon wrapper, j’y est ajouté la référence vers path de PhoneLib.lib, ainsi que pour les include (comme dans le tuto).
    A la génération, le compilateur me donne l’erreur :
    error LNK2019: symbole externe non résolu _prod référencé dans la fonction « public: virtual int __cdecl Wrapper::ProdClass::[Wrapper::__IProdClassPublicNonVirtuals]::prodCpp(int,int) » …

    (prod étant le nom de ma méthode « int prod (int a,int b),
    ProdClass le nom de ma class ref et
    prodCpp(int,int) la méthode de mon WinRT qui contient ma méthode prod() ici de ma librairie )

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s