]> git.sesse.net Git - vlc/blobdiff - activex/vlccontrol.cpp
Avoid \r\n problems between platforms
[vlc] / activex / vlccontrol.cpp
index 835f5d11663fd55612d729bc2e0c2eadfdcf90f8..083c64fe8ed8b232213aa2c733571c8ab58c504a 100644 (file)
-/*****************************************************************************\r
- * vlccontrol.cpp: ActiveX control for VLC\r
- *****************************************************************************\r
- * Copyright (C) 2005 VideoLAN\r
- *\r
- * Authors: Damien Fouilleul <Damien.Fouilleul@laposte.net>\r
- *\r
- * This program is free software; you can redistribute it and/or modify\r
- * it under the terms of the GNU General Public License as published by\r
- * the Free Software Foundation; either version 2 of the License, or\r
- * (at your option) any later version.\r
- *\r
- * This program is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
- * GNU General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU General Public License\r
- * along with this program; if not, write to the Free Software\r
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.\r
- *****************************************************************************/\r
-\r
-#include "plugin.h"\r
-#include "vlccontrol.h"\r
-\r
-#include "utils.h"\r
-\r
-VLCControl::~VLCControl()\r
-{\r
-    if( _p_typeinfo )\r
-        _p_typeinfo->Release();\r
-};\r
-\r
-HRESULT VLCControl::getTypeInfo(void)\r
-{\r
-    HRESULT hr = NOERROR;\r
-    if( NULL == _p_typeinfo )\r
-    {\r
-        ITypeLib *p_typelib;\r
-\r
-        HRESULT hr = _p_instance->getTypeLib(LOCALE_USER_DEFAULT, &p_typelib);\r
-        if( SUCCEEDED(hr) )\r
-        {\r
-            hr = p_typelib->GetTypeInfoOfGuid(IID_IVLCControl, &_p_typeinfo);\r
-            if( FAILED(hr) )\r
-            {\r
-                _p_typeinfo = NULL;\r
-            }\r
-            p_typelib->Release();\r
-        }\r
-    }\r
-    return hr;\r
-};\r
-\r
-STDMETHODIMP VLCControl::GetTypeInfoCount(UINT* pctInfo)\r
-{\r
-    if( SUCCEEDED(getTypeInfo()) )\r
-        *pctInfo = 1;\r
-    else\r
-        *pctInfo = 0;\r
-\r
-    return NOERROR;\r
-};\r
-\r
-STDMETHODIMP VLCControl::GetTypeInfo(UINT iTInfo, LCID lcid, LPTYPEINFO* ppTInfo)\r
-{\r
-    if( NULL == ppTInfo )\r
-        return E_INVALIDARG;\r
-\r
-    if( SUCCEEDED(getTypeInfo()) )\r
-    {\r
-        _p_typeinfo->AddRef();\r
-        *ppTInfo = _p_typeinfo;\r
-        return NO_ERROR;\r
-    }\r
-    *ppTInfo = NULL;\r
-    return E_NOTIMPL;\r
-};\r
-\r
-STDMETHODIMP VLCControl::GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, \r
-        UINT cNames, LCID lcid, DISPID* rgDispID)\r
-{\r
-    if( SUCCEEDED(getTypeInfo()) )\r
-    {\r
-        return DispGetIDsOfNames(_p_typeinfo, rgszNames, cNames, rgDispID);\r
-    }\r
-    return E_NOTIMPL;\r
-};\r
-\r
-STDMETHODIMP VLCControl::Invoke(DISPID dispIdMember, REFIID riid,\r
-        LCID lcid, WORD wFlags, DISPPARAMS* pDispParams,\r
-        VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr)\r
-{\r
-    if( SUCCEEDED(getTypeInfo()) )\r
-    {\r
-        return DispInvoke(this, _p_typeinfo, dispIdMember, wFlags, pDispParams,\r
-                pVarResult, pExcepInfo, puArgErr);\r
-    }\r
-    return E_NOTIMPL;\r
-};\r
-\r
-STDMETHODIMP VLCControl::get_Value(VARIANT *pvarValue)\r
-{\r
-    if( NULL == pvarValue )\r
-        return E_INVALIDARG;\r
-\r
-    V_VT(pvarValue) = VT_BOOL;\r
-    return get_Playing(&V_BOOL(pvarValue));\r
-};\r
-        \r
-STDMETHODIMP VLCControl::put_Value(VARIANT pvarValue)\r
-{\r
-    if( VT_BOOL != V_VT(&pvarValue) )\r
-    {\r
-        VARIANT boolValue;\r
-        HRESULT hr = VariantChangeType(&boolValue, &pvarValue, 0, VT_BOOL);\r
-        if( SUCCEEDED(hr) )\r
-        {\r
-            hr = get_Playing(&V_BOOL(&pvarValue));\r
-            //VariantClear(&boolValue);\r
-        }\r
-        return hr;\r
-    }\r
-    return get_Playing(&V_BOOL(&pvarValue));\r
-};\r
-        \r
-STDMETHODIMP VLCControl::get_Visible(VARIANT_BOOL *isVisible)\r
-{\r
-    if( NULL == isVisible )\r
-        return E_INVALIDARG;\r
-\r
-    *isVisible = _p_instance->getVisible();\r
-\r
-    return NOERROR;\r
-};\r
-        \r
-STDMETHODIMP VLCControl::put_Visible(VARIANT_BOOL isVisible)\r
-{\r
-    _p_instance->setVisible(isVisible != VARIANT_FALSE);\r
-\r
-    return NOERROR;\r
-};\r
-\r
-STDMETHODIMP VLCControl::play(void)\r
-{\r
-    int i_vlc = _p_instance->getVLCObject();\r
-    if( i_vlc )\r
-    {\r
-        VLC_Play(i_vlc);\r
-        _p_instance->fireOnPlayEvent();\r
-        return NOERROR;\r
-    }\r
-    return E_UNEXPECTED;\r
-};\r
\r
-STDMETHODIMP VLCControl::pause(void)\r
-{\r
-    int i_vlc = _p_instance->getVLCObject();\r
-    if( i_vlc )\r
-    {\r
-        VLC_Pause(i_vlc);\r
-        _p_instance->fireOnPauseEvent();\r
-        return NOERROR;\r
-    }\r
-    return E_UNEXPECTED;\r
-};\r
-        \r
-STDMETHODIMP VLCControl::stop(void)\r
-{\r
-    int i_vlc = _p_instance->getVLCObject();\r
-    if( i_vlc )\r
-    {\r
-        VLC_Stop(i_vlc);\r
-        _p_instance->fireOnStopEvent();\r
-        return NOERROR;\r
-    }\r
-    return E_UNEXPECTED;\r
-}\r
-        \r
-STDMETHODIMP VLCControl::get_Playing(VARIANT_BOOL *isPlaying)\r
-{\r
-    if( NULL == isPlaying )\r
-        return E_INVALIDARG;\r
-\r
-    int i_vlc = _p_instance->getVLCObject();\r
-    if( i_vlc )\r
-    {\r
-        *isPlaying = VLC_IsPlaying(i_vlc) ? VARIANT_TRUE : VARIANT_FALSE;\r
-        return NOERROR;\r
-    }\r
-    *isPlaying = VARIANT_FALSE;\r
-    return E_UNEXPECTED;\r
-};\r
-        \r
-STDMETHODIMP VLCControl::put_Playing(VARIANT_BOOL isPlaying)\r
-{\r
-    int i_vlc = _p_instance->getVLCObject();\r
-    if( i_vlc )\r
-    {\r
-        if( VARIANT_FALSE == isPlaying )\r
-        {\r
-            if( VLC_IsPlaying(i_vlc) )\r
-                VLC_Stop(i_vlc);\r
-        }\r
-        else\r
-        {\r
-            if( ! VLC_IsPlaying(i_vlc) )\r
-                VLC_Play(i_vlc);\r
-        }\r
-        return NOERROR;\r
-    }\r
-    return E_UNEXPECTED;\r
-};\r
-        \r
-STDMETHODIMP VLCControl::get_Position(float *position)\r
-{\r
-    if( NULL == position )\r
-        return E_INVALIDARG;\r
-\r
-    int i_vlc = _p_instance->getVLCObject();\r
-    if( i_vlc )\r
-    {\r
-        *position = VLC_PositionGet(i_vlc);\r
-        return NOERROR;\r
-    }\r
-    *position = 0.0f;\r
-    return E_UNEXPECTED;\r
-};\r
-        \r
-STDMETHODIMP VLCControl::put_Position(float position)\r
-{\r
-    int i_vlc = _p_instance->getVLCObject();\r
-    if( i_vlc )\r
-    {\r
-        VLC_PositionSet(i_vlc, position);\r
-        return NOERROR;\r
-    }\r
-    return E_UNEXPECTED;\r
-};\r
-        \r
-STDMETHODIMP VLCControl::get_Time(int *seconds)\r
-{\r
-    if( NULL == seconds )\r
-        return E_INVALIDARG;\r
-\r
-    int i_vlc = _p_instance->getVLCObject();\r
-    if( i_vlc )\r
-    {\r
-        *seconds = VLC_TimeGet(i_vlc);\r
-        return NOERROR;\r
-    }\r
-    *seconds = 0;\r
-    return E_UNEXPECTED;\r
-};\r
-        \r
-STDMETHODIMP VLCControl::put_Time(int seconds)\r
-{\r
-    int i_vlc = _p_instance->getVLCObject();\r
-    if( i_vlc )\r
-    {\r
-        VLC_TimeSet(i_vlc, seconds, VLC_FALSE);\r
-        return NOERROR;\r
-    }\r
-    return E_UNEXPECTED;\r
-};\r
-        \r
-STDMETHODIMP VLCControl::shuttle(int seconds)\r
-{\r
-    int i_vlc = _p_instance->getVLCObject();\r
-    if( i_vlc )\r
-    {\r
-        VLC_TimeSet(i_vlc, seconds, VLC_TRUE);\r
-        return NOERROR;\r
-    }\r
-    return E_UNEXPECTED;\r
-};\r
-        \r
-STDMETHODIMP VLCControl::fullscreen(void)\r
-{\r
-    int i_vlc = _p_instance->getVLCObject();\r
-    if( i_vlc )\r
-    {\r
-        VLC_FullScreen(i_vlc);\r
-        return NOERROR;\r
-    }\r
-    return E_UNEXPECTED;\r
-};\r
-        \r
-STDMETHODIMP VLCControl::get_Length(int *seconds)\r
-{\r
-    if( NULL == seconds )\r
-        return E_INVALIDARG;\r
-\r
-    int i_vlc = _p_instance->getVLCObject();\r
-    if( i_vlc )\r
-    {\r
-        *seconds = VLC_LengthGet(i_vlc);\r
-        return NOERROR;\r
-    }\r
-    *seconds = 0;\r
-    return E_UNEXPECTED;\r
-};\r
-        \r
-STDMETHODIMP VLCControl::playFaster(void)\r
-{\r
-    int i_vlc = _p_instance->getVLCObject();\r
-    if( i_vlc )\r
-    {\r
-        VLC_SpeedFaster(i_vlc);\r
-        return NOERROR;\r
-    }\r
-    return E_UNEXPECTED;\r
-};\r
-        \r
-STDMETHODIMP VLCControl::playSlower(void)\r
-{\r
-    int i_vlc = _p_instance->getVLCObject();\r
-    if( i_vlc )\r
-    {\r
-        VLC_SpeedSlower(i_vlc);\r
-        return NOERROR;\r
-    }\r
-    return E_UNEXPECTED;\r
-};\r
-        \r
-STDMETHODIMP VLCControl::get_Volume(int *volume)\r
-{\r
-    if( NULL == volume )\r
-        return E_INVALIDARG;\r
-\r
-    int i_vlc = _p_instance->getVLCObject();\r
-    if( i_vlc )\r
-    {\r
-        *volume  = VLC_VolumeGet(i_vlc);\r
-        return NOERROR;\r
-    }\r
-    *volume = 0;\r
-    return E_UNEXPECTED;\r
-};\r
-        \r
-STDMETHODIMP VLCControl::put_Volume(int volume)\r
-{\r
-    int i_vlc = _p_instance->getVLCObject();\r
-    if( i_vlc )\r
-    {\r
-        VLC_VolumeSet(i_vlc, volume);\r
-        return NOERROR;\r
-    }\r
-    return E_UNEXPECTED;\r
-};\r
-        \r
-STDMETHODIMP VLCControl::toggleMute(void)\r
-{\r
-    int i_vlc = _p_instance->getVLCObject();\r
-    if( i_vlc )\r
-    {\r
-        VLC_VolumeMute(i_vlc);\r
-        return NOERROR;\r
-    }\r
-    return E_UNEXPECTED;\r
-};\r
-\r
-static void freeTargetOptions(char **cOptions, int cOptionCount)\r
-{\r
-    // clean up \r
-    for( long pos=0; pos<cOptionCount; ++pos )\r
-    {\r
-        char *cOption = cOptions[pos];\r
-        if( NULL != cOption )\r
-            free(cOption);\r
-        else\r
-            break;\r
-    }\r
-    if( NULL != cOptions )\r
-        free(cOptions);\r
-};\r
-\r
-static HRESULT createTargetOptions(int codePage, VARIANT *options, char ***cOptions, int *cOptionCount)\r
-{\r
-    HRESULT hr = E_INVALIDARG;\r
-    if( VT_ERROR == V_VT(options) )\r
-    {\r
-        if( DISP_E_PARAMNOTFOUND == V_ERROR(options) )\r
-        {\r
-            // optional parameter not set\r
-            *cOptions = NULL;\r
-            *cOptionCount = 0;\r
-            return NOERROR;\r
-        }\r
-    }\r
-    else if( (VT_EMPTY == V_VT(options)) || (VT_NULL == V_VT(options)) )\r
-    {\r
-        // null parameter\r
-        *cOptions = NULL;\r
-        *cOptionCount = 0;\r
-        return NOERROR;\r
-    }\r
-    else if( VT_DISPATCH == V_VT(options) )\r
-    {\r
-        // collection parameter\r
-        VARIANT colEnum;\r
-        V_VT(&colEnum) = VT_UNKNOWN;\r
-        hr = GetObjectProperty(V_DISPATCH(options), DISPID_NEWENUM, colEnum);\r
-        if( SUCCEEDED(hr) )\r
-        {\r
-            IEnumVARIANT *enumVar;\r
-            hr = V_UNKNOWN(&colEnum)->QueryInterface(IID_IEnumVARIANT, (LPVOID *)&enumVar);\r
-            if( SUCCEEDED(hr) )\r
-            {\r
-                long pos = 0;\r
-                long capacity = 16;\r
-                VARIANT option;\r
-\r
-                *cOptions = (char **)malloc(capacity*sizeof(char *));\r
-                if( NULL != *cOptions )\r
-                {\r
-                    ZeroMemory(*cOptions, sizeof(char *)*capacity);\r
-                    while( SUCCEEDED(hr) && (S_OK == enumVar->Next(1, &option, NULL)) )\r
-                    {\r
-                        if( VT_BSTR == V_VT(&option) )\r
-                        {\r
-                            char *cOption = CStrFromBSTR(codePage, V_BSTR(&option));\r
-                            (*cOptions)[pos] = cOption;\r
-                            if( NULL != cOption )\r
-                            {\r
-                                ++pos;\r
-                                if( pos == capacity )\r
-                                {\r
-                                    char **moreOptions = (char **)realloc(*cOptions, (capacity+16)*sizeof(char *));\r
-                                    if( NULL != moreOptions )\r
-                                    {\r
-                                        ZeroMemory(moreOptions+capacity, sizeof(char *)*16);\r
-                                        capacity += 16;\r
-                                        *cOptions = moreOptions;\r
-                                    }\r
-                                    else\r
-                                        hr = E_OUTOFMEMORY;\r
-                                }\r
-                            }\r
-                            else\r
-                                hr = E_OUTOFMEMORY;\r
-                        }\r
-                        else\r
-                            hr = E_INVALIDARG;\r
-\r
-                        VariantClear(&option);\r
-                    }\r
-                    *cOptionCount = pos;\r
-                    if( FAILED(hr) )\r
-                    {\r
-                        // free already processed elements\r
-                        freeTargetOptions(*cOptions, *cOptionCount);\r
-                    }\r
-                }\r
-                else\r
-                    hr = E_OUTOFMEMORY;\r
-                enumVar->Release();\r
-            }\r
-        }\r
-    }\r
-    else if( V_ISARRAY(options) )\r
-    {\r
-        // array parameter\r
-        SAFEARRAY *array = V_ISBYREF(options) ? *V_ARRAYREF(options) : V_ARRAY(options);\r
-\r
-        if( SafeArrayGetDim(array) != 1 )\r
-            return E_INVALIDARG;\r
-\r
-        long lBound = 0;\r
-        long uBound = 0;\r
-        SafeArrayGetLBound(array, 1, &lBound);\r
-        SafeArrayGetUBound(array, 1, &uBound);\r
-\r
-        // have we got any options\r
-        if( uBound > lBound )\r
-        {\r
-            VARTYPE vType;\r
-            HRESULT hr = SafeArrayGetVartype(array, &vType);\r
-            if( FAILED(hr) )\r
-                return hr;\r
-\r
-            long pos;\r
-\r
-            // marshall options into an array of C strings\r
-            if( VT_VARIANT == vType )\r
-            {\r
-                *cOptions = (char **)malloc(sizeof(char *)*(uBound-lBound));\r
-                if( NULL != options )\r
-                    return E_OUTOFMEMORY;\r
-\r
-                for(pos=lBound; SUCCEEDED(hr) && (pos<uBound); ++pos )\r
-                {\r
-                    VARIANT option;\r
-                    hr = SafeArrayGetElement(array, &pos, &option);\r
-                    if( SUCCEEDED(hr) )\r
-                    {\r
-                        if( VT_BSTR == V_VT(&option) ) \r
-                        {\r
-                            char *cOption = CStrFromBSTR(codePage, V_BSTR(&option));\r
-                            (*cOptions)[pos-lBound] = cOption;\r
-                            if( NULL == cOption )\r
-                                hr = E_OUTOFMEMORY;\r
-                        }\r
-                        else\r
-                            hr = E_INVALIDARG;\r
-                        VariantClear(&option);\r
-                    }\r
-                }\r
-            }\r
-            else if( VT_BSTR == vType )\r
-            {\r
-                *cOptions = (char **)malloc(sizeof(char *)*(uBound-lBound));\r
-                if( NULL != options )\r
-                    return E_OUTOFMEMORY;\r
-\r
-                ZeroMemory(cOptions, sizeof(char *)*(uBound-lBound));\r
-                for(pos=lBound; SUCCEEDED(hr) && (pos<uBound); ++pos )\r
-                {\r
-                    BSTR option;\r
-                    hr = SafeArrayGetElement(array, &pos, &option);\r
-                    if( SUCCEEDED(hr) )\r
-                    {\r
-                        char *cOption = CStrFromBSTR(codePage, option);\r
-                        (*cOptions)[pos-lBound] = cOption;\r
-                        if( NULL == cOption )\r
-                            hr = E_OUTOFMEMORY;\r
-                        SysFreeString(option);\r
-                    }\r
-                }\r
-            }\r
-            else\r
-                // unsupported type\r
-                return E_INVALIDARG;\r
-\r
-            *cOptionCount = pos-lBound;\r
-            if( FAILED(hr) )\r
-            {\r
-                // free already processed elements\r
-                freeTargetOptions(*cOptions, *cOptionCount);\r
-            }\r
-        }\r
-        else\r
-        {\r
-            // empty array\r
-            *cOptions = NULL;\r
-            *cOptionCount = 0;\r
-            return NOERROR;\r
-        }\r
-    }\r
-    return hr;\r
-};\r
-\r
-/*\r
-** use VARIANT rather than a SAFEARRAY as argument type\r
-** for compatibility with some scripting language (JScript)\r
-*/\r
-\r
-STDMETHODIMP VLCControl::addTarget( BSTR uri, VARIANT options, enum VLCPlaylistMode mode, int position)\r
-{\r
-    if( NULL == uri )\r
-        return E_INVALIDARG;\r
-\r
-    HRESULT hr = E_UNEXPECTED;\r
-\r
-    int i_vlc = _p_instance->getVLCObject();\r
-    if( i_vlc )\r
-    {\r
-        int codePage = _p_instance->getCodePage();\r
-        char *cUri = CStrFromBSTR(codePage, uri);\r
-        if( NULL == cUri )\r
-            return E_OUTOFMEMORY;\r
-\r
-        int cOptionsCount;\r
-        char **cOptions;\r
-\r
-        if( FAILED(createTargetOptions(codePage, &options, &cOptions, &cOptionsCount)) )\r
-            return E_INVALIDARG;\r
-\r
-        VLC_AddTarget(i_vlc, cUri, (const char **)cOptions, cOptionsCount, mode, position);\r
-        hr = NOERROR;\r
-\r
-        freeTargetOptions(cOptions, cOptionsCount);\r
-        free(cUri);\r
-    }\r
-    return hr;\r
-};\r
-        \r
-STDMETHODIMP VLCControl::get_PlaylistIndex(int *index)\r
-{\r
-    if( NULL == index )\r
-        return E_INVALIDARG;\r
-\r
-    int i_vlc = _p_instance->getVLCObject();\r
-    if( i_vlc )\r
-    {\r
-        *index = VLC_PlaylistIndex(i_vlc);\r
-        return NOERROR;\r
-    }\r
-    *index = 0;\r
-    return E_UNEXPECTED;\r
-};\r
-        \r
-STDMETHODIMP VLCControl::get_PlaylistCount(int *count)\r
-{\r
-    int i_vlc = _p_instance->getVLCObject();\r
-    if( i_vlc )\r
-    {\r
-        *count = VLC_PlaylistNumberOfItems(i_vlc);\r
-        return NOERROR;\r
-    }\r
-    return E_UNEXPECTED;\r
-};\r
-        \r
-STDMETHODIMP VLCControl::playlistNext(void)\r
-{\r
-    int i_vlc = _p_instance->getVLCObject();\r
-    if( i_vlc )\r
-    {\r
-        VLC_PlaylistNext(i_vlc);\r
-        return NOERROR;\r
-    }\r
-    return E_UNEXPECTED;\r
-};\r
-        \r
-STDMETHODIMP VLCControl::playlistPrev(void)\r
-{\r
-    int i_vlc = _p_instance->getVLCObject();\r
-    if( i_vlc )\r
-    {\r
-        VLC_PlaylistPrev(i_vlc);\r
-        return NOERROR;\r
-    }\r
-    return E_UNEXPECTED;\r
-};\r
-        \r
-STDMETHODIMP VLCControl::playlistClear(void)\r
-{\r
-    int i_vlc = _p_instance->getVLCObject();\r
-    if( i_vlc )\r
-    {\r
-        VLC_PlaylistClear(i_vlc);\r
-        return NOERROR;\r
-    }\r
-    return E_UNEXPECTED;\r
-};\r
-        \r
-STDMETHODIMP VLCControl::get_VersionInfo(BSTR *version)\r
-{\r
-    if( NULL == version )\r
-        return E_INVALIDARG;\r
-\r
-    const char *versionStr = VLC_Version();\r
-    if( NULL != versionStr )\r
-    {\r
-        *version = BSTRFromCStr(_p_instance->getCodePage(), versionStr);\r
-        \r
-        return NULL == *version ? E_OUTOFMEMORY : NOERROR;\r
-    }\r
-    *version = NULL;\r
-    return E_FAIL;\r
-};\r
\r
+/*****************************************************************************
+ * vlccontrol.cpp: ActiveX control for VLC
+ *****************************************************************************
+ * Copyright (C) 2005 VideoLAN
+ *
+ * Authors: Damien Fouilleul <Damien.Fouilleul@laposte.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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.
+ *****************************************************************************/
+
+#include "plugin.h"
+#include "vlccontrol.h"
+
+#include "utils.h"
+
+VLCControl::~VLCControl()
+{
+    if( _p_typeinfo )
+        _p_typeinfo->Release();
+};
+
+HRESULT VLCControl::getTypeInfo(void)
+{
+    HRESULT hr = NOERROR;
+    if( NULL == _p_typeinfo )
+    {
+        ITypeLib *p_typelib;
+
+        HRESULT hr = _p_instance->getTypeLib(LOCALE_USER_DEFAULT, &p_typelib);
+        if( SUCCEEDED(hr) )
+        {
+            hr = p_typelib->GetTypeInfoOfGuid(IID_IVLCControl, &_p_typeinfo);
+            if( FAILED(hr) )
+            {
+                _p_typeinfo = NULL;
+            }
+            p_typelib->Release();
+        }
+    }
+    return hr;
+};
+
+STDMETHODIMP VLCControl::GetTypeInfoCount(UINT* pctInfo)
+{
+    if( SUCCEEDED(getTypeInfo()) )
+        *pctInfo = 1;
+    else
+        *pctInfo = 0;
+
+    return NOERROR;
+};
+
+STDMETHODIMP VLCControl::GetTypeInfo(UINT iTInfo, LCID lcid, LPTYPEINFO* ppTInfo)
+{
+    if( NULL == ppTInfo )
+        return E_INVALIDARG;
+
+    if( SUCCEEDED(getTypeInfo()) )
+    {
+        _p_typeinfo->AddRef();
+        *ppTInfo = _p_typeinfo;
+        return NO_ERROR;
+    }
+    *ppTInfo = NULL;
+    return E_NOTIMPL;
+};
+
+STDMETHODIMP VLCControl::GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, 
+        UINT cNames, LCID lcid, DISPID* rgDispID)
+{
+    if( SUCCEEDED(getTypeInfo()) )
+    {
+        return DispGetIDsOfNames(_p_typeinfo, rgszNames, cNames, rgDispID);
+    }
+    return E_NOTIMPL;
+};
+
+STDMETHODIMP VLCControl::Invoke(DISPID dispIdMember, REFIID riid,
+        LCID lcid, WORD wFlags, DISPPARAMS* pDispParams,
+        VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr)
+{
+    if( SUCCEEDED(getTypeInfo()) )
+    {
+        return DispInvoke(this, _p_typeinfo, dispIdMember, wFlags, pDispParams,
+                pVarResult, pExcepInfo, puArgErr);
+    }
+    return E_NOTIMPL;
+};
+
+STDMETHODIMP VLCControl::get_Value(VARIANT *pvarValue)
+{
+    if( NULL == pvarValue )
+        return E_INVALIDARG;
+
+    V_VT(pvarValue) = VT_BOOL;
+    return get_Playing(&V_BOOL(pvarValue));
+};
+        
+STDMETHODIMP VLCControl::put_Value(VARIANT pvarValue)
+{
+    if( VT_BOOL != V_VT(&pvarValue) )
+    {
+        VARIANT boolValue;
+        HRESULT hr = VariantChangeType(&boolValue, &pvarValue, 0, VT_BOOL);
+        if( SUCCEEDED(hr) )
+        {
+            hr = get_Playing(&V_BOOL(&pvarValue));
+            //VariantClear(&boolValue);
+        }
+        return hr;
+    }
+    return get_Playing(&V_BOOL(&pvarValue));
+};
+        
+STDMETHODIMP VLCControl::get_Visible(VARIANT_BOOL *isVisible)
+{
+    if( NULL == isVisible )
+        return E_INVALIDARG;
+
+    *isVisible = _p_instance->getVisible();
+
+    return NOERROR;
+};
+        
+STDMETHODIMP VLCControl::put_Visible(VARIANT_BOOL isVisible)
+{
+    _p_instance->setVisible(isVisible != VARIANT_FALSE);
+
+    return NOERROR;
+};
+
+STDMETHODIMP VLCControl::play(void)
+{
+    int i_vlc = _p_instance->getVLCObject();
+    if( i_vlc )
+    {
+        VLC_Play(i_vlc);
+        _p_instance->fireOnPlayEvent();
+        return NOERROR;
+    }
+    return E_UNEXPECTED;
+};
+STDMETHODIMP VLCControl::pause(void)
+{
+    int i_vlc = _p_instance->getVLCObject();
+    if( i_vlc )
+    {
+        VLC_Pause(i_vlc);
+        _p_instance->fireOnPauseEvent();
+        return NOERROR;
+    }
+    return E_UNEXPECTED;
+};
+        
+STDMETHODIMP VLCControl::stop(void)
+{
+    int i_vlc = _p_instance->getVLCObject();
+    if( i_vlc )
+    {
+        VLC_Stop(i_vlc);
+        _p_instance->fireOnStopEvent();
+        return NOERROR;
+    }
+    return E_UNEXPECTED;
+}
+        
+STDMETHODIMP VLCControl::get_Playing(VARIANT_BOOL *isPlaying)
+{
+    if( NULL == isPlaying )
+        return E_INVALIDARG;
+
+    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 )
+    {
+        if( VARIANT_FALSE == isPlaying )
+        {
+            if( VLC_IsPlaying(i_vlc) )
+                VLC_Stop(i_vlc);
+        }
+        else
+        {
+            if( ! VLC_IsPlaying(i_vlc) )
+                VLC_Play(i_vlc);
+        }
+        return NOERROR;
+    }
+    return E_UNEXPECTED;
+};
+        
+STDMETHODIMP VLCControl::get_Position(float *position)
+{
+    if( NULL == position )
+        return E_INVALIDARG;
+
+    int i_vlc = _p_instance->getVLCObject();
+    if( i_vlc )
+    {
+        *position = VLC_PositionGet(i_vlc);
+        return NOERROR;
+    }
+    *position = 0.0f;
+    return E_UNEXPECTED;
+};
+        
+STDMETHODIMP VLCControl::put_Position(float position)
+{
+    int i_vlc = _p_instance->getVLCObject();
+    if( i_vlc )
+    {
+        VLC_PositionSet(i_vlc, position);
+        return NOERROR;
+    }
+    return E_UNEXPECTED;
+};
+        
+STDMETHODIMP VLCControl::get_Time(int *seconds)
+{
+    if( NULL == seconds )
+        return E_INVALIDARG;
+
+    int i_vlc = _p_instance->getVLCObject();
+    if( i_vlc )
+    {
+        *seconds = VLC_TimeGet(i_vlc);
+        return NOERROR;
+    }
+    *seconds = 0;
+    return E_UNEXPECTED;
+};
+        
+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;
+};
+        
+STDMETHODIMP VLCControl::shuttle(int seconds)
+{
+    int i_vlc = _p_instance->getVLCObject();
+    if( i_vlc )
+    {
+        VLC_TimeSet(i_vlc, seconds, VLC_TRUE);
+        return NOERROR;
+    }
+    return E_UNEXPECTED;
+};
+        
+STDMETHODIMP VLCControl::fullscreen(void)
+{
+    int i_vlc = _p_instance->getVLCObject();
+    if( i_vlc )
+    {
+        VLC_FullScreen(i_vlc);
+        return NOERROR;
+    }
+    return E_UNEXPECTED;
+};
+        
+STDMETHODIMP VLCControl::get_Length(int *seconds)
+{
+    if( NULL == seconds )
+        return E_INVALIDARG;
+
+    int i_vlc = _p_instance->getVLCObject();
+    if( i_vlc )
+    {
+        *seconds = VLC_LengthGet(i_vlc);
+        return NOERROR;
+    }
+    *seconds = 0;
+    return E_UNEXPECTED;
+};
+        
+STDMETHODIMP VLCControl::playFaster(void)
+{
+    int i_vlc = _p_instance->getVLCObject();
+    if( i_vlc )
+    {
+        VLC_SpeedFaster(i_vlc);
+        return NOERROR;
+    }
+    return E_UNEXPECTED;
+};
+        
+STDMETHODIMP VLCControl::playSlower(void)
+{
+    int i_vlc = _p_instance->getVLCObject();
+    if( i_vlc )
+    {
+        VLC_SpeedSlower(i_vlc);
+        return NOERROR;
+    }
+    return E_UNEXPECTED;
+};
+        
+STDMETHODIMP VLCControl::get_Volume(int *volume)
+{
+    if( NULL == volume )
+        return E_INVALIDARG;
+
+    int i_vlc = _p_instance->getVLCObject();
+    if( i_vlc )
+    {
+        *volume  = VLC_VolumeGet(i_vlc);
+        return NOERROR;
+    }
+    *volume = 0;
+    return E_UNEXPECTED;
+};
+        
+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;
+};
+        
+STDMETHODIMP VLCControl::toggleMute(void)
+{
+    int i_vlc = _p_instance->getVLCObject();
+    if( i_vlc )
+    {
+        VLC_VolumeMute(i_vlc);
+        return NOERROR;
+    }
+    return E_UNEXPECTED;
+};
+
+static void freeTargetOptions(char **cOptions, int cOptionCount)
+{
+    // clean up 
+    for( long pos=0; pos<cOptionCount; ++pos )
+    {
+        char *cOption = cOptions[pos];
+        if( NULL != cOption )
+            free(cOption);
+        else
+            break;
+    }
+    if( NULL != cOptions )
+        free(cOptions);
+};
+
+static HRESULT createTargetOptions(int codePage, VARIANT *options, char ***cOptions, int *cOptionCount)
+{
+    HRESULT hr = E_INVALIDARG;
+    if( VT_ERROR == V_VT(options) )
+    {
+        if( DISP_E_PARAMNOTFOUND == V_ERROR(options) )
+        {
+            // optional parameter not set
+            *cOptions = NULL;
+            *cOptionCount = 0;
+            return NOERROR;
+        }
+    }
+    else if( (VT_EMPTY == V_VT(options)) || (VT_NULL == V_VT(options)) )
+    {
+        // null parameter
+        *cOptions = NULL;
+        *cOptionCount = 0;
+        return NOERROR;
+    }
+    else if( VT_DISPATCH == V_VT(options) )
+    {
+        // collection parameter
+        VARIANT colEnum;
+        V_VT(&colEnum) = VT_UNKNOWN;
+        hr = GetObjectProperty(V_DISPATCH(options), DISPID_NEWENUM, colEnum);
+        if( SUCCEEDED(hr) )
+        {
+            IEnumVARIANT *enumVar;
+            hr = V_UNKNOWN(&colEnum)->QueryInterface(IID_IEnumVARIANT, (LPVOID *)&enumVar);
+            if( SUCCEEDED(hr) )
+            {
+                long pos = 0;
+                long capacity = 16;
+                VARIANT option;
+
+                *cOptions = (char **)malloc(capacity*sizeof(char *));
+                if( NULL != *cOptions )
+                {
+                    ZeroMemory(*cOptions, sizeof(char *)*capacity);
+                    while( SUCCEEDED(hr) && (S_OK == enumVar->Next(1, &option, NULL)) )
+                    {
+                        if( VT_BSTR == V_VT(&option) )
+                        {
+                            char *cOption = CStrFromBSTR(codePage, V_BSTR(&option));
+                            (*cOptions)[pos] = cOption;
+                            if( NULL != cOption )
+                            {
+                                ++pos;
+                                if( pos == capacity )
+                                {
+                                    char **moreOptions = (char **)realloc(*cOptions, (capacity+16)*sizeof(char *));
+                                    if( NULL != moreOptions )
+                                    {
+                                        ZeroMemory(moreOptions+capacity, sizeof(char *)*16);
+                                        capacity += 16;
+                                        *cOptions = moreOptions;
+                                    }
+                                    else
+                                        hr = E_OUTOFMEMORY;
+                                }
+                            }
+                            else
+                                hr = E_OUTOFMEMORY;
+                        }
+                        else
+                            hr = E_INVALIDARG;
+
+                        VariantClear(&option);
+                    }
+                    *cOptionCount = pos;
+                    if( FAILED(hr) )
+                    {
+                        // free already processed elements
+                        freeTargetOptions(*cOptions, *cOptionCount);
+                    }
+                }
+                else
+                    hr = E_OUTOFMEMORY;
+                enumVar->Release();
+            }
+        }
+    }
+    else if( V_ISARRAY(options) )
+    {
+        // array parameter
+        SAFEARRAY *array = V_ISBYREF(options) ? *V_ARRAYREF(options) : V_ARRAY(options);
+
+        if( SafeArrayGetDim(array) != 1 )
+            return E_INVALIDARG;
+
+        long lBound = 0;
+        long uBound = 0;
+        SafeArrayGetLBound(array, 1, &lBound);
+        SafeArrayGetUBound(array, 1, &uBound);
+
+        // have we got any options
+        if( uBound > lBound )
+        {
+            VARTYPE vType;
+            HRESULT hr = SafeArrayGetVartype(array, &vType);
+            if( FAILED(hr) )
+                return hr;
+
+            long pos;
+
+            // marshall options into an array of C strings
+            if( VT_VARIANT == vType )
+            {
+                *cOptions = (char **)malloc(sizeof(char *)*(uBound-lBound));
+                if( NULL != options )
+                    return E_OUTOFMEMORY;
+
+                for(pos=lBound; SUCCEEDED(hr) && (pos<uBound); ++pos )
+                {
+                    VARIANT option;
+                    hr = SafeArrayGetElement(array, &pos, &option);
+                    if( SUCCEEDED(hr) )
+                    {
+                        if( VT_BSTR == V_VT(&option) ) 
+                        {
+                            char *cOption = CStrFromBSTR(codePage, V_BSTR(&option));
+                            (*cOptions)[pos-lBound] = cOption;
+                            if( NULL == cOption )
+                                hr = E_OUTOFMEMORY;
+                        }
+                        else
+                            hr = E_INVALIDARG;
+                        VariantClear(&option);
+                    }
+                }
+            }
+            else if( VT_BSTR == vType )
+            {
+                *cOptions = (char **)malloc(sizeof(char *)*(uBound-lBound));
+                if( NULL != options )
+                    return E_OUTOFMEMORY;
+
+                ZeroMemory(cOptions, sizeof(char *)*(uBound-lBound));
+                for(pos=lBound; SUCCEEDED(hr) && (pos<uBound); ++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;
+                        SysFreeString(option);
+                    }
+                }
+            }
+            else
+                // unsupported type
+                return E_INVALIDARG;
+
+            *cOptionCount = pos-lBound;
+            if( FAILED(hr) )
+            {
+                // free already processed elements
+                freeTargetOptions(*cOptions, *cOptionCount);
+            }
+        }
+        else
+        {
+            // empty array
+            *cOptions = NULL;
+            *cOptionCount = 0;
+            return NOERROR;
+        }
+    }
+    return hr;
+};
+
+/*
+** use VARIANT rather than a SAFEARRAY as argument type
+** for compatibility with some scripting language (JScript)
+*/
+
+STDMETHODIMP VLCControl::addTarget( BSTR uri, VARIANT options, enum VLCPlaylistMode mode, int position)
+{
+    if( NULL == uri )
+        return E_INVALIDARG;
+
+    HRESULT hr = E_UNEXPECTED;
+
+    int i_vlc = _p_instance->getVLCObject();
+    if( i_vlc )
+    {
+        int codePage = _p_instance->getCodePage();
+        char *cUri = CStrFromBSTR(codePage, uri);
+        if( NULL == cUri )
+            return E_OUTOFMEMORY;
+
+        int cOptionsCount;
+        char **cOptions;
+
+        if( FAILED(createTargetOptions(codePage, &options, &cOptions, &cOptionsCount)) )
+            return E_INVALIDARG;
+
+        VLC_AddTarget(i_vlc, cUri, (const char **)cOptions, cOptionsCount, mode, position);
+        hr = NOERROR;
+
+        freeTargetOptions(cOptions, cOptionsCount);
+        free(cUri);
+    }
+    return hr;
+};
+        
+STDMETHODIMP VLCControl::get_PlaylistIndex(int *index)
+{
+    if( NULL == index )
+        return E_INVALIDARG;
+
+    int i_vlc = _p_instance->getVLCObject();
+    if( i_vlc )
+    {
+        *index = VLC_PlaylistIndex(i_vlc);
+        return NOERROR;
+    }
+    *index = 0;
+    return E_UNEXPECTED;
+};
+        
+STDMETHODIMP VLCControl::get_PlaylistCount(int *count)
+{
+    int i_vlc = _p_instance->getVLCObject();
+    if( i_vlc )
+    {
+        *count = VLC_PlaylistNumberOfItems(i_vlc);
+        return NOERROR;
+    }
+    return E_UNEXPECTED;
+};
+        
+STDMETHODIMP VLCControl::playlistNext(void)
+{
+    int i_vlc = _p_instance->getVLCObject();
+    if( i_vlc )
+    {
+        VLC_PlaylistNext(i_vlc);
+        return NOERROR;
+    }
+    return E_UNEXPECTED;
+};
+        
+STDMETHODIMP VLCControl::playlistPrev(void)
+{
+    int i_vlc = _p_instance->getVLCObject();
+    if( i_vlc )
+    {
+        VLC_PlaylistPrev(i_vlc);
+        return NOERROR;
+    }
+    return E_UNEXPECTED;
+};
+        
+STDMETHODIMP VLCControl::playlistClear(void)
+{
+    int i_vlc = _p_instance->getVLCObject();
+    if( i_vlc )
+    {
+        VLC_PlaylistClear(i_vlc);
+        return NOERROR;
+    }
+    return E_UNEXPECTED;
+};
+        
+STDMETHODIMP VLCControl::get_VersionInfo(BSTR *version)
+{
+    if( NULL == version )
+        return E_INVALIDARG;
+
+    const char *versionStr = VLC_Version();
+    if( NULL != versionStr )
+    {
+        *version = BSTRFromCStr(_p_instance->getCodePage(), versionStr);
+        
+        return NULL == *version ? E_OUTOFMEMORY : NOERROR;
+    }
+    *version = NULL;
+    return E_FAIL;
+};