]> git.sesse.net Git - vlc/blob - activex/vlccontrol.cpp
- miscelleanous fixes and improvements
[vlc] / activex / vlccontrol.cpp
1 /*****************************************************************************\r
2  * vlccontrol.cpp: ActiveX control for VLC\r
3  *****************************************************************************\r
4  * Copyright (C) 2005 VideoLAN\r
5  *\r
6  * Authors: Damien Fouilleul <Damien.Fouilleul@laposte.net>\r
7  *\r
8  * This program is free software; you can redistribute it and/or modify\r
9  * it under the terms of the GNU General Public License as published by\r
10  * the Free Software Foundation; either version 2 of the License, or\r
11  * (at your option) any later version.\r
12  *\r
13  * This program is distributed in the hope that it will be useful,\r
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
16  * GNU General Public License for more details.\r
17  *\r
18  * You should have received a copy of the GNU General Public License\r
19  * along with this program; if not, write to the Free Software\r
20  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.\r
21  *****************************************************************************/\r
22 \r
23 #include "plugin.h"\r
24 #include "vlccontrol.h"\r
25 \r
26 #include "utils.h"\r
27 \r
28 VLCControl::~VLCControl()\r
29 {\r
30     if( _p_typeinfo )\r
31         _p_typeinfo->Release();\r
32 };\r
33 \r
34 HRESULT VLCControl::getTypeInfo(void)\r
35 {\r
36     HRESULT hr = NOERROR;\r
37     if( NULL == _p_typeinfo )\r
38     {\r
39         ITypeLib *p_typelib;\r
40 \r
41         HRESULT hr = _p_instance->getTypeLib(LOCALE_USER_DEFAULT, &p_typelib);\r
42         if( SUCCEEDED(hr) )\r
43         {\r
44             hr = p_typelib->GetTypeInfoOfGuid(IID_IVLCControl, &_p_typeinfo);\r
45             if( FAILED(hr) )\r
46             {\r
47                 _p_typeinfo = NULL;\r
48             }\r
49             p_typelib->Release();\r
50         }\r
51     }\r
52     return hr;\r
53 };\r
54 \r
55 STDMETHODIMP VLCControl::GetTypeInfoCount(UINT* pctInfo)\r
56 {\r
57     if( SUCCEEDED(getTypeInfo()) )\r
58         *pctInfo = 1;\r
59     else\r
60         *pctInfo = 0;\r
61 \r
62     return NOERROR;\r
63 };\r
64 \r
65 STDMETHODIMP VLCControl::GetTypeInfo(UINT iTInfo, LCID lcid, LPTYPEINFO* ppTInfo)\r
66 {\r
67     if( NULL == ppTInfo )\r
68         return E_INVALIDARG;\r
69 \r
70     if( SUCCEEDED(getTypeInfo()) )\r
71     {\r
72         _p_typeinfo->AddRef();\r
73         *ppTInfo = _p_typeinfo;\r
74         return NO_ERROR;\r
75     }\r
76     *ppTInfo = NULL;\r
77     return E_NOTIMPL;\r
78 };\r
79 \r
80 STDMETHODIMP VLCControl::GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, \r
81         UINT cNames, LCID lcid, DISPID* rgDispID)\r
82 {\r
83     if( SUCCEEDED(getTypeInfo()) )\r
84     {\r
85         return DispGetIDsOfNames(_p_typeinfo, rgszNames, cNames, rgDispID);\r
86     }\r
87     return E_NOTIMPL;\r
88 };\r
89 \r
90 STDMETHODIMP VLCControl::Invoke(DISPID dispIdMember, REFIID riid,\r
91         LCID lcid, WORD wFlags, DISPPARAMS* pDispParams,\r
92         VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr)\r
93 {\r
94     if( SUCCEEDED(getTypeInfo()) )\r
95     {\r
96         return DispInvoke(this, _p_typeinfo, dispIdMember, wFlags, pDispParams,\r
97                 pVarResult, pExcepInfo, puArgErr);\r
98     }\r
99     return E_NOTIMPL;\r
100 };\r
101 \r
102 STDMETHODIMP VLCControl::get_Value(VARIANT *pvarValue)\r
103 {\r
104     if( NULL == pvarValue )\r
105         return E_INVALIDARG;\r
106 \r
107     V_VT(pvarValue) = VT_BOOL;\r
108     return get_Playing(&V_BOOL(pvarValue));\r
109 };\r
110         \r
111 STDMETHODIMP VLCControl::put_Value(VARIANT pvarValue)\r
112 {\r
113     if( VT_BOOL != V_VT(&pvarValue) )\r
114     {\r
115         VARIANT boolValue;\r
116         HRESULT hr = VariantChangeType(&boolValue, &pvarValue, 0, VT_BOOL);\r
117         if( SUCCEEDED(hr) )\r
118         {\r
119             hr = get_Playing(&V_BOOL(&pvarValue));\r
120             //VariantClear(&boolValue);\r
121         }\r
122         return hr;\r
123     }\r
124     return get_Playing(&V_BOOL(&pvarValue));\r
125 };\r
126         \r
127 STDMETHODIMP VLCControl::get_Visible(VARIANT_BOOL *isVisible)\r
128 {\r
129     if( NULL == isVisible )\r
130         return E_INVALIDARG;\r
131 \r
132     *isVisible = _p_instance->getVisible();\r
133 \r
134     return NOERROR;\r
135 };\r
136         \r
137 STDMETHODIMP VLCControl::put_Visible(VARIANT_BOOL isVisible)\r
138 {\r
139     _p_instance->setVisible(isVisible != VARIANT_FALSE);\r
140 \r
141     return NOERROR;\r
142 };\r
143 \r
144 STDMETHODIMP VLCControl::play(void)\r
145 {\r
146     int i_vlc = _p_instance->getVLCObject();\r
147     if( i_vlc )\r
148     {\r
149         VLC_Play(i_vlc);\r
150         _p_instance->fireOnPlayEvent();\r
151         return NOERROR;\r
152     }\r
153     return E_UNEXPECTED;\r
154 };\r
155  \r
156 STDMETHODIMP VLCControl::pause(void)\r
157 {\r
158     int i_vlc = _p_instance->getVLCObject();\r
159     if( i_vlc )\r
160     {\r
161         VLC_Pause(i_vlc);\r
162         _p_instance->fireOnPauseEvent();\r
163         return NOERROR;\r
164     }\r
165     return E_UNEXPECTED;\r
166 };\r
167         \r
168 STDMETHODIMP VLCControl::stop(void)\r
169 {\r
170     int i_vlc = _p_instance->getVLCObject();\r
171     if( i_vlc )\r
172     {\r
173         VLC_Stop(i_vlc);\r
174         _p_instance->fireOnStopEvent();\r
175         return NOERROR;\r
176     }\r
177     return E_UNEXPECTED;\r
178 }\r
179         \r
180 STDMETHODIMP VLCControl::get_Playing(VARIANT_BOOL *isPlaying)\r
181 {\r
182     if( NULL == isPlaying )\r
183         return E_INVALIDARG;\r
184 \r
185     int i_vlc = _p_instance->getVLCObject();\r
186     if( i_vlc )\r
187     {\r
188         *isPlaying = VLC_IsPlaying(i_vlc) ? VARIANT_TRUE : VARIANT_FALSE;\r
189         return NOERROR;\r
190     }\r
191     *isPlaying = VARIANT_FALSE;\r
192     return E_UNEXPECTED;\r
193 };\r
194         \r
195 STDMETHODIMP VLCControl::put_Playing(VARIANT_BOOL isPlaying)\r
196 {\r
197     int i_vlc = _p_instance->getVLCObject();\r
198     if( i_vlc )\r
199     {\r
200         if( VARIANT_FALSE == isPlaying )\r
201         {\r
202             if( VLC_IsPlaying(i_vlc) )\r
203                 VLC_Stop(i_vlc);\r
204         }\r
205         else\r
206         {\r
207             if( ! VLC_IsPlaying(i_vlc) )\r
208                 VLC_Play(i_vlc);\r
209         }\r
210         return NOERROR;\r
211     }\r
212     return E_UNEXPECTED;\r
213 };\r
214         \r
215 STDMETHODIMP VLCControl::get_Position(float *position)\r
216 {\r
217     if( NULL == position )\r
218         return E_INVALIDARG;\r
219 \r
220     int i_vlc = _p_instance->getVLCObject();\r
221     if( i_vlc )\r
222     {\r
223         *position = VLC_PositionGet(i_vlc);\r
224         return NOERROR;\r
225     }\r
226     *position = 0.0f;\r
227     return E_UNEXPECTED;\r
228 };\r
229         \r
230 STDMETHODIMP VLCControl::put_Position(float position)\r
231 {\r
232     int i_vlc = _p_instance->getVLCObject();\r
233     if( i_vlc )\r
234     {\r
235         VLC_PositionSet(i_vlc, position);\r
236         return NOERROR;\r
237     }\r
238     return E_UNEXPECTED;\r
239 };\r
240         \r
241 STDMETHODIMP VLCControl::get_Time(int *seconds)\r
242 {\r
243     if( NULL == seconds )\r
244         return E_INVALIDARG;\r
245 \r
246     int i_vlc = _p_instance->getVLCObject();\r
247     if( i_vlc )\r
248     {\r
249         *seconds = VLC_TimeGet(i_vlc);\r
250         return NOERROR;\r
251     }\r
252     *seconds = 0;\r
253     return E_UNEXPECTED;\r
254 };\r
255         \r
256 STDMETHODIMP VLCControl::put_Time(int seconds)\r
257 {\r
258     int i_vlc = _p_instance->getVLCObject();\r
259     if( i_vlc )\r
260     {\r
261         VLC_TimeSet(i_vlc, seconds, VLC_FALSE);\r
262         return NOERROR;\r
263     }\r
264     return E_UNEXPECTED;\r
265 };\r
266         \r
267 STDMETHODIMP VLCControl::shuttle(int seconds)\r
268 {\r
269     int i_vlc = _p_instance->getVLCObject();\r
270     if( i_vlc )\r
271     {\r
272         VLC_TimeSet(i_vlc, seconds, VLC_TRUE);\r
273         return NOERROR;\r
274     }\r
275     return E_UNEXPECTED;\r
276 };\r
277         \r
278 STDMETHODIMP VLCControl::fullscreen(void)\r
279 {\r
280     int i_vlc = _p_instance->getVLCObject();\r
281     if( i_vlc )\r
282     {\r
283         VLC_FullScreen(i_vlc);\r
284         return NOERROR;\r
285     }\r
286     return E_UNEXPECTED;\r
287 };\r
288         \r
289 STDMETHODIMP VLCControl::get_Length(int *seconds)\r
290 {\r
291     if( NULL == seconds )\r
292         return E_INVALIDARG;\r
293 \r
294     int i_vlc = _p_instance->getVLCObject();\r
295     if( i_vlc )\r
296     {\r
297         *seconds = VLC_LengthGet(i_vlc);\r
298         return NOERROR;\r
299     }\r
300     *seconds = 0;\r
301     return E_UNEXPECTED;\r
302 };\r
303         \r
304 STDMETHODIMP VLCControl::playFaster(void)\r
305 {\r
306     int i_vlc = _p_instance->getVLCObject();\r
307     if( i_vlc )\r
308     {\r
309         VLC_SpeedFaster(i_vlc);\r
310         return NOERROR;\r
311     }\r
312     return E_UNEXPECTED;\r
313 };\r
314         \r
315 STDMETHODIMP VLCControl::playSlower(void)\r
316 {\r
317     int i_vlc = _p_instance->getVLCObject();\r
318     if( i_vlc )\r
319     {\r
320         VLC_SpeedSlower(i_vlc);\r
321         return NOERROR;\r
322     }\r
323     return E_UNEXPECTED;\r
324 };\r
325         \r
326 STDMETHODIMP VLCControl::get_Volume(int *volume)\r
327 {\r
328     if( NULL == volume )\r
329         return E_INVALIDARG;\r
330 \r
331     int i_vlc = _p_instance->getVLCObject();\r
332     if( i_vlc )\r
333     {\r
334         *volume  = VLC_VolumeGet(i_vlc);\r
335         return NOERROR;\r
336     }\r
337     *volume = 0;\r
338     return E_UNEXPECTED;\r
339 };\r
340         \r
341 STDMETHODIMP VLCControl::put_Volume(int volume)\r
342 {\r
343     int i_vlc = _p_instance->getVLCObject();\r
344     if( i_vlc )\r
345     {\r
346         VLC_VolumeSet(i_vlc, volume);\r
347         return NOERROR;\r
348     }\r
349     return E_UNEXPECTED;\r
350 };\r
351         \r
352 STDMETHODIMP VLCControl::toggleMute(void)\r
353 {\r
354     int i_vlc = _p_instance->getVLCObject();\r
355     if( i_vlc )\r
356     {\r
357         VLC_VolumeMute(i_vlc);\r
358         return NOERROR;\r
359     }\r
360     return E_UNEXPECTED;\r
361 };\r
362 \r
363 static void freeTargetOptions(char **cOptions, int cOptionCount)\r
364 {\r
365     // clean up \r
366     for( long pos=0; pos<cOptionCount; ++pos )\r
367     {\r
368         char *cOption = cOptions[pos];\r
369         if( NULL != cOption )\r
370             free(cOption);\r
371         else\r
372             break;\r
373     }\r
374     if( NULL != cOptions )\r
375         free(cOptions);\r
376 };\r
377 \r
378 static HRESULT createTargetOptions(int codePage, VARIANT *options, char ***cOptions, int *cOptionCount)\r
379 {\r
380     HRESULT hr = E_INVALIDARG;\r
381     if( VT_ERROR == V_VT(options) )\r
382     {\r
383         if( DISP_E_PARAMNOTFOUND == V_ERROR(options) )\r
384         {\r
385             // optional parameter not set\r
386             *cOptions = NULL;\r
387             *cOptionCount = 0;\r
388             return NOERROR;\r
389         }\r
390     }\r
391     else if( (VT_EMPTY == V_VT(options)) || (VT_NULL == V_VT(options)) )\r
392     {\r
393         // null parameter\r
394         *cOptions = NULL;\r
395         *cOptionCount = 0;\r
396         return NOERROR;\r
397     }\r
398     else if( VT_DISPATCH == V_VT(options) )\r
399     {\r
400         // collection parameter\r
401         VARIANT colEnum;\r
402         V_VT(&colEnum) = VT_UNKNOWN;\r
403         hr = GetObjectProperty(V_DISPATCH(options), DISPID_NEWENUM, colEnum);\r
404         if( SUCCEEDED(hr) )\r
405         {\r
406             IEnumVARIANT *enumVar;\r
407             hr = V_UNKNOWN(&colEnum)->QueryInterface(IID_IEnumVARIANT, (LPVOID *)&enumVar);\r
408             if( SUCCEEDED(hr) )\r
409             {\r
410                 long pos = 0;\r
411                 long capacity = 16;\r
412                 VARIANT option;\r
413 \r
414                 *cOptions = (char **)malloc(capacity*sizeof(char *));\r
415                 if( NULL != *cOptions )\r
416                 {\r
417                     ZeroMemory(*cOptions, sizeof(char *)*capacity);\r
418                     while( SUCCEEDED(hr) && (S_OK == enumVar->Next(1, &option, NULL)) )\r
419                     {\r
420                         if( VT_BSTR == V_VT(&option) )\r
421                         {\r
422                             char *cOption = CStrFromBSTR(codePage, V_BSTR(&option));\r
423                             (*cOptions)[pos] = cOption;\r
424                             if( NULL != cOption )\r
425                             {\r
426                                 ++pos;\r
427                                 if( pos == capacity )\r
428                                 {\r
429                                     char **moreOptions = (char **)realloc(*cOptions, (capacity+16)*sizeof(char *));\r
430                                     if( NULL != moreOptions )\r
431                                     {\r
432                                         ZeroMemory(moreOptions+capacity, sizeof(char *)*16);\r
433                                         capacity += 16;\r
434                                         *cOptions = moreOptions;\r
435                                     }\r
436                                     else\r
437                                         hr = E_OUTOFMEMORY;\r
438                                 }\r
439                             }\r
440                             else\r
441                                 hr = E_OUTOFMEMORY;\r
442                         }\r
443                         else\r
444                             hr = E_INVALIDARG;\r
445 \r
446                         VariantClear(&option);\r
447                     }\r
448                     *cOptionCount = pos;\r
449                     if( FAILED(hr) )\r
450                     {\r
451                         // free already processed elements\r
452                         freeTargetOptions(*cOptions, *cOptionCount);\r
453                     }\r
454                 }\r
455                 else\r
456                     hr = E_OUTOFMEMORY;\r
457                 enumVar->Release();\r
458             }\r
459         }\r
460     }\r
461     else if( V_ISARRAY(options) )\r
462     {\r
463         // array parameter\r
464         SAFEARRAY *array = V_ISBYREF(options) ? *V_ARRAYREF(options) : V_ARRAY(options);\r
465 \r
466         if( SafeArrayGetDim(array) != 1 )\r
467             return E_INVALIDARG;\r
468 \r
469         long lBound = 0;\r
470         long uBound = 0;\r
471         SafeArrayGetLBound(array, 1, &lBound);\r
472         SafeArrayGetUBound(array, 1, &uBound);\r
473 \r
474         // have we got any options\r
475         if( uBound > lBound )\r
476         {\r
477             VARTYPE vType;\r
478             HRESULT hr = SafeArrayGetVartype(array, &vType);\r
479             if( FAILED(hr) )\r
480                 return hr;\r
481 \r
482             long pos;\r
483 \r
484             // marshall options into an array of C strings\r
485             if( VT_VARIANT == vType )\r
486             {\r
487                 *cOptions = (char **)malloc(sizeof(char *)*(uBound-lBound));\r
488                 if( NULL != options )\r
489                     return E_OUTOFMEMORY;\r
490 \r
491                 for(pos=lBound; SUCCEEDED(hr) && (pos<uBound); ++pos )\r
492                 {\r
493                     VARIANT option;\r
494                     hr = SafeArrayGetElement(array, &pos, &option);\r
495                     if( SUCCEEDED(hr) )\r
496                     {\r
497                         if( VT_BSTR == V_VT(&option) ) \r
498                         {\r
499                             char *cOption = CStrFromBSTR(codePage, V_BSTR(&option));\r
500                             (*cOptions)[pos-lBound] = cOption;\r
501                             if( NULL == cOption )\r
502                                 hr = E_OUTOFMEMORY;\r
503                         }\r
504                         else\r
505                             hr = E_INVALIDARG;\r
506                         VariantClear(&option);\r
507                     }\r
508                 }\r
509             }\r
510             else if( VT_BSTR == vType )\r
511             {\r
512                 *cOptions = (char **)malloc(sizeof(char *)*(uBound-lBound));\r
513                 if( NULL != options )\r
514                     return E_OUTOFMEMORY;\r
515 \r
516                 ZeroMemory(cOptions, sizeof(char *)*(uBound-lBound));\r
517                 for(pos=lBound; SUCCEEDED(hr) && (pos<uBound); ++pos )\r
518                 {\r
519                     BSTR option;\r
520                     hr = SafeArrayGetElement(array, &pos, &option);\r
521                     if( SUCCEEDED(hr) )\r
522                     {\r
523                         char *cOption = CStrFromBSTR(codePage, option);\r
524                         (*cOptions)[pos-lBound] = cOption;\r
525                         if( NULL == cOption )\r
526                             hr = E_OUTOFMEMORY;\r
527                         SysFreeString(option);\r
528                     }\r
529                 }\r
530             }\r
531             else\r
532                 // unsupported type\r
533                 return E_INVALIDARG;\r
534 \r
535             *cOptionCount = pos-lBound;\r
536             if( FAILED(hr) )\r
537             {\r
538                 // free already processed elements\r
539                 freeTargetOptions(*cOptions, *cOptionCount);\r
540             }\r
541         }\r
542         else\r
543         {\r
544             // empty array\r
545             *cOptions = NULL;\r
546             *cOptionCount = 0;\r
547             return NOERROR;\r
548         }\r
549     }\r
550     return hr;\r
551 };\r
552 \r
553 /*\r
554 ** use VARIANT rather than a SAFEARRAY as argument type\r
555 ** for compatibility with some scripting language (JScript)\r
556 */\r
557 \r
558 STDMETHODIMP VLCControl::addTarget( BSTR uri, VARIANT options, enum VLCPlaylistMode mode, int position)\r
559 {\r
560     if( NULL == uri )\r
561         return E_INVALIDARG;\r
562 \r
563     HRESULT hr = E_UNEXPECTED;\r
564 \r
565     int i_vlc = _p_instance->getVLCObject();\r
566     if( i_vlc )\r
567     {\r
568         int codePage = _p_instance->getCodePage();\r
569         char *cUri = CStrFromBSTR(codePage, uri);\r
570         if( NULL == cUri )\r
571             return E_OUTOFMEMORY;\r
572 \r
573         int cOptionsCount;\r
574         char **cOptions;\r
575 \r
576         if( FAILED(createTargetOptions(codePage, &options, &cOptions, &cOptionsCount)) )\r
577             return E_INVALIDARG;\r
578 \r
579         VLC_AddTarget(i_vlc, cUri, (const char **)cOptions, cOptionsCount, mode, position);\r
580         hr = NOERROR;\r
581 \r
582         freeTargetOptions(cOptions, cOptionsCount);\r
583         free(cUri);\r
584     }\r
585     return hr;\r
586 };\r
587         \r
588 STDMETHODIMP VLCControl::get_PlaylistIndex(int *index)\r
589 {\r
590     if( NULL == index )\r
591         return E_INVALIDARG;\r
592 \r
593     int i_vlc = _p_instance->getVLCObject();\r
594     if( i_vlc )\r
595     {\r
596         *index = VLC_PlaylistIndex(i_vlc);\r
597         return NOERROR;\r
598     }\r
599     *index = 0;\r
600     return E_UNEXPECTED;\r
601 };\r
602         \r
603 STDMETHODIMP VLCControl::get_PlaylistCount(int *count)\r
604 {\r
605     int i_vlc = _p_instance->getVLCObject();\r
606     if( i_vlc )\r
607     {\r
608         *count = VLC_PlaylistNumberOfItems(i_vlc);\r
609         return NOERROR;\r
610     }\r
611     return E_UNEXPECTED;\r
612 };\r
613         \r
614 STDMETHODIMP VLCControl::playlistNext(void)\r
615 {\r
616     int i_vlc = _p_instance->getVLCObject();\r
617     if( i_vlc )\r
618     {\r
619         VLC_PlaylistNext(i_vlc);\r
620         return NOERROR;\r
621     }\r
622     return E_UNEXPECTED;\r
623 };\r
624         \r
625 STDMETHODIMP VLCControl::playlistPrev(void)\r
626 {\r
627     int i_vlc = _p_instance->getVLCObject();\r
628     if( i_vlc )\r
629     {\r
630         VLC_PlaylistPrev(i_vlc);\r
631         return NOERROR;\r
632     }\r
633     return E_UNEXPECTED;\r
634 };\r
635         \r
636 STDMETHODIMP VLCControl::playlistClear(void)\r
637 {\r
638     int i_vlc = _p_instance->getVLCObject();\r
639     if( i_vlc )\r
640     {\r
641         VLC_PlaylistClear(i_vlc);\r
642         return NOERROR;\r
643     }\r
644     return E_UNEXPECTED;\r
645 };\r
646         \r
647 STDMETHODIMP VLCControl::get_VersionInfo(BSTR *version)\r
648 {\r
649     if( NULL == version )\r
650         return E_INVALIDARG;\r
651 \r
652     const char *versionStr = VLC_Version();\r
653     if( NULL != versionStr )\r
654     {\r
655         *version = BSTRFromCStr(_p_instance->getCodePage(), versionStr);\r
656         \r
657         return NULL == *version ? E_OUTOFMEMORY : NOERROR;\r
658     }\r
659     *version = NULL;\r
660     return E_FAIL;\r
661 };\r
662  \r