Click here to Skip to main content
15,880,905 members
Articles / Programming Languages / Visual Basic
Article

Show dialogs in Microsoft XP Media Center UI from an external application

Rate me:
Please Sign up or sign in to vote.
4.67/5 (13 votes)
8 Apr 2005CPOL5 min read 92.1K   1.4K   26   16
This article explains how to show dialogs in Microsoft's Windows XP Media Center UI from an external application.

Sample Image

Introduction

Windows XP Media Center Edition offers the best Windows experience in any room in your home, whether you’re looking for a family computer or to enhance your home theater. Enjoy integrated home entertainment experiences including photos, music, TV, and more. Connect with devices around the home, and on the go that extends your entertainment (see Microsoft's Media Center website for details).

If you want to integrate your application into this new user experience, you might want to expand your existing application to show a notification to the user who is probably just watching TV on the PC. This article describes a simple way to show a notification with an image to the user.

Background

Microsoft did not add a direct way to show notifications in the Media Center UI from an external application, but they made another way possible: you can add "Background Add-ins" to the Media Center which will run all the time the Media Center UI is running, and use it to receive messages from the "outer world". This article shows how to use these background add-ins to open a simple way to show a message to the user.

Michael Creasy describes how to develop these background add-ins. In his blog (see here) you can find a basic sample of a background add-in.

To communicate to this running Media Center add-in, I use a simple WM_COPYDATA to send the texts to show and other information to the add-in. There are several ways of communication between two different applications, but this way is the easiest one to use if your program parts are developed in different programming languages.

To give an overview of all the components and the flow, I have prepared this flowchart:

Image 2

Using the code

The sample consists of two separate parts:

  1. A simple Visual Basic 6 program that demonstrates how to send some information to the Media Center add-in with WM_COPYDATA.

    The reason I chose VB 6 here is that this article has its roots in TapiRex, a shareware program I develop that shows CallerID on incoming calls, which also uses this technique to display a CallerID and some other information in the Media Center UI (see www.cbuenger.com for details).

  2. A background add-in for Media Center 2005 that is automatically loaded by the Media Center when it starts and which is listening to incoming WM_COPYDATA messages displays the containing texts with the Media Center API functions.

    This part has to be compiled with the .NET Framework 1.0, because Microsoft's Media Center only accepts add-ins to be in .NET 1.0. The source code contains a simple batch file that demonstrates how to compile the add-in without the Visual Studio IDE.

Let's get into the details: The "trick" in the background add-in is to derive this whole add-in not only from the base classes Microsoft proposes for add-ins (IAddInModule, IAddInEntryPoint, IDisposable) but also from System.Windows.Forms.NativeWindow. This gives us a window handle to hook on and listen for any Windows messages sent to this window and filter for WM_COPYDATA:

C#
protected override void WndProc(ref Message m)
{
    if (m.Msg == WM_COPYDATA)
    {
        ...
    }
    base.WndProc(ref m);
}

But just creating a window handle is only half way: this window has to be found by our MessageSender. So we just give this invisible window a very unique window title:

C#
public mceDialogAddIn()
{
    //Creating Window based on globally known name, and create handle
    //so we can start listening to Window Messages.
    CreateParams Params  = new CreateParams();
    Params.Caption = "<? .: mceDialog.MessageServer :. ?>";
    this.CreateHandle(Params);
}

This ensures that we will find this window in our MessageSender using FindWindow:

VB
'Get TargetWindow handle
hwndTarget = FindWindow(vbNullString, "<? .: mceDialog.MessageServer :. ?>")
If (hwndTarget = 0) Then
  ' MCE addin-window not found
  Exit Function
End If

The MessageSender in VB 6 has one important function, to send the message to the add-in using SendMessage:

VB
Dim uCopyData As COPYDATASTRUCT
Dim sData As String
Dim strDelim As String
strDelim = "¦"

' build string to send
' single parameters are seperated by "¦"
' the parameters:
'   [0] = caption
'   [1] = text to show
'   [2] = image to display
'   [3] = hide dialog automatically after these seconds
sData = strCaption & strDelim & strText & strDelim & _
        strImage & strDelim & intAutoHide & strDelim

'Fill up the structure
With uCopyData
    .cbData = LenB(sData)
    .lpData = StrPtr(sData)
End With

Call SendMessage(hwndTarget, WM_COPYDATA, 0, uCopyData)
' hwndTarget is the window handle of the invisble
' Media Center addin window

For simplicity, the data for the add-in is just separated by "¦". Doing this, we can split up the data when it is received by the add-in:

C#
if (m.Msg == WM_COPYDATA)
{
    // arguments are delimited by "¦".
    // the argument in order:
    // [0] = caption
    // [1] = text to show
    // [2] = image to display
    // [3] = hide dialog automatically after these seconds
    COPYDATASTRUCT st = (COPYDATASTRUCT) Marshal.PtrToStructure(m.LParam, 
                                                 typeof(COPYDATASTRUCT));
    string strData = Marshal.PtrToStringUni(st.lpData);
    string strDelim = "¦";
    string[] args = strData.Split(strDelim.ToCharArray());
    int intTimeOut = Int32.Parse(args[3]);
    string strImage = args[2].Replace("\\", "\\\\");
    if(!File.Exists(strImage))
    // if image does not exist,
    // do not pass to Dialog or it will not show up
        strImage = "";

    ...
}

Now we have the data right where we wanted it: in the process of Media Center GUI. Because this add-in has a reference to Microsoft.MediaCenter, we have access to the Media Center API from our add-in. But there is no direct way to show a MCE style MessageBox from just some point in the add-in... The MessageBox-function has a similar function in Media Center API which is HostControl.Dialog (see MSDN for details). So we need a handle to a HostControl. A reference to a HostControl is passed in to the add-in in the function void IAddInEntryPoint.Launch(AddInHost host). This function is called when Media Center launches the add-in on start. So all we have to do is save this reference to host for later usage to show the Dialog:

C#
void IAddInEntryPoint.Launch(AddInHost host)
{
    mhcControl = host.HostControl;
    ...
}

protected override void WndProc(ref Message m)
{
    if (m.Msg == WM_COPYDATA)
    {
        ...

        Object[] oButtons = new Object[1];
        oButtons[0] = 1;        // just an OK button

        mhcControl.Dialog(args[1], args[0], oButtons, intTimeOut, 
                  false, strImage, null);
        // mhcControl is our saved reference to a HostControl
    }
    base.WndProc(ref m);
}

Points of Interest

One very important thing to know is that a background add-in will be unloaded by Media Center when the execution leaves the IAddInEntryPoint.Launch function. So if you want an add-in to stay in memory (for example, to wait for specific messages like this one), you have to "hold" the execution in the Launch function and only give it back to the Media Center process if you want to be unloaded:

C#
void IAddInEntryPoint.Launch(AddInHost host)
{
    ...
    while (true)
    {
        // Yield processing till we sample for inactivity
        // if we let the execution exit "Launch",
        // the addin will be unloaded
        // and is then unable to get messages...
        Thread.Sleep(100);
        System.Windows.Forms.Application.DoEvents();
    }
}

The call to DoEvents is just there to let the thread handle the WndProc function to get a chance to filter incoming messages.

More

This example only shows a one-way "communication" from an external application to a background add-in. If you want to let your application know which button in the dialog box was clicked by the user, you have to establish a connection back from the add-in to your application. This could be done the same way (with WM_COPYDATA) or in any other way you like.

License

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


Written By
CEO Scavix Software GmbH & Co. KG
Germany Germany
Scavix Software offers high quality software development and consulting. That's what customers like Intel, AMD, eBay and Sage Software trusted in the last years. Be it on the desktop, in the web browser, on a mobile phone, on a tablet or on the TV: we can make your software visions come true.
Are you our next customer? Don't hesitate to contact us.

Imprint/Impressum: https://www.scavix.com/imprint/

Comments and Discussions

 
GeneralSimilar Problem like Addin Pin
Michael.F24-Jul-06 21:56
Michael.F24-Jul-06 21:56 
GeneralRe: Similar Problem like Addin Pin
benrjunk10-Jun-07 8:23
benrjunk10-Jun-07 8:23 
GeneralAdd-in getting unloaded after 10min Pin
Addin15-Dec-05 13:25
Addin15-Dec-05 13:25 
GeneralRe: Add-in getting unloaded after 10min Pin
Christoph Buenger15-Dec-05 13:31
professionalChristoph Buenger15-Dec-05 13:31 
GeneralRe: Add-in getting unloaded after 10min Pin
Addin20-Dec-05 7:03
Addin20-Dec-05 7:03 
GeneralRe: Add-in getting unloaded after 10min Pin
Christoph Buenger20-Dec-05 9:51
professionalChristoph Buenger20-Dec-05 9:51 
GeneralRe: Add-in getting unloaded after 10min Pin
Addin4-Jan-06 13:19
Addin4-Jan-06 13:19 
GeneralRe: Add-in getting unloaded after 10min Pin
Christoph Buenger6-Jan-06 11:36
professionalChristoph Buenger6-Jan-06 11:36 
it should be:
"YES" = 100
"No" = 101
"TEST" = 102
that's what i get back. so you have the result in btnArr when you just subtract 100 from the return value of Dialog().
that's what works very good in mcePhone for Skype which uses this dialog boxes as well...

Christoph
GeneralRe: Add-in getting unloaded after 10min Pin
gregoryfoster19-Dec-07 9:02
gregoryfoster19-Dec-07 9:02 
GeneralRe: Add-in getting unloaded after 10min Pin
alfaevans20-Jan-08 9:38
alfaevans20-Jan-08 9:38 
GeneralRe: Add-in getting unloaded after 10min Pin
bmnot22-Jan-10 14:14
bmnot22-Jan-10 14:14 
GeneralFailed to find the window created in Background Addin Pin
Addin29-Nov-05 7:53
Addin29-Nov-05 7:53 
GeneralRe: Failed to find the window created in Background Addin Pin
cyycfol14-Aug-06 20:53
cyycfol14-Aug-06 20:53 
GeneralRe: Failed to find the window created in Background Addin Pin
yuchih17-Sep-06 16:46
yuchih17-Sep-06 16:46 
GeneralRe: Failed to find the window created in Background Addin Pin
yuchih17-Sep-06 22:34
yuchih17-Sep-06 22:34 
GeneralGood Pin
Anonymous8-Apr-05 4:09
Anonymous8-Apr-05 4:09 

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

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