#WinJS et #CPP : appeler un callback #JS depuis mon C++

Une des grandes forces de Windows 8 est la possibilité d’utiliser conjointement et facilement des composants écrits en C#/VB, Javascript ou C++. Il y a cependant une “technique” à connaitre pour appeler correctement du Javascript depuis votre C++ sans se retrouver avec des erreurs. Cela est notamment le cas lorsque vous voulez utiliser SQLite3.js disponible sur GitHub.

 

Depuis votre application

C’est le cas  le plus classique et le plus simple, vous souhaitez passer un callback JS à appeler à votre code C++. Pour cela vous définissez un delegate C++ et vous l’utilisez par exemple en paramètre d’une fonction :

public delegate int MonDelegate( int a, int b);

//plus loin
void FunctionVisibleDepuisJavascript(MonDelegate^ func){  

  func->Invoke(3,4);
}

Ensuite, dans votre javascript, il est très simple d’appeler cette fonction :

var monCallBackJS =  function (a, b) { return a + b };

var cpp = new InfiniteSqure.MonComposantWinRTCPP();
cpp.FunctionVisibleDepuisJavascript(monCallBackJS );

 

Imaginons maintenant que vous souhaitez utiliser un peu la puissance de la PPL et que vous vouliez appeler le callback depuis une task : bing bam boum crash ! il est nécessaire d’appeler le callback sur le même thread que le code Javascript. Pour cela, il faut récupérer le Dispatcher de la fenêtre principale et l’utiliser :

//Récupération du Dispatcher
auto disp = Windows::UI::Core::CoreWindow::GetForCurrentThread()->Dispatcher;

//Création d'un handler à éxécuter
auto handler = ref new Windows::UI::Core::DispatchedHandler(
    [func]() { func->Invoke(3,4); });

auto task=    concurrency::create_task([handler,disp](){

    //Execution de l'handler
    disp->RunAsync(Windows::UI::Core::CoreDispatcherPriority::Normal, handler);

    //Cela crasherait :(
    //func->Invoke(3,4);
});


Depuis une BackgroundTask

Maintenant que nous avons ce code qui fonctionne dans l’application, on peut se sentir tranquille. Le problème est que si vous faite appel au composant depuis une tâche de fond, cela va crasher car il n’y a pas de fenêtre principale et donc pas de Dispatcher courant. La solution est plus simple qu’il n’y parait : on utilise le Dispatcher que s’il existe :

auto window = Windows::UI::Core::CoreWindow::GetForCurrentThread();

//Récupération du Dispatcher
Windows::UI::Core::CoreDispatcher^ disp = nullptr;

if(window){
    disp= window->Dispatcher;
}

if(!disp){
    func->Invoke(3,4);
}else{
    /*code précédent utilisant l'handler */
}

Photo de profil

Ces billets pourraient aussi vous intéresser

Vous nous direz ?!

Commentaires

comments powered by Disqus