Click here to Skip to main content
Click here to Skip to main content

Interoperating with Windows Media Player using P/Invoke and C#

By , 7 Feb 2004
 

Introduction

This article hopes to demonstrate:

  • How to use P/Invoke to call unmanaged code.
  • How to use Spy++ to log Windows messages and get wParam and lParam values.
  • How to implement FindWindow() and SendMessage() in C#.
  • How to Interoperate with Windows Media Player.

Introduction to Win32 APIs

MSDN's definition of the Windows API is:

The Windows API (Application Programming Interface) consists of the functions, messages, data structures, data types, and statements you can use in creating applications that run under Microsoft Windows. The parts of the API you use most are code elements for calling API functions from Windows. These include procedure declarations (for the Windows functions), user-defined type definitions (for data structures passed to those functions), and constant declarations (for values passed to and returned from those functions).

In short, Windows APIs are DLLs that are embedded in the Microsoft Windows operating system. The advantage of using Windows APIs in your code is that development time and complexity may be reduced because they contain hundreds of useful functions already written. The disadvantage is that Windows APIs do not use managed code and have data types that are different from those used with Visual Studio .NET. While the .NET framework has wrapped a significant portion of the Win32 API into managed code, the ones that remain unmanaged and without a .NET equivalent may be called by managed code using the platform invoke service.

Introducing Platform Invocation Services

Platform Invocation Services (P/Invoke) is a mechanism by which managed code calls unmanaged functions that are implemented in a DLL.

P/Invoke

When calling an unmanaged function, platform invoke must have the DLL file name and function or ordinal number. The DLLImport attribute is used to specify the DLL location that contains the implementation of an external method and its parameters are used to specify specific behavior such as EntryPoint and CharSet. For more information on the syntax of the DllImport attribute, see DllImportAttribute class at MSDN.

Table 1: Commonly used DLLs in the Win32 API

DLL

Description of its contents

Kernel32.dll

Low-level operating system functions for memory management and resource handling.

GDI32.dll

Graphics Device Interface (GDI) functions for device output, such as those for drawing and font management.

User32.dll

Windows management functions for message handling, timers, menus, and communications.

Steps to call Win32 API using C#

  1. Import the System.Runtime.InteropServices namespace.
  2. Define functions by using DLLImport.
  3. Add code to call the Win32 API.

We are going to implement the FindWindow() and SendMessage() related Win32 API functions found in the User32.dll as illustrated in the Win32 class below.

public class Win32
{
    // The WM_COMMAND message is sent when the user
    // selects a command item from a menu, 
    // when a control sends a notification message
    // to its parent window, or when an 
    // accelerator keystroke is translated.
    public const int WM_COMMAND = 0x111;

    // The FindWindow function retrieves a handle
    // to the top-level window whose class name
    // and window name match the specified strings.
    // This function does not search child windows.
    // This function does not perform a case-sensitive search.
    [DllImport("User32.dll")]
    public static extern int FindWindow(string strClassName, 
                                             string strWindowName);

    // The FindWindowEx function retrieves
    // a handle to a window whose class name 
    // and window name match the specified strings.
    // The function searches child windows, beginning
    // with the one following the specified child window.
    // This function does not perform a case-sensitive search.
    [DllImport("User32.dll")]
    public static extern int FindWindowEx(int hwndParent, 
        int hwndChildAfter, string strClassName, string strWindowName);


    // The SendMessage function sends the specified message to a 
    // window or windows. It calls the window procedure for the specified 
    // window and does not return until the window procedure
    // has processed the message. 
    [DllImport("User32.dll")]
    public static extern Int32 SendMessage(
        int hWnd,               // handle to destination window
        int Msg,                // message
        int wParam,             // first message parameter
        [MarshalAs(UnmanagedType.LPStr)] string lParam); 
                                // second message parameter

    [DllImport("User32.dll")]
    public static extern Int32 SendMessage(
        int hWnd,               // handle to destination window
        int Msg,                // message
        int wParam,             // first message parameter
        int lParam);            // second message parameter

    public Win32()
    {

    }

    ~Win32()
    {
    }
}

Windows Media Player Interoperability Conceptual Art

Sample screenshot

Requirements:

  • Microsoft Visual Studio .NET
  • Microsoft Spy++
  • Windows Media Player
  1. Open Spy++ and press the Log Messages button, or press Ctrl + M.
  2. Open Microsoft Windows Media Player and arrange your windows so that Spy++ and Windows Media Player are both visible.
  3. Make sure Windows Media Player is not using the Auto Hide Menu bar feature and drag the Finder Tool to the outer Windows Media Player Window entitled “Windows Media Player”.

- Or -

If you know the handle of the Windows Media Player window, you may type it into the Handle box.

Step1

Next, proceed to the Messages tab and clear all selected messages. In the Messages to View list box, scroll down and select WM_COMMAND and click on OK.

At this point, having only WM_COMMAND selected will make the next step much easier.

Step2

Next, choose Play->Stop from the Windows Media Player Main Menu or simply press Ctrl+S for Spy++ to log the WM_COMMAND message:

<00001> 0023017A P WM_COMMAND wNotifyCode:0 (sent from a menu) wID:18809

The Messages view appears as shown below. Note that the first column contains the window handle, and the second column contains a message code. Message parameters and return values are on the right.

Step3

Double click on this entry to view additional Message Properties such as the wParam and lParam hex values.

Step4

Repeating the above for the Start button yields:

<00001> 0023017A P WM_COMMAND wNotifyCode:0 (sent from a menu) wID:18808

Using P/Invoke and Spy++, it’s easy to extend functionality to include other options such as Eject, Repeat, or Volume control but for demonstration purposes, we shall only implement Start/Pause and Stop.

private System.Int32 iHandle;

private void btnStop_Click(object sender, System.EventArgs e)
{
    Win32.SendMessage(iHandle, Win32.WM_COMMAND, 0x00004979, 0x00000000);
}

private void btnPlayPause_Click(object sender, System.EventArgs e)
{
    Win32.SendMessage(iHandle, Win32.WM_COMMAND, 0x00004978, 0x00000000);
}

private void MainForm_Load(object sender, System.EventArgs e)
{
    // get Window handle
    iHandle = Win32.FindWindow("WMPlayerApp", "Windows Media Player"); 
}

Conclusion

I had fun writing this article even though it’s not an original idea, but hopefully somebody out there will find it useful enough. Originally, I was thinking to dig deep into Windows Media player using FindWindowEx() and start playing with ATL:SysListView32 the “Current Playlist” to manipulate Windows Media Player Playlists on selected remote machines using WMI. If anyone has any other ideas or feature request, just let me know.

History

  • Version 1.0 - February 08 2004 - Original submission.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Alexander Kent
Kentdome LLC
United States United States
Biography in progress Wink | ;-)

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
SuggestionWindows Mediamembertri phan ba10-Feb-12 23:12 
I think it can't work all kind of sound file.
 
I can see two bottom, Play/Pause and STOP.
No more and more.
QuestionMany Questions [modified]membereiladah16-Dec-11 5:14 
first, thank you some much!!!!!
 
2. it dosn´t work, as long as I don´t press Play in the WMP once - which i don´t understand, because wehen i press play in the wmp, it just starts playing the first song, but when i do so with the c# it´s just not able to "decide with what to start"...
Do you have an Idea how to fix that?
 
3. When I run the Code BEFORE I open the wmp, it NEVER works Frown | :(
Same here, do you have an Idea how to fix that?
 
4. Spy++ is not giving me any codes "Windows does not allow the access to that window...", why is that?
 
I´m using Windows7, wmp 12, on a MacBook Pro
 
Sorry, that i asked soo many questions, but I really need this to be working and would share my results with you, if you are interested!

modified 16-Dec-11 12:39pm.

QuestionHow I can get a player list?memberhendryck7-Nov-11 17:31 
Hello, very good article....

I want to know how to get the media player list?
ex: tracks that are currently being played

can you help?


thanks!
QuestionHow set zoom to 200%memberTheCodeVB15-May-10 12:34 
How set zoom 200% to windowsMediaPlayer?
I don't find the way to fill the Control with the Video,
I see a black band Up and Down.
 
thank you.
QuestionRef. sound cardmemberFlavioAR4-Apr-10 3:47 
is there any chance to use his example to select a sound card (when more than one installed on your computer), without using the DirectSound API.Confused | :confused:
GeneralDoesnt work with WMP 12memberFullmetal9901227-Feb-10 13:19 
I tried to use the application with WMP 12 and windows 7, no dice. I even tried to use Spy++ to get the messages, again no luck. how do i get it to work.
GeneralRe: Doesnt work with WMP 12memberFullmetal9901227-Feb-10 13:36 
Sorry, i didn't realize that WMP had to be open first for the program to work. Fixed this by adding timer to sent the handle so when WMP is opened, it'll set the handle.
GeneralAlternate version using WM_APPCOMMAND and should work with most playersmemberAlain VIZZINI6-Dec-09 3:00 
Hi,
I used your code and it's very usefulThumbs Up | :thumbsup: ! It was my startup point. I just modified the fact that I use WM_APPCOMMAND (the same function as the recent keyboards with extra buttons) that is supported by most "players" (wmp, media player classic,...). Code is the same or so, juste message and parameters is different.
 
Code is here if it helps someone : http://kalshagar.wikispaces.com/Remote+controlling+Windows+media+player+in+C[^]

Out of curiosity I didn't tested it on all players, so if it works with your own player, drop a reply please.

 
Regards,
Alan.
QuestionHow can i get Windows Media Player Status?memberSaccomani23-Aug-09 6:44 
Hello, very good article....
 
I want to know how to get the media player status?
 
ex: get if media player is playing, stopped, paused... etc
 

can you help?
 

thanks!
GeneralSmall mistake in codememberIdan Shimoni24-Jan-09 8:08 
hi,
 
you have a small mistake in the code:
public const int WM_COMMAND = 0x111;
 
it should be:
public const int WM_COMMAND = 0x0111;
 
even in your "step4" pic the message is 0111 so it should be 0x0111
GeneralRe: Small mistake in codemembericetea948-May-10 0:22 
is there any difference between the numbers 10 an 010 in decimal system?
no?
so why in hexadecimal system? In fact, it is the same number.
GeneralDoes not work with Vista any morememberDeppChef21-Jul-08 10:00 
Hello,
 
in Vista the Sendmessage approach does not work any more for security reasons.
 
Hansjörg
GeneralRe: Does not work with Vista any morememberIdan Shimoni24-Jan-09 8:10 
it works for me
QuestionVoice recordingmemberkaka sipahe27-Jun-08 3:53 
Dear Sir,
 
I want to record sound from mic and get its bytes. and then play these bytes.
 
any help ?
 
regards
GeneralNeed some helpmemberScalee24-Jun-08 11:39 
Hi im trying to make a program to open up the wireless connection pane,
The class/caption is "Connections Tray" im trying to use the sendmessage to open it.
But i cant get it work is there any chance of you having a look when you have time?
GeneralSpy++memberzinneaj17-Jun-08 2:20 
Where do you get Spy++? It looks like Spy++ was for 6.0 originally. Correct? Is Control Spy the same?
Thank you.
GeneralRe: Spy++memberzinneaj17-Jun-08 2:35 
Ah, answered my own question. It's right in the framework Wink | ;)
QuestionwNotifyCodememberncjlee8-Jun-08 21:01 
I am trying to pinvoke on real player. This is what i am doing
 
//from spy++
<00001> 00202C0 S WM_COMMAND wNotifyCode:1 (sent from an accelerator) wID:200
 
//Pinvoke play
SendMessage(ihandle, WM_COMMAND, 200, 0x000);
 
It doesn't work.. I know this is related to wNotifyCode:1
how can i actually set wNotifyCode = 1?
 
Thank you
AnswerRe: wNotifyCodememberncjlee8-Jun-08 23:03 
Nvm i got it Smile | :)
 
// the lower word of wParam holds the controls ID
// the HIWORD of wParam holds the notification event code
// lparam will be the HWND of the control sending the message.
 
SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
 
Just create a method to handle wParam hi and lo word
GeneralID3memberturtle@inf.furb.br13-Feb-08 1:56 
Hello...
 
How do you get ID3 in current music.
 
Omar

GeneralIt doesn`t work on wmp 11membernevecaju21-Jul-07 11:44 
I used this code but i have wmp 11 and the code doesn't work on it... someone can help me
 
juka

GeneralRe: It doesn`t work on wmp 11memberVirtual1ty15-Sep-07 8:58 
Find the commands that are parsed to WMP 11 by using Spy++ on it (just like we did in this article). They might differ from older versions of Windows Media Player.
 
Virtual1ty
--
"Any fool can learn from his own mistakes, but a wise man learns from mistakes of others"

GeneralRe: It doesn`t work on wmp 11memberVirtual1ty15-Sep-07 9:07 
Never mind, the values are actually the same as in the version of WMP in this article. Do you get an error message, or doesn't anything happen when you send the command(s) to Media Player?
 
Virtual1ty
--
"Any fool can learn from his own mistakes, but a wise man learns from mistakes of others"

GeneralVery usefulmemberbreakall18-Apr-07 8:45 
I was looking to do something like and found your article very useful. Thanks!
QuestionCan this be used to change the visualizer?memberJudah Himango26-Dec-06 17:28 
First, thanks for the article. I knew WinAmp could be controlled using various window messages, and now you've confirmed WMP can be controlled this way as well.
 
Question: can I change the visualizer using SendMessage?
 
I'd like to be able to change the visualizer of WMP - is there any way to do this? I'd really appreciate the help if you have any ideas.
 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web02 | 2.6.130617.1 | Last Updated 8 Feb 2004
Article Copyright 2004 by Alexander Kent
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid