Browsed by
Month: July 2012

[WinRT] Garder les espaces à la fin des textblocks

[WinRT] Garder les espaces à la fin des textblocks

Exceptionnellement je vais parler de Windows 8.

Voilà donc la problématique : contrairement à Silverlight et à WPF, lorsque l’on souhaite afficher un textblock terminant par des espaces, ces derniers sont tout simplement ignorés par le système.

Par exemple si on écrit le code suivant :


<StackPanel  Orientation="Horizontal">
<TextBlock Text="My name is " />
<TextBlock Text="Rudy" />
</StackPanel>

affichera sous Windows Phone (Silverlight 4) :

alors que le même code en WinRT sous Windows 8 affichera :

Un peu gênant ?

Pourquoi ne pas utiliser de Run ?

En effet, on pourrait écrire :


<TextBlock>

<Run Text="My name is : "/>

<Run Text="Rudy"/>

</TextBlock>

Mais pour une multitude de raison, on pourrait ne pas pouvoir utiliser de Run, comme par exemple si le deuxième élément n’est pas un texte ou un élément plus complexe, ou s’il on a besoin d’animer une des deux parties par exemple..

Solution ?

Une solution qui semble évidente au premier abord est d’utiliser &nbsp; bien connu des développeurs HTML, toutefois ne fonctionne pas, XAML ne connaissant pas ce mot clé html.

Seconde chance : tentons avec le code hexadécimal d’un espace soit 32 : &#32;

Résultat :

 

Bon ok, mauvaise pioche…

Même si &nbsp; n’existe qu’en html, il nous donne un bon indice pour savoir où chercher. Voyons ce que signifie nbsp pour commencer : non breaking space ou en français : “espace insécable”.

Quel est la différence entre un espace et un espace insécable ?

En fait un espace insécable est comme un espace classique à la différence près qu’il permet d’indiquer à un traitement de texte par exemple que l’on souhaite pas sauter une ligne au niveau de cet espace. Afin de ne pas avoir ce genre de résultat :

Bonjour David, comment vont tes lapins aujourd’hui
? Au fait j’ai fait un super score à World of Monger : 113

210 points !

En français par exemple, il est fortement conseillé d’utiliser un espace insécable entre le dernier mot d’une phrase et un point d’interrogation ou d’exclamation afin que ces derniers ne soient pas affiché à la ligne suivante ou encore lorsqu’on utilise un espace comme séparateur de groupes de 3 chiffres dans les nombres supérieurs au millier (ou encore dans les numéros de téléphone, etc…)

Sous windows, il est possible de l’écrire en utilisant la combinaison de touches : alt + 0160. Si toutefois vous ne pouvez saisir ce genre de combinaison (pas facile avec un clavier virtuel par exemple…) vous pouvez juste écrire &#0160; dans le xaml.

Exemple :


<StackPanel  Orientation="Horizontal">
<TextBlock Text="My name is&0160;" />
<TextBlock Text="Rudy" />
</StackPanel>

Donnera bien :

 

Ce qui est exactement ce que l’on souhaitait !

 

 

 

 

THE END

Conseils sur la décompilation et la désobfuscation

Conseils sur la décompilation et la désobfuscation

Il y a quelques semaines, je me suis fait volé mon pc portable avec quelques codes sources de projet que je n’avais pas encore sauvegardé car sans internet (quasiment 10 jours de travail de perdu).

Toutefois j’avais encore les xap à ma disposition ce qui m’a aidé a récupérer le code sources (offusqué) de l’app. Pour être honnête, même offusqué, en une dizaine d’heures et avec quelques aspirines, vous pouvez facilement revenir à l’original.

Voilà pour information à quoi ressemble un code offusqué une fois décompilé :

public class YoutubeHelper
{
[CompilerGenerated]
private sealed class a
{
private sealed class a
{
public YoutubeHelper.a a;
public List b;
public void c()
{
if (this.a.c)
{
this.a.b.Videos.Clear();
}
using (List.Enumerator enumerator = this.b.GetEnumerator())
{
while (enumerator.MoveNext())
{
YoutubeVideo current = enumerator.get_Current();
this.a.b.Videos.Add(current);
}
}

}
}
public HttpWebRequest a;
public YoutubeHelper b;
public bool c;
public void d(IAsyncResult A_0)
{
YoutubeHelper.a.a a = new YoutubeHelper.a.a();
a.a = this;
Stream responseStream = this.a.EndGetResponse(A_0).GetResponseStream();
a.b = this.b.ParseYoutubeData(responseStream);
if (a.b != null)
{
Deployment.get_Current().get_Dispatcher().BeginInvoke(new Action(a.c));
this.b._youtubeCurrentPage = 0;
}
}
}
[CompilerGenerated]
private bool b;
[CompilerGenerated]
private string c;
[CompilerGenerated]
private ObservableCollection d;

public void LoadYoutube(bool clear)
{
AsyncCallback asyncCallback = null;
YoutubeHelper.a a = new YoutubeHelper.a();
a.c = clear;
a.b = this;
this.Loading = true;
this.RaisePropertyChanged("Loading");
string text = string.Format("http://gdata.youtube.com/feeds/api/videos?q={0}&start-index={1}&max-results=20&v=2", this.Search, this._youtubeCurrentPage);
a.a = (HttpWebRequest)WebRequest.Create(new Uri(text, 1));
try
{
WebRequest arg_73_0 = a.a;
if (asyncCallback == null)
{
asyncCallback = new AsyncCallback(a.d);
}
arg_73_0.BeginGetResponse(asyncCallback, null);
}
catch (Exception)
{
}
}

}

En gros : ca pique les yeux, c’est difficilement lisible mais avec un peu de courage, ça se simplifie et surtout, ca ne compile pas.

Voilà donc un petit guide pour vous aider à la tâche !

Reconstruire vos pages et vos usercontrols

Imaginons que vous avez une page nommée MainPage.xaml (qui ne l’a pas ???)

Lorsque vous allez décompiler votre projet, vous allez avoir deux fichiers : mainpage.xaml et MainPage.cs. Commençons par les renommer correctement : MainPage.xaml et MainPage.xaml.cs et mettez Page en tant que Build Action pour votre page xaml.

Allons maintenant dans le code behind et indiquons notre classe comme partial. Supprimons le code qui a été auto-généré lors de la compilation initiale:

  • Supprimez la fonction InitializeComponent
  • Repérez les variables correspondants à votre élément XAML, ceci est plutôt simple, il précède la variable “private bool _contentLoaded” et sont indiqué comme internal :
  • Supprimez la variable _contentLoaded

Vos deux fichiers devraient maintenant être liés.

Toutefois vous remarquerez que visual ne fusionne pas les deux fichiers comme d’habitude :

Pour cela, pas besoin de s’embêter à éditer le fichier vcproj, installez (si ce n’est pas déjà fait) VSCommands (ici : http://visualstudiogallery.msdn.microsoft.com/d491911d-97f3-4cf6-87b0-6a2882120acf/)

Sélectionnez les deux éléments puis faites un clic droit et sélectionnez “Group Items”

Vous voila maintenant avec les deux fichiers regroupés comme d’origine.

Gérer les lambdas

Pour résumer le travail, toutes les lamba expressions ont été converti par le compilateur en classe interne, il faut donc les retransformer tout en faisant attention à un point : les classes sont nommés comme les variables et les fonctions soient : a, b, c … un même nom peut donc représenter à la fois une classe interne, une fonction et une variable, autant vous dire que la fonction rename de visual s’y perd.

Les tableaux

Voilà à quoi ressemble un tableau une fois décompilé :

accesseur :

int i = a[20];

=> int i = a.get_Item(0);

affectation :

a[20]=3;

=> a.set_Item(20,3);

Voici donc quelques expressions régulières pour vous aider :

replace .get_Item({[^)(]+}) par [1]

et

replace .set_Item({[^),(]+},{[^),(]+}) par [1] = 2

Attention, ces expressions régulières ne sont pas parfaites, elles ne prennent pas les expressions contenant des parenthèses à l’intérieur comme : a[toto(12)]. Faites donc une recherche de set_Item et de get_item après coup pour gérer les cas restants.

Les propriétés

Un des points positifs lorsque l’on doit décompiler un programme est que les propriétés même après offuscation, garde leurs noms (sinon il serait impossible de gérer les RaisePropertyChanged par exemple), toutefois, les décompilateurs du marché ont un peu de problèmes avec, par exemple :

MyGrid.Width=200;

deviendra :

MyGrid.set_Width(200);

ou encore :

int i=MyGrid.Width;

deviendra

int a=MyGrid.get_Width();

il faudra donc passer un peu de temps pour réécrire l’ensemble des affections ou utilisations des propriétés. Voici quelques expression régulière pour vous aider dans cette tâche (à n’utiliser que si vous n’avez pas de fonction nommées set_XXX ou get_XXX)

Modifier les accesseurs :

.get_{[^(]+}()   en .1

De même pour modifier les affectateurs

.set_{[^(]+} en .1=

Enregistrement et dés-enregistrement d’event handler

Après décompilations, vos events vont ressembler à cela :


contacts.add_SearchCompleted(delegate(object senderr, ContactsSearchEventArgs er)

au lieu de :


contacts.SearchCompleted+=(delegate(object senderr, ContactsSearchEventArgs er)

de même pour le dés-enregistrement.

Voici donc deux expressions régulières pour corriger cela.

enregistrement :

replacez .add_{[^(]+} par .1+=

dés-enregistrement :

replacez .remove_{[^(]+} par .1-=

 

Les affectations multiples

Si vous écrivez :


Toto.ScaleY=Toto.ScaleX=0;

une fois compilé, offusqué et redécompilé, le code deviendra :


ScaleTransform arg_108_0 = this.Toto;
double num3;
this.Toto.set_ScaleY(num3 = 0);
double initialScale;
arg_108_0.set_ScaleX(num3);

A vous donc de supprimer l’ensemble des variables intermédiaire pour simplifier la relecture de votre code.

Les énumérations

Toutes les énumérations sont interprété en tant que int dans le code décompilé, par exemple :


new Uri("/toto.xaml,Urikind.Relative);

sera décompilé comme :


new Uri("/toto.xaml,2);

Ce qui est tout de suite moins parlant. Pour vous faciliter le travail, je conseille vivement Refactor.

Pour cela, castez votre int avec la bonne énumération :


new Uri("/toto.xaml,(UriKind)2);

Puis sélectionnez dans la marge, l’outil “Compute constant value”.

Refactor se chargera alors automatiquement de trouver la bonne valeur pour l’énumération. Cela est encore plus intéressant quand on sait qu’il gère aussi automatiquement les OR binaire :

(RegexOptions) 5 

Deviendra alors :

RegexOptions.ExplicitCapture | RegexOptions.IgnoreCase | RegexOptions.None

 Override & virtual

Attention, parfois les méthodes override seront vu comme des méthodes virtuelles par le décompilateur, ce qui signifie qu’elles ne surchargeront pas parfois les méthodes initiales, par exemple :

protected virtual void OnNavigatedTo(NavigationEventArgs e)

ne sera jamais appelé contrairement à

protected override” void OnNavigatedTo(NavigationEventArgs e)

Gestion de la localisation

Une des difficultés que j’ai rencontré est de récupérer les localisations de mes apps.

Lorsque vous allez décompiler votre dll, vous aller trouver un fichier XXX.resources. L’extension resources correspond à la version binaire des fichiers resx de votre projet. Il est assez facile de le reconvertir en resx, grâce à l’outils resgen.exe inclut dans l’installation de visual studio.

Ouvrez “Visual Studio Command Prompt” et tapez la commande suivante :

resgen AppResources.resources AppResources.resx

(où AppResources correspond à votre fichier ressources)

Lorsque l’on ouvre le fichier resx généré, on se rend compte qu’il ne contient que la localisation par défaut de votre application.

Où trouver les autres localisations ?

Ouvrez de nouveau votre xap, vous remarquerez des dossiers fr, es, de…

Dans ces dossiers vous allez trouver des fichiers resources.dll

Si on décompile ce fichier, on peut voir :

que celle-ci contient le fichier “.resources” propre à une langue. Il nous reste donc à le sauvegarder, à le convertir en resx comme auparavant et de faire ceci pour chaque langue.

 

La communauté squatte Microsoft

La communauté squatte Microsoft

Le 22 juin dernier, j’ai eu la chance d’organiser dans les locaux de microsoft un évènement autour de windows phone nommé “la communauté squatte microsoft”.

Voici donc le off !

J-7

Beaucoup de taf m’attend et pour une fois, je ne vais pas lancer visual de la journée, au programme : illustrator et photoshop, à faire :

  • Le logo de l’event
  • Préparer le template powerpoint pour les speakers
  • Faire des covers facebook (normal, spécial speakers, etc…)

 

ouchhhh !!!!

10h

Arrivé chez Microsoft avec 30 minutes de retard, merci la SNCF (qui ne m’aura pas porté chance ce week-end, mon pc m’ayant été volé au retour…).

 

10h30

Je retrouve Damien Coquet notre correspondant à microsoft qui s’occupe des communautés, il me présente les tshirts et je n’ai qu’un seul mot en bouche : ENORME !!!

Le rendu est plutôt pas mal et change un peu des autres tshirts windows phone.

11h

Nous sommes à la recherche de Laura (de l’accélérateur) qui devait nous prêter les Lumia 610 pour le before, malheureusement, elle semble séquestré dans une aile du donjon et n’a pas le droit de sortir, grrrr…

11h30

En attendant de récupérer les téléphones, j’en profite pour dire bonjour à nos amis de DPE, je croise notamment Julie qui va elle aussi se faire séquestrer pour l’après-midi, il semble qu’il ne fait pas bon d’être une fille chez DPE !

11h40

Je termine mes slides, tout semble ok, je retrouve les squatteurs pour papoter un peu. Je peux enfin mettre des visages sur des pseudos, un vrai plaisir de pouvoir enfin se voir en vrai !

12h

On part à la recherche d’une boulangerie, nous nous contenterons finalement d’un sandwich plutôt fade, passons…

Je peux maintenant le dire, la date de l’évènement n’a pas été choisi au hasard. Suite aux annonces du 20 Juin, “Windows Phone 8” est dans la bouche de tout le monde et ce fut  vraiment agréable de partager nos impressions sur les annonces en réel, dans la vraie vie, d’échanger nos idées, nos visions de l’avenir, de windows phone 7.8 et 8, etc… Les clients de la boulangerie nous regardent bizarrement, peu importe !

12h50

Découverte de la salle et de sa scène : magnifique.

Les canapés, les poufs, la table de salon, tout est là, le lieu idéal pour un squat ! J’avoue que voir mon logo sur l’écran géant m’a fait bizarre.

Premier problème technique : Niels et Nabil ont décidé de prendre le nom de l’évènement à la lettre et de squatter la scène, d’un autre côté, c’est l’esprit de l’évènement aussi !

13h00

Début des hostilités et de la plénière, je demande aux speakers de monter sur scène. Quelques chiffres, quelques remerciements aux partenaires, c’est parti !

Je souhaitais dans un premier temps remercier l’ensemble des équipes de DPE pour leurs aides et leurs soutiens sans qui il aurait été très difficile d’organiser cet évènement.

Bon j’avoue, j’ai passé au moins 6h à modéliser l’ensemble des speakers et des personnes de DPE sous la forme d’avatar XBox… ce fut long, mais je suis plutôt fier de ma bétise.

J’en profite donc pour remercier l’ensemble des speakers : David Poulin, Cyril Cathala, Benjamin Baldacci, Arnauld Weil et Samuel Blanchard (qui est venu avec un cosplay de Kojak plutôt ressemblant).

13h37

On enchaine sur la première session : Windows Phone 8. J’ai la dur tâche de convaincre l’assistance que si leurs téléphones ne passeront pas en Windows Phone 8 c’est une bonne chose (et je reste convaincu de cela). Tout est un problème de marketing pour moi, on aurait appelé 7.8 : Windows Phone 8 Starter, les réactions auraient été différentes.

14h27

Premier jeu pour remporter des cadeaux… Bon en fait c’est plutôt un vide grenier, j’ai profité de l’event pour refourguer les goodies qui prenaient la poussière chez moi, comme :

  • Un tshirt Clippy compressé
  • Une magnifique doudoune sans manche Windows Phone
  • Un tire-bouchon Windows Phone

 

Problème : j’avais prévu des défis type “Smoked By Windows Phone” puissance 1 000, sauf… qu’on ne captait pas dans la salle…

Juste pour les curieux, voici les défis qui auraient du être fait :

Le premier qui m’envoie par mail : un document word contenant la température de Seattle et mon G-score (xbox)

 

Le premier qui publie sur twitter avec le hashtag de l’event, le prix du livre suivant (avec la couverture d’un livre affiché sur le rétroprojecteur)

 

Un QR-Code affiché l’écran, menant à un site web qui afficherait la question suivante : “Envoie moi par MMS une photo de toi en train de faire une grimace à ton voisin de gauche au 06 63 .. .. ..”

 

Envoyez moi par SMS le numéro de téléphone du restaurant chinois le plus proche qui a au moins 4 étoiles dans ses avis

 

Au final, j’ai du improviser des questions, mais peu importe, le fun était là.

16h22

On commence a distribuer les tshirts et surprise : il y en a 300 dont des féminins !!! Ils sont fous !

17h45

Les sessions s’enchaînent avec un bon rythme et avec qualité et humour. Etant une journée communautaire, je m’étais donné deux objectifs :

  • faire speaker uniquement des membres actifs de la communauté et ne venant pas de microsoft
  • ne pas se prendre la tête et speaker comme si tu étais entre potes.
L’objectif a été tenu et je suis très fier du travail des speakers pour cela !

17h50

Il nous reste un peu de temps, j’enchaine sur une session express Coding4Fun, j’ai du faire pas mal de coupe, la résolution du rétroprojecteur ne m’a pas aidé (on voyait uniquement 3 lignes de code…) mais ça c’est plutôt bien passé.

Pour la première fois en live, j’ai pu montrer Livetris qui avaient été fait avec la beta de mango à l’époque et pas mal de mes hacks ne fonctionnaient plus, il a fallu en trouver d’autres mais au final l’application fonctionne !

18h20

Moulla, un magicien qui utilise Kinect notamment vient nous faire un petit show à base de windows phone, merci beaucoup à lui pour sa venue !

18h45

Les taxis nous attendent pour nous rendre au Week-end BeMyApp, il est donc l’heure de partir, j’essaie de dire au revoir à tout le monde, mais on nous presse, désolé !

 

Les slides :

(mon pc ayant été volé à la fin du WE, ce n’est pas forcément version définitive des slides, dsl !)

pleniere

coding4fun

Asynchronous MessageBox

Asynchronous MessageBox

It is sometimes useful to launch a messagebox asynchronously.

By default, all silverlight messagebox are synchronous but… there is a solution.

solution

One might consider reimplementing the messagebox, it is a possibility, but we will see today that it is possible to access advanced features of MessageBox through one back door, thanks to our friend XNA!

If you look at the Microsoft.Xna.Framework.GameServices assembly, you will notice that the Guide object has methods quite interesting:

BeginShowMessageBox !

This method displays a native and asynchronously messagebox with  parameters:

  • title: Title of the message box
  • text: text to be displayed in the message box
  • buttons: Legends associated with the buttons on the message box. The maximum number of buttons is two.
  • focusButton: 0-based index that defines the button highlighted.
  • icon: Type icon in the message box.
  • callback: method to call when the asynchronous operation is complete.
  • STATE: The unique user-created that identifies this request.

Title and text match mutually the parameters “caption” and “messageboxtext” of Silverlight.

One difference here: the text can not exceed 256 characters, otherwise an exception is thrown.

Buttons is here much more advanced than our Silverlight MessageBox, we can specify the button text, for example, we can modify the “ok” and “cancel” text like that :

*Le example

Microsoft.Xna.Framework.GamerServices.Guide.BeginShowMessageBox(
"Aimez vous Fuse ?",
"Avez vous acheté la super application Fuse ?",
new string[] { "évidemment !", "c'est quoi ?" },
0,
Microsoft.Xna.Framework.GamerServices.MessageBoxIcon.Alert,
null,
null);

This offers us a lot of new possibilities!

But be careful to localize your buttons!

How to make synchronous messagebox again?

Able to have a dialog asynchronous’s pretty cool, but in most cases, we expect it to be synchronous. To do this simply to retrieve the result of the asynchronous call and wait for its execution.

IAsyncResult result = Microsoft.Xna.Framework.GamerServices.Guide.BeginShowMessageBox(
"Do you like  Fuse ?",
"And do you buy it ?",
new string[] { "of course !", "what's Fuse ?" },
0,
Microsoft.Xna.Framework.GamerServices.MessageBoxIcon.None,
null,
null);

result.AsyncWaitHandle.WaitOne();

and here we have a native, synchronous and customizable message box !

Test result of the dialog

If you want to test the result of your dialog box (which button was clicked), simply call the method EndShowMessageBox :

int? choice = Microsoft.Xna.Framework.GamerServices.Guide.EndShowMessageBox(result);
if(choice.HasValue)
{
if(choice.Value==0)
{
//usezr clicks the first button
}
}

Summary

  • Add reference Microsoft.Xna.Framework.GameServices
  • Write the following code:

 

 

IAsyncResult result = Microsoft.Xna.Framework.GamerServices.Guide.BeginShowMessageBox(
"Do you like Fuse ?",
"and do you buy it ?",
new string[] { "of course !", "what is fuse ?" },
0,
Microsoft.Xna.Framework.GamerServices.MessageBoxIcon.None,
null,
null);

result.AsyncWaitHandle.WaitOne();

int? choice = Microsoft.Xna.Framework.GamerServices.Guide.EndShowMessageBox(result);
if(choice.HasValue)
{
if(choice.Value==0)
{
//l'utilisateur a cliqué sur le premier bouton
}
}

Bonus

How to disable the messagebox sound  ?

 

To remove the beep or the vibration, just change the icon … Ok I know this is not great logic, but that’s how. In fact it should be understood that XNA is a common platform between Windows, Xbox and Windows Phone. In the windows world, we are used to display icons ‘warning’, ‘alert’, etc. .. left of the dialog box, which is not super top for a mobile display or width of the screen is already binding. The distinction between a normal dialog and a dialog box warning / alert, is therefore the sound / vibration. To remove the sound, we just have not typify the messagebox:

 

 

Microsoft.Xna.Framework.GamerServices.Guide.BeginShowMessageBox(
"Do you like Fuse ?",
"and do you buy it ?",
new string[] { "of course !", "what is fuse ?" },
0,
Microsoft.Xna.Framework.GamerServices.MessageBoxIcon.None,
null,
null);

Voilà !!!