vlccontrol.cpp
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:28k
源码类别:

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * vlccontrol.cpp: ActiveX control for VLC
  3.  *****************************************************************************
  4.  * Copyright (C) 2005 the VideoLAN team
  5.  *
  6.  * Authors: Damien Fouilleul <Damien.Fouilleul@laposte.net>
  7.  *          Jean-Paul Saman <jpsaman@videolan.org>
  8.  *
  9.  * This program is free software; you can redistribute it and/or modify
  10.  * it under the terms of the GNU General Public License as published by
  11.  * the Free Software Foundation; either version 2 of the License, or
  12.  * (at your option) any later version.
  13.  *
  14.  * This program is distributed in the hope that it will be useful,
  15.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.  * GNU General Public License for more details.
  18.  *
  19.  * You should have received a copy of the GNU General Public License
  20.  * along with this program; if not, write to the Free Software
  21.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  22.  *****************************************************************************/
  23. #include "plugin.h"
  24. #include "vlccontrol.h"
  25. #include "utils.h"
  26. using namespace std;
  27. VLCControl::~VLCControl()
  28. {
  29.     if( _p_typeinfo )
  30.         _p_typeinfo->Release();
  31. };
  32. HRESULT VLCControl::getTypeInfo(void)
  33. {
  34.     HRESULT hr = NOERROR;
  35.     if( NULL == _p_typeinfo )
  36.     {
  37.         ITypeLib *p_typelib;
  38.         hr = _p_instance->getTypeLib(LOCALE_USER_DEFAULT, &p_typelib);
  39.         if( SUCCEEDED(hr) )
  40.         {
  41.             hr = p_typelib->GetTypeInfoOfGuid(IID_IVLCControl, &_p_typeinfo);
  42.             if( FAILED(hr) )
  43.             {
  44.                 _p_typeinfo = NULL;
  45.             }
  46.             p_typelib->Release();
  47.         }
  48.     }
  49.     return hr;
  50. };
  51. STDMETHODIMP VLCControl::GetTypeInfoCount(UINT* pctInfo)
  52. {
  53.     if( NULL == pctInfo )
  54.         return E_INVALIDARG;
  55.     if( SUCCEEDED(getTypeInfo()) )
  56.         *pctInfo = 1;
  57.     else
  58.         *pctInfo = 0;
  59.     return NOERROR;
  60. };
  61. STDMETHODIMP VLCControl::GetTypeInfo(UINT iTInfo, LCID lcid, LPTYPEINFO* ppTInfo)
  62. {
  63.     if( NULL == ppTInfo )
  64.         return E_INVALIDARG;
  65.     if( SUCCEEDED(getTypeInfo()) )
  66.     {
  67.         _p_typeinfo->AddRef();
  68.         *ppTInfo = _p_typeinfo;
  69.         return NOERROR;
  70.     }
  71.     *ppTInfo = NULL;
  72.     return E_NOTIMPL;
  73. };
  74. STDMETHODIMP VLCControl::GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames,
  75.         UINT cNames, LCID lcid, DISPID* rgDispID)
  76. {
  77.     if( SUCCEEDED(getTypeInfo()) )
  78.     {
  79.         return DispGetIDsOfNames(_p_typeinfo, rgszNames, cNames, rgDispID);
  80.     }
  81.     return E_NOTIMPL;
  82. };
  83. STDMETHODIMP VLCControl::Invoke(DISPID dispIdMember, REFIID riid,
  84.         LCID lcid, WORD wFlags, DISPPARAMS* pDispParams,
  85.         VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr)
  86. {
  87.     if( SUCCEEDED(getTypeInfo()) )
  88.     {
  89.         return DispInvoke(this, _p_typeinfo, dispIdMember, wFlags, pDispParams,
  90.                 pVarResult, pExcepInfo, puArgErr);
  91.     }
  92.     return E_NOTIMPL;
  93. };
  94. STDMETHODIMP VLCControl::get_Visible(VARIANT_BOOL *isVisible)
  95. {
  96.     if( NULL == isVisible )
  97.         return E_POINTER;
  98.     *isVisible = _p_instance->getVisible() ? VARIANT_TRUE : VARIANT_FALSE;
  99.     return NOERROR;
  100. };
  101. STDMETHODIMP VLCControl::put_Visible(VARIANT_BOOL isVisible)
  102. {
  103.     _p_instance->setVisible(isVisible != VARIANT_FALSE);
  104.     return NOERROR;
  105. };
  106. STDMETHODIMP VLCControl::play(void)
  107. {
  108.     libvlc_exception_t ex;
  109.     libvlc_exception_init(&ex);
  110.     _p_instance->playlist_play(&ex);
  111.     if( libvlc_exception_raised(&ex) )
  112.     {
  113.         _p_instance->setErrorInfo(IID_IVLCControl,
  114.             libvlc_exception_get_message(&ex));
  115.         libvlc_exception_clear(&ex);
  116.         return E_FAIL;
  117.     }
  118.     _p_instance->fireOnPlayEvent();
  119.     return NOERROR;
  120. };
  121. STDMETHODIMP VLCControl::pause(void)
  122. {
  123.     libvlc_media_player_t* p_md;
  124.     HRESULT result = _p_instance->getMD(&p_md);
  125.     if( SUCCEEDED(result) )
  126.     {
  127.         libvlc_exception_t ex;
  128.         libvlc_exception_init(&ex);
  129.         libvlc_media_player_pause(p_md, &ex);
  130.         if( libvlc_exception_raised(&ex) )
  131.         {
  132.             _p_instance->setErrorInfo(IID_IVLCControl,
  133.                 libvlc_exception_get_message(&ex));
  134.             libvlc_exception_clear(&ex);
  135.             return E_FAIL;
  136.         }
  137.         _p_instance->fireOnPauseEvent();
  138.         return NOERROR;
  139.     }
  140.     return result;
  141. };
  142. STDMETHODIMP VLCControl::stop(void)
  143. {
  144.     libvlc_media_player_t *p_md;
  145.     HRESULT result = _p_instance->getMD(&p_md);
  146.     if( SUCCEEDED(result) )
  147.     {
  148.         libvlc_exception_t ex;
  149.         libvlc_exception_init(&ex);
  150.         libvlc_media_player_stop(p_md, &ex);
  151.         if( libvlc_exception_raised(&ex) )
  152.         {
  153.             _p_instance->setErrorInfo(IID_IVLCControl,
  154.                 libvlc_exception_get_message(&ex));
  155.             libvlc_exception_clear(&ex);
  156.             return E_FAIL;
  157.         }
  158.         return NOERROR;
  159.     }
  160.     _p_instance->fireOnStopEvent();
  161.     return result;
  162. };
  163. STDMETHODIMP VLCControl::get_Playing(VARIANT_BOOL *isPlaying)
  164. {
  165.     if( NULL == isPlaying )
  166.         return E_POINTER;
  167.     libvlc_media_player_t *p_md;
  168.     HRESULT result = _p_instance->getMD(&p_md);
  169.     if( SUCCEEDED(result) )
  170.     {
  171.         *isPlaying = libvlc_media_player_is_playing(p_md, NULL) ?
  172.                      VARIANT_TRUE : VARIANT_FALSE;
  173.         return NOERROR;
  174.     }
  175.     *isPlaying = VARIANT_FALSE;
  176.     return result;
  177. };
  178. STDMETHODIMP VLCControl::get_Position(float *position)
  179. {
  180.     if( NULL == position )
  181.         return E_POINTER;
  182.     *position = 0.0f;
  183.     libvlc_media_player_t *p_md;
  184.     HRESULT result = _p_instance->getMD(&p_md);
  185.     if( SUCCEEDED(result) )
  186.     {
  187.         libvlc_exception_t ex;
  188.         libvlc_exception_init(&ex);
  189.         *position = libvlc_media_player_get_position(p_md, &ex);
  190.         if( ! libvlc_exception_raised(&ex) )
  191.         {
  192.             return NOERROR;
  193.         }
  194.         _p_instance->setErrorInfo(IID_IVLCControl,
  195.                      libvlc_exception_get_message(&ex));
  196.         libvlc_exception_clear(&ex);
  197.         return E_FAIL;
  198.     }
  199.     return result;
  200. };
  201. STDMETHODIMP VLCControl::put_Position(float position)
  202. {
  203.     libvlc_media_player_t *p_md;
  204.     HRESULT result = _p_instance->getMD(&p_md);
  205.     if( SUCCEEDED(result) )
  206.     {
  207.         libvlc_exception_t ex;
  208.         libvlc_exception_init(&ex);
  209.         libvlc_media_player_set_position(p_md, position, &ex);
  210.         if( ! libvlc_exception_raised(&ex) )
  211.         {
  212.             return NOERROR;
  213.         }
  214.         _p_instance->setErrorInfo(IID_IVLCControl,
  215.                      libvlc_exception_get_message(&ex));
  216.         libvlc_exception_clear(&ex);
  217.         return E_FAIL;
  218.     }
  219.     return result;
  220. };
  221. STDMETHODIMP VLCControl::get_Time(int *seconds)
  222. {
  223.     if( NULL == seconds )
  224.         return E_POINTER;
  225.     *seconds = 0;
  226.     libvlc_media_player_t *p_md;
  227.     HRESULT result = _p_instance->getMD(&p_md);
  228.     if( SUCCEEDED(result) )
  229.     {
  230.         libvlc_exception_t ex;
  231.         libvlc_exception_init(&ex);
  232.         *seconds = libvlc_media_player_get_time(p_md, &ex);
  233.         if( ! libvlc_exception_raised(&ex) )
  234.         {
  235.             return NOERROR;
  236.         }
  237.         _p_instance->setErrorInfo(IID_IVLCControl,
  238.                      libvlc_exception_get_message(&ex));
  239.         libvlc_exception_clear(&ex);
  240.         return E_FAIL;
  241.     }
  242.     return result;
  243. };
  244. STDMETHODIMP VLCControl::put_Time(int seconds)
  245. {
  246.     /* setTime function of the plugin sets the time. */
  247.     _p_instance->setTime(seconds);
  248.     return NOERROR;
  249. };
  250. STDMETHODIMP VLCControl::shuttle(int seconds)
  251. {
  252.     libvlc_media_player_t *p_md;
  253.     HRESULT result = _p_instance->getMD(&p_md);
  254.     if( SUCCEEDED(result) )
  255.     {
  256.         libvlc_exception_t ex;
  257.         libvlc_exception_init(&ex);
  258.         if( seconds < 0 ) seconds = 0;
  259.         libvlc_media_player_set_time(p_md, (int64_t)seconds, &ex);
  260.         if( ! libvlc_exception_raised(&ex) )
  261.         {
  262.             return NOERROR;
  263.         }
  264.         _p_instance->setErrorInfo(IID_IVLCControl,
  265.                      libvlc_exception_get_message(&ex));
  266.         libvlc_exception_clear(&ex);
  267.         return E_FAIL;
  268.     }
  269.     return result;
  270. };
  271. STDMETHODIMP VLCControl::fullscreen(void)
  272. {
  273.     libvlc_media_player_t *p_md;
  274.     HRESULT result = _p_instance->getMD(&p_md);
  275.     if( SUCCEEDED(result) )
  276.     {
  277.         if( libvlc_media_player_is_playing(p_md, NULL) )
  278.         {
  279.             libvlc_toggle_fullscreen(p_md, NULL);
  280.         }
  281.     }
  282.     return result;
  283. };
  284. STDMETHODIMP VLCControl::get_Length(int *seconds)
  285. {
  286.     if( NULL == seconds )
  287.         return E_POINTER;
  288.     *seconds = 0;
  289.     libvlc_media_player_t *p_md;
  290.     HRESULT result = _p_instance->getMD(&p_md);
  291.     if( SUCCEEDED(result) )
  292.     {
  293.         libvlc_exception_t ex;
  294.         libvlc_exception_init(&ex);
  295.         *seconds = (double)libvlc_media_player_get_length(p_md, &ex);
  296.         if( ! libvlc_exception_raised(&ex) )
  297.         {
  298.             return NOERROR;
  299.         }
  300.         _p_instance->setErrorInfo(IID_IVLCControl,
  301.                      libvlc_exception_get_message(&ex));
  302.         libvlc_exception_clear(&ex);
  303.         return E_FAIL;
  304.     }
  305.     return result;
  306. };
  307. STDMETHODIMP VLCControl::playFaster(void)
  308. {
  309.     int32_t rate = 2;
  310.     libvlc_media_player_t *p_md;
  311.     HRESULT result = _p_instance->getMD(&p_md);
  312.     if( SUCCEEDED(result) )
  313.     {
  314.         libvlc_exception_t ex;
  315.         libvlc_exception_init(&ex);
  316.         if( ! libvlc_exception_raised(&ex) )
  317.         {
  318.             libvlc_media_player_set_rate(p_md, rate, &ex);
  319.             if( ! libvlc_exception_raised(&ex) )
  320.             {
  321.                 return NOERROR;
  322.             }
  323.         }
  324.         _p_instance->setErrorInfo(IID_IVLCControl,
  325.                      libvlc_exception_get_message(&ex));
  326.         libvlc_exception_clear(&ex);
  327.         return E_FAIL;
  328.     }
  329.     return result;
  330. };
  331. STDMETHODIMP VLCControl::playSlower(void)
  332. {
  333.     float rate = 0.5;
  334.     libvlc_media_player_t *p_md;
  335.     HRESULT result = _p_instance->getMD(&p_md);
  336.     if( SUCCEEDED(result) )
  337.     {
  338.         libvlc_exception_t ex;
  339.         libvlc_exception_init(&ex);
  340.         libvlc_media_player_set_rate(p_md, rate, &ex);
  341.         if( ! libvlc_exception_raised(&ex) )
  342.         {
  343.             return NOERROR;
  344.         }
  345.         _p_instance->setErrorInfo(IID_IVLCControl,
  346.                      libvlc_exception_get_message(&ex));
  347.         libvlc_exception_clear(&ex);
  348.         return E_FAIL;
  349.     }
  350.     return result;
  351. };
  352. STDMETHODIMP VLCControl::get_Volume(int *volume)
  353. {
  354.     if( NULL == volume )
  355.         return E_POINTER;
  356.     *volume  = _p_instance->getVolume();
  357.     return NOERROR;
  358. };
  359. STDMETHODIMP VLCControl::put_Volume(int volume)
  360. {
  361.     _p_instance->setVolume(volume);
  362.     return NOERROR;
  363. };
  364. STDMETHODIMP VLCControl::toggleMute(void)
  365. {
  366.     libvlc_instance_t* p_libvlc;
  367.     HRESULT result = _p_instance->getVLC(&p_libvlc);
  368.     if( SUCCEEDED(result) )
  369.     {
  370.         libvlc_exception_t ex;
  371.         libvlc_exception_init(&ex);
  372.         libvlc_audio_toggle_mute(p_libvlc, &ex);
  373.         if( libvlc_exception_raised(&ex) )
  374.         {
  375.             _p_instance->setErrorInfo(IID_IVLCControl,
  376.                          libvlc_exception_get_message(&ex));
  377.             libvlc_exception_clear(&ex);
  378.             return E_FAIL;
  379.         }
  380.         return NOERROR;
  381.     }
  382.     return result;
  383. };
  384. STDMETHODIMP VLCControl::setVariable(BSTR name, VARIANT value)
  385. {
  386.     libvlc_instance_t* p_libvlc;
  387.     HRESULT result = _p_instance->getVLC(&p_libvlc);
  388.     if( SUCCEEDED(result) )
  389.     {
  390.         _p_instance->setErrorInfo(IID_IVLCControl,
  391.             "setVariable() is an unsafe interface to use. "
  392.             "It has been removed because of security implications." );
  393.     }
  394.     return E_FAIL;
  395. };
  396. STDMETHODIMP VLCControl::getVariable(BSTR name, VARIANT *value)
  397. {
  398.     libvlc_instance_t* p_libvlc;
  399.     HRESULT result = _p_instance->getVLC(&p_libvlc);
  400.     if( SUCCEEDED(result) )
  401.     {
  402.         _p_instance->setErrorInfo(IID_IVLCControl,
  403.             "getVariable() is an unsafe interface to use. "
  404.             "It has been removed because of security implications." );
  405.     }
  406.     return E_FAIL;
  407. };
  408. void VLCControl::FreeTargetOptions(char **cOptions, int cOptionCount)
  409. {
  410.     // clean up
  411.     if( NULL != cOptions )
  412.     {
  413.         for( int pos=0; pos<cOptionCount; ++pos )
  414.         {
  415.             char *cOption = cOptions[pos];
  416.             if( NULL != cOption )
  417.                 CoTaskMemFree(cOption);
  418.             else
  419.                 break;
  420.         }
  421.         CoTaskMemFree(cOptions);
  422.     }
  423. };
  424. static HRESULT parseStringOptions(int codePage, BSTR bstr, char*** cOptions, int *cOptionCount)
  425. {
  426.     HRESULT hr = E_INVALIDARG;
  427.     if( SysStringLen(bstr) > 0 )
  428.     {
  429.         hr = E_OUTOFMEMORY;
  430.         char *s = CStrFromBSTR(codePage, bstr);
  431.         char *val = s;
  432.         if( val )
  433.         {
  434.             long capacity = 16;
  435.             char **options = (char **)CoTaskMemAlloc(capacity*sizeof(char *));
  436.             if( options )
  437.             {
  438.                 int nOptions = 0;
  439.                 char *end = val + strlen(val);
  440.                 while( val < end )
  441.                 {
  442.                     // skip leading blanks
  443.                     while( (val < end)
  444.                         && ((*val == ' ' ) || (*val == 't')) )
  445.                         ++val;
  446.                     char *start = val;
  447.                     // skip till we get a blank character
  448.                     while( (val < end)
  449.                         && (*val != ' ' )
  450.                         && (*val != 't') )
  451.                     {
  452.                         char c = *(val++);
  453.                         if( (''' == c) || ('"' == c) )
  454.                         {
  455.                             // skip till end of string
  456.                             while( (val < end) && (*(val++) != c ) );
  457.                         }
  458.                     }
  459.                     if( val > start )
  460.                     {
  461.                         if( nOptions == capacity )
  462.                         {
  463.                             capacity += 16;
  464.                             char **moreOptions = (char **)CoTaskMemRealloc(options, capacity*sizeof(char*));
  465.                             if( ! moreOptions )
  466.                             {
  467.                                 /* failed to allocate more memory */
  468.                                 CoTaskMemFree(s);
  469.                                 /* return what we got so far */
  470.                                 *cOptionCount = nOptions;
  471.                                 *cOptions = options;
  472.                                 return NOERROR;
  473.                             }
  474.                             options = moreOptions;
  475.                         }
  476.                         *(val++) = '';
  477.                         options[nOptions] = (char *)CoTaskMemAlloc(val-start);
  478.                         if( options[nOptions] )
  479.                         {
  480.                             memcpy(options[nOptions], start, val-start);
  481.                             ++nOptions;
  482.                         }
  483.                         else
  484.                         {
  485.                             /* failed to allocate memory */
  486.                             CoTaskMemFree(s);
  487.                             /* return what we got so far */
  488.                             *cOptionCount = nOptions;
  489.                             *cOptions = options;
  490.                             return NOERROR;
  491.                         }
  492.                     }
  493.                     else
  494.                         // must be end of string
  495.                         break;
  496.                 }
  497.                 *cOptionCount = nOptions;
  498.                 *cOptions = options;
  499.                 hr = NOERROR;
  500.             }
  501.             CoTaskMemFree(s);
  502.         }
  503.     }
  504.     return hr;
  505. }
  506. HRESULT VLCControl::CreateTargetOptions(int codePage, VARIANT *options, char ***cOptions, int *cOptionCount)
  507. {
  508.     HRESULT hr = E_INVALIDARG;
  509.     if( VT_ERROR == V_VT(options) )
  510.     {
  511.         if( DISP_E_PARAMNOTFOUND == V_ERROR(options) )
  512.         {
  513.             // optional parameter not set
  514.             *cOptions = NULL;
  515.             *cOptionCount = 0;
  516.             return NOERROR;
  517.         }
  518.     }
  519.     else if( (VT_EMPTY == V_VT(options)) || (VT_NULL == V_VT(options)) )
  520.     {
  521.         // null parameter
  522.         *cOptions = NULL;
  523.         *cOptionCount = 0;
  524.         return NOERROR;
  525.     }
  526.     else if( VT_DISPATCH == V_VT(options) )
  527.     {
  528.         // if object is a collection, retrieve enumerator
  529.         VARIANT colEnum;
  530.         V_VT(&colEnum) = VT_UNKNOWN;
  531.         hr = GetObjectProperty(V_DISPATCH(options), DISPID_NEWENUM, colEnum);
  532.         if( SUCCEEDED(hr) )
  533.         {
  534.             IEnumVARIANT *enumVar;
  535.             hr = V_UNKNOWN(&colEnum)->QueryInterface(IID_IEnumVARIANT, (LPVOID *)&enumVar);
  536.             if( SUCCEEDED(hr) )
  537.             {
  538.                 long pos = 0;
  539.                 long capacity = 16;
  540.                 VARIANT option;
  541.                 *cOptions = (char **)CoTaskMemAlloc(capacity*sizeof(char *));
  542.                 if( NULL != *cOptions )
  543.                 {
  544.                     ZeroMemory(*cOptions, sizeof(char *)*capacity);
  545.                     while( SUCCEEDED(hr) && (S_OK == enumVar->Next(1, &option, NULL)) )
  546.                     {
  547.                         if( VT_BSTR == V_VT(&option) )
  548.                         {
  549.                             char *cOption = CStrFromBSTR(codePage, V_BSTR(&option));
  550.                             (*cOptions)[pos] = cOption;
  551.                             if( NULL != cOption )
  552.                             {
  553.                                 ++pos;
  554.                                 if( pos == capacity )
  555.                                 {
  556.                                     char **moreOptions = (char **)CoTaskMemRealloc(*cOptions, (capacity+16)*sizeof(char *));
  557.                                     if( NULL != moreOptions )
  558.                                     {
  559.                                         ZeroMemory(moreOptions+capacity, sizeof(char *)*16);
  560.                                         capacity += 16;
  561.                                         *cOptions = moreOptions;
  562.                                     }
  563.                                     else
  564.                                         hr = E_OUTOFMEMORY;
  565.                                 }
  566.                             }
  567.                             else
  568.                                 hr = ( SysStringLen(V_BSTR(&option)) > 0 ) ?
  569.                                     E_OUTOFMEMORY : E_INVALIDARG;
  570.                         }
  571.                         else
  572.                             hr = E_INVALIDARG;
  573.                         VariantClear(&option);
  574.                     }
  575.                     *cOptionCount = pos;
  576.                     if( FAILED(hr) )
  577.                     {
  578.                         // free already processed elements
  579.                         FreeTargetOptions(*cOptions, *cOptionCount);
  580.                     }
  581.                 }
  582.                 else
  583.                     hr = E_OUTOFMEMORY;
  584.                 enumVar->Release();
  585.             }
  586.         }
  587.         else
  588.         {
  589.             // coerce object into a string and parse it
  590.             VARIANT v_name;
  591.             VariantInit(&v_name);
  592.             hr = VariantChangeType(&v_name, options, 0, VT_BSTR);
  593.             if( SUCCEEDED(hr) )
  594.             {
  595.                 hr = parseStringOptions(codePage, V_BSTR(&v_name), cOptions, cOptionCount);
  596.                 VariantClear(&v_name);
  597.             }
  598.         }
  599.     }
  600.     else if( V_ISARRAY(options) )
  601.     {
  602.         // array parameter
  603.         SAFEARRAY *array = V_ISBYREF(options) ? *V_ARRAYREF(options) : V_ARRAY(options);
  604.         if( SafeArrayGetDim(array) != 1 )
  605.             return E_INVALIDARG;
  606.         long lBound = 0;
  607.         long uBound = 0;
  608.         SafeArrayGetLBound(array, 1, &lBound);
  609.         SafeArrayGetUBound(array, 1, &uBound);
  610.         // have we got any options
  611.         if( uBound >= lBound )
  612.         {
  613.             VARTYPE vType;
  614.             hr = SafeArrayGetVartype(array, &vType);
  615.             if( FAILED(hr) )
  616.                 return hr;
  617.             long pos;
  618.             // marshall options into an array of C strings
  619.             if( VT_VARIANT == vType )
  620.             {
  621.                 *cOptions = (char **)CoTaskMemAlloc(sizeof(char *)*(uBound-lBound+1));
  622.                 if( NULL == *cOptions )
  623.                     return E_OUTOFMEMORY;
  624.                 ZeroMemory(*cOptions, sizeof(char *)*(uBound-lBound+1));
  625.                 for(pos=lBound; (pos<=uBound) && SUCCEEDED(hr); ++pos )
  626.                 {
  627.                     VARIANT option;
  628.                     hr = SafeArrayGetElement(array, &pos, &option);
  629.                     if( SUCCEEDED(hr) )
  630.                     {
  631.                         if( VT_BSTR == V_VT(&option) )
  632.                         {
  633.                             char *cOption = CStrFromBSTR(codePage, V_BSTR(&option));
  634.                             (*cOptions)[pos-lBound] = cOption;
  635.                             if( NULL == cOption )
  636.                                 hr = ( SysStringLen(V_BSTR(&option)) > 0 ) ?
  637.                                     E_OUTOFMEMORY : E_INVALIDARG;
  638.                         }
  639.                         else
  640.                             hr = E_INVALIDARG;
  641.                         VariantClear(&option);
  642.                     }
  643.                 }
  644.             }
  645.             else if( VT_BSTR == vType )
  646.             {
  647.                 *cOptions = (char **)CoTaskMemAlloc(sizeof(char *)*(uBound-lBound+1));
  648.                 if( NULL == *cOptions )
  649.                     return E_OUTOFMEMORY;
  650.                 ZeroMemory(*cOptions, sizeof(char *)*(uBound-lBound+1));
  651.                 for(pos=lBound; (pos<=uBound) && SUCCEEDED(hr); ++pos )
  652.                 {
  653.                     BSTR option;
  654.                     hr = SafeArrayGetElement(array, &pos, &option);
  655.                     if( SUCCEEDED(hr) )
  656.                     {
  657.                         char *cOption = CStrFromBSTR(codePage, option);
  658.                         (*cOptions)[pos-lBound] = cOption;
  659.                         if( NULL == cOption )
  660.                             hr = ( SysStringLen(option) > 0 ) ?
  661.                                 E_OUTOFMEMORY : E_INVALIDARG;
  662.                         SysFreeString(option);
  663.                     }
  664.                 }
  665.             }
  666.             else
  667.             {
  668.                 // unsupported type
  669.                 return E_INVALIDARG;
  670.             }
  671.             *cOptionCount = pos-lBound;
  672.             if( FAILED(hr) )
  673.             {
  674.                 // free already processed elements
  675.                 FreeTargetOptions(*cOptions, *cOptionCount);
  676.             }
  677.         }
  678.         else
  679.         {
  680.             // empty array
  681.             *cOptions = NULL;
  682.             *cOptionCount = 0;
  683.             return NOERROR;
  684.         }
  685.     }
  686.     else if( VT_UNKNOWN == V_VT(options) )
  687.     {
  688.         // coerce object into a string and parse it
  689.         VARIANT v_name;
  690.         VariantInit(&v_name);
  691.         hr = VariantChangeType(&v_name, options, 0, VT_BSTR);
  692.         if( SUCCEEDED(hr) )
  693.         {
  694.             hr = parseStringOptions(codePage, V_BSTR(&v_name), cOptions, cOptionCount);
  695.             VariantClear(&v_name);
  696.         }
  697.     }
  698.     else if( VT_BSTR == V_VT(options) )
  699.     {
  700.         hr = parseStringOptions(codePage, V_BSTR(options), cOptions, cOptionCount);
  701.     }
  702.     return hr;
  703. };
  704. /*
  705. ** use VARIANT rather than a SAFEARRAY as argument type
  706. ** for compatibility with some scripting language (JScript)
  707. */
  708. STDMETHODIMP VLCControl::addTarget(BSTR uri, VARIANT options, enum VLCPlaylistMode mode, int position)
  709. {
  710.     if( 0 == SysStringLen(uri) )
  711.         return E_INVALIDARG;
  712.     libvlc_instance_t *p_libvlc;
  713.     HRESULT hr = _p_instance->getVLC(&p_libvlc);
  714.     if( SUCCEEDED(hr) )
  715.     {
  716.         char *cUri = CStrFromBSTR(CP_UTF8, uri);
  717.         if( NULL == cUri )
  718.             return E_OUTOFMEMORY;
  719.         int cOptionsCount;
  720.         char **cOptions;
  721.         if( FAILED(CreateTargetOptions(CP_UTF8, &options, &cOptions, &cOptionsCount)) )
  722.             return E_INVALIDARG;
  723.         libvlc_exception_t ex;
  724.         libvlc_exception_init(&ex);
  725.         position = _p_instance->playlist_add_extended_untrusted(cUri,
  726.                        cOptionsCount, const_cast<const char**>(cOptions), &ex);
  727.         FreeTargetOptions(cOptions, cOptionsCount);
  728.         CoTaskMemFree(cUri);
  729.         if( libvlc_exception_raised(&ex) )
  730.         {
  731.             _p_instance->setErrorInfo(IID_IVLCPlaylist,
  732.                 libvlc_exception_get_message(&ex));
  733.             libvlc_exception_clear(&ex);
  734.             if( mode & VLCPlayListAppendAndGo )
  735.                 _p_instance->fireOnStopEvent();
  736.             return E_FAIL;
  737.         }
  738.         if( mode & VLCPlayListAppendAndGo )
  739.             _p_instance->fireOnPlayEvent();
  740.         return NOERROR;
  741.     }
  742.     return hr;
  743. };
  744. STDMETHODIMP VLCControl::get_PlaylistIndex(int *index)
  745. {
  746.     if( NULL == index )
  747.         return E_POINTER;
  748.     *index = 0;
  749.     libvlc_instance_t *p_libvlc;
  750.     HRESULT result = _p_instance->getVLC(&p_libvlc);
  751.     if( SUCCEEDED(result) )
  752.     {
  753.         libvlc_exception_t ex;
  754.         libvlc_exception_init(&ex);
  755.         *index = _p_instance->playlist_get_current_index(&ex);
  756.         if( libvlc_exception_raised(&ex) )
  757.         {
  758.             _p_instance->setErrorInfo(IID_IVLCControl,
  759.                 libvlc_exception_get_message(&ex));
  760.             libvlc_exception_clear(&ex);
  761.             return E_FAIL;
  762.         }
  763.         return NOERROR;
  764.     }
  765.     return result;
  766. };
  767. STDMETHODIMP VLCControl::get_PlaylistCount(int *count)
  768. {
  769.     if( NULL == count )
  770.         return E_POINTER;
  771.     libvlc_exception_t ex;
  772.     libvlc_exception_init(&ex);
  773.     *count = _p_instance->playlist_count(&ex);
  774.     if( libvlc_exception_raised(&ex) )
  775.     {
  776.         _p_instance->setErrorInfo(IID_IVLCControl,
  777.             libvlc_exception_get_message(&ex));
  778.         libvlc_exception_clear(&ex);
  779.         return E_FAIL;
  780.     }
  781.     return NOERROR;
  782. };
  783. STDMETHODIMP VLCControl::playlistNext(void)
  784. {
  785.     libvlc_instance_t* p_libvlc;
  786.     HRESULT result = _p_instance->getVLC(&p_libvlc);
  787.     if( SUCCEEDED(result) )
  788.     {
  789.         libvlc_exception_t ex;
  790.         libvlc_exception_init(&ex);
  791.         _p_instance->playlist_next(&ex);
  792.         if( libvlc_exception_raised(&ex) )
  793.         {
  794.             _p_instance->setErrorInfo(IID_IVLCControl,
  795.                 libvlc_exception_get_message(&ex));
  796.             libvlc_exception_clear(&ex);
  797.             return E_FAIL;
  798.         }
  799.         return NOERROR;
  800.     }
  801.     return result;
  802. };
  803. STDMETHODIMP VLCControl::playlistPrev(void)
  804. {
  805.     libvlc_instance_t* p_libvlc;
  806.     HRESULT result = _p_instance->getVLC(&p_libvlc);
  807.     if( SUCCEEDED(result) )
  808.     {
  809.         libvlc_exception_t ex;
  810.         libvlc_exception_init(&ex);
  811.         _p_instance->playlist_prev(&ex);
  812.         if( libvlc_exception_raised(&ex) )
  813.         {
  814.             _p_instance->setErrorInfo(IID_IVLCControl,
  815.                 libvlc_exception_get_message(&ex));
  816.             libvlc_exception_clear(&ex);
  817.             return E_FAIL;
  818.         }
  819.         return NOERROR;
  820.     }
  821.     return result;
  822. };
  823. STDMETHODIMP VLCControl::playlistClear(void)
  824. {
  825.     libvlc_instance_t* p_libvlc;
  826.     HRESULT result = _p_instance->getVLC(&p_libvlc);
  827.     if( SUCCEEDED(result) )
  828.     {
  829.         libvlc_exception_t ex;
  830.         libvlc_exception_init(&ex);
  831.         _p_instance->playlist_clear(&ex);
  832.         if( libvlc_exception_raised(&ex) )
  833.         {
  834.             _p_instance->setErrorInfo(IID_IVLCControl,
  835.                 libvlc_exception_get_message(&ex));
  836.             libvlc_exception_clear(&ex);
  837.             return E_FAIL;
  838.         }
  839.         return NOERROR;
  840.     }
  841.     return result;
  842. };
  843. STDMETHODIMP VLCControl::get_VersionInfo(BSTR *version)
  844. {
  845.     if( NULL == version )
  846.         return E_POINTER;
  847.     const char *versionStr = libvlc_get_version();
  848.     if( NULL != versionStr )
  849.     {
  850.         *version = BSTRFromCStr(CP_UTF8, versionStr);
  851.         return (NULL == *version) ? E_OUTOFMEMORY : NOERROR;
  852.     }
  853.     *version = NULL;
  854.     return E_FAIL;
  855. };
  856. STDMETHODIMP VLCControl::get_MRL(BSTR *mrl)
  857. {
  858.     if( NULL == mrl )
  859.         return E_POINTER;
  860.     *mrl = SysAllocStringLen(_p_instance->getMRL(),
  861.                 SysStringLen(_p_instance->getMRL()));
  862.     return NOERROR;
  863. };
  864. STDMETHODIMP VLCControl::put_MRL(BSTR mrl)
  865. {
  866.     _p_instance->setMRL(mrl);
  867.     return S_OK;
  868. };
  869. STDMETHODIMP VLCControl::get_AutoPlay(VARIANT_BOOL *autoplay)
  870. {
  871.     if( NULL == autoplay )
  872.         return E_POINTER;
  873.     *autoplay = _p_instance->getAutoPlay() ? VARIANT_TRUE: VARIANT_FALSE;
  874.     return S_OK;
  875. };
  876. STDMETHODIMP VLCControl::put_AutoPlay(VARIANT_BOOL autoplay)
  877. {
  878.     _p_instance->setAutoPlay((VARIANT_FALSE != autoplay) ? TRUE: FALSE);
  879.     return S_OK;
  880. };
  881. STDMETHODIMP VLCControl::get_AutoLoop(VARIANT_BOOL *autoloop)
  882. {
  883.     if( NULL == autoloop )
  884.         return E_POINTER;
  885.     *autoloop = _p_instance->getAutoLoop() ? VARIANT_TRUE: VARIANT_FALSE;
  886.     return S_OK;
  887. };
  888. STDMETHODIMP VLCControl::put_AutoLoop(VARIANT_BOOL autoloop)
  889. {
  890.     _p_instance->setAutoLoop((VARIANT_FALSE != autoloop) ? TRUE: FALSE);
  891.     return S_OK;
  892. };