C# Com Interop with Windows Media Player Visualisation (With Sample Code) -


i attempting create windows media player (wmp) visualization plugin in c#. quite new exposing c# com , may have missed basic. have persisted 3 days (about 20 hours) , not got past single issue describe below.

for don't know, wmp visualizations pretty images show in media player while listening music.

in nutshell: wmp call methods on c# com interface, not others.

i have wmp 11 installed

i downloaded latest windows sdk contains c++ plugin wizard compile working visualization sample. sample registers , works without issues in wmp.

the dev kit contains c++ header file named effects.h contains 2 interfaces must implemented plugin work wmp. doesn't appear more complicated that.

here are

midl_interface("d3984c13-c3cb-48e2-8be5-5168340b4f35") iwmpeffects : public iunknown { public:     virtual /* [helpstring][local] */ hresult stdmethodcalltype render(          /* [in] */ timedlevel *plevels,         /* [in] */ hdc hdc,         /* [in] */ rect *prc) = 0;      virtual /* [helpstring] */ hresult stdmethodcalltype mediainfo(          /* [in] */ long lchannelcount,         /* [in] */ long lsamplerate,         /* [in] */ bstr bstrtitle) = 0;      virtual /* [helpstring] */ hresult stdmethodcalltype getcapabilities(          /* [out] */ dword *pdwcapabilities) = 0;      virtual /* [helpstring] */ hresult stdmethodcalltype gettitle(          /* [out] */ bstr *bstrtitle) = 0;      virtual /* [helpstring] */ hresult stdmethodcalltype getpresettitle(          /* [in] */ long npreset,         /* [out] */ bstr *bstrpresettitle) = 0;      virtual /* [helpstring] */ hresult stdmethodcalltype getpresetcount(          /* [out] */ long *pnpresetcount) = 0;      virtual /* [helpstring] */ hresult stdmethodcalltype setcurrentpreset(          /* [in] */ long npreset) = 0;      virtual /* [helpstring] */ hresult stdmethodcalltype getcurrentpreset(          /* [out] */ long *pnpreset) = 0;      virtual /* [helpstring] */ hresult stdmethodcalltype displaypropertypage(          /* [in] */ hwnd hwndowner) = 0;      virtual /* [helpstring] */ hresult stdmethodcalltype gofullscreen(          /* [in] */ bool ffullscreen) = 0;      virtual /* [helpstring] */ hresult stdmethodcalltype renderfullscreen(          /* [in] */ timedlevel *plevels) = 0;  };  midl_interface("695386ec-aa3c-4618-a5e1-dd9a8b987632") iwmpeffects2 : public iwmpeffects { public:     virtual hresult stdmethodcalltype setcore(          /* [in] */ iwmpcore *pplayer) = 0;      virtual hresult stdmethodcalltype create(          /* [in] */ hwnd hwndparent) = 0;      virtual hresult stdmethodcalltype destroy( void) = 0;      virtual hresult stdmethodcalltype notifynewmedia(          /* [in] */ iwmpmedia *pmedia) = 0;      virtual hresult stdmethodcalltype onwindowmessage(          /* [in] */ uint msg,         /* [in] */ wparam wparam,         /* [in] */ lparam lparam,         /* [in] */ lresult *plresultparam) = 0;      virtual hresult stdmethodcalltype renderwindowed(          /* [in] */ timedlevel *pdata,         /* [in] */ bool frequiredrender) = 0;  }; 

as mentioned, com knowledge not best. did port c#.

i converted interfaces following

using system; using system.collections.generic; using system.linq; using system.text; using system.runtime.interopservices;  namespace wmptestplugin {      [comvisible(true)]     [interfacetype(cominterfacetype.interfaceisiunknown)]     [guid("d3984c13-c3cb-48e2-8be5-5168340b4f35")]     public interface iwmpeffects     {         int render(ref timedlevel plevels, intptr hdc, ref rect prc);         int mediainfo(int lchannelcount, int lsamplerate, string bstrtitle);         int getcapabilities(ref int pdwcapabilities);         int gettitle(ref string bstrtitle);         int getpresettitle([in] int npreset, [marshalas(unmanagedtype.bstr)] ref string bstrpresettitle);         int getpresetcount(ref int count);         int setcurrentpreset(int currentpreset);         int getcurrentpreset(ref int currentpreset);         int displaypropertypage(intptr hwndowner);         int gofullscreen(bool ffullscreen);         int renderfullscreen(ref timedlevel plevels);     }      [comvisible(true)]     [interfacetype(cominterfacetype.interfaceisiunknown)]     [guid("695386ec-aa3c-4618-a5e1-dd9a8b987632")]     public interface iwmpeffects2 : iwmpeffects     {         int setcore(intptr pplayer);         int create(intptr hwndparent);         int destroy();         int notifynewmedia(intptr pmedia);         int onwindowmessage(int msg, int wparam, int lparam, ref int plresultparam);         int renderwindowed(ref timedlevel pdata, bool frequiredrender);     }      [comvisible(true)]     [structlayout(layoutkind.sequential)]     public struct data     {         [marshalas(unmanagedtype.byvalarray, sizeconst = 0x400)]         public byte[] data0;         [marshalas(unmanagedtype.byvalarray, sizeconst = 0x400)]         public byte[] data1;     }      [comvisible(true)]     public enum playerstate     {         stop_state,         pause_state,         play_state     }      [comvisible(true)]     [structlayout(layoutkind.sequential)]     public struct timedlevel     {         public data frequency;         public data waveform;         public playerstate state;         public long timestamp;     }      [comvisible(true)]     [structlayout(layoutkind.sequential)]     public struct rect     {         public int left;         public int top;         public int right;         public int bottom;     } } 

the code class implementing interfaces follows

using system; using system.collections.generic; using system.linq; using system.text; using system.runtime.interopservices; using wmptestplugin; using system.io; using system.windows.forms;        [comvisible(true)]     [guid("c476ff24-5e5c-419d-9110-05ec2eed8511")]     //[progid("wmptestplugin.wmptest")]     [classinterface(classinterfacetype.none)]     public class testplugin : iwmpeffects2     {         [dllimport("user32.dll", entrypoint = "getclientrect")]         private static extern bool getclientrect(intptr windowhandle, ref intptr rectangle);          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);           public testplugin()         {             _parenthwnd = intptr.zero;             _preset = 0;             file.appendalltext("c:\\wmp.txt", string.format("{0} : construct{1}", datetime.now.tostring(), environment.newline));          }          ~testplugin()         {             file.appendalltext("c:\\wmp.txt", string.format("{0} : deconstruct{1}", datetime.now.tostring(), environment.newline));         }          #region iwmpeffects2 members          /// <summary>         /// set wmp core interface         /// </summary>         /// <param name="pplayer"></param>         /// <returns></returns>         public int setcore(intptr pplayer)         {             file.appendalltext("c:\\wmp.txt", string.format("{0} : setcore{1}", datetime.now.tostring(), environment.newline));              // release existing wmp core interfaces             //releasecore();              if (pplayer == intptr.zero)                 return s_ok;              _playercore = pplayer;              //connect events             return s_ok;         }          /// <summary>         /// invoked when visualization should initialized.         ///         /// if hwndparent != null, renderwindowed() called , visualization         /// should draw window specified hwndparent.         /// behavior when visualization hosted in window.         ///         /// if hwndparent == null, render() called , visualization         /// should draw dc passed render(). behavior when         /// visualization hosted windowless (like in skin example).         /// </summary>         /// <param name="hwndparent"></param>         /// <returns></returns>         public int create(intptr hwndparent)         {             file.appendalltext("c:\\wmp.txt", string.format("{0} : create{1}", datetime.now.tostring(), environment.newline));              _parenthwnd = hwndparent;             return s_ok;         }          /// <summary>         /// invoked when visualization should released.         /// resources allocated rendering should released.         /// </summary>         /// <returns></returns>         public int destroy()         {             file.appendalltext("c:\\wmp.txt", string.format("{0} : destroy{1}", datetime.now.tostring(), environment.newline));             _parenthwnd = intptr.zero;             return s_ok;         }          /// <summary>         /// invoked when new media stream begins playing.         /// visualization can inspect object properties (like name or artist)         /// might interesting visualization.         /// </summary>         /// <param name="pmedia"></param>         /// <returns></returns>         public int notifynewmedia(intptr pmedia)         {             file.appendalltext("c:\\wmp.txt", string.format("{0} : notifynewmedia{1}", datetime.now.tostring(), environment.newline));             return s_ok;         }          /// <summary>         /// window messages sent parent window.         /// </summary>         /// <param name="msg"></param>         /// <param name="wparam"></param>         /// <param name="lparam"></param>         /// <param name="plresultparam"></param>         /// <returns></returns>         public int onwindowmessage(int msg, int wparam, int lparam, ref int plresultparam)         {             file.appendalltext("c:\\wmp.txt", string.format("{0} : onwindowmessage{1}", datetime.now.tostring(), environment.newline));             // return s_ok if plugin has handled window message             // return s_false let defwindowproc handle 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 effect should render screen.         /// frequiredrender flag specifies if update required, otherwise         /// update optional. allows visualizations static (for example,         /// album art visualizations) render when parent window requires it,         /// instead of n times second dynamic visualizations.         /// </summary>         /// <param name="pdata"></param>         /// <param name="frequiredrender"></param>         /// <returns></returns>         public int renderwindowed(ref timedlevel pdata, bool frequiredrender)         {             file.appendalltext("c:\\wmp.txt", string.format("{0} : renderwindowed{1}", datetime.now.tostring(), environment.newline));             //windowed              // null parent window should not happen              if (_parenthwnd == intptr.zero)                 return e_unexpected;              //rect rect = new rect();              //testplugin.getclientrect(_parenthwnd, ref rect);              //do render//              return s_ok;         }          #endregion          #region iwmpeffects members          /// <summary>         /// called when effect should render 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)         {             file.appendalltext("c:\\wmp.txt", string.format("{0} : render{1}", datetime.now.tostring(), environment.newline));             //not windowed               //do render             return s_ok;         }          /// <summary>         /// everytime new media loaded, method called pass         /// number of channels (mono/stereo), sample rate of media, ,         /// title of 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)         {             file.appendalltext("c:\\wmp.txt", string.format("{0} : mediainfo{1}", datetime.now.tostring(), environment.newline));             return s_ok;         }          /// <summary>         /// returns capabilities of effect. flags can returned are:         /// effect_cangofullscreen  -- effect supports full-screen rendering         /// effect_haspropertypage  -- effect supports property page         /// </summary>         /// <param name="pdwcapabilities"></param>         /// <returns></returns>         public int getcapabilities(ref int pdwcapabilities)         {             file.appendalltext("c:\\wmp.txt", string.format("{0} : getcapabilities{1}", datetime.now.tostring(), environment.newline));             //no capabilities             pdwcapabilities = effect_haspropertypage;              return s_ok;         }          /// <summary>         /// invoked when host wants obtain title of effect         /// </summary>         /// <param name="bstrtitle"></param>         /// <returns></returns>         public int gettitle(ref string bstrtitle)         {             file.appendalltext("c:\\wmp.txt", string.format("{0} : gettitle{1}", datetime.now.tostring(), environment.newline));             bstrtitle = "test wmp c# plugin";             return s_ok;         }          /// <summary>         /// invoked when host wants obtain title of given preset         /// </summary>         /// <param name="npreset"></param>         /// <param name="bstrpresettitle"></param>         /// <returns></returns>         public int getpresettitle(int npreset, ref string bstrpresettitle)         {             file.appendalltext("c:\\wmp.txt", string.format("{0} : getpresettitle{1}", datetime.now.tostring(), environment.newline));             //bstrpresettitle = "default";             return s_ok;         }          /// <summary>         /// invoked when host wants obtain number of supported presets         /// </summary>         /// <param name="count"></param>         /// <returns></returns>         public int getpresetcount(ref int count)         {             file.appendalltext("c:\\wmp.txt", string.format("{0} : getpresetcount{1}", datetime.now.tostring(), environment.newline));             count = 1;             return s_ok;         }            /// <summary>         /// invoked when host wants obtain index of current preset         /// </summary>         /// <param name="currentpreset"></param>         /// <returns></returns>         public int setcurrentpreset(int currentpreset)         {             file.appendalltext("c:\\wmp.txt", string.format("{0} : setcurrentpreset{1}", datetime.now.tostring(), environment.newline));             _preset = currentpreset;             return s_ok;         }          /// <summary>         /// invoked when host wants obtain index of current preset         /// </summary>         /// <param name="currentpreset"></param>         /// <returns></returns>         public int getcurrentpreset(ref int currentpreset)         {             file.appendalltext("c:\\wmp.txt", string.format("{0} : getcurrentpreset{1}", datetime.now.tostring(), environment.newline));             currentpreset = _preset;             return s_ok;         }          /// <summary>         /// invoked when host wants display property page effect         /// </summary>         /// <param name="hwndowner"></param>         /// <returns></returns>         public int displaypropertypage(intptr hwndowner)         {             file.appendalltext("c:\\wmp.txt", string.format("{0} : displaypropertypage, owner={1}{2}", datetime.now.tostring(), hwndowner.tostring(), environment.newline));             messagebox.show("hello me!");             return s_ok;         }          public int gofullscreen(bool ffullscreen)         {             file.appendalltext("c:\\wmp.txt", string.format("{0} : gofullscreen{1}", datetime.now.tostring(), environment.newline));             return s_ok;         }          public int renderfullscreen(ref timedlevel plevels)         {             file.appendalltext("c:\\wmp.txt", string.format("{0} : renderfullscreen{1}", datetime.now.tostring(), environment.newline));             return s_ok;         }          #endregion          private intptr _parenthwnd;         private int _preset;          private intptr _playercore;      } 

as can see code pretty empty, nothing more stubs really. debugging simple job.

once compiled strong name can registered with:

regasm assemblyname.dll /tlb

then dropped in gac.

open regedit , add the following info:

under hkey_local_machine\software\microsoft\mediaplayer\objects\effects

new key: wmptestplugin

under new key add new string value: name: classid value: {c476ff24-5e5c-419d-9110-05ec2eed8511}

so have built plugin conforms interfaces, registered in gac , told media player it's there.

if open media player , right-click on visualization space menu appear. in menu our new plugin. when move mouse down new item wmp call getpresetcount on plugin (this log file). wmp supposed call getpresettitle never me.

if open tools\options menu bar , select plugins tab can select new plugin. if click properties wmp call getcapabilities displaypropertypage , message box plugin appear. wmp crashes. in c++ version finalconstruct() called on ccomcoclass interface - don't have , don't know is. think may lower level using??

i have tried many many things work including changing method declarations. please can @ , help. i've looked on web solution , found nothing.

thanks reading, nanook

after looking @ windows shell interop code discovered should have been using [comimport] , not [comvisible] interfaces. make signatures equal registered used [preservesig]. interface inheritence needed redeclaring base interface within parent.

i hope helps someone.

here working class

using system; using system.collections.generic; using system.linq; using system.text; using system.runtime.interopservices;  namespace wmptestplugin {     [comimport]     [interfacetype(cominterfacetype.interfaceisiunknown)]     [guid("695386ec-aa3c-4618-a5e1-dd9a8b987632")]     public interface iwmpeffects2 : iwmpeffects     {         [preservesig]         new int render(ref timedlevel plevels, intptr hdc, ref rect prc);         [preservesig]         new int mediainfo(int lchannelcount, int lsamplerate, string bstrtitle);         [preservesig]         new int getcapabilities(ref int pdwcapabilities);         [preservesig]         new int gettitle(ref string bstrtitle);         [preservesig]         new int getpresettitle(int npreset, ref string bstrpresettitle);         [preservesig]         new int getpresetcount(ref int count);         [preservesig]         new int setcurrentpreset(int currentpreset);         [preservesig]         new int getcurrentpreset(ref int currentpreset);         [preservesig]         new int displaypropertypage(intptr hwndowner);         [preservesig]         new int gofullscreen(bool ffullscreen);         [preservesig]         new int renderfullscreen(ref timedlevel plevels);          [preservesig]         int setcore(intptr pplayer);         [preservesig]         int create(intptr hwndparent);         [preservesig]         int destroy();         [preservesig]         int notifynewmedia(intptr pmedia);         [preservesig]         int onwindowmessage(int msg, int wparam, int lparam, ref int plresultparam);         [preservesig]         int renderwindowed(ref timedlevel pdata, bool frequiredrender);     }      [comimport]     [interfacetype(cominterfacetype.interfaceisiunknown)]     [guid("d3984c13-c3cb-48e2-8be5-5168340b4f35")]     public interface iwmpeffects     {         [preservesig]         int render(ref timedlevel plevels, intptr hdc, ref rect prc);         [preservesig]         int mediainfo(int lchannelcount, int lsamplerate, string bstrtitle);         [preservesig]         int getcapabilities(ref int pdwcapabilities);         [preservesig]         int gettitle(ref string bstrtitle);         [preservesig]         int getpresettitle(int npreset, ref string bstrpresettitle);         [preservesig]         int getpresetcount(ref int count);         [preservesig]         int setcurrentpreset(int currentpreset);         [preservesig]         int getcurrentpreset(ref int currentpreset);         [preservesig]         int displaypropertypage(intptr hwndowner);         [preservesig]         int gofullscreen(bool ffullscreen);         [preservesig]         int renderfullscreen(ref timedlevel plevels);     }       //[comvisible(true)]     [structlayout(layoutkind.sequential)]     public struct data     {         [marshalas(unmanagedtype.byvalarray, sizeconst = 0x400)]         public byte[] data0;         [marshalas(unmanagedtype.byvalarray, sizeconst = 0x400)]         public byte[] data1;     }      //[comvisible(true)]     public enum playerstate     {         stop_state,         pause_state,         play_state     }      //[comvisible(true)]     [structlayout(layoutkind.sequential)]     public struct timedlevel     {         public data frequency;         public data waveform;         public playerstate state;         public long timestamp;     }      //[comvisible(true)]     [structlayout(layoutkind.sequential)]     public struct rect     {         public int left;         public int top;         public int right;         public int bottom;         public int width { { return this.right - this.left; } }         public int height { { return this.bottom - this.top; } }     } } 

Comments

Popular posts from this blog

c++ - Convert big endian to little endian when reading from a binary file -

C#: Application without a window or taskbar item (background app) that can still use Console.WriteLine() -

unicode - Are email addresses allowed to contain non-alphanumeric characters? -