Click here to Skip to main content
15,881,882 members
Articles / Desktop Programming / MFC

Using screensavers inside the Windows Media Player

Rate me:
Please Sign up or sign in to vote.
4.94/5 (12 votes)
15 Jul 2011CPOL1 min read 107.8K   3.1K   53  
Wrapping a screensaver inside a WMP visualization plug-in.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.IO;
using System.Diagnostics;

namespace SheepWMP.NET
{

    [ComVisible(true)]
    [Guid("C476FF24-5E5C-419d-9110-05EC2EED8511")]    
    [ClassInterface(ClassInterfaceType.None)]
    public class SheepWMP : IWmpEffects2
    {
        private const int EFFECT_CANGOFULLSCREEN = 1;
        private const int EFFECT_HASPROPERTYPAGE = 2;

        private const int S_OK = 0;
        private const int S_FALSE = 1;
        private const int E_ABORT = unchecked((int)0x80004004);
        private const int E_ACCESSDENIED = unchecked((int)0x80070005);
        private const int E_FAIL = unchecked((int)0x80004005);
        private const int E_HANDLE = unchecked((int)0x80070006);
        private const int E_INVALIDARG = unchecked((int)0x80070057);
        private const int E_NOINTERFACE = unchecked((int)0x80004002);
        private const int E_NOTIMPL = unchecked((int)0x80004001);
        private const int E_OUTOFMEMORY = unchecked((int)0x8007000E);
        private const int E_POINTER = unchecked((int)0x80004003);
        private const int E_UNEXPECTED = unchecked((int)0x8000FFFF);


        private List<string> mScreenSavers     = new List<string>();
        private List<string> mScreenSaversDesc = new List<string>();

        public SheepWMP()
        {
            mParentWindow = IntPtr.Zero;
            mPreset = 0;

            string lSystemPath = Environment.GetFolderPath(Environment.SpecialFolder.System);
            Debug.Assert(string.IsNullOrEmpty(lSystemPath) == false);

            string[] lSystemScreenSavers = Directory.GetFiles(lSystemPath, "*.scr");
            ProcessScreenSavers(lSystemScreenSavers);


            string lWindowsPath = Environment.GetEnvironmentVariable("SystemRoot");
            Debug.Assert(string.IsNullOrEmpty(lWindowsPath) == false);

            string[] lWindowsScreenSavers = Directory.GetFiles(lWindowsPath, "*.scr");
            ProcessScreenSavers(lWindowsScreenSavers);
        }

        private void ProcessScreenSavers(string[] aSystemScreenSavers)
        {

            foreach (var lScr in aSystemScreenSavers)
            {
                FileVersionInfo lVersionInfo = FileVersionInfo.GetVersionInfo(lScr);
                if (string.IsNullOrEmpty(lVersionInfo.FileDescription))
                {
                    string lDisplayName = Path.GetFileNameWithoutExtension(lScr);
                    if (lDisplayName == "es")
                    {
                        lDisplayName = "Electric Sheep";
                    }
                    mScreenSaversDesc.Add(lDisplayName);
                }
                else
                {
                    mScreenSaversDesc.Add(lVersionInfo.FileDescription);
                }
                mScreenSavers.Add(lScr);
            }
            Debug.Assert(mScreenSavers.Count == mScreenSaversDesc.Count);
        }

        ~SheepWMP()
        {
        }

        #region IWmpEffects2 Members

        /// <summary>
        /// Set WMP core interface
        /// </summary>
        /// <param name="pPlayer"></param>
        /// <returns></returns>
        public int SetCore(IntPtr pPlayer)
        {

            // release any existing WMP core interfaces
            //ReleaseCore();

            if (pPlayer == IntPtr.Zero)
                return S_OK;

            mPlayerCore = pPlayer;

            //connect up any events
            return S_OK;
        }

        /// <summary>
        /// Invoked when the visualization should be initialized.
        ///
        /// If hwndParent != NULL, RenderWindowed() will be called and the visualization
        /// should draw into the window specified by hwndParent. This will be the
        /// behavior when the visualization is hosted in a window.
        ///
        /// If hwndParent == NULL, Render() will be called and the visualization
        /// should draw into the DC passed to Render(). This will be the behavior when
        /// the visualization is hosted windowless (like in a skin for example).
        /// </summary>
        /// <param name="hwndParent"></param>
        /// <returns></returns>
        public int Create(IntPtr hwndParent)
        {
            KillProcess();
            mParentWindow = hwndParent;
            return S_OK;
        }

        /// <summary>
        /// Invoked when the visualization should be released.
        /// Any resources allocated for rendering should be released.
        /// </summary>
        /// <returns></returns>
        public int Destroy()
        {
            KillProcess();
            mParentWindow = IntPtr.Zero;
            return S_OK;
        }

        /// <summary>
        /// Invoked when a new media stream begins playing.
        /// The visualization can inspect this object for properties (like name or artist)
        /// that might be interesting for visualization.
        /// </summary>
        /// <param name="pMedia"></param>
        /// <returns></returns>
        public int NotifyNewMedia(IntPtr pMedia)
        {
            return S_OK;
        }

        /// <summary>
        /// Window messages sent to the parent window.
        /// </summary>
        /// <param name="Msg"></param>
        /// <param name="WParam"></param>
        /// <param name="LParam"></param>ce
        /// <param name="plResultParam"></param>
        /// <returns></returns>
        public int OnWindowMessage(int Msg, int WParam, int LParam, ref int plResultParam)
        {
            // return S_OK only if the plugin has handled the window message
            // return S_FALSE to let the defWindowProc handle the message

            //if (_parentHwnd == IntPtr.Zero)
            //m_NonWindowedRenderer.OnWindowMessage(&m_RenderContext, msg, WParam, LParam, plResultParam);
            //else
            //    m_WindowedRenderer.OnWindowMessage(&m_RenderContext, msg, WParam, LParam, plResultParam);

            return S_FALSE;
        }

        /// <summary>
        /// Called when an effect should render itself to the screen.
        /// The fRequiredRender flag specifies if an update is required, otherwise the
        /// update is optional. This allows visualizations that are fairly static (for example,
        /// album art visualizations) to only render when the parent window requires it,
        /// instead of n times a second for dynamic visualizations.
        /// </summary>
        /// <param name="pData"></param>
        /// <param name="fRequiredRender"></param>
        /// <returns></returns>
        public int RenderWindowed(ref TimedLevel pData, bool fRequiredRender)
        {
            //windowed

            // NULL parent window should not happen 
            if (mParentWindow == IntPtr.Zero)
                return E_UNEXPECTED;

            KillProcess();
            StartProcess();
            MoveWindow();

            return S_OK;
        }

        private void MoveWindow()
        {
            if (mProcess != null)
            {
                RECT lRect = new RECT();
                Win32.GetClientRect(mParentWindow, out lRect);

                IntPtr lWnd = IntPtr.Zero;
                for (IntPtr lChild = Win32.GetWindow(mParentWindow, Win32.GetWindowCmd.GW_CHILD); lChild != IntPtr.Zero; lChild = Win32.GetWindow(lChild, Win32.GetWindowCmd.GW_HWNDNEXT))
                {
                    uint lPID = 0;
                    Win32.GetWindowThreadProcessId(lChild, out lPID);
                    if (mProcess.Id == lPID)
                    {
                        lWnd = lChild;
                        break;
                    }
                }

                if (lWnd != IntPtr.Zero)
                {
                    Win32.SetWindowPos(lWnd, IntPtr.Zero, lRect.Left, lRect.Top, lRect.Right - lRect.Left, lRect.Bottom - lRect.Top, Win32.SWP_SHOWWINDOW);
                }
            }
        }

        private void StartProcess()
        {
            if (mProcess == null)
            {
                ProcessStartInfo lStartInfo = new ProcessStartInfo(mScreenSavers[mPreset], "/p " + mParentWindow.ToInt64().ToString());
                lStartInfo.UseShellExecute = false;
                mProcess = Process.Start(lStartInfo);
            }
        }

        private void KillProcess()
        {
            if (mProcess != null )
            {
                if (mProcess.StartInfo.FileName.Contains(mScreenSavers[mPreset]) == false)
                {
                    try
                    {
                        if (mProcess.HasExited == false)
                            mProcess.Kill();
                    }
                    catch (Exception)
                    {
                    }
                    mProcess = null;
                }
            }
        }

        #endregion

        #region IWmpEffects Members

        /// <summary>
        /// Called when an effect should render itself to the screen.
        /// </summary>
        /// <param name="pLevels"></param>
        /// <param name="Hdc"></param>
        /// <param name="pRC"></param>
        /// <returns></returns>
        public int Render(ref TimedLevel pLevels, IntPtr Hdc, ref RECT pRC)
        {
            //not windowed


            //do render
            return S_OK;
        }

        /// <summary>
        /// Everytime new media is loaded, this method is called to pass the
        /// number of channels (mono/stereo), the sample rate of the media, and the
        /// title of the media
        /// </summary>
        /// <param name="lChannelCount"></param>
        /// <param name="lSampleRate"></param>
        /// <param name="bstrTitle"></param>
        /// <returns></returns>
        public int MediaInfo(int lChannelCount, int lSampleRate, string bstrTitle)
        {
            return S_OK;
        }

        /// <summary>
        /// Returns the capabilities of this effect. Flags that can be returned are:
        /// EFFECT_CANGOFULLSCREEN  -- effect supports full-screen rendering
        /// EFFECT_HASPROPERTYPAGE  -- effect supports a property page
        /// </summary>
        /// <param name="pdwCapabilities"></param>
        /// <returns></returns>
        public int GetCapabilities(ref int pdwCapabilities)
        {
            //no capabilities
            pdwCapabilities = 0;

            return S_OK;
        }

        /// <summary>
        /// Invoked when a host wants to obtain the title of the effect
        /// </summary>
        /// <param name="bstrTitle"></param>
        /// <returns></returns>
        public int GetTitle(ref string bstrTitle)
        {
            bstrTitle = "Test Wmp C# Plugin";
            return S_OK;
        }

        /// <summary>
        /// Invoked when a host wants to obtain the title of the given preset
        /// </summary>
        /// <param name="nPreset"></param>
        /// <param name="bstrPresetTitle"></param>
        /// <returns></returns>
        public int GetPresetTitle(int nPreset, ref string bstrPresetTitle)
        {
            bstrPresetTitle = mScreenSaversDesc[nPreset];
            return S_OK;
        }

        /// <summary>
        /// Invoked when a host wants to obtain the number of supported presets
        /// </summary>
        /// <param name="count"></param>
        /// <returns></returns>
        public int GetPresetCount(ref int count)
        {
            count = mScreenSavers.Count;
            return S_OK;
        }



        /// <summary>
        /// Invoked when a host wants to obtain the index of the current preset
        /// </summary>
        /// <param name="currentpreset"></param>
        /// <returns></returns>
        public int SetCurrentPreset(int currentpreset)
        {
            KillProcess();
            mPreset = currentpreset;
            return S_OK;
        }

        /// <summary>
        /// Invoked when a host wants to obtain the index of the current preset
        /// </summary>
        /// <param name="currentpreset"></param>
        /// <returns></returns>
        public int GetCurrentPreset(ref int currentpreset)
        {
            currentpreset = mPreset;
            return S_OK;
        }

        /// <summary>
        /// Invoked when a host wants to display the property page for the effect
        /// </summary>
        /// <param name="hwndOwner"></param>
        /// <returns></returns>
        public int DisplayPropertyPage(IntPtr hwndOwner)
        {
            return S_OK;
        }

        public int GoFullScreen(bool fFullscreen)
        {
            return S_OK;
        }

        public int RenderFullScreen(ref TimedLevel pLevels)
        {
            return S_OK;
        }

        #endregion

        private IntPtr mParentWindow;
        private int mPreset;
        private IntPtr mPlayerCore;
        private Process mProcess = null;

    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

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


Written By
Web Developer
Australia Australia
Developing windows applications for over 15 years now starting on Win 3.1 with Object Oriented Pascal, progressed to C++ and OWL, in 1996 switch to MFC and never looked back, now focusing on .NET/Mono.

Comments and Discussions