Blog de JP Gouigoux

05/01/2010

PartCover

Filed under: .NET — jpgouigoux @ 8:38

Comme certainement beaucoup d’entre vous, j’ai été assez déçu de voir que NCover était désormais un logiciel commercial. Dans le cadre de mon travail, j’ai demandé à disposer de la version professionnelle, surtout pour pouvoir utiliser une GUI. En pratique, je ne trouve pas terribles les améliorations par rapport à la 1.5.8. Il s’agit de la dernière version Open Source, disponible, bien que pas tellement publiée, sur le site ncover.com, en cliquant sur le lien pour télécharger la version d’essai, puis en cliquant sur le bouton “Have a license ? Download here”.

Les messages d’erreur dans la version commerciale sont toujours aussi abscons que dans la version Open Source. En particulier, si vous obtenez une couverture de code absolument vide, c’est classiquement parce que les fichiers .pdb n’étaient pas avec vos fichiers .dll. Pas de message, rien, alors que c’est pourtant une erreur habituelle. De même pour la non-registration de la librairie de base. Pourquoi ne pas remonter un message d’erreur ? Et quand vous avez passé tous ces problèmes, il vous reste encore à ne pas oublier de rajouter /noshadow en option de NUnit, sinon il place en cache les .dll… mais pas les .pdb, et vous retombez dans le même souci que précédemment.

Bref, beaucoup de travail pour une version commerciale. D’où l’idée de voir si un projet Open Source avait pris le relai. C’est le cas, avec PartCover, disponible sur SourceForge. SharpDevelop utilise désormais ce logiciel plutôt que NCover, pour rester au plus près de l’esprit Open Source.

Publicités

02/08/2009

Mise à jour des librairies pour FOP en .NET

Filed under: .NET,FOP — jpgouigoux @ 2:13
Tags: ,

Suite à une demande dans les commentaires d’un précédent article, voici les librairies compilées en .NET pour faire du XSL/FO par interop avec IKVM. J’en profite pour passer aux nouvelles versions de FOP (0.95) et d’IKVM (0.40.0.1).

Le tout a été buildé sur la base d’une VM 1.6.0_13-b03, et sans clé de nom fort.

Voici le lien. Si vous utilisez ces librairies, merci de m’envoyer un petit message sur votre retour d’expérience, satisfaisant ou pas.

Tant que j’y suis… Cette méthode est manuelle, et ne sélectionne pas les classes utilisées pour la compilation par IKVM. Si vous voulez seulement faire du XSLFO, vous pouvez utiliser également le projet NFOP. D’après ce que j’ai compris, ce n’est pas un portage de FOP en .NET, mais plutôt la même chose que ce que j’ai détaillé dans le post sur XSL/FO en .NET, à savoir une recompilation. Par contre, ils font bien sûr beaucoup mieux les choses, et en particulier, ils doivent filtrer les classes nécessaires lorsqu’ils compilent les JAR de dépendances, ce qui fait que le résultat est bien plus léger. Je vais tester si il n’y a pas autre chose, et je posterai mes remarques dans quelque temps.

21/03/2009

Programmation parallèle en .NET

Filed under: .NET — jpgouigoux @ 8:21

Un petit test de la parallélisation en .NET, avec la CTP de Juin 2008 des Parallel Extensions.

A utiliser, c’est très simple : on utilise une nouvelle librairie System.Threading, qui rajoute des opérateurs parallélisés ainsi que des listes supportant la parallélisation.

Voici un petit bout de code pour tester sur un AMD 64X2 4400+, avec donc deux coeurs :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Threading;

namespace TestParallelisation
{
class Program
{
static void Main(string[] args)
{
List Entiers = new List();

for (int ind = 100000; ind < 120000; ind++) Entiers.Add(ind); Stopwatch Chrono = Stopwatch.StartNew(); List Premiers = new List();

foreach (int Entier in Entiers)
if (EstPremier(Entier))
Premiers.Add(Entier);
Console.WriteLine(« {0} premiers trouvés en {1} ms », Premiers.Count, Chrono.Elapsed.Milliseconds);

 Chrono = Stopwatch.StartNew();
List PremiersSynchro = new List();
Parallel.ForEach(Entiers, i => { if (EstPremier(i)) PremiersSynchro.Add(i); });
Console.WriteLine(« {0} premiers trouvés en {1} ms », PremiersSynchro.Count, Chrono.Elapsed.Milliseconds);
}

private static bool EstPremier(int Nombre)
{
for (int ind = 2; ind < Nombre - 1; ind++) if (Nombre % ind == 0) return false; return true; } } } [/sourcecode] On voit qu'on cherche la liste des nombres premiers entre 100 000 et 120 000, avec une première version standard, et qui s'exécutera donc sur un seul core, et une seconde permettant la parallélisation. Ici, rien de compliqué puisque chaque nombre est traité séparément, donc c'est très simple de répartir sur autant de processeurs que nécessaire. Les résultats : 539 ms en mono-core, 388 ms en parallèle sur deux cores. Une amélioration de performance d'environ 30%, en informatique, c'est déjà pas mal... Et imaginez sur un octo-core. Les résultats varient un peu en fonction du temps, mais on a une bonne idée du ratio sur ce type d'algo. Toutefois, un bug est présent dans ce code : on écrit les résultats dans une liste d'entiers, et le multithread peut faire que les résultats sont écrits en même temps, résultant en des écrasements, que j'ai pu constater sur un test avec un résultat de référence de 1709 entiers premiers, et 1708 seulement sur le deuxième. Le premier réflexe est de créer plusieurs listes et de les grouper à la fin, mais comment faire quand on n'a pas la main sur le nombre de threads ? Après recherche sur internet, il se trouve que Microsoft a tout prévu. Au lieu d'utiliser des listes génériques, il faut utiliser System.Threading.BlockingCollection<T>, qui est faite spécialement pour ça... Bref, un premier essai convaincant !

21/08/2008

UI Automation : le framework

Filed under: .NET,UIAutomation — jpgouigoux @ 9:57
Tags: , ,

J’ai finalement fait beaucoup plus vite que je ne pensais pour créer une première version de ce que je voudrais voir devenir une grammaire XML spécialisée dans le test des interfaces graphiques, et un moteur d’exécution de ces tests basé sur UI Automation Framework.

Miboboio m’a donné la solution pour gérer du texte, j’ai trouvé comment régler le problème des fenêtres principales qui changent (typiquement quand on a une fenêtre de login qui s’efface pour laisser la place à une fenêtre principale), et le reste était relativement simple.

Bon, ce n’est vraiment qu’un prototype pour l’instant, mais j’ai quand même créé un projet sur CodePlex. Vous pouvez aller voir sur http://www.codeplex.com/uiautotestxml pour plus de détails, et tester la release 0.1. J’ai mis deux exemples de scenario XML de test. Un qui pilote la calculatrice :


<?xml version="1.0" encoding="utf-8" ?>
<scenario>
 <application path="calc.exe">
  <launchWaitTimeout>2000</launchWaitTimeout>
 </application>
 <actions>
  <setText target="403" value="123"/>
  <buttonClick target="92" waitForAction="100"/>
  <setText target="403" value="456"/>
  <buttonClick target="112" waitForAction="100"/>
  <checkText target="403" value="579, " errMsg="Mauvais calcul"/>
 </actions>
</scenario>

Un autre qui pilote une application de test que j’ai montée pour l’occasion, afin de tester la prise en compte du changement de fenêtre active :


<?xml version="1.0" encoding="utf-8" ?>
<scenario>
 <application path="UIAutoTest.TestTargetApp.exe">
  <launchWaitTimeout>2000</launchWaitTimeout>
 </application>
 <actions>
  <clearText target="txtPassword"/>
  <setText target="txtPassword" value="coucou"/>
	<linkClick target="linkLabel1" waitForAction="100"/>
  <formSwitch/>
  <checkLabel target="lblLogUser" value="User72" errMsg="Problem with the login"/>
 </actions>
</scenario>

A priori, la grammaire doit parler d’elle-même, et sinon rendez-vous sur le site pour plus de détails. Merci par avance de vos commentaires et remarques sur ce qu’il manque pour que ça puisse servir.

IKVM et FOP

Filed under: .NET,FOP — jpgouigoux @ 8:15

SI vous avez lu mon premier post sur l’utilisation d’Apache FOP en .NET par interop IKVM, vous serez peut-être intéressés de savoir que FOP 0.95 est sorti en version finale, et que les tests d’interop sont concluants.

En tout cas, pas de problème de mise à niveau sur les quelques XSL-FO testé…

15/08/2008

UI Automation : on touche au but !

Filed under: .NET,UIAutomation — jpgouigoux @ 9:51
Tags: , , ,

Miboboio a gagné le droit de me traiter d’andouille, et a eu la noblesse de ne pas le faire dans son commentaire de mon précédent post. Il a pourtant trouvé la solution à mon problème récurrent sur UIAutomation et je l’en remercie vivement !

Son approche est la suivante : puisque le TextPattern ne propose pas de SetValue, mais juste un GetValue, on va passer par le ValuePattern. J’avais essayé ce pattern ainsi que le InvokePattern, mais sans succès. Et c’est là que Miboboio a trouvé l’astuce : dans le cas où la zone de texte ne constitue pas un ValuePattern, il place le focus dessus (pas besoin de passer par un pattern pour ça, c’est appelable directement sur l’instance de AutomationElement), et ensuite fait un System.Windows.Forms.SendKeys.SendWait. Je précise bien le namespace sur le nom de classe, car il ne fait pas partie des espaces de nommages liés à l’UIAutomation.

Je me suis permis de raccourcir un peu le code de Miboboio, et de l’intégrer dans un code complet incluant le lancement du processus à contrôler, de façon que les personnes intéressées puissent simplement copier-coller dans VS.NET et lancer. Je vous laisse aller sur son commentaire pour voir l’original avec tous les commentaires. Et sinon, vous pouvez tester directement ceci :

Process notepad = Process.Start("notepad.exe");
Thread.Sleep(2000);
AutomationElement notepadForm = AutomationElement.FromHandle(notepad.MainWindowHandle);
AutomationElement zoneTexte = notepadForm.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.NameProperty, ""));
TextPattern txtPattern = zoneTexte.GetCurrentPattern(TextPattern.Pattern) as TextPattern;
object valuePattern = null;
if (!zoneTexte.TryGetCurrentPattern(ValuePattern.Pattern, out valuePattern))
{
 zoneTexte.SetFocus();
 Thread.Sleep(500);
 SendKeys.SendWait("coucou");
}
else
{
 zoneTexte.SetFocus();
 ((ValuePattern)valuePattern).SetValue("coucou");
}

Vous aurez juste besoin de rajouter les using ci-dessous :

using System;
using System.Diagnostics;
using System.Threading;
using System.Windows.Automation; // inclure l'assembly UIAutomation
using System.Windows.Forms; // inclure l'assembly System.Windows.Forms

Moralité de l’histoire : quand la doc Microsoft dit que ce n’est pas possible de le faire pour des raisons de sécurité… trouvez une autre faille… pardon, une autre façon de faire.

Ah, juste un petit détail : n’essayez pas de faire fonctionner ce code en debug, ou en tout cas, ne passez pas par VS.NET entre le SetFocus et le SendKeys : en effet, dans ce cas-là, le focus repasse à VS.NET, au lieu du contrôle à piloter, et le SendKeys sur VS.NET pendant qu’il est en train de débugger ne se passe pas bien du tout (blocage du processus).

C’est d’ailleurs ça, la clé de l’astuce de Miboboio : quand vous faites un SetFocus sur un AutomationElement, le focus est vraiment passé à l’application piloté. L’UIAutomation ne fonctionne pas comme ManagedSpy++ avec des hooks Windows activés depuis le processus pilote : il envoie vraiment les messages Windows correspondants. Je vous encourage à voir l’article de Frédéric Queudret qui comprend un schéma très détaillé de comment ça fonctionne. J’avais d’ailleurs oublié de donner le lien dans mon post précédent. Désolé. Le voici.

Allez, un dernier lien pour la route : le forum de Microsoft dédié à l’accessibilité. Il y a pas mal de questions sur des cas précis : comment activer une combo, etc. Je pense que je vais trouver les réponses au reste de mes questions là-dedans, et j’espère dans quelques mois avoir mis en place un petit framework pour utiliser tout ça. Idéalement, une grammaire XML pour écrire des tests automatisés sur une application, avec un système de test unitaire embarqué. Bien évidemment, je vous tiendrai au courant.

En attendant, merci encore à Miboboio !

12/08/2008

UI Automation : cent fois sur le métier remettez votre ouvrage…

Filed under: .NET,UIAutomation — jpgouigoux @ 8:27
Tags: , , , ,

L’automatisation de test me titille à nouveau…

Dans un post précédent (Microsoft UI Automation : déçu, encore une fois…), j’avais expliqué ce qui, selon moi, faisait que le framework UI Automation ne permettait pas de faire de l’automatisation de test : le manque de possibilité d’écrire dans une zone de texte. En effet, je veux bien croire que certaines applications fonctionnent uniquement avec des boutons, mais moi je bosse sur des applications de gestion, qui sont utilisées par des secrétaires et des personnes qui instruisent des dossiers, et quand ils s’en tapent une centaine pas jour, ils ont usé le clavier…

Bref, je pensais avoir tiré une croix sur le sujet, et voilatipa qu’un nouvel article sort là-dessus, dans les flux RSS qui s’affiche au démarrage de Visual Studio. L’auteur n’est autre que Frédéric Queudret, qui était également l’auteur si je me rappelle bien d’un article dans Programmez! sur le même sujet. Je me dis qu’il y a peut-être du nouveau, et surtout une réponse à mon interrogation : dans mon post précédent, je finissais en disant que je serais heureux de me faire traiter d’andouille par quelqu’un qui peut me montrer que je suis passé à côté de la plaque, et je le pense vraiment.

Me voilà donc sur l’article cité, et l’exemple n’est pas avec le notepad comme dans les tutoriels que j’avais trouvé sur le sujet : chouette, ça veut dire que c’est du nouveau. Donc peut-être avec une réponse à ce fameux problème : comment entrer du texte ?

L’application traitée est la calculatrice. On va donc vérifier un calcul. Et donc avoir à entrer des données. Youpi, on chauffe !

Et bien non : c’est là tout l’avantage de cette application : il y a des boutons sur lesquels on tape pour rentrer du texte. Vous l’avez compris : le test automatisé pour vérifier que la calculatrice donne bien trois quand on tape 1 + 3 consiste à simuler le clic sur le bouton 1, puis sur le bouton +, etc.

Voyons les choses du bon côté : ça tend à prouver tout simplement ce que j’avais conclu l’autre fois, et je vois s’éloigner les chances de me faire traiter à juste titre d’andouille. Le mauvais côté des choses est que je suis toujours bredouille.

Il paraît que la CTP de Rosario prend en charge les tests automatisés. J’espère deux choses :

  1. que Microsoft aura étendu son UI Framework, ou au pire créé des hooks sur les contrôles pour pouvoir entrer du texte
  2. que les commerciaux de Microsoft seront un jour au courant de ce qui se passe dans leur application avant de l’apprendre par des blogs de personnes extérieures à leur société : j’ai demandé plusieurs fois au commercial France sur Visual Studio si il y allait avoir quelque chose là-dessus, et il n’était au courant de rien. Même chose aux TechDays.

En attendant, je vais envoyer de ce pas un petit mail à Frédéric Queudret en lui proposant de me traiter d’andouille, à condition qu’il me donne la solution à ce problème de 10 ans ! Si des gens lisent ce post, je m’engage à vous tenir au courant de sa réponse, et de ma quête sans fin sur ce sujet…

01/08/2008

DataSets typés et multi-bases de données

Filed under: .NET — jpgouigoux @ 8:45
Tags: , , ,

ADO.NET supporte plusieurs bases de données, et pas seulement SQLServer. Vous pouvez faire de l’Oracle, principalement, et vous disposez aussi d’un driver OLEDB. Mais ne comptez que sur vous-mêmes si vous souhaitez développer une application supportant plusieurs bases de données. Vous pouvez utiliser les interfaces de programmation pour la connexion, quelques classes de résultats, mais dès que vous faites une commande paramétrée, vous devrez prendre en compte les différents cas possibles.

Le problème devient plus complexe lorsque vous désirez utiliser des DataSets typés. Si vous créez les mêmes structures dans deux bases de données différentes, les types C# correspondants ne sont pas les mêmes dans tous les cas, et surtout, le code généré contient le pointeur vers la base ainsi qu’une grosse partie de code spécifique à la base de données pointée.

Bref, si vous souhaitez écrire du code générique utilisant un DataSet typé dans deux bases de données, vous êtes bons pour écrire une couche intermédiaire. Et c’est là que ça devient drôle : comme les fonctions du DataSet typé renvoyent elles-mêmes des objets typés selon la base, vous êtes bons pour réécrire une redirection pour toutes les fonctionnalités que vous utilisez. En tout cas, je n’ai personnellement pas trouvé d’autre solution.

Le mieux que j’ai trouvé pour l’instant et de créer une classe chapeautant les deux DataSet typés et contenant des instances pour chacune des bases, sachant qu’une seule sera effectivement instanciée à la fois. On fait la même chose en interne, à savoir que les objets dont on a besoin sont eux-mêmes rendus génériques en créant une classe contenant une instance de chaque sous-objet typé. Ensuite, l’idée est de mettre en place des constructeurs différenciés pour chaque instance typée, et dans chaque classe correspondant à une table, de pointer sur le DataSet parent, ce qui nous permettra de retrouver le DataSet typé à utiliser à chaque moment.

Enfin, si vous avez du code qui bouclait sur la collection Rows, vous implémentez l’interface IEnumerable sur ces tables, l’implémentation de la fonction GetEnumerator contenant le code ci-dessous :


foreach (DataSet.MaTableRow Ligne in InstanceDataSetParent.InstanceDataSetTypee.MaTable.Rows)
 yield return new MaTableRow(Ligne);

Personnellement, c’est la première fois que je trouve une utilité hors des exemples standards pour le mot clé yield. Dans ce cas précis, je ne sais pas comment j’aurais fait pour transformer la collection sans trop perdre en performance.

Si vous êtes intéressé par le code un peu plus complet que cette rapide description, n’hésitez pas à me contacter.

Retour d’expérience sur ClickOnce

Filed under: .NET — jpgouigoux @ 8:17
Tags: , ,

Si jamais quelqu’un de Microsoft me lit, je serais curieux de savoir si ClickOnce est considéré comme déjà enterré par Silverlight et consorts, ou si c’est toujours présenté comme une technologie à utiliser. Outre le fait que ClickOnce ne soit pas supporté officiellement (en tout cas, dixit le support téléphonique), plusieurs bugs vraiment gênants existent sur cette technologie, et ne sont visiblement pas en voie de résolution.

Il y en a au moins un qui a été corrigé, mais c’était tellement criant qu’il pouvait difficilement en être autrement : il s’agit du non-support des proxies authentifiés pour le téléchargement. Ca fonctionne grâce à un fix qu’on peut se procurer en le demandant à la hotline Microsoft (http://support.microsoft.com/default.aspx/kb/917952). Je n’ai pas bien compris pourquoi il n’avait pas été mis à disposition publique, mais bon… le problème est réglé.

Par contre, je suis récemment tombé sur un autre souci, à savoir que l’authentification du client .NET se chargeant du téléchargement des modules (donc, l’API ClickOnce de System.Deployment) n’était visiblement pas capable de gérer un saut d’adresse.

Après quelques recherches sur le net, il semblerait que le client de téléchargement se base toujours sur l’adresse effective du fichier .application, et non sur l’adresse à laquelle a été adressée la requête HTTP pour récupérer celui-ci. Ce qui pose problème en cas de pare-feu, DMZ, translation, etc. Un incident a été enregistré, mais il n’y a ni réponse ni activité depuis Juin.

Je commence à me demander si ClickOnce n’est pas en train d’être mis de côté par Microsoft, vu que les problèmes de déploiement d’un client lourd ne se posent plus suite à la mise en place de Silverlight. Pourtant, les applications WPF sont mises en avant, et on trouve de nombreux liens sur le déploiement d’applications basées sur cette techno relativement récente.

En conclusion, si vous devez utiliser ClickOnce de manière industrielle, faites des tests dans la configuration exacte de production (réseau, proxy, authentification, SSL, etc.).

29/06/2008

Microsoft UI Automation : déçu, encore une fois…

Filed under: .NET,UIAutomation — jpgouigoux @ 2:16
Tags: , , , ,

Que je vous expose mon problème, avant tout : ça fait presque dix ans que je cherche une méthode efficace pour tester des interfaces rapides. J’ai essayé des outils commerciaux (Mercury et consorts), des outils gratuits, des méthodes (instrumentation, scripting VSA, invocation sur hooks, etc.), des bidouilles ignobles (surcharger la librairie ManagedSpy de Ben Wulfe de Microsoft R&D, entre autres). J’ai posé le problème aux DevDays suite à la présentation de Rosario, harcelé des gens de Microsoft pour leur demander quand on aurait enfin un outil pour faire du test d’interface.

Et il y a deux jours, j’ai cru avoir enfin trouvé la voie. Un article de Programmez parlait de UI Automation, qui est un framework d’accessibilité, permettant de parcourir et de lire les contrôles de manière externe au programme cible. Ce framework est intégré à .NET 3.5. Je me renseigne un peu, trouve quelques liens intéressants, et me demande pourquoi mes recherches ne m’avaient pas fait trouvé cette technologie. J’ai pourtant passé un bon bout de temps à chercher ce qui se faisait en .NET, mais visiblement pas avec les bons mots clés.

Bref, je me mets à l’oeuvre en ouvrant Visual Studio 2008, et en rajoutant les références sur UIAutomationClient et UIAutomationTypes, et je reprends l’exemple trouvé sur http://blogs.developpeur.org/tom/archive/2007/07/25/wpf-wpf-ui-automation-rendez-vos-interfaces-graphiques-accessibles.aspx en me disant qu’il ne devrait pas être trop dur de l’étendre pour insérer du texte dans un notepad depuis une application console extérieure.

C’est là que les choses se corsent. J’ai d’abord la surprise de découvrir que UISpy ne fait pas partie du SDK 6.0. Voir à ce sujet http://blogs.msdn.com/windowssdk/archive/2008/02/18/where-is-uispy-exe.aspx. Ce n’est pas grave, je télécharge, j’installe le tout comme un 6.1, et je découvre la structure du notepad grâce à l’outil UISpy. Il y a un élément de type document, qui semble être le contrôle par défaut. Je lui associe un TextPattern, sur lequel un DocumentRange me donne accès à GetText(). Bizarre, il n’y a pas de SetText()…

Mon premier réflexe est de me dire que l’injection doit se faire avec un autre pattern que la lecture de texte. Je trouve un bon candidat, à savoir le InvokePattern, mais ça ne sert apparemment pas à ça, ou bien je n’ai pas compris comment ça fonctionne exactement. Avant de poursuivre plus loin, je me dis que je ferais mieux de me renseigner un peu plus sur le pourquoi de l’absence d’un SetText() dans le TextPattern. Et ce que je trouve sur http://msdn.microsoft.com/en-us/library/ms745158.aspx à la rubrique Security me confirme mes doutes : dixit l’article, « Microsoft UI Automation text providers supply read-only interfaces and do not provide the ability to change the existing text in a control ». Bref, c’est plié encore une fois pour l’automatisation des tests d’interface.

Au passage, la sécurité a bon dos : c’est tout à fait possible d’injecter des valeurs dans un contrôle en passant par les API Win32, ou même en utilisant ManagedSpy.dll (je tiens le code à disposition si quelqu’un est intéressé). Si on voulait simplement empêcher la nouvelle technologie de prendre ce risque, il était également possible de mettre en place un système autorisant la modification distante à condition qu’une autorisation ait été donnée par avance. Ca peut être fait avec un certificat, un token, n’importe quoi. Même si ça ne fonctionne pas avec des applications existantes et que ça force les applications cibles à rajouter une propriété quelconque dans leur code. Ou bien un setting quelque part dans la base de registre, n’importe.

Ma conclusion est la suivante. De deux choses l’une :

  1. Microsoft ne veut pas qu’on fasse de l’automatisation de tests automatisés d’interface avec ses outils. Il est également possible que les problèmes qu’on rencontre avec une approche ManagedSpy (impossibilité de sauter d’un handle de fenêtre principale à un handle de dialogue modal, etc.) existent toujours avec l’approche UI Automation (je ne serais d’ailleurs pas étonné que les deux approches utilisent le même principe, vu la proximité étonnante de UISpy.exe avec ManagedSpy.exe). Peut-être que c’est tout simplement impossible sous Windows…
  2. Je suis passé à côté d’un truc, et il est possible d’envoyer du texte dans un contrôle depuis UI Automation en utilisant un autre pattern. Je dois dire que ce cas-là me ravirait… Oui, je serais content de me faire traiter d’andouille par n’importe qui qui pourra m’apporter un code réalisant enfin ce que je veux faire depuis 10 ans que je bosse dans l’informatique.
Page suivante »

Propulsé par WordPress.com.