Photo Screensaver

This article demonstrates how to use a smartphone running Windows Mobile 5 to remotely control a host machine running Windows Media Center. I will describe how to create an add-in application that runs within Windows Media Center, and how to create a Windows Mobile 5 application that you can use to communicate with the Media Center over a wireless internet connection. Finally, I will demonstrate how to use this implementation to manipulate Media Center using the Windows Media Center API.
Difficulty: Intermediate
Time Required: 6-10 hours
Cost: $100-$200
Software: Visual Basic or Visual C# Express Editions, Windows Media Center SDK 5.0, Windows Mobile 5.0 Smartphone SDK
Hardware: Mobile device running Windows Mobile 5.0
Download: C# and VB.Net
By combining the power of a Media Center add-in with a mobile device running Windows Mobile 5.0, we can extend the capabilities of a Media Center add-in even further. The add-in service I developed runs as a listener service within Windows Media Center on the host machine. It is initialized when Windows Media Center is started, runs invisibly in the background, and allows mobile devices to connect and submit requests to it. The mobile solution leverages an existing WiFi internet connection to communicate with the add-in via TCP socket connections. The mobile device runs a .NET Compact Framework 2.0 forms application designed for devices running Windows Mobile 5 or higher.
The included remote control application is capable of the following functionality:
Figure 1 - Creating the project
Using the Windows Media Center Presentation Layer Application project template yields the following project skeleton:
Figure 2 - Solution Explorer for our new project
There are two files of interest here: AddIn.vb and App.xml. AddIn.vb contains our add-in class. Interface methods implemented in this class will be invoked by Windows Media Center when our add-in is launched. App.xml contains configuration information identifying our assemblies and add-in attributes. The setup project will use this XML to register our add-in with Windows Media Center during installation.
Public Class Class1 Implements IAddInModule Implements IAddInEntryPoint ' Initialize (IAddInModule) Public Sub Initialize(ByVal appInfo As Dictionary(Of String, Object), ByVal entryPointInfo As Dictionary(Of String, Object)) Implements IAddInModule.Initialize ' Initialization logic goes here End Sub ' Uninitialize (IAddInModule) Public Sub Uninitialize() Implements IAddInModule.Uninitialize ' Clean-up logic goes here End Sub ' Launch (IAddInEntryPoint) Public Sub Launch(ByVal host As AddInHost) Implements IAddInEntryPoint.Launch ' This is where normal execution begins End Sub End Class
public class Class1 : IAddInModule, IAddInEntryPoint { // Initialize (IAddInModule) public void Initialize(Dictionary<string, object> appInfo, Dictionary<string, object> entryPointInfo) { // Initialization logic goes here } // Uninitialize (IAddInModule) public void Uninitialize() { // Clean-up logic goes here } // Launch (IAddInEntryPoint) public void Launch(AddInHost host) { // This is where normal execution begins } }
The IAddInModule.Initialize and IAddInModule.Uninitialize interface methods are used by Media Center to signal the beginning and end of the add-in application's lifetime. Use Initialize to create any internal objects your application may require, and the Uninitialize to perform any clean-up. Keep in mind that since the add-in application runs within Media Center, it may decide to close your add-in application before it has a chance to exit on its own. In any case, Media Center will call the Uninitialize method and give the add-in a window of execution to exit as gracefully as possible.
The IAddInEntryPoint.Launch method is where normal execution code should begin. Media Center will pass an AddInHost object as an input parameter. Through this object, your add-in application can access all the features of the Media Center API.
Figure 3 - Signing our assembly
Explicit instruction is also available here:
How to: Sign an Assembly (Visual Studio)
<application title="DemoProject" id="{f6dd1141-f288-46fe-bcdb-2d9c5ffd986e}"> <entrypoint id="{31a15ce9-0487-43bc-94de-a43409129641}" addin="DemoProject.Class1, DemoProject,Culture=Neutral,Version=6.0.6000.0" title="DemoProject" description="DemoProject" ImageUrl=".\AppIcon.png"> <category category="More Programs"/> </entrypoint> </application>
The XML definition specifies the add-in applications and their points of entry within Media Center. Add-in applications can be launched on demand from various locations within Media Center, such as from an icon in the “More Programs” group. A full listing of all the available points of entry can be found here. Add-in applications can also be launched in the background when Media Center starts. To indicate this, we specify “Background” in the “category” attribute. The “addin” attribute must also be modified to point to our add-in class in the format “Assemblyname.ClassName”. The “title”, “description”, and “ImageUrl” attributes are used primarily for on-demand add-ins.
After making our changes, the Windows Media Center Remote application XML looks like this:
<application title="WMCServerAddIn" id="{7b71a7ca-b459-4023-ab12-d5cc8c56b991}"> <entrypoint id="{5fe9982b-ca4a-459e-b62c-40399e875d66}" addin="WMCServerAddIn.ServerAddIn, WMCServerAddIn,Culture=Neutral,Version=6.0.6000.0" title="WMCServerAddIn" description="WMCServerAddIn" ImageUrl=".\AppIcon.png"> <category category="Background"/> </entrypoint> </application>
With a basic interface implementation complete and a configuration XML created, we are ready to create the setup project. The setup project will install our assemblies into the Global Assembly Cache and register our XML-defined entry point with Media Center. A full step-by-step walkthrough can be found here:
Creating a Windows Installer File for a Windows Media Center Add-in
Once the setup project is complete, it's time for a test. By using the Host.MediaCenterEnvironment.Dialog class off of the AddInHost object, we can present a dialog box to the user to ensure the add-in launches successfully. After compiling the solution, run the installer by right-clicking the setup project and choosing “Install”. Once installation has completed, run Windows Media Center. A few seconds after startup, the add-in is launched:
Figure 4 - Running our Hello World Media Center Add-in
Installing the Windows Mobile Smartphone SDK 5.0 makes this step simple. Once the SDK is installed, you can create a project in Visual Studio using the Windows CE 5.0 Project template.
The only other typical setup required for developing mobile apps is to change the deployment settings to point to your WM5 device. This can be configured within the Visual Studio toolbar:
Figure 5 - changing the deployment settings to target the mobile device
The socket server uses the Socket object from the System.Networking.Sockets namespace for all of its communications. The listener service begins by binding to the host machine's local address and listening on a port of your choosing. Once the socket is instantiated and bound to a local port, it begins listening for and accepting inbound connections. When a new connection is established, a target method BeginSocketConversation will be invoked on a new thread, where the actual communication between the two parties will take place. Once the new thread has been invoked, execution will continue in the AcceptConnections method. At this time the newly launched thread notifies the listener to begin accepting new connections again. A ManualResetEvent from the System.Threading namespace can be used to communicate changes in state between two or more threads. Here is the code implementation of the socket listener:
Private Sub AcceptConnections() Dim localMachineInfo As IPHostEntry Dim localEndPoint As IPEndPoint Dim listener As New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp) Try localMachineInfo = Dns.Resolve(String.Empty) localEndPoint = New IPEndPoint(localMachineInfo.AddressList(0), _port) listener.Bind(localEndPoint) listener.Listen(10) While True threadEvent.Reset() listener.BeginAccept(New AsyncCallback(AddressOf BeginSocketConversation), listener) threadEvent.WaitOne() End While Catch ex As Exception Log.Write(ex) End Try End Sub
Public Class Class1 Implements IAddInModule Implements IAddInEntryPoint ' Initialize (IAddInModule) Public Sub Initialize(ByVal appInfo As Dictionary(Of String, Object), ByVal entryPointInfo As Dictionary(Of String, Object)) Implements IAddInModule.Initialize ' Initialization logic goes here End Sub ' Uninitialize (IAddInModule) Public Sub Uninitialize() Implements IAddInModule.Uninitialize ' Clean-up logic goes here End Sub ' Launch (IAddInEntryPoint) Public Sub Launch(ByVal host As AddInHost) Implements IAddInEntryPoint.Launch ' This is where normal execution begins End Sub End Class
Once a connection has been established, the server begins to listen for inbound messages. When new data is received, it is parsed into a custom Message object for easy inspection by a consuming class. An event is then raised to any consuming classes, passing a reference to the newly created Message object. The server then resumes listening for new data on the same socket. Here is the code implementation:
Private Sub BeginSocketConversation(ByVal ar As IAsyncResult) threadEvent.Set() RaiseEvent ClientConnected() Dim listener As Socket = CType(ar.AsyncState, Socket) _socket = listener.EndAccept(ar) Dim buffer(PACKET_SIZE) As Byte Dim bytesReadCount As Integer = 0 While True Dim sb As New System.Text.StringBuilder Do Try bytesReadCount = _socket.Receive(buffer, buffer.Length, SocketFlags.None) Catch ex As Exception _socket.Close() Exit While End Try sb.Append(System.Text.ASCIIEncoding.ASCII.GetString(buffer, 0, bytesReadCount)) Loop While _socket.Available > 0 Dim requestMessage As New RequestMessage() requestMessage.DeSerialize(sb.ToString()) RaiseEvent MessageReceived(requestMessage) End While RaiseEvent ClientDisconnected() End Sub
private void BeginSocketConversation(IAsyncResult ar) { threadEvent.Set(); ClientConnected(); Socket listener = ((Socket)(ar.AsyncState)); _socket = listener.EndAccept(ar); byte[,] buffer; int bytesReadCount = 0; while (true) { System.Text.StringBuilder sb = new System.Text.StringBuilder(); for ( ; (_socket.Available > 0); ) { try { bytesReadCount = _socket.Receive(buffer, buffer.Length, SocketFlags.None); } catch (Exception ex) { _socket.Close(); break; } sb.Append(System.Text.ASCIIEncoding.ASCII.GetString(buffer, 0, bytesReadCount)); } RequestMessage requestMessage = new RequestMessage(); requestMessage.DeSerialize(sb.ToString()); MessageReceived(requestMessage); } ClientDisconnected(); }
The custom server object created in the previous section encapsulates all the grunt work of socket-level protocol, accepting connections, serializing / deserializing message objects, and data transfer. Within the AddIn class implementation, all we have to do now is instantiate the Server class, indicating the port to listen on:
Public Sub Launch(ByVal host As AddInHost) Implements IAddInEntryPoint.Launch _wmcHost = host _waitForExit = New System.Threading.ManualResetEvent(False) _server.Start(DEFAULT_PORT) System.Threading.Thread.CurrentThread.Priority = Threading.ThreadPriority.Lowest _waitForExit.WaitOne() End Sub
public void Launch(AddInHost host) { _wmcHost = host; _waitForExit = new System.Threading.ManualResetEvent(false); _server.Start(DEFAULT_PORT); System.Threading.Thread.CurrentThread.Priority = Threading.ThreadPriority.Lowest; _waitForExit.WaitOne(); }
We also perform two other critical tasks at this time. First, we assign a reference to the AddInHost to a private member variable for later use. Second, we reduce the priority of the add-in's main thread and use a ManualResetEvent to put it to sleep until Media Center is closed. The reason for this relates to the nature of an add-in's lifetime within Media Center. The Media Center add-in hosting process will only allow an add-in to execute for the duration of its Launch method. This means that as soon as the Launch method returns, the add-in and any child threads it has spawned will be terminated. For this reason, we must keep the add-in alive by blocking the Launch method from exiting.
Using the communications layer and socket listener developed in the previous sections, we can finally get to the task of performing something useful with the input requests. By subscribing to the custom Server object's MessageReceived event, the AddIn class's OnDataReceived method will automatically be invoked when a new request message is received from the listener:
Private Sub OnDataReceived(ByVal message As RequestMessage) Handles _server.MessageReceived Select Case message.RequestAction Case RequestMessage.Action.PauseMedia _wmcHost.MediaCenterEnvironment.MediaExperience.Transport.PlayRate = PlayRates.PLAYRATE_PAUSE Case RequestMessage.Action.VolumeUp _wmcHost.MediaCenterEnvironment.AudioMixer.VolumeUp() Case RequestMessage.Action.VolumeDown _wmcHost.MediaCenterEnvironment.AudioMixer.VolumeDown() Case RequestMessage.Action.NextMedia _wmcHost.MediaCenterEnvironment.MediaExperience.Transport.SkipForward() Case Else End Select SendAcknowledgement(message) End Sub
private void OnDataReceived(RequestMessage message) { switch (message.RequestAction) { case RequestMessage.Action.PauseMedia: _wmcHost.MediaCenterEnvironment.MediaExperience.Transport.PlayRate = PlayRates.PLAYRATE_PAUSE; break; case RequestMessage.Action.VolumeUp: _wmcHost.MediaCenterEnvironment.AudioMixer.VolumeUp(); break; case RequestMessage.Action.VolumeDown: _wmcHost.MediaCenterEnvironment.AudioMixer.VolumeDown(); break; case RequestMessage.Action.NextMedia: _wmcHost.MediaCenterEnvironment.MediaExperience.Transport.SkipForward(); break; } SendAcknowledgement(message); }
The RequestMessage class shown above is a custom object, originally created by Windows Mobile 5 application running on a connected mobile device. The transport object was then serialized on the device, transmitted, deserialized in the listener service, and
raised to the add-in class via the MessageReceived event. The RequestAction property is an enumerable type indicating the type of action to take within Media Center. The Media Center API exposed by the AddInHost object (_wmcHost) can then be used to actually
perform the desired Media Center operation. Finally, we send an acknowledgement message to the mobile device.
The design of the socket client is much simpler than that of the socket server. All execution will be performed on the primary thread. The client begins by establishing a connection with an add-in server. Once established, the socket client sends and receives data synchronously over the socket. Consumers of the socket client need only call the Send method, which will return with the transactional response:
Public Function Send(ByVal request As Message) As String Dim responseString As String = Nothing Try If ((Not (_socket) Is Nothing) _ AndAlso _socket.Connected) Then Dim requestString As String = request.Serialize Send(requestString) responseString = RecvSynchronous Return responseString End If Catch ex As Exception Return Nothing End Try Return responseString End Function
public string Send(Message request) { string responseString = null; try { if (_socket != null && _socket.Connected) { string requestString = request.Serialize(); Send(requestString); responseString = RecvSynchronous(); return responseString; } } catch (Exception ex) { return null; } return responseString; }
Figure 6 - The configuration screen on the mobile device
Once we've specified the host and port of our running Media Center add-in service, we can click the “Connect” button to initialize the TCP/IP socket connection. Using the TCP Client class developed earlier, the code required to handle this event is simple:
Private Sub btnConnect_Click(ByVal sender As Object, ByVal e As EventArgs) Dim host As String = Me.txtHost.Text.Trim Dim port As String = Me.txtPort.Text.Trim _client.Connect(host, Convert.ToInt32(port)) End Sub
private void btnConnect_Click(object sender, EventArgs e) { string host = this.txtHost.Text.Trim(); string port = this.txtPort.Text.Trim(); _client.Connect(host, Convert.ToInt32(port)); }
Once connected, the user can navigate the application using the provided tabs at the bottom of the screen. Since this application is intended to function as a remote control, there is a standard media control screen:
Figure 8: The control screen on the mobile device
Nothing exotic here, but the basic media control functionality you'd expect from a remote is available. Here's a sample of the code required to support the “Stop” button's click event:
Private Sub btnConnect_Click(ByVal sender As Object, ByVal e As EventArgs) Dim host As String = Me.txtHost.Text.Trim Dim port As String = Me.txtPort.Text.Trim _client.Connect(host, Convert.ToInt32(port)) End Sub
private void btnStop_Click(object sender, EventArgs e) { RequestMessage message = new RequestMessage(); message.RequestAction = RequestMessage.Action.StopMedia; message.Data = String.Empty; string responseString = client.Send(message); ResponseMessage response = new ResponseMessage(responseString); }
The UI form uses the connected Client object to execute the Stop command. First, the form constructs a Request message, populating the type of action desired (StopMedia). Next, the Request message is passed to the Client class, where it is serialized for transport and sent over the connected TCP socket. From there, the running Media Center service will receive the request, perform the media stop, and send an acknowledgement. The Client then returns a Response message, which will contain a Boolean indicating if the request was successful or not.
On a Media Stop request, examining the Response object is not very informative. However, for other commands, the Media Center add-in service can be designed to return any kind of information required of the host. The Detail screen is a good example:
Figure 9 - The detail page
When a song or video is currently playing, the above screen can be used to retrieve any metadata associated with it. The event handler for the screen's “Refresh” button looks similar in form to the Stop button's handler:
Private Sub btnRefreshDetail_Click(ByVal sender As Object, ByVal e As EventArgs) Dim request As RequestMessage = New RequestMessage request.RequestAction = RequestMessage.Action.GetMediaMetadata Dim responseString As String = _client.Send(request) Dim response As MediaMetadataMessage = New MediaMetadataMessage(responseString) For Each item As MediaMetadataMessage.MediaMetadataItem In message.Data If ((Not (item.Value) Is Nothing) AndAlso (item.Value.Length > 0)) Then Me.txtDetail.Text = (Me.txtDetail.Text + (item.Key + (": " + item.Value))) Me.txtDetail.Text = (Me.txtDetail.Text + "" & vbCrLf) End If Next End Sub
private void btnRefreshDetail_Click(object sender, EventArgs e) { RequestMessage request = new RequestMessage(); request.RequestAction = RequestMessage.Action.GetMediaMetadata; string responseString = _client.Send(request); MediaMetadataMessage response = new MediaMetadataMessage(responseString); foreach (MediaMetadataMessage.MediaMetadataItem item in message.Data) { if (item.Value != null && item.Value.Length > 0){ this.txtDetail.Text += item.Key + ": " + item.Value; this.txtDetail.Text += "\r\n"; } } }
This time, however, the Response object has a list of metadata keys and values, which are then enumerated and displayed in a textbox. This Response object was originally populated by the Media Center add-in service:
Private Sub SendMediaMetadata() Dim response As New MediaMetadataMessage() Dim val As String For Each key As String In _wmcHost.MediaCenterEnvironment.MediaExperience.MediaMetadata.Keys val = _wmcHost.MediaCenterEnvironment.MediaExperience.MediaMetadata.Item(key).ToString() response.Data.Add(New MediaMetadataMessage.MediaMetadataItem(key, val)) Next response.ResponseIndicator = MediaMetadataMessage.ResponseCode.Success _server.Send(response) End Sub
private void SendMediaMetadata() { MediaMetadataMessage response = new MediaMetadataMessage(); string val; foreach (string key in _wmcHost.MediaCenterEnvironment.MediaExperience.MediaMetadata.Keys) { val = _wmcHost.MediaCenterEnvironment.MediaExperience.MediaMetadata.Item[key].ToString(); response.Data.Add(new MediaMetadataMessage.MediaMetadataItem(key, val)); } response.ResponseIndicator = MediaMetadataMessage.ResponseCode.Success; _server.Send(response); }
After receiving a request from the mobile device for the currently playing media's metadata, the Media Center add-in service constructs a list of custom objects (MediaMetadataItem). It populates this list by enumerating properties of the AddInHost object, through the namespace MediaCenterEnvironment.MediaExperience.MediaMetadata. It then sends this list on the Response object, where the mobile device will inspect and display the data, as shown above.
The last feature that the mobile remote application provides is the ability to select specific media to play based on a list of available media on the host. This functionality is provided for audio, video, and images:
Figure 10 - Music and Video list management
The mobile application requests the list of available media in a similar fashion to the Details screen implementation. The resulting list of files is then bound and displayed in a DataGrid. The Media Center add-in service can then be instructed to play individual songs or videos using the AddInHost's MediaCenterEnvironment.PlayMedia method.
Developing on the mobile platform introduces design challenges not found in Windows Forms applications due to the small amount of screen real estate available. Many typical form layouts found in Windows Forms applications won't work well on a mobile device's small screen. When developing for a mobile application, try to keep the user interface as simple as possible. Window containers and managers such as a tabbed control enable the developer to functionally divide an application into logical components. This alleviates the clutter created by having too many controls in a single window. Also try to keep your text and controls as simple and large as possible. This makes the application easier to view and manipulate, especially in outdoor or bright conditions.
Once complete, the remote application gives you a level of control simply not available on hardware-based remote controls. I really enjoyed working on this application because it gave me a chance to integrate a number of different technologies into a single implementation. Be sure to download the code and take the remote for a spin. For those not familiar with all of the components used in this article (Media Center add-in services, socket communication, installer and assembly signing, etc.), don't be intimidated. The Microsoft-provided SDK packages for both parts of the solution make creating your own add-in projects a snap. Plus, the technical challenges unique to this project have already been overcome! Feel free to modify my implementation, or reuse the included socket classes to create an add-in all your own. Finally, please post feedback or questions here or at my blog.
Matt Ivers is a software engineer at Chicago-based Clarity Consulting. He has extensive professional experience developing .NET solutions in both Visual C# .NET and VB.NET. Check him out at his blog or through the Clarity blog site, Clarity Blogs.
Windows Media Center SDK 5.0
Windows Mobile 5.0 Smartphone SDK
How to: Sign an Assembly using Visual Studio 2005
How to: Create a Windows Installer File for a Windows Media Center Add-in
Windows Media Center - SDK Overview
Windows Media Center - Understanding the Basics
Windows Media Center - Development Tools
Windows Media Center - AddIn example: "Time Travel"
Using an Asynchronous Server Socket
@Matt: Currently Express can't do Windows Mobile development.
Are you a student? That does open a few doors for you. hit the contact button at the top if you want to talk more about this.
I think maybe a few changes are needed to work with VS 2008. I slogged through to where I can get the C# template "Windows Media Center Application - Background". I got the Installer project set up, and it "installs" without errors. But that's about as far as I get.
From what I can tell, if I install the template project without modification, it should pop up a dialog "The background application did something." when I launch Media Center, but nothing happens. Is there a place I can view what addins MC thinks are registered? Can I debug this somehow? It's a pretty basic hurdle to get over, but MC addin development is not that common of a discussion topic.
Hi...I'm new to programming...
but I recieve the error "resx://WMCHookServer/WMCHookServer.Resources/_Default : Failure acquiring MCML markup from 'resx://WMCHookServer/WMCHookServer.Resources/_Default "...It seems like the image failed to load(I think) but...can you help me?
PS: I'm only 13 yrs old
I have Vista Ultimate and a Pocket PC
with CE 5
@Trent are you using the download we provided at the top and you are getting that error?
Yes...and i also have VS 2005 full version..I'm not using the express edition... I'm currently using the VB version too... is there another version of the software that I should download?
I am getting could not load file or assembly 'WMCServer' when I try to load Media Center after install. Using Visual Studio 2005, MS Vista Home Premium.
WMCServer and WMCCommon are included in the solution as references. Looks like it is failing in the Launch method at the first _server call. I added the code to initialize the event handlers as stated above; however, no dice. I also used WiX to build the install.
Any suggestions?
is there anther file i should download besides the one on the top of the page?
@Trent and @Jay did you install the Windows Media Center SDK?
Yes. I have the Media Center SDK
Pinging Matt on this.
Interesting article, but after creating the project (for Media Center, not for Mobile) there are warnings about references for this imports:
Imports Microsoft.MediaCenter.Hosting
Imports Microsoft.MediaCenter.UI
I have the SDK installed, what am I doing wrong?
Do you have Media Center on your dev computer? If no, copy the dll:s from the ehome dir on a Media Center computer.
The source code link does not work, can anyone help me find the c# source code for this?
THIS IS AN AWSOME ARTICLE!! ive been looking for some instructions on how to control media center in this way. This is the first in depth article ive seen thanks!!
@jay2008 looking into getting this resolved, thanks for telling me.
@miki, I know, I'm attempting to get in contact with the author.
The source code link still doesn't work.
What a shame the link is now dead.. yea if anyone has it please email me it!!!
deloford[at][hot]mail com
Thanks!
@tomdel working on getting tracking down the author, sadly this is an old article, processes have been put in place so this shouldn't happen to future articles.
Source code located, article updated with new link, emailed the people that requested it when found.
Sorry about that guys, processes are put in place to prevent this with future articles and I should have some time to go through and catch these issues in older articles as well. There are just a LOT of posts ...
hello... 1st of all.. i must mention that this is a great piece of work
instead of using the remote connection with media Center, , can we use it as a file manager /? ?
how can i run the basic commands like opening the Start menu and simple tasks using the same connection ?
@GaYan Silva, excellent question, you'd have to build out a server on the other end of the remote control to be able to do this. WCF would be an easy way to accomplish this task then just script stuff out.
@GaYan The article walks through how to do this. Creating an up-to-date example here is on my list of things to do but i have zero ETA on it.
@ Coding4Fun ! Thanks ! !
I tried to implement WCF .. ! wuh,,, too difficult
by the way when i try to compile the app ! i get this error
///////////////////////////////////////////////////////////////
Resx://wmcHookServer/wmcHookServer.resoures/_default': Failure acquiring MCML markup from 'resx://wmcHookServer/wmcHookServer.resoures/_default'.
////////////////////////////////////////////////////////////////
Any Ideas ? im suing windows vista and vs 2008 ! ..
Thanks in advance !
@ Coding4Fun, .. yeh,, Thanks ~ ! Ill try to do that, , but the problem occurs when we try to register the addin with the media center,, ,,
anyway .. ill see about it .. thanks ! if i get it working. ill post the code here !