Personnalisation d'MSN 7 avec C#

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 Donner une note à l'article (5)

Article lu   fois.

L'auteur

Profil ProSite personnel

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

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 "chatez". Pour ceux qui ne voient toujours pas de quoi je veux parlez, voici une capture d'écran;

Image non disponible
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,...

Image non disponible
afficher ce que j'écoute

II. Développement du programme

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'icone 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 au final ce que permet le programme;

Image non disponible
Le programme affiche une icone 'jeux' et met à jours 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.

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 2 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
Sélectionnez

using System.Runtime.InteropServices;
2. Ajout dans la définition de la classe
Sélectionnez

[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 d'MSN (SendMessage). Mais avant, il faut construire un string reprenant l'ensemble des informations (icone+message).

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

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çons ;

 
Sélectionnez

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'icone à afficher, on a le choix entre trois : "Office", "Games" ou "Music"

Image non disponible
Office - Games - Music

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

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.

Image non disponible

Le principe est simple, l'utilisateur choisit l'icone à 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 ca pas besoin d'aide :p.

Nous aurons besoins 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.

 
Sélectionnez

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.

 
Sélectionnez

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.

 
Sélectionnez

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
Sélectionnez

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'icone à envoyer à MSN, et pour finir l'appel de la méthode SendMSNMessage.

timer_Tick
Sélectionnez

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 2ème bouton (bouton Stop) arrête le compteur et remet l'ancien message personnel;

btnStop_Click
Sélectionnez

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 2,3 aspects du programme.

D. Lecture/Ecriture 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/Ecriture dans fichier XML
Sélectionnez

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;
	}
}

E. Réduction en icone de notification

Ce genre d'application reste en général longtemps en fonctionnement, et dans de tel cas, il vaut mieux allez se loger dans la zone de notification (à gauche de l'horloge). Pour ne pas surcharger la barre de tache 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
Sélectionnez

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...Ca 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]

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

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.