]> git.sesse.net Git - vlc/blobdiff - activex/vlccontrol.cpp
Removes trailing spaces. Removes tabs.
[vlc] / activex / vlccontrol.cpp
index 89320207a7d382297d93ae3a1fd415f7ee7a0c12..d9793bf30a87f384bcbe5b56d4aebd6305b1a953 100644 (file)
@@ -1,7 +1,7 @@
 /*****************************************************************************
  * vlccontrol.cpp: ActiveX control for VLC
  *****************************************************************************
- * Copyright (C) 2005 VideoLAN
+ * Copyright (C) 2005 the VideoLAN team
  *
  * Authors: Damien Fouilleul <Damien.Fouilleul@laposte.net>
  *
@@ -17,7 +17,7 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  *****************************************************************************/
 
 #include "plugin.h"
@@ -40,7 +40,7 @@ HRESULT VLCControl::getTypeInfo(void)
     {
         ITypeLib *p_typelib;
 
-        HRESULT hr = _p_instance->getTypeLib(LOCALE_USER_DEFAULT, &p_typelib);
+        hr = _p_instance->getTypeLib(LOCALE_USER_DEFAULT, &p_typelib);
         if( SUCCEEDED(hr) )
         {
             hr = p_typelib->GetTypeInfoOfGuid(IID_IVLCControl, &_p_typeinfo);
@@ -76,13 +76,13 @@ STDMETHODIMP VLCControl::GetTypeInfo(UINT iTInfo, LCID lcid, LPTYPEINFO* ppTInfo
     {
         _p_typeinfo->AddRef();
         *ppTInfo = _p_typeinfo;
-        return NO_ERROR;
+        return NOERROR;
     }
     *ppTInfo = NULL;
     return E_NOTIMPL;
 };
 
-STDMETHODIMP VLCControl::GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, 
+STDMETHODIMP VLCControl::GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames,
         UINT cNames, LCID lcid, DISPID* rgDispID)
 {
     if( SUCCEEDED(getTypeInfo()) )
@@ -113,7 +113,7 @@ STDMETHODIMP VLCControl::get_Visible(VARIANT_BOOL *isVisible)
 
     return NOERROR;
 };
-        
+
 STDMETHODIMP VLCControl::put_Visible(VARIANT_BOOL isVisible)
 {
     _p_instance->setVisible(isVisible != VARIANT_FALSE);
@@ -123,307 +123,359 @@ STDMETHODIMP VLCControl::put_Visible(VARIANT_BOOL isVisible)
 
 STDMETHODIMP VLCControl::play(void)
 {
-    int i_vlc = _p_instance->getVLCObject();
-    if( i_vlc )
+    int i_vlc;
+    HRESULT result = _p_instance->getVLCObject(&i_vlc);
+    if( SUCCEEDED(result) )
     {
         VLC_Play(i_vlc);
         _p_instance->fireOnPlayEvent();
-        return NOERROR;
     }
-    return E_UNEXPECTED;
+    return result;
 };
+
 STDMETHODIMP VLCControl::pause(void)
 {
-    int i_vlc = _p_instance->getVLCObject();
-    if( i_vlc )
+    int i_vlc;
+    HRESULT result = _p_instance->getVLCObject(&i_vlc);
+    if( SUCCEEDED(result) )
     {
         VLC_Pause(i_vlc);
         _p_instance->fireOnPauseEvent();
-        return NOERROR;
     }
-    return E_UNEXPECTED;
+    return result;
 };
-        
+
 STDMETHODIMP VLCControl::stop(void)
 {
-    int i_vlc = _p_instance->getVLCObject();
-    if( i_vlc )
+    int i_vlc;
+    HRESULT result = _p_instance->getVLCObject(&i_vlc);
+    if( SUCCEEDED(result) )
     {
         VLC_Stop(i_vlc);
         _p_instance->fireOnStopEvent();
-        return NOERROR;
     }
-    return E_UNEXPECTED;
-}
-        
+    return result;
+};
+
 STDMETHODIMP VLCControl::get_Playing(VARIANT_BOOL *isPlaying)
 {
     if( NULL == isPlaying )
         return E_POINTER;
 
-    int i_vlc = _p_instance->getVLCObject();
-    if( i_vlc )
-    {
-        *isPlaying = VLC_IsPlaying(i_vlc) ? VARIANT_TRUE : VARIANT_FALSE;
-        return NOERROR;
-    }
-    *isPlaying = VARIANT_FALSE;
-    return E_UNEXPECTED;
-};
-        
-STDMETHODIMP VLCControl::put_Playing(VARIANT_BOOL isPlaying)
-{
-    int i_vlc = _p_instance->getVLCObject();
-    if( i_vlc )
+    HRESULT result = NOERROR;
+    if( _p_instance->isRunning() )
     {
-        if( VARIANT_FALSE == isPlaying )
-        {
-            if( VLC_IsPlaying(i_vlc) )
-                VLC_Stop(i_vlc);
-        }
-        else
+        int i_vlc;
+        result = _p_instance->getVLCObject(&i_vlc);
+        if( SUCCEEDED(result) )
         {
-            if( ! VLC_IsPlaying(i_vlc) )
-                VLC_Play(i_vlc);
+            *isPlaying = VLC_IsPlaying(i_vlc) ? VARIANT_TRUE : VARIANT_FALSE;
+            return NOERROR;
         }
-        return NOERROR;
     }
-    return E_UNEXPECTED;
+    *isPlaying = VARIANT_FALSE;
+    return result;
 };
-        
+
 STDMETHODIMP VLCControl::get_Position(float *position)
 {
     if( NULL == position )
         return E_POINTER;
 
-    int i_vlc = _p_instance->getVLCObject();
-    if( i_vlc )
+    HRESULT result = E_UNEXPECTED;
+    if( _p_instance->isRunning() )
     {
-        *position = VLC_PositionGet(i_vlc);
-        return NOERROR;
+        int i_vlc;
+        result = _p_instance->getVLCObject(&i_vlc);
+        if( SUCCEEDED(result) )
+        {
+            *position = VLC_PositionGet(i_vlc);
+            return NOERROR;
+        }
     }
     *position = 0.0f;
-    return E_UNEXPECTED;
+    return result;
 };
-        
+
 STDMETHODIMP VLCControl::put_Position(float position)
 {
-    int i_vlc = _p_instance->getVLCObject();
-    if( i_vlc )
+    HRESULT result = E_UNEXPECTED;
+    if( _p_instance->isRunning() )
     {
-        VLC_PositionSet(i_vlc, position);
-        return NOERROR;
+        int i_vlc;
+        result = _p_instance->getVLCObject(&i_vlc);
+        if( SUCCEEDED(result) )
+        {
+            VLC_PositionSet(i_vlc, position);
+        }
     }
-    return E_UNEXPECTED;
+    return result;
 };
-        
+
 STDMETHODIMP VLCControl::get_Time(int *seconds)
 {
     if( NULL == seconds )
         return E_POINTER;
 
-    int i_vlc = _p_instance->getVLCObject();
-    if( i_vlc )
+    HRESULT result = NOERROR;
+    if( _p_instance->isRunning() )
     {
-        *seconds = VLC_TimeGet(i_vlc);
-        return NOERROR;
+        int i_vlc;
+        result = _p_instance->getVLCObject(&i_vlc);
+        if( SUCCEEDED(result) )
+        {
+            *seconds = VLC_TimeGet(i_vlc);
+        }
     }
-    *seconds = 0;
-    return E_UNEXPECTED;
+    else
+        *seconds = _p_instance->getTime();
+
+    return result;
 };
-        
+
 STDMETHODIMP VLCControl::put_Time(int seconds)
 {
-    int i_vlc = _p_instance->getVLCObject();
-    if( i_vlc )
-    {
-        VLC_TimeSet(i_vlc, seconds, VLC_FALSE);
-        return NOERROR;
-    }
-    return E_UNEXPECTED;
+    _p_instance->setTime(seconds);
+
+    return NOERROR;
 };
-        
+
 STDMETHODIMP VLCControl::shuttle(int seconds)
 {
-    int i_vlc = _p_instance->getVLCObject();
-    if( i_vlc )
+    HRESULT result = E_UNEXPECTED;
+    if( _p_instance->isRunning() )
     {
-        VLC_TimeSet(i_vlc, seconds, VLC_TRUE);
-        return NOERROR;
+        int i_vlc;
+        result = _p_instance->getVLCObject(&i_vlc);
+        if( SUCCEEDED(result) )
+        {
+            VLC_TimeSet(i_vlc, seconds, VLC_TRUE);
+        }
     }
-    return E_UNEXPECTED;
+    return result;
 };
-        
+
 STDMETHODIMP VLCControl::fullscreen(void)
 {
-    int i_vlc = _p_instance->getVLCObject();
-    if( i_vlc )
+    HRESULT result = E_UNEXPECTED;
+    if( _p_instance->isRunning() )
     {
-        VLC_FullScreen(i_vlc);
-        return NOERROR;
+        int i_vlc;
+        result = _p_instance->getVLCObject(&i_vlc);
+        if( SUCCEEDED(result) )
+        {
+            VLC_FullScreen(i_vlc);
+        }
     }
-    return E_UNEXPECTED;
+    return result;
 };
-        
+
 STDMETHODIMP VLCControl::get_Length(int *seconds)
 {
     if( NULL == seconds )
         return E_POINTER;
 
-    int i_vlc = _p_instance->getVLCObject();
-    if( i_vlc )
+    HRESULT result = NOERROR;
+    if( _p_instance->isRunning() )
     {
-        *seconds = VLC_LengthGet(i_vlc);
-        return NOERROR;
+        int i_vlc;
+        result = _p_instance->getVLCObject(&i_vlc);
+        if( SUCCEEDED(result) )
+        {
+            *seconds = VLC_LengthGet(i_vlc);
+            return NOERROR;
+        }
     }
     *seconds = 0;
-    return E_UNEXPECTED;
+    return result;
 };
-        
+
 STDMETHODIMP VLCControl::playFaster(void)
 {
-    int i_vlc = _p_instance->getVLCObject();
-    if( i_vlc )
+    HRESULT result = E_UNEXPECTED;
+    if( _p_instance->isRunning() )
     {
-        VLC_SpeedFaster(i_vlc);
-        return NOERROR;
+        int i_vlc;
+        result = _p_instance->getVLCObject(&i_vlc);
+        if( SUCCEEDED(result) )
+        {
+            VLC_SpeedFaster(i_vlc);
+        }
     }
-    return E_UNEXPECTED;
+    return result;
 };
-        
+
 STDMETHODIMP VLCControl::playSlower(void)
 {
-    int i_vlc = _p_instance->getVLCObject();
-    if( i_vlc )
+    HRESULT result = E_UNEXPECTED;
+    if( _p_instance->isRunning() )
     {
-        VLC_SpeedSlower(i_vlc);
-        return NOERROR;
+        int i_vlc;
+        result = _p_instance->getVLCObject(&i_vlc);
+        if( SUCCEEDED(result) )
+        {
+            VLC_SpeedSlower(i_vlc);
+        }
     }
-    return E_UNEXPECTED;
+    return result;
 };
-        
+
 STDMETHODIMP VLCControl::get_Volume(int *volume)
 {
     if( NULL == volume )
         return E_POINTER;
 
-    int i_vlc = _p_instance->getVLCObject();
-    if( i_vlc )
-    {
-        *volume  = VLC_VolumeGet(i_vlc);
-        return NOERROR;
-    }
-    *volume = 0;
-    return E_UNEXPECTED;
+    *volume  = _p_instance->getVolume();
+    return NOERROR;
 };
-        
+
 STDMETHODIMP VLCControl::put_Volume(int volume)
 {
-    int i_vlc = _p_instance->getVLCObject();
-    if( i_vlc )
-    {
-        VLC_VolumeSet(i_vlc, volume);
-        return NOERROR;
-    }
-    return E_UNEXPECTED;
+    _p_instance->setVolume(volume);
+    return NOERROR;
 };
-        
+
 STDMETHODIMP VLCControl::toggleMute(void)
 {
-    int i_vlc = _p_instance->getVLCObject();
-    if( i_vlc )
+    int i_vlc;
+    HRESULT result = _p_instance->getVLCObject(&i_vlc);
+    if( SUCCEEDED(result) )
     {
         VLC_VolumeMute(i_vlc);
-        return NOERROR;
     }
-    return E_UNEXPECTED;
+    return result;
 };
 
-STDMETHODIMP VLCControl::setVariable( BSTR name, VARIANT value)
+STDMETHODIMP VLCControl::setVariable(BSTR name, VARIANT value)
 {
     if( 0 == SysStringLen(name) )
         return E_INVALIDARG;
 
-    int i_vlc = _p_instance->getVLCObject();
-    if( i_vlc )
+    int i_vlc;
+    HRESULT hr = _p_instance->getVLCObject(&i_vlc);
+    if( SUCCEEDED(hr) )
     {
         int codePage = _p_instance->getCodePage();
         char *psz_varname = CStrFromBSTR(codePage, name);
         if( NULL == psz_varname )
             return E_OUTOFMEMORY;
 
-        HRESULT hr = E_INVALIDARG;
         int i_type;
+        vlc_value_t val;
+
         if( VLC_SUCCESS == VLC_VariableType(i_vlc, psz_varname, &i_type) )
         {
             VARIANT arg;
             VariantInit(&arg);
 
-            vlc_value_t val;
-
-            hr = DISP_E_TYPEMISMATCH;
-
             switch( i_type )
             {
                 case VLC_VAR_BOOL:
-                    hr = VariantChangeType(&value, &arg, 0, VT_BOOL);
+                    hr = VariantChangeType(&arg, &value, 0, VT_BOOL);
                     if( SUCCEEDED(hr) )
                         val.b_bool = (VARIANT_TRUE == V_BOOL(&arg)) ? VLC_TRUE : VLC_FALSE;
                     break;
 
                 case VLC_VAR_INTEGER:
-                    hr = VariantChangeType(&value, &arg, 0, VT_I4);
+                case VLC_VAR_HOTKEY:
+                    hr = VariantChangeType(&arg, &value, 0, VT_I4);
                     if( SUCCEEDED(hr) )
                         val.i_int = V_I4(&arg);
                     break;
 
                 case VLC_VAR_FLOAT:
-                    hr = VariantChangeType(&value, &arg, 0, VT_R4);
+                    hr = VariantChangeType(&arg, &value, 0, VT_R4);
                     if( SUCCEEDED(hr) )
                         val.f_float = V_R4(&arg);
                     break;
 
                 case VLC_VAR_STRING:
-                    hr = VariantChangeType(&value, &arg, 0, VT_BSTR);
+                case VLC_VAR_MODULE:
+                case VLC_VAR_FILE:
+                case VLC_VAR_DIRECTORY:
+                case VLC_VAR_VARIABLE:
+                    hr = VariantChangeType(&arg, &value, 0, VT_BSTR);
                     if( SUCCEEDED(hr) )
+                    {
+                        i_type = VLC_VAR_STRING;
                         val.psz_string = CStrFromBSTR(codePage, V_BSTR(&arg));
+                        VariantClear(&arg);
+                    }
                     break;
-            }
-            if( SUCCEEDED(hr) )
-            {
-                VariantClear(&arg);
 
-                hr = (VLC_SUCCESS == VLC_VariableSet(i_vlc, psz_varname, val)) ? NOERROR : E_FAIL;
+                case VLC_VAR_TIME:
+                    // use a double value to represent time (base is expressed in seconds)
+                    hr = VariantChangeType(&arg, &value, 0, VT_R8);
+                    if( SUCCEEDED(hr) )
+                        val.i_time = (signed __int64)(V_R8(&arg)*1000000.0);
+                    break;
 
-                if( (VLC_VAR_STRING == i_type) && (NULL != val.psz_string) )
-                    free(val.psz_string);
+                default:
+                    hr = DISP_E_TYPEMISMATCH;
             }
         }
-        free(psz_varname);
+        else {
+            // no defined type, use type in VARIANT
+            hr = NO_ERROR;
+            switch( V_VT(&value) )
+            {
+                case VT_BOOL:
+                    val.b_bool = (VARIANT_TRUE == V_BOOL(&value)) ? VLC_TRUE : VLC_FALSE;
+                    i_type = VLC_VAR_BOOL;
+                    break;
+                case VT_I4:
+                    val.i_int = V_I4(&value);
+                    i_type = VLC_VAR_INTEGER;
+                    break;
+                case VT_R4:
+                    val.f_float = V_R4(&value);
+                    i_type = VLC_VAR_FLOAT;
+                    break;
+                case VT_BSTR:
+                    val.psz_string = CStrFromBSTR(codePage, V_BSTR(&value));
+                    i_type = VLC_VAR_STRING;
+                    break;
+                case VT_R8:
+                    // use a double value to represent time (base is expressed in seconds)
+                    val.i_time = (signed __int64)(V_R8(&value)*1000000.0);
+                    i_type = VLC_VAR_TIME;
+                    break;
+                default:
+                    hr = DISP_E_TYPEMISMATCH;
+            }
+        }
+        if( SUCCEEDED(hr) )
+        {
+            hr = (VLC_SUCCESS == VLC_VariableSet(i_vlc, psz_varname, val)) ? NOERROR : E_FAIL;
 
-        return hr;
+            if( (VLC_VAR_STRING == i_type) && (NULL != val.psz_string) )
+                CoTaskMemFree(val.psz_string);
+        }
+        CoTaskMemFree(psz_varname);
     }
-    return E_UNEXPECTED;
+    return hr;
 };
 
 STDMETHODIMP VLCControl::getVariable( BSTR name, VARIANT *value)
 {
-    if( 0 == SysStringLen(name) )
-        return E_INVALIDARG;
-
     if( NULL == value )
         return E_POINTER;
 
-    int i_vlc = _p_instance->getVLCObject();
-    if( i_vlc )
+    VariantInit(value);
+
+    if( 0 == SysStringLen(name) )
+        return E_INVALIDARG;
+
+    int i_vlc;
+    HRESULT hr = _p_instance->getVLCObject(&i_vlc);
+    if( SUCCEEDED(hr) )
     {
-        int codePage = _p_instance->getCodePage();
+        UINT codePage = _p_instance->getCodePage();
         char *psz_varname = CStrFromBSTR(codePage, name);
         if( NULL == psz_varname )
             return E_OUTOFMEMORY;
 
-        HRESULT hr = E_INVALIDARG;
+        hr = E_INVALIDARG;
 
         vlc_value_t val;
         int i_type;
@@ -440,6 +492,7 @@ STDMETHODIMP VLCControl::getVariable( BSTR name, VARIANT *value)
                     break;
 
                 case VLC_VAR_INTEGER:
+                case VLC_VAR_HOTKEY:
                     V_VT(value) = VT_I4;
                     V_I4(value) = val.i_int;
                     break;
@@ -450,36 +503,136 @@ STDMETHODIMP VLCControl::getVariable( BSTR name, VARIANT *value)
                     break;
 
                 case VLC_VAR_STRING:
+                case VLC_VAR_MODULE:
+                case VLC_VAR_FILE:
+                case VLC_VAR_DIRECTORY:
+                case VLC_VAR_VARIABLE:
                     V_VT(value) = VT_BSTR;
                     V_BSTR(value) = BSTRFromCStr(codePage, val.psz_string);
-                    free(val.psz_string);
+                    if( NULL != val.psz_string)
+                        free(val.psz_string);
                     break;
+
+                case VLC_VAR_TIME:
+                    // use a double value to represent time (base is expressed in seconds)
+                    V_VT(value) = VT_R8;
+                    V_R8(value) = ((double)val.i_time)/1000000.0;
+                    break;
+
                 default:
                     hr = DISP_E_TYPEMISMATCH;
             }
         }
-        free(psz_varname);
+        CoTaskMemFree(psz_varname);
         return hr;
     }
-    return E_UNEXPECTED;
+    return hr;
 };
 
-static void freeTargetOptions(char **cOptions, int cOptionCount)
+void VLCControl::FreeTargetOptions(char **cOptions, int cOptionCount)
 {
-    // clean up 
-    for( long pos=0; pos<cOptionCount; ++pos )
+    // clean up
+    if( NULL != cOptions )
     {
-        char *cOption = cOptions[pos];
-        if( NULL != cOption )
-            free(cOption);
-        else
-            break;
+        for( int pos=0; pos<cOptionCount; ++pos )
+        {
+            char *cOption = cOptions[pos];
+            if( NULL != cOption )
+                CoTaskMemFree(cOption);
+            else
+                break;
+        }
+        CoTaskMemFree(cOptions);
     }
-    if( NULL != cOptions )
-        free(cOptions);
 };
 
-static HRESULT createTargetOptions(int codePage, VARIANT *options, char ***cOptions, int *cOptionCount)
+static HRESULT parseStringOptions(int codePage, BSTR bstr, char*** cOptions, int *cOptionCount)
+{
+    HRESULT hr = E_INVALIDARG;
+    if( SysStringLen(bstr) > 0 )
+    {
+        hr = E_OUTOFMEMORY;
+        char *s = CStrFromBSTR(codePage, bstr);
+        char *val = s;
+        if( val )
+        {
+            long capacity = 16;
+            char **options = (char **)CoTaskMemAlloc(capacity*sizeof(char *));
+            if( options )
+            {
+                int nOptions = 0;
+
+                char *end = val + strlen(val);
+                while( val < end )
+                {
+                    // skip leading blanks
+                    while( (val < end)
+                        && ((*val == ' ' ) || (*val == '\t')) )
+                        ++val;
+
+                    char *start = val;
+                    // skip till we get a blank character
+                    while( (val < end)
+                        && (*val != ' ' )
+                        && (*val != '\t') )
+                    {
+                        char c = *(val++);
+                        if( ('\'' == c) || ('"' == c) )
+                        {
+                            // skip till end of string
+                            while( (val < end) && (*(val++) != c ) );
+                        }
+                    }
+
+                    if( val > start )
+                    {
+                        if( nOptions == capacity )
+                        {
+                            capacity += 16;
+                            char **moreOptions = (char **)CoTaskMemRealloc(options, capacity*sizeof(char*));
+                            if( ! moreOptions )
+                            {
+                                /* failed to allocate more memory */
+                                CoTaskMemFree(s);
+                                /* return what we got so far */
+                                *cOptionCount = nOptions;
+                                *cOptions = options;
+                                return NOERROR;
+                            }
+                            options = moreOptions;
+                        }
+                        *(val++) = '\0';
+                        options[nOptions] = (char *)CoTaskMemAlloc(val-start);
+                        if( options[nOptions] )
+                        {
+                            memcpy(options[nOptions], start, val-start);
+                            ++nOptions;
+                        }
+                        else
+                        {
+                            /* failed to allocate memory */
+                            CoTaskMemFree(s);
+                            /* return what we got so far */
+                            *cOptionCount = nOptions;
+                            *cOptions = options;
+                            return NOERROR;
+                        }
+                    }
+                    else
+                        // must be end of string
+                        break;
+                }
+                *cOptionCount = nOptions;
+                *cOptions = options;
+                hr = NOERROR;
+            }
+            CoTaskMemFree(s);
+        }
+    }
+    return hr;
+}
+
+HRESULT VLCControl::CreateTargetOptions(int codePage, VARIANT *options, char ***cOptions, int *cOptionCount)
 {
     HRESULT hr = E_INVALIDARG;
     if( VT_ERROR == V_VT(options) )
@@ -501,7 +654,7 @@ static HRESULT createTargetOptions(int codePage, VARIANT *options, char ***cOpti
     }
     else if( VT_DISPATCH == V_VT(options) )
     {
-        // collection parameter
+        // if object is a collection, retrieve enumerator
         VARIANT colEnum;
         V_VT(&colEnum) = VT_UNKNOWN;
         hr = GetObjectProperty(V_DISPATCH(options), DISPID_NEWENUM, colEnum);
@@ -515,7 +668,7 @@ static HRESULT createTargetOptions(int codePage, VARIANT *options, char ***cOpti
                 long capacity = 16;
                 VARIANT option;
 
-                *cOptions = (char **)malloc(capacity*sizeof(char *));
+                *cOptions = (char **)CoTaskMemAlloc(capacity*sizeof(char *));
                 if( NULL != *cOptions )
                 {
                     ZeroMemory(*cOptions, sizeof(char *)*capacity);
@@ -530,7 +683,7 @@ static HRESULT createTargetOptions(int codePage, VARIANT *options, char ***cOpti
                                 ++pos;
                                 if( pos == capacity )
                                 {
-                                    char **moreOptions = (char **)realloc(*cOptions, (capacity+16)*sizeof(char *));
+                                    char **moreOptions = (char **)CoTaskMemRealloc(*cOptions, (capacity+16)*sizeof(char *));
                                     if( NULL != moreOptions )
                                     {
                                         ZeroMemory(moreOptions+capacity, sizeof(char *)*16);
@@ -542,7 +695,8 @@ static HRESULT createTargetOptions(int codePage, VARIANT *options, char ***cOpti
                                 }
                             }
                             else
-                                hr = E_OUTOFMEMORY;
+                                hr = ( SysStringLen(V_BSTR(&option)) > 0 ) ?
+                                    E_OUTOFMEMORY : E_INVALIDARG;
                         }
                         else
                             hr = E_INVALIDARG;
@@ -553,14 +707,27 @@ static HRESULT createTargetOptions(int codePage, VARIANT *options, char ***cOpti
                     if( FAILED(hr) )
                     {
                         // free already processed elements
-                        freeTargetOptions(*cOptions, *cOptionCount);
+                        FreeTargetOptions(*cOptions, *cOptionCount);
                     }
                 }
                 else
                     hr = E_OUTOFMEMORY;
+
                 enumVar->Release();
             }
         }
+        else
+        {
+            // coerce object into a string and parse it
+            VARIANT v_name;
+            VariantInit(&v_name);
+            hr = VariantChangeType(&v_name, options, 0, VT_BSTR);
+            if( SUCCEEDED(hr) )
+            {
+                hr = parseStringOptions(codePage, V_BSTR(&v_name), cOptions, cOptionCount);
+                VariantClear(&v_name);
+            }
+        }
     }
     else if( V_ISARRAY(options) )
     {
@@ -576,10 +743,10 @@ static HRESULT createTargetOptions(int codePage, VARIANT *options, char ***cOpti
         SafeArrayGetUBound(array, 1, &uBound);
 
         // have we got any options
-        if( uBound > lBound )
+        if( uBound >= lBound )
         {
             VARTYPE vType;
-            HRESULT hr = SafeArrayGetVartype(array, &vType);
+            hr = SafeArrayGetVartype(array, &vType);
             if( FAILED(hr) )
                 return hr;
 
@@ -588,22 +755,24 @@ static HRESULT createTargetOptions(int codePage, VARIANT *options, char ***cOpti
             // marshall options into an array of C strings
             if( VT_VARIANT == vType )
             {
-                *cOptions = (char **)malloc(sizeof(char *)*(uBound-lBound));
-                if( NULL != options )
+                *cOptions = (char **)CoTaskMemAlloc(sizeof(char *)*(uBound-lBound+1));
+                if( NULL == *cOptions )
                     return E_OUTOFMEMORY;
 
-                for(pos=lBound; SUCCEEDED(hr) && (pos<uBound); ++pos )
+                ZeroMemory(*cOptions, sizeof(char *)*(uBound-lBound+1));
+                for(pos=lBound; (pos<=uBound) && SUCCEEDED(hr); ++pos )
                 {
                     VARIANT option;
                     hr = SafeArrayGetElement(array, &pos, &option);
                     if( SUCCEEDED(hr) )
                     {
-                        if( VT_BSTR == V_VT(&option) ) 
+                        if( VT_BSTR == V_VT(&option) )
                         {
                             char *cOption = CStrFromBSTR(codePage, V_BSTR(&option));
                             (*cOptions)[pos-lBound] = cOption;
                             if( NULL == cOption )
-                                hr = E_OUTOFMEMORY;
+                                hr = ( SysStringLen(V_BSTR(&option)) > 0 ) ?
+                                    E_OUTOFMEMORY : E_INVALIDARG;
                         }
                         else
                             hr = E_INVALIDARG;
@@ -613,34 +782,38 @@ static HRESULT createTargetOptions(int codePage, VARIANT *options, char ***cOpti
             }
             else if( VT_BSTR == vType )
             {
-                *cOptions = (char **)malloc(sizeof(char *)*(uBound-lBound));
-                if( NULL != options )
+                *cOptions = (char **)CoTaskMemAlloc(sizeof(char *)*(uBound-lBound+1));
+                if( NULL == *cOptions )
                     return E_OUTOFMEMORY;
 
-                ZeroMemory(cOptions, sizeof(char *)*(uBound-lBound));
-                for(pos=lBound; SUCCEEDED(hr) && (pos<uBound); ++pos )
+                ZeroMemory(*cOptions, sizeof(char *)*(uBound-lBound+1));
+                for(pos=lBound; (pos<=uBound) && SUCCEEDED(hr); ++pos )
                 {
                     BSTR option;
                     hr = SafeArrayGetElement(array, &pos, &option);
                     if( SUCCEEDED(hr) )
                     {
                         char *cOption = CStrFromBSTR(codePage, option);
+
                         (*cOptions)[pos-lBound] = cOption;
                         if( NULL == cOption )
-                            hr = E_OUTOFMEMORY;
+                            hr = ( SysStringLen(option) > 0 ) ?
+                                E_OUTOFMEMORY : E_INVALIDARG;
                         SysFreeString(option);
                     }
                 }
             }
             else
+            {
                 // unsupported type
                 return E_INVALIDARG;
+            }
 
             *cOptionCount = pos-lBound;
             if( FAILED(hr) )
             {
                 // free already processed elements
-                freeTargetOptions(*cOptions, *cOptionCount);
+                FreeTargetOptions(*cOptions, *cOptionCount);
             }
         }
         else
@@ -651,6 +824,22 @@ static HRESULT createTargetOptions(int codePage, VARIANT *options, char ***cOpti
             return NOERROR;
         }
     }
+    else if( VT_UNKNOWN == V_VT(options) )
+    {
+        // coerce object into a string and parse it
+        VARIANT v_name;
+        VariantInit(&v_name);
+        hr = VariantChangeType(&v_name, options, 0, VT_BSTR);
+        if( SUCCEEDED(hr) )
+        {
+            hr = parseStringOptions(codePage, V_BSTR(&v_name), cOptions, cOptionCount);
+            VariantClear(&v_name);
+        }
+    }
+    else if( VT_BSTR == V_VT(options) )
+    {
+        hr = parseStringOptions(codePage, V_BSTR(options), cOptions, cOptionCount);
+    }
     return hr;
 };
 
@@ -664,100 +853,104 @@ STDMETHODIMP VLCControl::addTarget( BSTR uri, VARIANT options, enum VLCPlaylistM
     if( 0 == SysStringLen(uri) )
         return E_INVALIDARG;
 
-    HRESULT hr = E_UNEXPECTED;
-
-    int i_vlc = _p_instance->getVLCObject();
-    if( i_vlc )
+    int i_vlc;
+    HRESULT hr = _p_instance->getVLCObject(&i_vlc);
+    if( SUCCEEDED(hr) )
     {
-        int codePage = _p_instance->getCodePage();
-        char *cUri = CStrFromBSTR(codePage, uri);
+        char *cUri = CStrFromBSTR(CP_UTF8, uri);
         if( NULL == cUri )
             return E_OUTOFMEMORY;
 
         int cOptionsCount;
         char **cOptions;
 
-        if( FAILED(createTargetOptions(codePage, &options, &cOptions, &cOptionsCount)) )
+        if( FAILED(CreateTargetOptions(CP_UTF8, &options, &cOptions, &cOptionsCount)) )
             return E_INVALIDARG;
 
         if( VLC_SUCCESS <= VLC_AddTarget(i_vlc, cUri, (const char **)cOptions, cOptionsCount, mode, position) )
         {
             hr = NOERROR;
-            if( mode & VLCPlayListGo )
+            if( mode & PLAYLIST_GO )
                 _p_instance->fireOnPlayEvent();
         }
         else
         {
             hr = E_FAIL;
-            if( mode & VLCPlayListGo )
+            if( mode & PLAYLIST_GO )
                 _p_instance->fireOnStopEvent();
         }
 
-        freeTargetOptions(cOptions, cOptionsCount);
-        free(cUri);
+        FreeTargetOptions(cOptions, cOptionsCount);
+        CoTaskMemFree(cUri);
     }
     return hr;
 };
-        
+
 STDMETHODIMP VLCControl::get_PlaylistIndex(int *index)
 {
     if( NULL == index )
         return E_POINTER;
 
-    int i_vlc = _p_instance->getVLCObject();
-    if( i_vlc )
+    int i_vlc;
+    HRESULT result = _p_instance->getVLCObject(&i_vlc);
+    if( SUCCEEDED(result) )
     {
         *index = VLC_PlaylistIndex(i_vlc);
         return NOERROR;
     }
     *index = 0;
-    return E_UNEXPECTED;
+    return result;
 };
-        
+
 STDMETHODIMP VLCControl::get_PlaylistCount(int *count)
 {
-    int i_vlc = _p_instance->getVLCObject();
-    if( i_vlc )
+    int i_vlc;
+    HRESULT result = _p_instance->getVLCObject(&i_vlc);
+    if( SUCCEEDED(result) )
     {
         *count = VLC_PlaylistNumberOfItems(i_vlc);
         return NOERROR;
     }
-    return E_UNEXPECTED;
+    *count = 0;
+    return result;
 };
-        
+
 STDMETHODIMP VLCControl::playlistNext(void)
 {
-    int i_vlc = _p_instance->getVLCObject();
-    if( i_vlc )
+    int i_vlc;
+    HRESULT result = _p_instance->getVLCObject(&i_vlc);
+    if( SUCCEEDED(result) )
     {
         VLC_PlaylistNext(i_vlc);
         return NOERROR;
     }
-    return E_UNEXPECTED;
+    return result;
 };
-        
+
 STDMETHODIMP VLCControl::playlistPrev(void)
 {
-    int i_vlc = _p_instance->getVLCObject();
-    if( i_vlc )
+    int i_vlc;
+    HRESULT result = _p_instance->getVLCObject(&i_vlc);
+    if( SUCCEEDED(result) )
     {
         VLC_PlaylistPrev(i_vlc);
         return NOERROR;
     }
-    return E_UNEXPECTED;
+    return result;
 };
-        
+
 STDMETHODIMP VLCControl::playlistClear(void)
 {
-    int i_vlc = _p_instance->getVLCObject();
-    if( i_vlc )
+    int i_vlc;
+    HRESULT result = _p_instance->getVLCObject(&i_vlc);
+    if( SUCCEEDED(result) )
     {
         VLC_PlaylistClear(i_vlc);
         return NOERROR;
     }
-    return E_UNEXPECTED;
+    return result;
 };
-        
+
 STDMETHODIMP VLCControl::get_VersionInfo(BSTR *version)
 {
     if( NULL == version )
@@ -766,11 +959,57 @@ STDMETHODIMP VLCControl::get_VersionInfo(BSTR *version)
     const char *versionStr = VLC_Version();
     if( NULL != versionStr )
     {
-        *version = BSTRFromCStr(_p_instance->getCodePage(), versionStr);
-        
+        *version = BSTRFromCStr(CP_UTF8, versionStr);
         return NULL == *version ? E_OUTOFMEMORY : NOERROR;
     }
     *version = NULL;
     return E_FAIL;
 };
+
+STDMETHODIMP VLCControl::get_MRL(BSTR *mrl)
+{
+    if( NULL == mrl )
+        return E_POINTER;
+
+    *mrl = SysAllocStringLen(_p_instance->getMRL(),
+                SysStringLen(_p_instance->getMRL()));
+    return NOERROR;
+};
+
+STDMETHODIMP VLCControl::put_MRL(BSTR mrl)
+{
+    _p_instance->setMRL(mrl);
+
+    return S_OK;
+};
+
+STDMETHODIMP VLCControl::get_AutoPlay(VARIANT_BOOL *autoplay)
+{
+    if( NULL == autoplay )
+        return E_POINTER;
+
+    *autoplay = _p_instance->getAutoPlay() ? VARIANT_TRUE: VARIANT_FALSE;
+    return S_OK;
+};
+
+STDMETHODIMP VLCControl::put_AutoPlay(VARIANT_BOOL autoplay)
+{
+    _p_instance->setAutoPlay((VARIANT_FALSE != autoplay) ? TRUE: FALSE);
+    return S_OK;
+};
+
+STDMETHODIMP VLCControl::get_AutoLoop(VARIANT_BOOL *autoloop)
+{
+    if( NULL == autoloop )
+        return E_POINTER;
+
+    *autoloop = _p_instance->getAutoLoop() ? VARIANT_TRUE: VARIANT_FALSE;
+    return S_OK;
+};
+
+STDMETHODIMP VLCControl::put_AutoLoop(VARIANT_BOOL autoloop)
+{
+    _p_instance->setAutoLoop((VARIANT_FALSE != autoloop) ? TRUE: FALSE);
+    return S_OK;
+};