]> git.sesse.net Git - vlc/blob - activex/vlccontrol.cpp
Make Zorglub less unhappy
[vlc] / activex / vlccontrol.cpp
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  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
21  *****************************************************************************/
22
23 #include "plugin.h"
24 #include "vlccontrol.h"
25
26 #include "utils.h"
27
28 using namespace std;
29
30 VLCControl::~VLCControl()
31 {
32     if( _p_typeinfo )
33         _p_typeinfo->Release();
34 };
35
36 HRESULT VLCControl::getTypeInfo(void)
37 {
38     HRESULT hr = NOERROR;
39     if( NULL == _p_typeinfo )
40     {
41         ITypeLib *p_typelib;
42
43         HRESULT hr = _p_instance->getTypeLib(LOCALE_USER_DEFAULT, &p_typelib);
44         if( SUCCEEDED(hr) )
45         {
46             hr = p_typelib->GetTypeInfoOfGuid(IID_IVLCControl, &_p_typeinfo);
47             if( FAILED(hr) )
48             {
49                 _p_typeinfo = NULL;
50             }
51             p_typelib->Release();
52         }
53     }
54     return hr;
55 };
56
57 STDMETHODIMP VLCControl::GetTypeInfoCount(UINT* pctInfo)
58 {
59     if( NULL == pctInfo )
60         return E_INVALIDARG;
61
62     if( SUCCEEDED(getTypeInfo()) )
63         *pctInfo = 1;
64     else
65         *pctInfo = 0;
66
67     return NOERROR;
68 };
69
70 STDMETHODIMP VLCControl::GetTypeInfo(UINT iTInfo, LCID lcid, LPTYPEINFO* ppTInfo)
71 {
72     if( NULL == ppTInfo )
73         return E_INVALIDARG;
74
75     if( SUCCEEDED(getTypeInfo()) )
76     {
77         _p_typeinfo->AddRef();
78         *ppTInfo = _p_typeinfo;
79         return NO_ERROR;
80     }
81     *ppTInfo = NULL;
82     return E_NOTIMPL;
83 };
84
85 STDMETHODIMP VLCControl::GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, 
86         UINT cNames, LCID lcid, DISPID* rgDispID)
87 {
88     if( SUCCEEDED(getTypeInfo()) )
89     {
90         return DispGetIDsOfNames(_p_typeinfo, rgszNames, cNames, rgDispID);
91     }
92     return E_NOTIMPL;
93 };
94
95 STDMETHODIMP VLCControl::Invoke(DISPID dispIdMember, REFIID riid,
96         LCID lcid, WORD wFlags, DISPPARAMS* pDispParams,
97         VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr)
98 {
99     if( SUCCEEDED(getTypeInfo()) )
100     {
101         return DispInvoke(this, _p_typeinfo, dispIdMember, wFlags, pDispParams,
102                 pVarResult, pExcepInfo, puArgErr);
103     }
104     return E_NOTIMPL;
105 };
106
107 STDMETHODIMP VLCControl::get_Visible(VARIANT_BOOL *isVisible)
108 {
109     if( NULL == isVisible )
110         return E_POINTER;
111
112     *isVisible = _p_instance->getVisible() ? VARIANT_TRUE : VARIANT_FALSE;
113
114     return NOERROR;
115 };
116         
117 STDMETHODIMP VLCControl::put_Visible(VARIANT_BOOL isVisible)
118 {
119     _p_instance->setVisible(isVisible != VARIANT_FALSE);
120
121     return NOERROR;
122 };
123
124 STDMETHODIMP VLCControl::play(void)
125 {
126     int i_vlc = _p_instance->getVLCObject();
127     if( i_vlc )
128     {
129         VLC_Play(i_vlc);
130         _p_instance->fireOnPlayEvent();
131         return NOERROR;
132     }
133     return E_UNEXPECTED;
134 };
135  
136 STDMETHODIMP VLCControl::pause(void)
137 {
138     int i_vlc = _p_instance->getVLCObject();
139     if( i_vlc )
140     {
141         VLC_Pause(i_vlc);
142         _p_instance->fireOnPauseEvent();
143         return NOERROR;
144     }
145     return E_UNEXPECTED;
146 };
147         
148 STDMETHODIMP VLCControl::stop(void)
149 {
150     int i_vlc = _p_instance->getVLCObject();
151     if( i_vlc )
152     {
153         VLC_Stop(i_vlc);
154         _p_instance->fireOnStopEvent();
155         return NOERROR;
156     }
157     return E_UNEXPECTED;
158 }
159         
160 STDMETHODIMP VLCControl::get_Playing(VARIANT_BOOL *isPlaying)
161 {
162     if( NULL == isPlaying )
163         return E_POINTER;
164
165     int i_vlc = _p_instance->getVLCObject();
166     if( i_vlc )
167     {
168         *isPlaying = VLC_IsPlaying(i_vlc) ? VARIANT_TRUE : VARIANT_FALSE;
169         return NOERROR;
170     }
171     *isPlaying = VARIANT_FALSE;
172     return E_UNEXPECTED;
173 };
174         
175 STDMETHODIMP VLCControl::put_Playing(VARIANT_BOOL isPlaying)
176 {
177     int i_vlc = _p_instance->getVLCObject();
178     if( i_vlc )
179     {
180         if( VARIANT_FALSE == isPlaying )
181         {
182             if( VLC_IsPlaying(i_vlc) )
183                 VLC_Stop(i_vlc);
184         }
185         else
186         {
187             if( ! VLC_IsPlaying(i_vlc) )
188                 VLC_Play(i_vlc);
189         }
190         return NOERROR;
191     }
192     return E_UNEXPECTED;
193 };
194         
195 STDMETHODIMP VLCControl::get_Position(float *position)
196 {
197     if( NULL == position )
198         return E_POINTER;
199
200     int i_vlc = _p_instance->getVLCObject();
201     if( i_vlc )
202     {
203         *position = VLC_PositionGet(i_vlc);
204         return NOERROR;
205     }
206     *position = 0.0f;
207     return E_UNEXPECTED;
208 };
209         
210 STDMETHODIMP VLCControl::put_Position(float position)
211 {
212     int i_vlc = _p_instance->getVLCObject();
213     if( i_vlc )
214     {
215         VLC_PositionSet(i_vlc, position);
216         return NOERROR;
217     }
218     return E_UNEXPECTED;
219 };
220         
221 STDMETHODIMP VLCControl::get_Time(int *seconds)
222 {
223     if( NULL == seconds )
224         return E_POINTER;
225
226     int i_vlc = _p_instance->getVLCObject();
227     if( i_vlc )
228     {
229         *seconds = VLC_TimeGet(i_vlc);
230         return NOERROR;
231     }
232     *seconds = 0;
233     return E_UNEXPECTED;
234 };
235         
236 STDMETHODIMP VLCControl::put_Time(int seconds)
237 {
238     int i_vlc = _p_instance->getVLCObject();
239     if( i_vlc )
240     {
241         VLC_TimeSet(i_vlc, seconds, VLC_FALSE);
242         return NOERROR;
243     }
244     return E_UNEXPECTED;
245 };
246         
247 STDMETHODIMP VLCControl::shuttle(int seconds)
248 {
249     int i_vlc = _p_instance->getVLCObject();
250     if( i_vlc )
251     {
252         VLC_TimeSet(i_vlc, seconds, VLC_TRUE);
253         return NOERROR;
254     }
255     return E_UNEXPECTED;
256 };
257         
258 STDMETHODIMP VLCControl::fullscreen(void)
259 {
260     int i_vlc = _p_instance->getVLCObject();
261     if( i_vlc )
262     {
263         VLC_FullScreen(i_vlc);
264         return NOERROR;
265     }
266     return E_UNEXPECTED;
267 };
268         
269 STDMETHODIMP VLCControl::get_Length(int *seconds)
270 {
271     if( NULL == seconds )
272         return E_POINTER;
273
274     int i_vlc = _p_instance->getVLCObject();
275     if( i_vlc )
276     {
277         *seconds = VLC_LengthGet(i_vlc);
278         return NOERROR;
279     }
280     *seconds = 0;
281     return E_UNEXPECTED;
282 };
283         
284 STDMETHODIMP VLCControl::playFaster(void)
285 {
286     int i_vlc = _p_instance->getVLCObject();
287     if( i_vlc )
288     {
289         VLC_SpeedFaster(i_vlc);
290         return NOERROR;
291     }
292     return E_UNEXPECTED;
293 };
294         
295 STDMETHODIMP VLCControl::playSlower(void)
296 {
297     int i_vlc = _p_instance->getVLCObject();
298     if( i_vlc )
299     {
300         VLC_SpeedSlower(i_vlc);
301         return NOERROR;
302     }
303     return E_UNEXPECTED;
304 };
305         
306 STDMETHODIMP VLCControl::get_Volume(int *volume)
307 {
308     if( NULL == volume )
309         return E_POINTER;
310
311     int i_vlc = _p_instance->getVLCObject();
312     if( i_vlc )
313     {
314         *volume  = VLC_VolumeGet(i_vlc);
315         return NOERROR;
316     }
317     *volume = 0;
318     return E_UNEXPECTED;
319 };
320         
321 STDMETHODIMP VLCControl::put_Volume(int volume)
322 {
323     int i_vlc = _p_instance->getVLCObject();
324     if( i_vlc )
325     {
326         VLC_VolumeSet(i_vlc, volume);
327         return NOERROR;
328     }
329     return E_UNEXPECTED;
330 };
331         
332 STDMETHODIMP VLCControl::toggleMute(void)
333 {
334     int i_vlc = _p_instance->getVLCObject();
335     if( i_vlc )
336     {
337         VLC_VolumeMute(i_vlc);
338         return NOERROR;
339     }
340     return E_UNEXPECTED;
341 };
342
343 STDMETHODIMP VLCControl::setVariable( BSTR name, VARIANT value)
344 {
345     if( 0 == SysStringLen(name) )
346         return E_INVALIDARG;
347
348     int i_vlc = _p_instance->getVLCObject();
349     if( i_vlc )
350     {
351         int codePage = _p_instance->getCodePage();
352         char *psz_varname = CStrFromBSTR(codePage, name);
353         if( NULL == psz_varname )
354             return E_OUTOFMEMORY;
355
356         HRESULT hr = E_INVALIDARG;
357         int i_type;
358         vlc_value_t val;
359         
360         if( VLC_SUCCESS == VLC_VariableType(i_vlc, psz_varname, &i_type) )
361         {
362             VARIANT arg;
363             VariantInit(&arg);
364
365             switch( i_type )
366             {
367                 case VLC_VAR_BOOL:
368                     hr = VariantChangeType(&value, &arg, 0, VT_BOOL);
369                     if( SUCCEEDED(hr) )
370                         val.b_bool = (VARIANT_TRUE == V_BOOL(&arg)) ? VLC_TRUE : VLC_FALSE;
371                     break;
372
373                 case VLC_VAR_INTEGER:
374                 case VLC_VAR_HOTKEY:
375                     hr = VariantChangeType(&value, &arg, 0, VT_I4);
376                     if( SUCCEEDED(hr) )
377                         val.i_int = V_I4(&arg);
378                     break;
379
380                 case VLC_VAR_FLOAT:
381                     hr = VariantChangeType(&value, &arg, 0, VT_R4);
382                     if( SUCCEEDED(hr) )
383                         val.f_float = V_R4(&arg);
384                     break;
385
386                 case VLC_VAR_STRING:
387                 case VLC_VAR_MODULE:
388                 case VLC_VAR_FILE:
389                 case VLC_VAR_DIRECTORY:
390                 case VLC_VAR_VARIABLE:
391                     hr = VariantChangeType(&value, &arg, 0, VT_BSTR);
392                     if( SUCCEEDED(hr) )
393                     {
394                         val.psz_string = CStrFromBSTR(codePage, V_BSTR(&arg));
395                         VariantClear(&arg);
396                     }
397                     break;
398
399                 case VLC_VAR_TIME:
400                     // use a double value to represent time (base is expressed in seconds)
401                     hr = VariantChangeType(&value, &arg, 0, VT_R8);
402                     if( SUCCEEDED(hr) )
403                         val.i_time = (signed __int64)(V_R8(&arg)*1000000.0);
404                     break;
405
406                 default:
407                     hr = DISP_E_TYPEMISMATCH;
408             }
409         }
410         else {
411             // no defined type, defaults to VARIANT type
412             hr = NO_ERROR;
413             switch( V_VT(&value) )
414             {
415                 case VT_BOOL:
416                     val.b_bool = (VARIANT_TRUE == V_BOOL(&value)) ? VLC_TRUE : VLC_FALSE;
417                     i_type = VLC_VAR_BOOL;
418                     break;
419                 case VT_I4:
420                     val.i_int = V_I4(&value);
421                     i_type = VLC_VAR_INTEGER;
422                     break;
423                 case VT_R4:
424                     val.f_float = V_R4(&value);
425                     i_type = VLC_VAR_FLOAT;
426                     break;
427                 case VT_BSTR:
428                     val.psz_string = CStrFromBSTR(codePage, V_BSTR(&value));
429                     i_type = VLC_VAR_STRING;
430                     break;
431                 case VT_R8:
432                     // use a double value to represent time (base is expressed in seconds)
433                     val.i_time = (signed __int64)(V_R8(&value)*1000000.0);
434                     i_type = VLC_VAR_TIME;
435                     break;
436                 default:
437                     hr = DISP_E_TYPEMISMATCH;
438             }
439         }
440         if( SUCCEEDED(hr) )
441         {
442             hr = (VLC_SUCCESS == VLC_VariableSet(i_vlc, psz_varname, val)) ? NOERROR : E_FAIL;
443
444             if( (VLC_VAR_STRING == i_type) && (NULL != val.psz_string) )
445                 free(val.psz_string);
446         }
447         free(psz_varname);
448
449         return hr;
450     }
451     return E_UNEXPECTED;
452 };
453
454 STDMETHODIMP VLCControl::getVariable( BSTR name, VARIANT *value)
455 {
456     if( 0 == SysStringLen(name) )
457         return E_INVALIDARG;
458
459     if( NULL == value )
460         return E_POINTER;
461
462     int i_vlc = _p_instance->getVLCObject();
463     if( i_vlc )
464     {
465         int codePage = _p_instance->getCodePage();
466         char *psz_varname = CStrFromBSTR(codePage, name);
467         if( NULL == psz_varname )
468             return E_OUTOFMEMORY;
469
470         HRESULT hr = E_INVALIDARG;
471
472         vlc_value_t val;
473         int i_type;
474
475         if( (VLC_SUCCESS == VLC_VariableGet(i_vlc, psz_varname, &val))
476          && (VLC_SUCCESS == VLC_VariableType(i_vlc, psz_varname, &i_type)) )
477         {
478             hr = NOERROR;
479             switch( i_type )
480             {
481                 case VLC_VAR_BOOL:
482                     V_VT(value) = VT_BOOL;
483                     V_BOOL(value) = val.b_bool ? VARIANT_TRUE : VARIANT_FALSE;
484                     break;
485
486                 case VLC_VAR_INTEGER:
487                 case VLC_VAR_HOTKEY:
488                     V_VT(value) = VT_I4;
489                     V_I4(value) = val.i_int;
490                     break;
491
492                 case VLC_VAR_FLOAT:
493                     V_VT(value) = VT_R4;
494                     V_R4(value) = val.f_float;
495                     break;
496
497                 case VLC_VAR_STRING:
498                 case VLC_VAR_MODULE:
499                 case VLC_VAR_FILE:
500                 case VLC_VAR_DIRECTORY:
501                 case VLC_VAR_VARIABLE:
502                     V_VT(value) = VT_BSTR;
503                     V_BSTR(value) = BSTRFromCStr(codePage, val.psz_string);
504                     free(val.psz_string);
505                     break;
506
507                 case VLC_VAR_TIME:
508                     // use a double value to represent time (base is expressed in seconds)
509                     V_VT(value) = VT_R8;
510                     V_R8(value) = ((double)val.i_time)/1000000.0;
511                     break;
512
513                 default:
514                     hr = DISP_E_TYPEMISMATCH;
515             }
516         }
517         free(psz_varname);
518         return hr;
519     }
520     return E_UNEXPECTED;
521 };
522
523 static void freeTargetOptions(char **cOptions, int cOptionCount)
524 {
525     // clean up 
526     for( long pos=0; pos<cOptionCount; ++pos )
527     {
528         char *cOption = cOptions[pos];
529         if( NULL != cOption )
530             free(cOption);
531         else
532             break;
533     }
534     if( NULL != cOptions )
535         free(cOptions);
536 };
537
538 static HRESULT createTargetOptions(int codePage, VARIANT *options, char ***cOptions, int *cOptionCount)
539 {
540     HRESULT hr = E_INVALIDARG;
541     if( VT_ERROR == V_VT(options) )
542     {
543         if( DISP_E_PARAMNOTFOUND == V_ERROR(options) )
544         {
545             // optional parameter not set
546             *cOptions = NULL;
547             *cOptionCount = 0;
548             return NOERROR;
549         }
550     }
551     else if( (VT_EMPTY == V_VT(options)) || (VT_NULL == V_VT(options)) )
552     {
553         // null parameter
554         *cOptions = NULL;
555         *cOptionCount = 0;
556         return NOERROR;
557     }
558     else if( VT_DISPATCH == V_VT(options) )
559     {
560         // collection parameter
561         VARIANT colEnum;
562         V_VT(&colEnum) = VT_UNKNOWN;
563         hr = GetObjectProperty(V_DISPATCH(options), DISPID_NEWENUM, colEnum);
564         if( SUCCEEDED(hr) )
565         {
566             IEnumVARIANT *enumVar;
567             hr = V_UNKNOWN(&colEnum)->QueryInterface(IID_IEnumVARIANT, (LPVOID *)&enumVar);
568             if( SUCCEEDED(hr) )
569             {
570                 long pos = 0;
571                 long capacity = 16;
572                 VARIANT option;
573
574                 *cOptions = (char **)malloc(capacity*sizeof(char *));
575                 if( NULL != *cOptions )
576                 {
577                     ZeroMemory(*cOptions, sizeof(char *)*capacity);
578                     while( SUCCEEDED(hr) && (S_OK == enumVar->Next(1, &option, NULL)) )
579                     {
580                         if( VT_BSTR == V_VT(&option) )
581                         {
582                             char *cOption = CStrFromBSTR(codePage, V_BSTR(&option));
583                             (*cOptions)[pos] = cOption;
584                             if( NULL != cOption )
585                             {
586                                 ++pos;
587                                 if( pos == capacity )
588                                 {
589                                     char **moreOptions = (char **)realloc(*cOptions, (capacity+16)*sizeof(char *));
590                                     if( NULL != moreOptions )
591                                     {
592                                         ZeroMemory(moreOptions+capacity, sizeof(char *)*16);
593                                         capacity += 16;
594                                         *cOptions = moreOptions;
595                                     }
596                                     else
597                                         hr = E_OUTOFMEMORY;
598                                 }
599                             }
600                             else
601                                 hr = E_OUTOFMEMORY;
602                         }
603                         else
604                             hr = E_INVALIDARG;
605
606                         VariantClear(&option);
607                     }
608                     *cOptionCount = pos;
609                     if( FAILED(hr) )
610                     {
611                         // free already processed elements
612                         freeTargetOptions(*cOptions, *cOptionCount);
613                     }
614                 }
615                 else
616                     hr = E_OUTOFMEMORY;
617                 enumVar->Release();
618             }
619         }
620     }
621     else if( V_ISARRAY(options) )
622     {
623         // array parameter
624         SAFEARRAY *array = V_ISBYREF(options) ? *V_ARRAYREF(options) : V_ARRAY(options);
625
626         if( SafeArrayGetDim(array) != 1 )
627             return E_INVALIDARG;
628
629         long lBound = 0;
630         long uBound = 0;
631         SafeArrayGetLBound(array, 1, &lBound);
632         SafeArrayGetUBound(array, 1, &uBound);
633
634         // have we got any options
635         if( uBound > lBound )
636         {
637             VARTYPE vType;
638             HRESULT hr = SafeArrayGetVartype(array, &vType);
639             if( FAILED(hr) )
640                 return hr;
641
642             long pos;
643
644             // marshall options into an array of C strings
645             if( VT_VARIANT == vType )
646             {
647                 *cOptions = (char **)malloc(sizeof(char *)*(uBound-lBound));
648                 if( NULL != options )
649                     return E_OUTOFMEMORY;
650
651                 for(pos=lBound; SUCCEEDED(hr) && (pos<uBound); ++pos )
652                 {
653                     VARIANT option;
654                     hr = SafeArrayGetElement(array, &pos, &option);
655                     if( SUCCEEDED(hr) )
656                     {
657                         if( VT_BSTR == V_VT(&option) ) 
658                         {
659                             char *cOption = CStrFromBSTR(codePage, V_BSTR(&option));
660                             (*cOptions)[pos-lBound] = cOption;
661                             if( NULL == cOption )
662                                 hr = E_OUTOFMEMORY;
663                         }
664                         else
665                             hr = E_INVALIDARG;
666                         VariantClear(&option);
667                     }
668                 }
669             }
670             else if( VT_BSTR == vType )
671             {
672                 *cOptions = (char **)malloc(sizeof(char *)*(uBound-lBound));
673                 if( NULL != options )
674                     return E_OUTOFMEMORY;
675
676                 ZeroMemory(cOptions, sizeof(char *)*(uBound-lBound));
677                 for(pos=lBound; SUCCEEDED(hr) && (pos<uBound); ++pos )
678                 {
679                     BSTR option;
680                     hr = SafeArrayGetElement(array, &pos, &option);
681                     if( SUCCEEDED(hr) )
682                     {
683                         char *cOption = CStrFromBSTR(codePage, option);
684                         (*cOptions)[pos-lBound] = cOption;
685                         if( NULL == cOption )
686                             hr = E_OUTOFMEMORY;
687                         SysFreeString(option);
688                     }
689                 }
690             }
691             else
692                 // unsupported type
693                 return E_INVALIDARG;
694
695             *cOptionCount = pos-lBound;
696             if( FAILED(hr) )
697             {
698                 // free already processed elements
699                 freeTargetOptions(*cOptions, *cOptionCount);
700             }
701         }
702         else
703         {
704             // empty array
705             *cOptions = NULL;
706             *cOptionCount = 0;
707             return NOERROR;
708         }
709     }
710     return hr;
711 };
712
713 /*
714 ** use VARIANT rather than a SAFEARRAY as argument type
715 ** for compatibility with some scripting language (JScript)
716 */
717
718 STDMETHODIMP VLCControl::addTarget( BSTR uri, VARIANT options, enum VLCPlaylistMode mode, int position)
719 {
720     if( 0 == SysStringLen(uri) )
721         return E_INVALIDARG;
722
723     HRESULT hr = E_UNEXPECTED;
724
725     int i_vlc = _p_instance->getVLCObject();
726     if( i_vlc )
727     {
728         int codePage = _p_instance->getCodePage();
729         char *cUri = CStrFromBSTR(codePage, uri);
730         if( NULL == cUri )
731             return E_OUTOFMEMORY;
732
733         int cOptionsCount;
734         char **cOptions;
735
736         if( FAILED(createTargetOptions(codePage, &options, &cOptions, &cOptionsCount)) )
737             return E_INVALIDARG;
738
739         if( VLC_SUCCESS <= VLC_AddTarget(i_vlc, cUri, (const char **)cOptions, cOptionsCount, mode, position) )
740         {
741             hr = NOERROR;
742             if( mode & VLCPlayListGo )
743                 _p_instance->fireOnPlayEvent();
744         }
745         else
746         {
747             hr = E_FAIL;
748             if( mode & VLCPlayListGo )
749                 _p_instance->fireOnStopEvent();
750         }
751
752         freeTargetOptions(cOptions, cOptionsCount);
753         free(cUri);
754     }
755     return hr;
756 };
757         
758 STDMETHODIMP VLCControl::get_PlaylistIndex(int *index)
759 {
760     if( NULL == index )
761         return E_POINTER;
762
763     int i_vlc = _p_instance->getVLCObject();
764     if( i_vlc )
765     {
766         *index = VLC_PlaylistIndex(i_vlc);
767         return NOERROR;
768     }
769     *index = 0;
770     return E_UNEXPECTED;
771 };
772         
773 STDMETHODIMP VLCControl::get_PlaylistCount(int *count)
774 {
775     int i_vlc = _p_instance->getVLCObject();
776     if( i_vlc )
777     {
778         *count = VLC_PlaylistNumberOfItems(i_vlc);
779         return NOERROR;
780     }
781     return E_UNEXPECTED;
782 };
783         
784 STDMETHODIMP VLCControl::playlistNext(void)
785 {
786     int i_vlc = _p_instance->getVLCObject();
787     if( i_vlc )
788     {
789         VLC_PlaylistNext(i_vlc);
790         return NOERROR;
791     }
792     return E_UNEXPECTED;
793 };
794         
795 STDMETHODIMP VLCControl::playlistPrev(void)
796 {
797     int i_vlc = _p_instance->getVLCObject();
798     if( i_vlc )
799     {
800         VLC_PlaylistPrev(i_vlc);
801         return NOERROR;
802     }
803     return E_UNEXPECTED;
804 };
805         
806 STDMETHODIMP VLCControl::playlistClear(void)
807 {
808     int i_vlc = _p_instance->getVLCObject();
809     if( i_vlc )
810     {
811         VLC_PlaylistClear(i_vlc);
812         return NOERROR;
813     }
814     return E_UNEXPECTED;
815 };
816         
817 STDMETHODIMP VLCControl::get_VersionInfo(BSTR *version)
818 {
819     if( NULL == version )
820         return E_POINTER;
821
822     const char *versionStr = VLC_Version();
823     if( NULL != versionStr )
824     {
825         *version = BSTRFromCStr(_p_instance->getCodePage(), versionStr);
826         
827         return NULL == *version ? E_OUTOFMEMORY : NOERROR;
828     }
829     *version = NULL;
830     return E_FAIL;
831 };
832