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

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

, 7 Feb 2004
Rate this:
Please Sign up or sign in to vote.
An article demonstrating the usage of Platform Invoke Services in Visual C# to interoperate with Windows Media Player.

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

Comments and Discussions

 
QuestionHow set zoom to 200% PinmemberTheCodeVB15-May-10 12:34 

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

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web03 | 2.8.140718.1 | Last Updated 8 Feb 2004
Article Copyright 2004 by Alexander Kent
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid