[C# .NET 2.0] Interagir avec Winamp (VS 2005 express)

Interagir avec Winamp (VS 2005 express) [C# .NET 2.0] - C#/.NET managed - Programmation

Marsh Posté le 31-12-2006 à 14:18:43    

Bonjour,
 
Je souhaite récupérer en C# (.NET 2.0) le chemin de la musique en cours de lecture dans Winamp. Les portages du WinampSDK pour C# sont tous en beta, peu avancés et surtout plus maintenu.
 
Je sais qu'il faut récupérer le handle de la fenetre de winamp, pour pouvoir lui transmettre des messages mais je ne m'en sort pas trop. J'ai reussi à récupéré le numéro de la chanson en cours de lecture dans la playlist (via le WinAmpSDK C#) mais bon, dés qu'il faut faire transiter des données plus complexe j'ai du mal.  
 
si quelqu'un a des infos, je suis prenneur. merci!
 
ps : j'ai aussi trouvé ça : http://msmvps.com/blogs/ch21st/arc [...] /3279.aspx
c'est du VB mais je pense que la méthode doit etre bonne. Reste que je suis pas expert du PInvoke et de la programmation système donc...


Message édité par xtream le 12-01-2007 à 21:01:01
Reply

Marsh Posté le 31-12-2006 à 14:18:43   

Reply

Marsh Posté le 31-12-2006 à 14:20:48    

harrrkkoooooooo

Reply

Marsh Posté le 31-12-2006 à 14:39:50    

bon, là je dois m'absenter, mais je réponds dés que je suis de retour :o


---------------
J'ai un string dans l'array (Paris Hilton)
Reply

Marsh Posté le 31-12-2006 à 15:11:33    

voilà déjà ce que j'ai et qui fonctionne :

Code :
  1. [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
  2. private static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
  3. [DllImport("user32.dll" )]
  4. private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
  5. private const int IPC_GETPLAYLISTFILE = 211;
  6. private const int IPC_GETLISTPOS = 125;
  7. private const uint WM_USER = 0x400;
  8.        
  9. ...
  10. IntPtr winampWindowsHandle = FindWindow("Winamp v1.x", null);
  11. IntPtr playlistPosition = SendMessage(winampWindowsHandle, WM_USER, (IntPtr)0, (IntPtr)IPC_GETLISTPOS);
  12. Console.WriteLine(playlistPosition);
  13. IntPtr playlistFilePtr = SendMessage(winampWindowsHandle, WM_USER, playlistPosition, (IntPtr)IPC_GETPLAYLISTFILE);
  14. Console.WriteLine(playlistFilePtr);


 
si j'ai a peu prés compris ce que j'ai fait, je récupère le numéro de la chanson en cours d'écoute dans la playlist et grace à ce numéro, je récupère une sorte d'adresse mémoire ou je devrait trouver des infos sur le fichier en cours de lecture (dans le process de winamp). Mais aprés je coince.
 
j'ai bon déjà ? :-)


Message édité par xtream le 31-12-2006 à 15:12:22
Reply

Marsh Posté le 07-01-2007 à 22:39:55    

Désolé pour le retard, avec les fêtes ce topic m'est complètement sorti de la tête [:ddr555]
 
Alors, reprenons :
 

  • ligne 2 : pourquoi déclarer wParam et lParam en IntPtr alors que le SDK de Winamp les utilise comme des int ?

Personnellement, j'importe SendMessage comme ceci :

Code :
  1. [DllImport("user32.dll", EntryPoint = "SendMessageW" )]
  2.        static unsafe extern int SendMessage(
  3.            IntPtr hWnd,
  4.            int msg,
  5.            int wParam,
  6.            int lParam);


Je reviendrais plus tard sur le unsafe.
 
Ensuite, venons en au vif du sujet : la ligne 16. C'est effectivement le message IPC_GETPLAYLISTFILE qui renverra le fichier en cours de lecture. Tu reçois effectivement en retour un pointeur vers la chaine de caractère contenant le nom du fichier. Or, en C#, pas de pointeurs, donc pas de possibilité de récupérer la valeur pointée. Bienvenue dans le calvaire de l'API en C de Winamp...
 
Néanmoins, le C# permet d'utiliser des pointeurs en faisant du code unsafe. Ce qui signifie que ce sera à toi de gérer la mémoire dans ton bloc unsafe. D'ou ma déclaration unsafe de SendMessage, car je vais utiliser des pointeurs en paramètre.
J'avoue que j'ai choisi la solution la plus "pratique" : l'API de Winamp utilise des pointeurs, donc j'utilise des pointeurs. Il y a surement moyen de rendre le code safe en utilisant des ref machin. Je m'y penche pour la prochaine version de mon plugin.
 
Une fois ta chaine récupérée, c'est tout bête : tu construis un objet String, managé celui ci, avec le buffer en paramètre.
 
Venons en au type du buffer dans lequel sera stocké la chaine. En C, tu récupères un char*, donc il faut trouver l'équivalent en C#, et surtout d'un type accepté par le constructeur de String. Une fois la doc parcourue, on découvre le type sbyte, qui convient tout à fait.
 
Ce qui nous donne :

Code :
  1. unsafe
  2. {
  3.   sbyte* fileName = (sbyte*)SendMessage(pluginWindow, WM_WA_IPC, pos, IPC_GETPLAYLISTFILE);
  4.   string CurrentFile = new string(fileName);
  5. }


ligne 3 : je récupère le résultat de SendMessage (donc le chemin du fichier joué) dans la variable fileName
ligne 4 : je construis un objet String (donc managé) à partir de cette variable.
 
Voila. Après tu fais ce que tu veux de ta String, elle est utilisable avec toutes les classes .NET
 
Bon courage avec le P/Invoke, le Marshalling, et l'API pourrie de Winamp en C tout aussi pourri :D


Message édité par Harkonnen le 07-01-2007 à 22:41:03

---------------
J'ai un string dans l'array (Paris Hilton)
Reply

Marsh Posté le 08-01-2007 à 20:39:42    

super! je vais tester ça de suite. Finalement ça me rassure, j'étais pas si loin du résultat mais un grand merci à toi car j'étais complètement bloqué sur ce truc :-(
 
C'est la seule interaction que je vais avoir avec Winamp. Une fois que j'ai le chemin du fichier, je récupère toutes les valeurs des Tags (ID3 pour le MP3 ou autre pour le OGG, APE etc...) via un librairie (DLL) que j'ai trouvé chez Novell. Elle est pas documenté mais finalement j'ai trouvé comment m'en servir facilement en C# (ctc moi en MP si ça intéresse quelqu'un).
 
encore merci!

Reply

Marsh Posté le 09-01-2007 à 05:57:41    

oh la cest vraiment la fete dutiliser win32 en C#
 
on a limpression de faire du win32 en vb (voir pire encore)


Message édité par red faction le 10-01-2007 à 19:41:01
Reply

Marsh Posté le 10-01-2007 à 19:38:06    

bon, je dois pas être doué parce meme avec ce que tu m'as donné, il me retourne toujours une chaine vide :-(
 
ci joint un extrait de mon code

Code :
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using System.Runtime.InteropServices;
  5. namespace Xtream_ToolBox.Utils.Multimedia {
  6.     class Winamp : IMultimediaPlayer {
  7.         [DllImport("user32.dll", EntryPoint = "SendMessageW" )]
  8.         static unsafe extern int SendMessage(
  9.             IntPtr hWnd,
  10.             int msg,
  11.             int wParam,
  12.             int lParam);
  13.        
  14.         private IntPtr handle = IntPtr.Zero;
  15.         private static String classname = "Winamp v1.x";
  16.         private int IPC_GETPLAYLISTFILE = 211;
  17.         private int IPC_GETLISTPOS = 125;       
  18.         private int WM_USER = 0x400;
  19.         public void findAndSetHandle() {
  20.             handle = SystemUtils.FindWindow(classname, null);
  21.         }
  22.         public String getCurrentSongPath() {
  23.             int playlistPosition;
  24.             String musicPath = null;
  25.             findAndSetHandle();
  26.             Console.WriteLine("handle : " + handle);
  27.             if (handle != IntPtr.Zero){
  28.                 playlistPosition = SendMessage(handle, WM_USER, 0, IPC_GETLISTPOS);
  29.                 Console.WriteLine("playlistPosition : " + playlistPosition);
  30.                 unsafe {
  31.                     sbyte* fileName = (sbyte*)SendMessage(handle, WM_USER, playlistPosition, IPC_GETPLAYLISTFILE);
  32.                     musicPath = new string(fileName);
  33.                 }
  34.                 Console.WriteLine("musicPath : [" + musicPath + "]" );
  35.             }
  36.             return musicPath;
  37.         }
  38.     }
  39. }


 
je lance donc mon winamp, et quand mon programme execute le getCurrentSongPath() j'ai ça dans mon log :

handle : 132100
playlistPosition : 1
musicPath : []


 
je ne vois pas bien ou peut se trouver l'erreur...
 
je n'ai pas trouvé la valeur de WM_WA_IPC mais j'ai lu que WM_WA_IPC était la meme chose que WM_USER (0x400) donc j'ai utilisé WM_USER à la place. Le probleme vient peut etre de là ? une idée ?

Reply

Marsh Posté le 14-01-2007 à 19:00:44    

j'ai lu a droite à gauche qu'il n'était pas possible de récupérer le chemin de la musique en cours de lecture dans winamp dans une application externe (autre qu'un plugin winamp) ce qui pourrait peut etre expliqué que mon code soit bon mais que je n'ai pas le retour escompté.
 
J'ai également vu des exemple pour lire dans la mémoire du processus de winamp pour contourner le probleme mais je n'y arrive pas. Pour lire dans la mémoire d'un process il faut récupéré son hande à partir du hande du thread mais cette fonction (OpenProcess) me retourne toujours zero.  
 

Code :
  1. playlistPosition = (int)SendMessage(handle, WM_USER, 0, IPC_GETLISTPOS);
  2. Console.WriteLine("playlistPosition : " + playlistPosition);
  3. IntPtr lp = SendMessage(handle, WM_USER, playlistPosition, IPC_GETPLAYLISTFILE);
  4. Console.WriteLine("IPC_GETPLAYLISTFILE lp : " + lp);
  5.                              
  6. IntPtr ThreadID = IntPtr.Zero;
  7. ThreadID = GetWindowThreadProcessId(handle, ThreadID);
  8. Console.WriteLine("ThreadID : " + ThreadID);
  9. IntPtr lpWinamp = OpenProcess(PROCESS_ALL_ACCESS, 0, (uint)ThreadID);
  10. Console.WriteLine("OpenProcess return " + lpWinamp);
  11. IntPtr nbByteRead;
  12. byte[] buffer = new byte[260];
  13. ReadProcessMemory(lpWinamp, lp, buffer, 260, out nbByteRead);
  14. Console.WriteLine("buffer : " + buffer.ToString());
  15. Console.WriteLine("nbByteRead : " + nbByteRead);
  16. CloseHandle(lpWinamp);


 
sortie dans le log :

playlistPosition : 4
IPC_GETPLAYLISTFILE lp : 4711816
ThreadID : 2364
OpenProcess return 0
buffer : System.Byte[]
nbByteRead : 0


 
je suis donc dans une impasse... vraiment personne pour me donner un coup de main ?


Message édité par xtream le 14-01-2007 à 19:04:50
Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed