]> git.sesse.net Git - vlc/blob - activex/vlccontrol.cpp
livedotcom.cpp: Do not url encode sdp data coming from sap before passing to
[vlc] / activex / vlccontrol.cpp
1 /*****************************************************************************
2  * vlccontrol.cpp: ActiveX control for VLC
3  *****************************************************************************
4  * Copyright (C) 2005 VideoLAN
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         if( VLC_SUCCESS == VLC_VariableType(i_vlc, psz_varname, &i_type) )
359         {
360             VARIANT arg;
361             VariantInit(&arg);
362
363             vlc_value_t val;
364
365             hr = DISP_E_TYPEMISMATCH;
366
367             switch( i_type )
368             {
369                 case VLC_VAR_BOOL:
370                     hr = VariantChangeType(&value, &arg, 0, VT_BOOL);
371                     if( SUCCEEDED(hr) )
372                         val.b_bool = (VARIANT_TRUE == V_BOOL(&arg)) ? VLC_TRUE : VLC_FALSE;
373                     break;
374
375                 case VLC_VAR_INTEGER:
376                     hr = VariantChangeType(&value, &arg, 0, VT_I4);
377                     if( SUCCEEDED(hr) )
378                         val.i_int = V_I4(&arg);
379                     break;
380
381                 case VLC_VAR_FLOAT:
382                     hr = VariantChangeType(&value, &arg, 0, VT_R4);
383                     if( SUCCEEDED(hr) )
384                         val.f_float = V_R4(&arg);
385                     break;
386
387                 case VLC_VAR_STRING:
388                     hr = VariantChangeType(&value, &arg, 0, VT_BSTR);
389                     if( SUCCEEDED(hr) )
390                         val.psz_string = CStrFromBSTR(codePage, V_BSTR(&arg));
391                     break;
392             }
393             if( SUCCEEDED(hr) )
394             {
395                 VariantClear(&arg);
396
397                 hr = (VLC_SUCCESS == VLC_VariableSet(i_vlc, psz_varname, val)) ? NOERROR : E_FAIL;
398
399                 if( (VLC_VAR_STRING == i_type) && (NULL != val.psz_string) )
400                     free(val.psz_string);
401             }
402         }
403         free(psz_varname);
404
405         return hr;
406     }
407     return E_UNEXPECTED;
408 };
409
410 STDMETHODIMP VLCControl::getVariable( BSTR name, VARIANT *value)
411 {
412     if( 0 == SysStringLen(name) )
413         return E_INVALIDARG;
414
415     if( NULL == value )
416         return E_POINTER;
417
418     int i_vlc = _p_instance->getVLCObject();
419     if( i_vlc )
420     {
421         int codePage = _p_instance->getCodePage();
422         char *psz_varname = CStrFromBSTR(codePage, name);
423         if( NULL == psz_varname )
424             return E_OUTOFMEMORY;
425
426         HRESULT hr = E_INVALIDARG;
427
428         vlc_value_t val;
429         int i_type;
430
431         if( (VLC_SUCCESS == VLC_VariableGet(i_vlc, psz_varname, &val))
432          && (VLC_SUCCESS == VLC_VariableType(i_vlc, psz_varname, &i_type)) )
433         {
434             hr = NOERROR;
435             switch( i_type )
436             {
437                 case VLC_VAR_BOOL:
438                     V_VT(value) = VT_BOOL;
439                     V_BOOL(value) = val.b_bool ? VARIANT_TRUE : VARIANT_FALSE;
440                     break;
441
442                 case VLC_VAR_INTEGER:
443                     V_VT(value) = VT_I4;
444                     V_I4(value) = val.i_int;
445                     break;
446
447                 case VLC_VAR_FLOAT:
448                     V_VT(value) = VT_R4;
449                     V_R4(value) = val.f_float;
450                     break;
451
452                 case VLC_VAR_STRING:
453                     V_VT(value) = VT_BSTR;
454                     V_BSTR(value) = BSTRFromCStr(codePage, val.psz_string);
455                     free(val.psz_string);
456                     break;
457                 default:
458                     hr = DISP_E_TYPEMISMATCH;
459             }
460         }
461         free(psz_varname);
462         return hr;
463     }
464     return E_UNEXPECTED;
465 };
466
467 static void freeTargetOptions(char **cOptions, int cOptionCount)
468 {
469     // clean up 
470     for( long pos=0; pos<cOptionCount; ++pos )
471     {
472         char *cOption = cOptions[pos];
473         if( NULL != cOption )
474             free(cOption);
475         else
476             break;
477     }
478     if( NULL != cOptions )
479         free(cOptions);
480 };
481
482 static HRESULT createTargetOptions(int codePage, VARIANT *options, char ***cOptions, int *cOptionCount)
483 {
484     HRESULT hr = E_INVALIDARG;
485     if( VT_ERROR == V_VT(options) )
486     {
487         if( DISP_E_PARAMNOTFOUND == V_ERROR(options) )
488         {
489             // optional parameter not set
490             *cOptions = NULL;
491             *cOptionCount = 0;
492             return NOERROR;
493         }
494     }
495     else if( (VT_EMPTY == V_VT(options)) || (VT_NULL == V_VT(options)) )
496     {
497         // null parameter
498         *cOptions = NULL;
499         *cOptionCount = 0;
500         return NOERROR;
501     }
502     else if( VT_DISPATCH == V_VT(options) )
503     {
504         // collection parameter
505         VARIANT colEnum;
506         V_VT(&colEnum) = VT_UNKNOWN;
507         hr = GetObjectProperty(V_DISPATCH(options), DISPID_NEWENUM, colEnum);
508         if( SUCCEEDED(hr) )
509         {
510             IEnumVARIANT *enumVar;
511             hr = V_UNKNOWN(&colEnum)->QueryInterface(IID_IEnumVARIANT, (LPVOID *)&enumVar);
512             if( SUCCEEDED(hr) )
513             {
514                 long pos = 0;
515                 long capacity = 16;
516                 VARIANT option;
517
518                 *cOptions = (char **)malloc(capacity*sizeof(char *));
519                 if( NULL != *cOptions )
520                 {
521                     ZeroMemory(*cOptions, sizeof(char *)*capacity);
522                     while( SUCCEEDED(hr) && (S_OK == enumVar->Next(1, &option, NULL)) )
523                     {
524                         if( VT_BSTR == V_VT(&option) )
525                         {
526                             char *cOption = CStrFromBSTR(codePage, V_BSTR(&option));
527                             (*cOptions)[pos] = cOption;
528                             if( NULL != cOption )
529                             {
530                                 ++pos;
531                                 if( pos == capacity )
532                                 {
533                                     char **moreOptions = (char **)realloc(*cOptions, (capacity+16)*sizeof(char *));
534                                     if( NULL != moreOptions )
535                                     {
536                                         ZeroMemory(moreOptions+capacity, sizeof(char *)*16);
537                                         capacity += 16;
538                                         *cOptions = moreOptions;
539                                     }
540                                     else
541                                         hr = E_OUTOFMEMORY;
542                                 }
543                             }
544                             else
545                                 hr = E_OUTOFMEMORY;
546                         }
547                         else
548                             hr = E_INVALIDARG;
549
550                         VariantClear(&option);
551                     }
552                     *cOptionCount = pos;
553                     if( FAILED(hr) )
554                     {
555                         // free already processed elements
556                         freeTargetOptions(*cOptions, *cOptionCount);
557                     }
558                 }
559                 else
560                     hr = E_OUTOFMEMORY;
561                 enumVar->Release();
562             }
563         }
564     }
565     else if( V_ISARRAY(options) )
566     {
567         // array parameter
568         SAFEARRAY *array = V_ISBYREF(options) ? *V_ARRAYREF(options) : V_ARRAY(options);
569
570         if( SafeArrayGetDim(array) != 1 )
571             return E_INVALIDARG;
572
573         long lBound = 0;
574         long uBound = 0;
575         SafeArrayGetLBound(array, 1, &lBound);
576         SafeArrayGetUBound(array, 1, &uBound);
577
578         // have we got any options
579         if( uBound > lBound )
580         {
581             VARTYPE vType;
582             HRESULT hr = SafeArrayGetVartype(array, &vType);
583             if( FAILED(hr) )
584                 return hr;
585
586             long pos;
587
588             // marshall options into an array of C strings
589             if( VT_VARIANT == vType )
590             {
591                 *cOptions = (char **)malloc(sizeof(char *)*(uBound-lBound));
592                 if( NULL != options )
593                     return E_OUTOFMEMORY;
594
595                 for(pos=lBound; SUCCEEDED(hr) && (pos<uBound); ++pos )
596                 {
597                     VARIANT option;
598                     hr = SafeArrayGetElement(array, &pos, &option);
599                     if( SUCCEEDED(hr) )
600                     {
601                         if( VT_BSTR == V_VT(&option) ) 
602                         {
603                             char *cOption = CStrFromBSTR(codePage, V_BSTR(&option));
604                             (*cOptions)[pos-lBound] = cOption;
605                             if( NULL == cOption )
606                                 hr = E_OUTOFMEMORY;
607                         }
608                         else
609                             hr = E_INVALIDARG;
610                         VariantClear(&option);
611                     }
612                 }
613             }
614             else if( VT_BSTR == vType )
615             {
616                 *cOptions = (char **)malloc(sizeof(char *)*(uBound-lBound));
617                 if( NULL != options )
618                     return E_OUTOFMEMORY;
619
620                 ZeroMemory(cOptions, sizeof(char *)*(uBound-lBound));
621                 for(pos=lBound; SUCCEEDED(hr) && (pos<uBound); ++pos )
622                 {
623                     BSTR option;
624                     hr = SafeArrayGetElement(array, &pos, &option);
625                     if( SUCCEEDED(hr) )
626                     {
627                         char *cOption = CStrFromBSTR(codePage, option);
628                         (*cOptions)[pos-lBound] = cOption;
629                         if( NULL == cOption )
630                             hr = E_OUTOFMEMORY;
631                         SysFreeString(option);
632                     }
633                 }
634             }
635             else
636                 // unsupported type
637                 return E_INVALIDARG;
638
639             *cOptionCount = pos-lBound;
640             if( FAILED(hr) )
641             {
642                 // free already processed elements
643                 freeTargetOptions(*cOptions, *cOptionCount);
644             }
645         }
646         else
647         {
648             // empty array
649             *cOptions = NULL;
650             *cOptionCount = 0;
651             return NOERROR;
652         }
653     }
654     return hr;
655 };
656
657 /*
658 ** use VARIANT rather than a SAFEARRAY as argument type
659 ** for compatibility with some scripting language (JScript)
660 */
661
662 STDMETHODIMP VLCControl::addTarget( BSTR uri, VARIANT options, enum VLCPlaylistMode mode, int position)
663 {
664     if( 0 == SysStringLen(uri) )
665         return E_INVALIDARG;
666
667     HRESULT hr = E_UNEXPECTED;
668
669     int i_vlc = _p_instance->getVLCObject();
670     if( i_vlc )
671     {
672         int codePage = _p_instance->getCodePage();
673         char *cUri = CStrFromBSTR(codePage, uri);
674         if( NULL == cUri )
675             return E_OUTOFMEMORY;
676
677         int cOptionsCount;
678         char **cOptions;
679
680         if( FAILED(createTargetOptions(codePage, &options, &cOptions, &cOptionsCount)) )
681             return E_INVALIDARG;
682
683         if( VLC_SUCCESS <= VLC_AddTarget(i_vlc, cUri, (const char **)cOptions, cOptionsCount, mode, position) )
684         {
685             hr = NOERROR;
686             if( mode & VLCPlayListGo )
687                 _p_instance->fireOnPlayEvent();
688         }
689         else
690         {
691             hr = E_FAIL;
692             if( mode & VLCPlayListGo )
693                 _p_instance->fireOnStopEvent();
694         }
695
696         freeTargetOptions(cOptions, cOptionsCount);
697         free(cUri);
698     }
699     return hr;
700 };
701         
702 STDMETHODIMP VLCControl::get_PlaylistIndex(int *index)
703 {
704     if( NULL == index )
705         return E_POINTER;
706
707     int i_vlc = _p_instance->getVLCObject();
708     if( i_vlc )
709     {
710         *index = VLC_PlaylistIndex(i_vlc);
711         return NOERROR;
712     }
713     *index = 0;
714     return E_UNEXPECTED;
715 };
716         
717 STDMETHODIMP VLCControl::get_PlaylistCount(int *count)
718 {
719     int i_vlc = _p_instance->getVLCObject();
720     if( i_vlc )
721     {
722         *count = VLC_PlaylistNumberOfItems(i_vlc);
723         return NOERROR;
724     }
725     return E_UNEXPECTED;
726 };
727         
728 STDMETHODIMP VLCControl::playlistNext(void)
729 {
730     int i_vlc = _p_instance->getVLCObject();
731     if( i_vlc )
732     {
733         VLC_PlaylistNext(i_vlc);
734         return NOERROR;
735     }
736     return E_UNEXPECTED;
737 };
738         
739 STDMETHODIMP VLCControl::playlistPrev(void)
740 {
741     int i_vlc = _p_instance->getVLCObject();
742     if( i_vlc )
743     {
744         VLC_PlaylistPrev(i_vlc);
745         return NOERROR;
746     }
747     return E_UNEXPECTED;
748 };
749         
750 STDMETHODIMP VLCControl::playlistClear(void)
751 {
752     int i_vlc = _p_instance->getVLCObject();
753     if( i_vlc )
754     {
755         VLC_PlaylistClear(i_vlc);
756         return NOERROR;
757     }
758     return E_UNEXPECTED;
759 };
760         
761 STDMETHODIMP VLCControl::get_VersionInfo(BSTR *version)
762 {
763     if( NULL == version )
764         return E_POINTER;
765
766     const char *versionStr = VLC_Version();
767     if( NULL != versionStr )
768     {
769         *version = BSTRFromCStr(_p_instance->getCodePage(), versionStr);
770         
771         return NULL == *version ? E_OUTOFMEMORY : NOERROR;
772     }
773     *version = NULL;
774     return E_FAIL;
775 };
776