Personnalisation de MSN 7 avec C#

François Laloux

Développement d'un programme C# permettant la personnalisation de la nouvelle zone de message personnel d'MSN7.

N'hésitez pas à commenter cet article ! Commentez ♪

- Titre : Personnalisation de MSN 7 avec C#

- Auteur : François Laloux

- Parution : 29 juin 2005

- Licence : Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright ® 2005 Frechy. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. Introduction

- II. Développement du programme

- II-A. Présentation

- II-B. Communication avec MSN Messenger 7

- II-C. Création du compte à rebours

- II-D. Lecture/Écriture des paramètres dans un fichier XML

- II-E. Réduction en icône de notification

- III. Conclusion

- IV. Téléchargements

I - Introduction

Une nouveauté du célèbre MSN Messenger 7 est qu'il permet d'afficher un message personnel. Un petit message qui ne se retrouve pas exactement dans votre pseudo puisque celui-ci n'est pas repris lorsque vous « tchatchez ». Pour ceux qui ne voient toujours pas de quoi je veux parler, voici une capture d'écran :

la nouvelle zone de texte msn

Cette nouvelle zone peut également être utilisée pour afficher ce que vous êtes en train d'écouter avec Windows Media PLayer,Winamp…

afficher ce que j'écoute

II - Développement du programme

II-A - Présentation

Pour cet article, je vais réaliser un programme permettant de modifier cette zone personnelle. Deux paramètres peuvent être modifiés :
1. L'icône affichée (Icone jeux, office ou musique) ;
2. Le texte affiché.

Afin de rendre l'article plus intéressant, je vais rajouter une fonctionnalité importante, le texte affiché sera en fait un compte à rebours. Et voici finalement ce que permet le programme :

Le programme affiche une icône 'jeux' et met à jour un décompte chaque seconde dans la zone de texte

J'ai décidé d'y afficher un compte à rebours, mais vous pouvez programmez tout ce que vous voulez afficher (la température du cpu, votre vitesse de download, le programme que vous êtes en train d'utiliser…) il n'y a pas de limite.

II-B - Communication avec MSN Messenger 7

Afin de communiquer, en fait d'envoyer le message personnel, nous devons appeler une fonction propre à MSN 7. Avant d'appeler cette fonction, nous allons importer deux dll ainsi que tous les objets nécessaires. Nous n'avons pas besoin d'ajouter manuellement des références.
Si vous souhaitez comprendre le mécanisme qui permet d'appeler des fonctions dont le code est implémenté dans des DLL natives, je vous incite à lire cet article : Les DLL natives en .NET (Morpheus)

1. Ajout du Namespace

using System.Runtime.InteropServices;

2. Ajout dans la définition de la classe

[DllImport("user32", EntryPoint="SendMessageA")]
private static extern int SendMessage(int Hwnd, int wMsg, int wParam, int lParam);

[DllImport("user32", EntryPoint="FindWindowExA")]
private static extern int FindWindowEx(int hWnd1, int hWnd2, string lpsz1, string lpsz2);

private const short WM_COPYDATA = 74;

public struct COPYDATASTRUCT
{
public int dwData;
public int cbData;
public int lpData;
}
public COPYDATASTRUCT data;

Nous avons tous les objets nécessaires, nous pouvons maintenant faire appel à la méthode de MSN (SendMessage). Mais avant, il faut construire un string reprenant l'ensemble des informations (icône+message).

3. Appel à la méthode SendMessage après avoir construit le string contenant les informations à envoyer

public int VarPtr(object e)
{
GCHandle GC = GCHandle.Alloc(e, GCHandleType.Pinned);
int gc = GC.AddrOfPinnedObject().ToInt32();
GC.Free();
return gc;
}

private void SendMSNMessage(bool enable, string category, string message)
{
string buffer = "\\0" + category + "\\0" + (enable ? "1" : "0") + "\\0{0}\\0" + message + "\\0\\0\\0\\0\0";
int handle = 0;

data.dwData = 0x0547;
data.lpData = VarPtr(buffer);
data.cbData = buffer.Length * 2;

handle = FindWindowEx(0, handle, "MsnMsgrUIManager", null);
if (handle > 0)
SendMessage(handle, WM_COPYDATA, 0, VarPtr(data));
}

Tout est en place et nous pouvons envoyer le message personnel en appelant la méthode SendMSNMessage de cette façon :

SendMSNMessage(true, "Office", "travaille sous Word");

- Le premier paramètre (bool enable), indique s'il faut afficher le message que l'on envoie…la réponse est oui, enfin true ;)
Par contre, on peut imaginer mettre ce paramètre à false lorsque l'on quitte l'application. Ceci aura pour effet de remettre le précédent message personnel.

- Le second paramètre représente l'icône à afficher, on a le choix entre trois : « Office », « Games » ou « Music »

Office - Games - Music

- Le dernier paramètre est le texte à afficher.

II-C - Création du compte à rebours

Vous pourrez retrouver le code source de ce programme dans le fond de l'article. Voici à quoi ressemble l'application en elle-même.

Le principe est simple, l'utilisateur choisit l'icône à afficher puis choisit une date/heure à décompter (Date time to countdown) ou directement une durée pour le décompte (Countdown).
Pour finir, il ne reste plus qu'à spécifier le texte à afficher (Text to display) ainsi que le taux de rafraichissement du décompte dans MSN (Refresh rate).

Je ne vais pas vous expliquer en détail chaque ligne, mais uniquement les gros concepts utilisés. Le code source n'est pas compliqué à comprendre. Pour résumer; beaucoup d'évènements, peu de traitements.

La première étape consiste à créer un projet WinForm et à placer tous les contrôles, pour ça pas besoin d'aide :p.

Nous aurons besoin d'un objet DateTime pour retenir la date et l'heure de la zone Date time to countdown ainsi qu'un objet TimeSpan pour retenir la durée du compte à rebours.

System.DateTime dtcountdown = System.DateTime.Now;
System.TimeSpan dtthecd;

Maintenant pour chaque modification de la date et/ou de l'heure de la zone Date time to countdown nous devrons mettre dtcountdown et dtthecd à jour. Je ne vous montre qu'un évènement, mais c'est à chaque fois pareil.

private void numUpDownTimeH_ValueChanged(object sender, System.EventArgs e)
{
try
{
dtcountdown = dtcountdown.AddHours((double)this.numUpDownTimeH.Value-dtcountdown.Hour);
MajcountDown();
}
catch(Exception err)
{
Form FrmDebug = new FrmDebug(err.ToString());
FrmDebug.ShowDialog();
}
}

private void MajcountDown()
{
try
{
dtthecd = dtcountdown.Subtract(System.DateTime.Now);
if (dtthecd.TotalSeconds <=0 )
{
this.numUpDownCDD.Value=0;
this.numUpDownCDH.Value=0;
this.numUpDownCDM.Value=0;
this.numUpDownCDS.Value=0;
}
else
{
this.numUpDownCDD.Value=(decimal)dtthecd.Days;
this.numUpDownCDH.Value=(decimal)dtthecd.Hours;
this.numUpDownCDM.Value=(decimal)dtthecd.Minutes;
this.numUpDownCDS.Value=(decimal)dtthecd.Seconds;
}
}
catch(Exception err)
{
Form FrmDebug = new FrmDebug(err.ToString());
FrmDebug.ShowDialog();
}
}

De même, lors de la modification du décompte (zone Countdown), il faut mettre à jour l'objet dtthecd (TimeSpan) qui se cache derrière.

private void numUpDownCDD_ValueChanged(object sender, System.EventArgs e)
{
try
{
dtthecd = dtthecd.Add(System.TimeSpan.FromDays((double)this.numUpDownCDD.Value - dtthecd.Days));
}
catch(Exception err)
{
Form FrmDebug = new FrmDebug(err.ToString());
FrmDebug.ShowDialog();
}
}

Tout est en place, nous pouvons lancer le compte à rebours. Le compte à rebours est lancé lorsque l'utilisateur appuie sur le premier bouton tout en bas.
Le compte à rebours est implémenté à l'aide d'un Timer.

Lancement du Timer

private void btnStart_Click(object sender, System.EventArgs e)
{
try
{
this.timer.Interval=(int)numUpDownRefRate.Value*1000;
this.timer.Start();
this.timer.Tick+=new EventHandler(timer_Tick);

...

}
catch(Exception err)
{
Form FrmDebug = new FrmDebug(err.ToString());
FrmDebug.ShowDialog();
}
}

Grâce au timer, la méthode timer_Tick sera lancée à intervalle de temps régulier. L'intervalle de temps (représenté en ms) est en fait le nombre de secondes spécifié dans Refresh rate.

La méthode timer_Tick représente le plus gros du traitement : la mise à jour du compteur, du texte et de l'icône à envoyer à MSN, et pour finir l'appel de la méthode SendMSNMessage.

timer_Tick

private void timer_Tick(object sender, EventArgs e)
{
try
{
string ico,message;
if(dtthecd.TotalSeconds>0)
{
if(this.radioOffice.Checked==true)
{
ico="Office";
}
else
{
if(this.radioGames.Checked==true)
{
ico="Games";
}
else
{
ico="Music";
}
}
message=this.txtBxToDisp.Text;

dtthecd = dtthecd.Subtract(System.TimeSpan.FromSeconds((double)numUpDownRefRate.Value));

numUpDownCDD.Value = (decimal)dtthecd.Days;
numUpDownCDH.Value = (decimal)dtthecd.Hours;
numUpDownCDM.Value = (decimal)dtthecd.Minutes;
numUpDownCDS.Value = (decimal)dtthecd.Seconds;

message = message.Replace("[D]",((decimal)dtthecd.Days).ToString());
if(dtthecd.Days>1)
{
message = message.Replace("[ds]","s");
}
else
{
message = message.Replace("[ds]","");
}
message = message.Replace("[H]",((decimal)dtthecd.Hours).ToString());
if(dtthecd.Hours>1)
{
message = message.Replace("[hs]","s");
}
else
{
message = message.Replace("[hs]","");
}
message = message.Replace("[M]",((decimal)dtthecd.Minutes).ToString());
if(dtthecd.Minutes>1)
{
message = message.Replace("[ms]","s");
}
else
{
message = message.Replace("[ms]","");
}
message = message.Replace("[S]",((decimal)dtthecd.Seconds).ToString());
if(dtthecd.Seconds>1)
{
message = message.Replace("[ss]","s");
}
else
{
message = message.Replace("[ss]","");
}

SendMSNMessage(true, ico, message);
}
else
{
if(this.radioOffice.Checked==true)
{
ico="Office";
}
else
{
if(this.radioGames.Checked==true)
{
ico="Games";
}
else
{
ico="Music";
}
}

SendMSNMessage(true, ico, this.txtBxAfter.Text);
}
}
catch(Exception err)
{
Form FrmDebug = new FrmDebug(err.ToString());
FrmDebug.ShowDialog();
}

}

Le 2e bouton (bouton Stop) arrête le compteur et remet l'ancien message personnel :

btnStop_Click

private void btnStop_Click(object sender, System.EventArgs e)
{
try
{
this.timer.Tick-=new EventHandler(timer_Tick);
this.timer.Stop();
SendMSNMessage(false, "Office", "");

...

}
catch(Exception err)
{
Form FrmDebug = new FrmDebug(err.ToString());
FrmDebug.ShowDialog();
}

}

La partie compte à rebours est maintenant terminée, il me reste à vous parler de deux trois aspects du programme.

II-D - Lecture/Écriture des paramètres dans un fichier XML

Il y a ici très peu de paramètres personnels, en fait juste le texte à afficher durant et après le décompte. Ces informations sont retenues dans un fichier XML en sortie de programme et sont lues en entrée (pour remplir les textbox).

Lecture/Écriture dans fichier XML

private void ReadXML()
{
try
{
XmlTextReader xReader;
XmlDocument xDoc;
XmlNode node;
xDoc = new XmlDocument();
xReader = new XmlTextReader("TxtToDisp.xml");
xDoc.Load(xReader);
xReader.Close();
node = xDoc.SelectSingleNode("TxtToDisp/UserDuring");
this.txtBxToDisp.Text = node.InnerText;
node = xDoc.SelectSingleNode("TxtToDisp/UserAfter");
this.txtBxAfter.Text = node.InnerText;
}
catch(Exception err)
{
Form FrmDebug = new FrmDebug(err.ToString());
FrmDebug.ShowDialog();
}
}

private void WriteXML()
{
try
{
XmlDocument xDoc;
XmlTextWriter xWriter;
XmlNode xNode;
xDoc = new XmlDataDocument();
xDoc.AppendChild(xDoc.CreateXmlDeclaration("1.0", "utf-8", null));
xNode = AddNode(xDoc, null, "TxtToDisp", "");
AddNode(xDoc, xNode, "UserDuring", this.txtBxToDisp.Text);
AddNode(xDoc, xNode, "UserAfter", this.txtBxAfter.Text);
xWriter = new XmlTextWriter("TxtToDisp.xml", System.Text.Encoding.GetEncoding("utf-8"));
xDoc.WriteTo(xWriter);
xWriter.Close();
}
catch(Exception err)
{
Form FrmDebug = new FrmDebug(err.ToString());
FrmDebug.ShowDialog();
}
}

private XmlNode AddNode(XmlDocument xDoc, XmlNode xNodeParent, string name, string innerValue)
{
try
{
XmlNode xNode;
xNode = xDoc.CreateNode(XmlNodeType.Element, name, "");
xNode.InnerText = innerValue;

if (xNodeParent==null)
{
xDoc.AppendChild(xNode);
}
else
{
xNodeParent.AppendChild(xNode);
}

return xNode;
}

catch(Exception err)
{
Form FrmDebug = new FrmDebug(err.ToString());
FrmDebug.ShowDialog();
return null;
}
}

II-E - Réduction en icône de notification

Ce genre d'application reste en général longtemps en fonctionnement, et dans de tels cas, il vaut mieux aller se loger dans la zone de notification (à gauche de l'horloge). Pour ne pas surcharger la barre de tâches de windows. Un autre avantage est que lorsque l'on réduit l'application, elle utilise beaucoup moins de mémoire (24Mo->1.5Mo).

Au passage, je vous montre le code de la méthode FrmMsnCntDown_Closing déclenchée lors de la fermeture de la fenêtre.

réduction sous forme de notifyIcon

int quit=0;

...

private void FrmMsnCntDown_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
SendMSNMessage(false, "Office", "");
quit=1;
}

private void FrmMsnCntDown_Deactivate(object sender, System.EventArgs e)
{
try
{
if(quit==0 && this.WindowState==FormWindowState.Minimized)
{
this.notifyIcon1.Visible=true;
this.Visible=false;
}
}
catch(Exception err)
{
Form FrmDebug = new FrmDebug(err.ToString());
FrmDebug.ShowDialog();
}
}

private void notifyIcon1_Click(object sender, System.EventArgs e)
{
this.Visible=true;
this.WindowState = FormWindowState.Normal;
this.notifyIcon1.Visible=false;
}

III - Conclusion

Si l'actualisation du compteur sur votre MSN se fait sans problème chaque seconde, il faut cependant savoir que les autres ne verront pas changer cette zone chaque seconde… Ça serait trop beau. En fait cette zone est actualisée en général toutes les 5-10 secondes.
Contrairement au pseudo qui lui est retenu sur un serveur MSN, cette zone de texte, tout comme votre image perso ne sont pas envoyées à MSN. C'est vous qui partagez ces données. Peut-être qu'en achetant une ligne T4 vous arriverez à actualiser ces données chaque seconde ;)

J'allais oublier le plus important! Pour que ce procédé fonctionne, il faut choisir dans MSN « Activer ce que j'écoute ».

Pour toute remarque ou question sur l'article, n'hésitez pas à me contacter par MP ou posez votre question sur le forum Général Dotnet.

IV - Téléchargements

- Code source (Miroir) [330Ko]

- Exécutable (Miroir) [60Ko]