libvlc_audio_*: remove useless exception parameters
[vlc.git] / projects / activex / plugin.cpp
1 /*****************************************************************************
2  * plugin.cpp: ActiveX control for VLC
3  *****************************************************************************
4  * Copyright (C) 2006 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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21  *****************************************************************************/
22
23 #include "plugin.h"
24
25 #include "oleobject.h"
26 #include "olecontrol.h"
27 #include "oleinplaceobject.h"
28 #include "oleinplaceactiveobject.h"
29 #include "persistpropbag.h"
30 #include "persiststreaminit.h"
31 #include "persiststorage.h"
32 #include "provideclassinfo.h"
33 #include "connectioncontainer.h"
34 #include "objectsafety.h"
35 #include "vlccontrol.h"
36 #include "vlccontrol2.h"
37 #include "viewobject.h"
38 #include "dataobject.h"
39 #include "supporterrorinfo.h"
40
41 #include "utils.h"
42
43 #include <stdio.h>
44 #include <string.h>
45 #include <winreg.h>
46 #include <winuser.h>
47 #include <servprov.h>
48 #include <shlwapi.h>
49 #include <wininet.h>
50
51 using namespace std;
52
53 ////////////////////////////////////////////////////////////////////////
54 //class factory
55
56 static LRESULT CALLBACK VLCInPlaceClassWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
57     VLCPlugin *p_instance = reinterpret_cast<VLCPlugin *>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
58
59     switch( uMsg )
60     {
61         case WM_ERASEBKGND:
62             return 1L;
63
64         case WM_PAINT:
65             PAINTSTRUCT ps;
66             RECT pr;
67             if( GetUpdateRect(hWnd, &pr, FALSE) )
68             {
69                 RECT bounds;
70                 GetClientRect(hWnd, &bounds);
71                 BeginPaint(hWnd, &ps);
72                 p_instance->onPaint(ps.hdc, bounds, pr);
73                 EndPaint(hWnd, &ps);
74             }
75             return 0L;
76
77         default:
78             return DefWindowProc(hWnd, uMsg, wParam, lParam);
79     }
80 };
81
82 VLCPluginClass::VLCPluginClass(LONG *p_class_ref, HINSTANCE hInstance, REFCLSID rclsid) :
83     _p_class_ref(p_class_ref),
84     _hinstance(hInstance),
85     _classid(rclsid),
86     _inplace_picture(NULL)
87 {
88     WNDCLASS wClass;
89
90     if( ! GetClassInfo(hInstance, getInPlaceWndClassName(), &wClass) )
91     {
92         wClass.style          = CS_NOCLOSE|CS_DBLCLKS;
93         wClass.lpfnWndProc    = VLCInPlaceClassWndProc;
94         wClass.cbClsExtra     = 0;
95         wClass.cbWndExtra     = 0;
96         wClass.hInstance      = hInstance;
97         wClass.hIcon          = NULL;
98         wClass.hCursor        = LoadCursor(NULL, IDC_ARROW);
99         wClass.hbrBackground  = NULL;
100         wClass.lpszMenuName   = NULL;
101         wClass.lpszClassName  = getInPlaceWndClassName();
102
103         _inplace_wndclass_atom = RegisterClass(&wClass);
104     }
105     else
106     {
107         _inplace_wndclass_atom = 0;
108     }
109
110     HBITMAP hbitmap = (HBITMAP)LoadImage(getHInstance(), MAKEINTRESOURCE(2), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR);
111     if( NULL != hbitmap )
112     {
113         PICTDESC pictDesc;
114
115         pictDesc.cbSizeofstruct = sizeof(PICTDESC);
116         pictDesc.picType        = PICTYPE_BITMAP;
117         pictDesc.bmp.hbitmap    = hbitmap;
118         pictDesc.bmp.hpal       = NULL;
119
120         if( FAILED(OleCreatePictureIndirect(&pictDesc, IID_IPicture, TRUE, reinterpret_cast<LPVOID*>(&_inplace_picture))) )
121             _inplace_picture = NULL;
122     }
123     AddRef();
124 };
125
126 VLCPluginClass::~VLCPluginClass()
127 {
128     if( 0 != _inplace_wndclass_atom )
129         UnregisterClass(MAKEINTATOM(_inplace_wndclass_atom), _hinstance);
130
131     if( NULL != _inplace_picture )
132         _inplace_picture->Release();
133 };
134
135 STDMETHODIMP VLCPluginClass::QueryInterface(REFIID riid, void **ppv)
136 {
137     if( NULL == ppv )
138         return E_INVALIDARG;
139
140     if( (IID_IUnknown == riid)
141      || (IID_IClassFactory == riid) )
142     {
143         AddRef();
144         *ppv = reinterpret_cast<LPVOID>(this);
145
146         return NOERROR;
147     }
148
149     *ppv = NULL;
150
151     return E_NOINTERFACE;
152 };
153
154 STDMETHODIMP_(ULONG) VLCPluginClass::AddRef(void)
155 {
156     return InterlockedIncrement(_p_class_ref);
157 };
158
159 STDMETHODIMP_(ULONG) VLCPluginClass::Release(void)
160 {
161     ULONG refcount = InterlockedDecrement(_p_class_ref);
162     if( 0 == refcount )
163     {
164         delete this;
165         return 0;
166     }
167     return refcount;
168 };
169
170 STDMETHODIMP VLCPluginClass::CreateInstance(LPUNKNOWN pUnkOuter, REFIID riid, void **ppv)
171 {
172     if( NULL == ppv )
173         return E_POINTER;
174
175     *ppv = NULL;
176
177     if( (NULL != pUnkOuter) && (IID_IUnknown != riid) ) {
178         return CLASS_E_NOAGGREGATION;
179     }
180
181     VLCPlugin *plugin = new VLCPlugin(this, pUnkOuter);
182     if( NULL != plugin )
183     {
184         HRESULT hr = plugin->QueryInterface(riid, ppv);
185         // the following will destroy the object if QueryInterface() failed
186         plugin->Release();
187         return hr;
188     }
189     return E_OUTOFMEMORY;
190 };
191
192 STDMETHODIMP VLCPluginClass::LockServer(BOOL fLock)
193 {
194     if( fLock )
195         AddRef();
196     else
197         Release();
198
199     return S_OK;
200 };
201
202 ////////////////////////////////////////////////////////////////////////
203
204 VLCPlugin::VLCPlugin(VLCPluginClass *p_class, LPUNKNOWN pUnkOuter) :
205     _inplacewnd(NULL),
206     _p_class(p_class),
207     _i_ref(1UL),
208     _p_libvlc(NULL),
209     _p_mlist(NULL),
210     _p_mplayer(NULL),
211     _i_midx(-1),
212     _i_codepage(CP_ACP),
213     _b_usermode(TRUE)
214 {
215     p_class->AddRef();
216
217     vlcOleControl = new VLCOleControl(this);
218     vlcOleInPlaceObject = new VLCOleInPlaceObject(this);
219     vlcOleInPlaceActiveObject = new VLCOleInPlaceActiveObject(this);
220     vlcPersistStorage = new VLCPersistStorage(this);
221     vlcPersistStreamInit = new VLCPersistStreamInit(this);
222     vlcPersistPropertyBag = new VLCPersistPropertyBag(this);
223     vlcProvideClassInfo = new VLCProvideClassInfo(this);
224     vlcConnectionPointContainer = new VLCConnectionPointContainer(this);
225     vlcObjectSafety = new VLCObjectSafety(this);
226     vlcControl = new VLCControl(this);
227     vlcControl2 = new VLCControl2(this);
228     vlcViewObject = new VLCViewObject(this);
229     vlcDataObject = new VLCDataObject(this);
230     vlcOleObject = new VLCOleObject(this);
231     vlcSupportErrorInfo = new VLCSupportErrorInfo(this);
232
233     // configure controlling IUnknown interface for implemented interfaces
234     this->pUnkOuter = (NULL != pUnkOuter) ? pUnkOuter : dynamic_cast<LPUNKNOWN>(this);
235
236     // default picure
237     _p_pict = p_class->getInPlacePict();
238
239     // make sure that persistable properties are initialized
240     onInit();
241 };
242
243 VLCPlugin::~VLCPlugin()
244 {
245     /*
246     ** bump refcount to avoid recursive release from
247     ** following interfaces when releasing this interface
248     */
249     AddRef();
250
251     delete vlcSupportErrorInfo;
252     delete vlcOleObject;
253     delete vlcDataObject;
254     delete vlcViewObject;
255     delete vlcControl2;
256     delete vlcControl;
257     delete vlcConnectionPointContainer;
258     delete vlcProvideClassInfo;
259     delete vlcPersistPropertyBag;
260     delete vlcPersistStreamInit;
261     delete vlcPersistStorage;
262     delete vlcOleInPlaceActiveObject;
263     delete vlcOleInPlaceObject;
264     delete vlcObjectSafety;
265
266     delete vlcOleControl;
267     if( _p_pict )
268         _p_pict->Release();
269
270     SysFreeString(_bstr_mrl);
271     SysFreeString(_bstr_baseurl);
272
273     if( _p_mplayer ) { libvlc_media_player_release(_p_mplayer); _p_mplayer=NULL; }
274     if( _p_mlist )   { libvlc_media_list_release(_p_mlist); _p_mlist=NULL; }
275     if( _p_libvlc )  { libvlc_release(_p_libvlc); _p_libvlc=NULL; }
276
277     _p_class->Release();
278 };
279
280 STDMETHODIMP VLCPlugin::QueryInterface(REFIID riid, void **ppv)
281 {
282     if( NULL == ppv )
283         return E_INVALIDARG;
284
285     if( IID_IUnknown == riid )
286         *ppv = reinterpret_cast<LPVOID>(this);
287     else if( IID_IOleObject == riid )
288         *ppv = reinterpret_cast<LPVOID>(vlcOleObject);
289     else if( IID_IOleControl == riid )
290         *ppv = reinterpret_cast<LPVOID>(vlcOleControl);
291     else if( IID_IOleWindow == riid )
292         *ppv = reinterpret_cast<LPVOID>(vlcOleInPlaceObject);
293     else if( IID_IOleInPlaceObject == riid )
294         *ppv = reinterpret_cast<LPVOID>(vlcOleInPlaceObject);
295     else if( IID_IOleInPlaceActiveObject == riid )
296         *ppv = reinterpret_cast<LPVOID>(vlcOleInPlaceActiveObject);
297     else if( IID_IPersist == riid )
298         *ppv = reinterpret_cast<LPVOID>(vlcPersistStreamInit);
299     else if( IID_IPersistStreamInit == riid )
300         *ppv = reinterpret_cast<LPVOID>(vlcPersistStreamInit);
301     else if( IID_IPersistStorage == riid )
302         *ppv = reinterpret_cast<LPVOID>(vlcPersistStorage);
303     else if( IID_IPersistPropertyBag == riid )
304         *ppv = reinterpret_cast<LPVOID>(vlcPersistPropertyBag);
305     else if( IID_IProvideClassInfo == riid )
306         *ppv = reinterpret_cast<LPVOID>(vlcProvideClassInfo);
307     else if( IID_IProvideClassInfo2 == riid )
308         *ppv = reinterpret_cast<LPVOID>(vlcProvideClassInfo);
309     else if( IID_IConnectionPointContainer == riid )
310         *ppv = reinterpret_cast<LPVOID>(vlcConnectionPointContainer);
311     else if( IID_IObjectSafety == riid )
312         *ppv = reinterpret_cast<LPVOID>(vlcObjectSafety);
313     else if( IID_IDispatch == riid )
314         *ppv = (CLSID_VLCPlugin2 == getClassID()) ?
315                 reinterpret_cast<LPVOID>(vlcControl2) :
316                 reinterpret_cast<LPVOID>(vlcControl);
317     else if( IID_IVLCControl == riid )
318         *ppv = reinterpret_cast<LPVOID>(vlcControl);
319     else if( IID_IVLCControl2 == riid )
320         *ppv = reinterpret_cast<LPVOID>(vlcControl2);
321     else if( IID_IViewObject == riid )
322         *ppv = reinterpret_cast<LPVOID>(vlcViewObject);
323     else if( IID_IViewObject2 == riid )
324         *ppv = reinterpret_cast<LPVOID>(vlcViewObject);
325     else if( IID_IDataObject == riid )
326         *ppv = reinterpret_cast<LPVOID>(vlcDataObject);
327     else if( IID_ISupportErrorInfo == riid )
328         *ppv = reinterpret_cast<LPVOID>(vlcSupportErrorInfo);
329     else
330     {
331         *ppv = NULL;
332         return E_NOINTERFACE;
333     }
334     ((LPUNKNOWN)*ppv)->AddRef();
335     return NOERROR;
336 };
337
338 STDMETHODIMP_(ULONG) VLCPlugin::AddRef(void)
339 {
340     return InterlockedIncrement((LONG *)&_i_ref);
341 };
342
343 STDMETHODIMP_(ULONG) VLCPlugin::Release(void)
344 {
345     if( ! InterlockedDecrement((LONG *)&_i_ref) )
346     {
347         delete this;
348         return 0;
349     }
350     return _i_ref;
351 };
352
353 //////////////////////////////////////
354
355 HRESULT VLCPlugin::onInit(void)
356 {
357     if( NULL == _p_libvlc )
358     {
359         // initialize persistable properties
360         _b_autoplay   = TRUE;
361         _b_autoloop   = FALSE;
362         _b_toolbar    = FALSE;
363         _bstr_baseurl = NULL;
364         _bstr_mrl     = NULL;
365         _b_visible    = TRUE;
366         _b_mute       = FALSE;
367         _i_volume     = 50;
368         _i_time       = 0;
369         _i_backcolor  = 0;
370         // set default/preferred size (320x240) pixels in HIMETRIC
371         HDC hDC = CreateDevDC(NULL);
372         _extent.cx = 320;
373         _extent.cy = 240;
374         HimetricFromDP(hDC, (LPPOINT)&_extent, 1);
375         DeleteDC(hDC);
376
377         return S_OK;
378     }
379     return CO_E_ALREADYINITIALIZED;
380 };
381
382 HRESULT VLCPlugin::onLoad(void)
383 {
384     if( SysStringLen(_bstr_baseurl) == 0 )
385     {
386         /*
387         ** try to retreive the base URL using the client site moniker, which for Internet Explorer
388         ** is the URL of the page the plugin is embedded into.
389         */
390         LPOLECLIENTSITE pClientSite;
391         if( SUCCEEDED(vlcOleObject->GetClientSite(&pClientSite)) && (NULL != pClientSite) )
392         {
393             IBindCtx *pBC = 0;
394             if( SUCCEEDED(CreateBindCtx(0, &pBC)) )
395             {
396                 LPMONIKER pContMoniker = NULL;
397                 if( SUCCEEDED(pClientSite->GetMoniker(OLEGETMONIKER_ONLYIFTHERE,
398                                 OLEWHICHMK_CONTAINER, &pContMoniker)) )
399                 {
400                     LPOLESTR base_url;
401                     if( SUCCEEDED(pContMoniker->GetDisplayName(pBC, NULL, &base_url)) )
402                     {
403                         /*
404                         ** check that the moniker name is a URL
405                         */
406                         if( UrlIsW(base_url, URLIS_URL) )
407                         {
408                             /* copy base URL */
409                             _bstr_baseurl = SysAllocString(base_url);
410                         }
411                         CoTaskMemFree(base_url);
412                     }
413                 }
414             }
415         }
416     }
417     setDirty(FALSE);
418     return S_OK;
419 };
420
421
422 void VLCPlugin::initVLC()
423 {
424     extern HMODULE DllGetModule();
425
426     /*
427     ** default initialization options
428     */
429     const char *ppsz_argv[32] = { };
430     int   ppsz_argc = 0;
431
432     char p_progpath[MAX_PATH];
433     {
434         TCHAR w_progpath[MAX_PATH];
435         DWORD len = GetModuleFileName(DllGetModule(), w_progpath, MAX_PATH);
436         if( len > 0 )
437         {
438             len = WideCharToMultiByte(CP_UTF8, 0, w_progpath, len, p_progpath,
439                        sizeof(p_progpath)-1, NULL, NULL);
440             if( len > 0 )
441             {
442                 p_progpath[len] = '\0';
443                 ppsz_argv[0] = p_progpath;
444             }
445         }
446     }
447
448     ppsz_argv[ppsz_argc++] = "-vv";
449
450     HKEY h_key;
451     char p_pluginpath[MAX_PATH];
452     if( RegOpenKeyEx( HKEY_LOCAL_MACHINE, TEXT("Software\\VideoLAN\\VLC"),
453                       0, KEY_READ, &h_key ) == ERROR_SUCCESS )
454     {
455         DWORD i_type, i_data = MAX_PATH;
456         TCHAR w_pluginpath[MAX_PATH];
457         if( RegQueryValueEx( h_key, TEXT("InstallDir"), 0, &i_type,
458                              (LPBYTE)w_pluginpath, &i_data ) == ERROR_SUCCESS )
459         {
460             if( i_type == REG_SZ )
461             {
462                 if( WideCharToMultiByte(CP_UTF8, 0, w_pluginpath, -1, p_pluginpath,
463                          sizeof(p_pluginpath)-sizeof("\\plugins")+1, NULL, NULL) )
464                 {
465                     strcat( p_pluginpath, "\\plugins" );
466                     ppsz_argv[ppsz_argc++] = "--plugin-path";
467                     ppsz_argv[ppsz_argc++] = p_pluginpath;
468                 }
469             }
470         }
471         RegCloseKey( h_key );
472     }
473
474     // make sure plugin isn't affected with VLC single instance mode
475     ppsz_argv[ppsz_argc++] = "--no-one-instance";
476
477     /* common settings */
478     ppsz_argv[ppsz_argc++] = "-vv";
479     ppsz_argv[ppsz_argc++] = "--no-stats";
480     ppsz_argv[ppsz_argc++] = "--no-media-library";
481     ppsz_argv[ppsz_argc++] = "--intf=dummy";
482     ppsz_argv[ppsz_argc++] = "--no-video-title-show";
483
484
485     // loop mode is a configuration option only
486     if( _b_autoloop )
487         ppsz_argv[ppsz_argc++] = "--loop";
488
489     libvlc_exception_t ex;
490     libvlc_exception_init(&ex);
491
492     _p_libvlc = libvlc_new(ppsz_argc, ppsz_argv, &ex);
493     if( libvlc_exception_raised(&ex) )
494         return;
495
496     _p_mlist = libvlc_media_list_new(_p_libvlc, &ex);
497     if( libvlc_exception_raised(&ex) )
498     {
499         libvlc_release(_p_libvlc);
500         return;
501     }
502
503     // initial volume setting
504     libvlc_audio_set_volume(_p_libvlc, _i_volume, NULL);
505     if( _b_mute )
506     {
507         libvlc_audio_set_mute(_p_libvlc, TRUE);
508     }
509
510     // initial playlist item
511     if( SysStringLen(_bstr_mrl) > 0 )
512     {
513         char *psz_mrl = NULL;
514
515         if( SysStringLen(_bstr_baseurl) > 0 )
516         {
517             /*
518             ** if the MRL a relative URL, we should end up with an absolute URL
519             */
520             LPWSTR abs_url = CombineURL(_bstr_baseurl, _bstr_mrl);
521             if( NULL != abs_url )
522             {
523                 psz_mrl = CStrFromWSTR(CP_UTF8, abs_url, wcslen(abs_url));
524                 CoTaskMemFree(abs_url);
525             }
526             else
527             {
528                 psz_mrl = CStrFromBSTR(CP_UTF8, _bstr_mrl);
529             }
530         }
531         else
532         {
533             /*
534             ** baseURL is empty, assume MRL is absolute
535             */
536             psz_mrl = CStrFromBSTR(CP_UTF8, _bstr_mrl);
537         }
538         if( NULL != psz_mrl )
539         {
540             const char *options[1];
541             int i_options = 0;
542
543             char timeBuffer[32];
544             if( _i_time )
545             {
546                 snprintf(timeBuffer, sizeof(timeBuffer), ":start-time=%d", _i_time);
547                 options[i_options++] = timeBuffer;
548             }
549             // add default target to playlist
550             playlist_add_extended_untrusted(psz_mrl, i_options, options, NULL);
551             CoTaskMemFree(psz_mrl);
552         }
553     }
554 };
555
556 void VLCPlugin::setErrorInfo(REFIID riid, const char *description)
557 {
558     vlcSupportErrorInfo->setErrorInfo( getClassID() == CLSID_VLCPlugin2 ?
559         OLESTR("VideoLAN.VLCPlugin.2") : OLESTR("VideoLAN.VLCPlugin.1"),
560         riid, description );
561 };
562
563 HRESULT VLCPlugin::onAmbientChanged(LPUNKNOWN pContainer, DISPID dispID)
564 {
565     VARIANT v;
566     switch( dispID )
567     {
568         case DISPID_AMBIENT_BACKCOLOR:
569             VariantInit(&v);
570             V_VT(&v) = VT_I4;
571             if( SUCCEEDED(GetObjectProperty(pContainer, dispID, v)) )
572             {
573                 setBackColor(V_I4(&v));
574             }
575             break;
576         case DISPID_AMBIENT_DISPLAYNAME:
577             break;
578         case DISPID_AMBIENT_FONT:
579             break;
580         case DISPID_AMBIENT_FORECOLOR:
581             break;
582         case DISPID_AMBIENT_LOCALEID:
583             break;
584         case DISPID_AMBIENT_MESSAGEREFLECT:
585             break;
586         case DISPID_AMBIENT_SCALEUNITS:
587             break;
588         case DISPID_AMBIENT_TEXTALIGN:
589             break;
590         case DISPID_AMBIENT_USERMODE:
591             VariantInit(&v);
592             V_VT(&v) = VT_BOOL;
593             if( SUCCEEDED(GetObjectProperty(pContainer, dispID, v)) )
594             {
595                 setUserMode(V_BOOL(&v) != VARIANT_FALSE);
596             }
597             break;
598         case DISPID_AMBIENT_UIDEAD:
599             break;
600         case DISPID_AMBIENT_SHOWGRABHANDLES:
601             break;
602         case DISPID_AMBIENT_SHOWHATCHING:
603             break;
604         case DISPID_AMBIENT_DISPLAYASDEFAULT:
605             break;
606         case DISPID_AMBIENT_SUPPORTSMNEMONICS:
607             break;
608         case DISPID_AMBIENT_AUTOCLIP:
609             break;
610         case DISPID_AMBIENT_APPEARANCE:
611             break;
612         case DISPID_AMBIENT_CODEPAGE:
613             VariantInit(&v);
614             V_VT(&v) = VT_I4;
615             if( SUCCEEDED(GetObjectProperty(pContainer, dispID, v)) )
616             {
617                 setCodePage(V_I4(&v));
618             }
619             break;
620         case DISPID_AMBIENT_PALETTE:
621             break;
622         case DISPID_AMBIENT_CHARSET:
623             break;
624         case DISPID_AMBIENT_RIGHTTOLEFT:
625             break;
626         case DISPID_AMBIENT_TOPTOBOTTOM:
627             break;
628         case DISPID_UNKNOWN:
629             /*
630             ** multiple property change, look up the ones we are interested in
631             */
632             VariantInit(&v);
633             V_VT(&v) = VT_BOOL;
634             if( SUCCEEDED(GetObjectProperty(pContainer, DISPID_AMBIENT_USERMODE, v)) )
635             {
636                 setUserMode(V_BOOL(&v) != VARIANT_FALSE);
637             }
638             VariantInit(&v);
639             V_VT(&v) = VT_I4;
640             if( SUCCEEDED(GetObjectProperty(pContainer, DISPID_AMBIENT_CODEPAGE, v)) )
641             {
642                 setCodePage(V_I4(&v));
643             }
644             break;
645     }
646     return S_OK;
647 };
648
649 HRESULT VLCPlugin::onClose(DWORD dwSaveOption)
650 {
651     if( isInPlaceActive() )
652     {
653         onInPlaceDeactivate();
654     }
655     if( isRunning() )
656     {
657         libvlc_instance_t* p_libvlc = _p_libvlc;
658
659         IVLCLog *p_log;
660         if( SUCCEEDED(vlcControl2->get_log(&p_log)) )
661         {
662             // make sure the log is disabled
663             p_log->put_verbosity(-1);
664             p_log->Release();
665         }
666
667         _p_libvlc = NULL;
668         vlcDataObject->onClose();
669
670         if( p_libvlc )
671             libvlc_release(p_libvlc);
672     }
673     return S_OK;
674 };
675
676 BOOL VLCPlugin::isInPlaceActive(void)
677 {
678     return (NULL != _inplacewnd);
679 };
680
681 HRESULT VLCPlugin::onActivateInPlace(LPMSG lpMesg, HWND hwndParent, LPCRECT lprcPosRect, LPCRECT lprcClipRect)
682 {
683     RECT clipRect = *lprcClipRect;
684     libvlc_exception_t ex;
685     libvlc_exception_init(&ex);
686
687     /*
688     ** record keeping of control geometry within container
689     */
690     _posRect = *lprcPosRect;
691
692     /*
693     ** Create a window for in place activated control.
694     ** the window geometry matches the control viewport
695     ** within container so that embedded video is always
696     ** properly displayed.
697     */
698     _inplacewnd = CreateWindow(_p_class->getInPlaceWndClassName(),
699             TEXT("VLC Plugin In-Place Window"),
700             WS_CHILD|WS_CLIPCHILDREN|WS_CLIPSIBLINGS,
701             lprcPosRect->left,
702             lprcPosRect->top,
703             lprcPosRect->right-lprcPosRect->left,
704             lprcPosRect->bottom-lprcPosRect->top,
705             hwndParent,
706             0,
707             _p_class->getHInstance(),
708             NULL
709            );
710
711     if( NULL == _inplacewnd )
712         return E_FAIL;
713
714     SetWindowLongPtr(_inplacewnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this));
715
716     /* change cliprect coordinates system relative to window bounding rect */
717     OffsetRect(&clipRect, -lprcPosRect->left, -lprcPosRect->top);
718
719     HRGN clipRgn = CreateRectRgnIndirect(&clipRect);
720     SetWindowRgn(_inplacewnd, clipRgn, TRUE);
721
722     if( _b_usermode )
723     {
724         /* will run vlc if not done already */
725         libvlc_instance_t* p_libvlc;
726         HRESULT result = getVLC(&p_libvlc);
727         if( FAILED(result) )
728             return result;
729
730         if( _b_autoplay && playlist_select(0,NULL) )
731         {
732             libvlc_media_player_play(_p_mplayer,NULL);
733             fireOnPlayEvent();
734         }
735     }
736
737     if( isVisible() )
738         ShowWindow(_inplacewnd, SW_SHOW);
739
740     return S_OK;
741 };
742
743 HRESULT VLCPlugin::onInPlaceDeactivate(void)
744 {
745     if( isPlaying(NULL) )
746     {
747         playlist_stop(NULL);
748         fireOnStopEvent();
749     }
750
751     DestroyWindow(_inplacewnd);
752     _inplacewnd = NULL;
753
754     return S_OK;
755 };
756
757 void VLCPlugin::setVisible(BOOL fVisible)
758 {
759     if( fVisible != _b_visible )
760     {
761         _b_visible = fVisible;
762         if( isInPlaceActive() )
763         {
764             ShowWindow(_inplacewnd, fVisible ? SW_SHOW : SW_HIDE);
765             if( fVisible )
766                 InvalidateRect(_inplacewnd, NULL, TRUE);
767         }
768         setDirty(TRUE);
769         firePropChangedEvent(DISPID_Visible);
770     }
771 };
772
773 void VLCPlugin::setVolume(int volume)
774 {
775     if( volume < 0 )
776         volume = 0;
777     else if( volume > 200 )
778         volume = 200;
779
780     if( volume != _i_volume )
781     {
782         _i_volume = volume;
783         if( isRunning() )
784         {
785             libvlc_audio_set_volume(_p_libvlc, _i_volume, NULL);
786         }
787         setDirty(TRUE);
788     }
789 };
790
791 void VLCPlugin::setBackColor(OLE_COLOR backcolor)
792 {
793     if( _i_backcolor != backcolor )
794     {
795         _i_backcolor = backcolor;
796         if( isInPlaceActive() )
797         {
798
799         }
800         setDirty(TRUE);
801     }
802 };
803
804 void VLCPlugin::setTime(int seconds)
805 {
806     if( seconds < 0 )
807         seconds = 0;
808
809     if( seconds != _i_time )
810     {
811         setStartTime(_i_time);
812         if( NULL != _p_mplayer )
813         {
814             libvlc_media_player_set_time(_p_mplayer, _i_time, NULL);
815         }
816     }
817 };
818
819 void VLCPlugin::setFocus(BOOL fFocus)
820 {
821     if( fFocus )
822         SetActiveWindow(_inplacewnd);
823 };
824
825 BOOL VLCPlugin::hasFocus(void)
826 {
827     return GetActiveWindow() == _inplacewnd;
828 };
829
830 void VLCPlugin::onDraw(DVTARGETDEVICE * ptd, HDC hicTargetDev,
831         HDC hdcDraw, LPCRECTL lprcBounds, LPCRECTL lprcWBounds)
832 {
833     if( isVisible() )
834     {
835         long width = lprcBounds->right-lprcBounds->left;
836         long height = lprcBounds->bottom-lprcBounds->top;
837
838         RECT bounds = { lprcBounds->left, lprcBounds->top, lprcBounds->right, lprcBounds->bottom };
839
840         if( isUserMode() )
841         {
842             /* VLC is in user mode, just draw background color */
843             COLORREF colorref = RGB(0, 0, 0);
844             OleTranslateColor(_i_backcolor, (HPALETTE)GetStockObject(DEFAULT_PALETTE), &colorref);
845             if( colorref != RGB(0, 0, 0) )
846             {
847                 /* custom background */
848                 HBRUSH colorbrush = CreateSolidBrush(colorref);
849                 FillRect(hdcDraw, &bounds, colorbrush);
850                 DeleteObject((HANDLE)colorbrush);
851             }
852             else
853             {
854                 /* black background */
855                 FillRect(hdcDraw, &bounds, (HBRUSH)GetStockObject(BLACK_BRUSH));
856             }
857         }
858         else
859         {
860             /* VLC is in design mode, draw the VLC logo */
861             FillRect(hdcDraw, &bounds, (HBRUSH)GetStockObject(WHITE_BRUSH));
862
863             LPPICTURE pict = getPicture();
864             if( NULL != pict )
865             {
866                 OLE_XSIZE_HIMETRIC picWidth;
867                 OLE_YSIZE_HIMETRIC picHeight;
868
869                 pict->get_Width(&picWidth);
870                 pict->get_Height(&picHeight);
871
872                 SIZEL picSize = { picWidth, picHeight };
873
874                 if( NULL != hicTargetDev )
875                 {
876                     DPFromHimetric(hicTargetDev, (LPPOINT)&picSize, 1);
877                 }
878                 else if( NULL != (hicTargetDev = CreateDevDC(ptd)) )
879                 {
880                     DPFromHimetric(hicTargetDev, (LPPOINT)&picSize, 1);
881                     DeleteDC(hicTargetDev);
882                 }
883
884                 if( picSize.cx > width-4 )
885                     picSize.cx = width-4;
886                 if( picSize.cy > height-4 )
887                     picSize.cy = height-4;
888
889                 LONG dstX = lprcBounds->left+(width-picSize.cx)/2;
890                 LONG dstY = lprcBounds->top+(height-picSize.cy)/2;
891
892                 if( NULL != lprcWBounds )
893                 {
894                     RECT wBounds = { lprcWBounds->left, lprcWBounds->top, lprcWBounds->right, lprcWBounds->bottom };
895                     pict->Render(hdcDraw, dstX, dstY, picSize.cx, picSize.cy,
896                             0L, picHeight, picWidth, -picHeight, &wBounds);
897                 }
898                 else
899                     pict->Render(hdcDraw, dstX, dstY, picSize.cx, picSize.cy,
900                             0L, picHeight, picWidth, -picHeight, NULL);
901
902                 pict->Release();
903             }
904
905             SelectObject(hdcDraw, GetStockObject(BLACK_BRUSH));
906
907             MoveToEx(hdcDraw, bounds.left, bounds.top, NULL);
908             LineTo(hdcDraw, bounds.left+width-1, bounds.top);
909             LineTo(hdcDraw, bounds.left+width-1, bounds.top+height-1);
910             LineTo(hdcDraw, bounds.left, bounds.top+height-1);
911             LineTo(hdcDraw, bounds.left, bounds.top);
912         }
913     }
914 };
915
916 void VLCPlugin::onPaint(HDC hdc, const RECT &bounds, const RECT &clipRect)
917 {
918     if( isVisible() )
919     {
920         /* if VLC is in design mode, draw control logo */
921         HDC hdcDraw = CreateCompatibleDC(hdc);
922         if( NULL != hdcDraw )
923         {
924             SIZEL size = getExtent();
925             DPFromHimetric(hdc, (LPPOINT)&size, 1);
926             RECTL posRect = { 0, 0, size.cx, size.cy };
927
928             int width = bounds.right-bounds.left;
929             int height = bounds.bottom-bounds.top;
930
931             HBITMAP hBitmap = CreateCompatibleBitmap(hdc, width, height);
932             if( NULL != hBitmap )
933             {
934                 HBITMAP oldBmp = (HBITMAP)SelectObject(hdcDraw, hBitmap);
935
936                 if( (size.cx != width) || (size.cy != height) )
937                 {
938                     // needs to scale canvas
939                     SetMapMode(hdcDraw, MM_ANISOTROPIC);
940                     SetWindowExtEx(hdcDraw, size.cx, size.cy, NULL);
941                     SetViewportExtEx(hdcDraw, width, height, NULL);
942                 }
943
944                 onDraw(NULL, hdc, hdcDraw, &posRect, NULL);
945
946                 SetMapMode(hdcDraw, MM_TEXT);
947                 BitBlt(hdc, bounds.left, bounds.top,
948                         width, height,
949                         hdcDraw, 0, 0,
950                         SRCCOPY);
951
952                 SelectObject(hdcDraw, oldBmp);
953                 DeleteObject(hBitmap);
954             }
955             DeleteDC(hdcDraw);
956         }
957     }
958 };
959
960 void VLCPlugin::onPositionChange(LPCRECT lprcPosRect, LPCRECT lprcClipRect)
961 {
962     RECT clipRect = *lprcClipRect;
963
964     //RedrawWindow(GetParent(_inplacewnd), &_posRect, NULL, RDW_INVALIDATE|RDW_ERASE|RDW_ALLCHILDREN);
965
966     /*
967     ** record keeping of control geometry within container
968     */
969     _posRect = *lprcPosRect;
970
971     /*
972     ** change in-place window geometry to match clipping region
973     */
974     SetWindowPos(_inplacewnd, NULL,
975             lprcPosRect->left,
976             lprcPosRect->top,
977             lprcPosRect->right-lprcPosRect->left,
978             lprcPosRect->bottom-lprcPosRect->top,
979             SWP_NOACTIVATE|
980             SWP_NOCOPYBITS|
981             SWP_NOZORDER|
982             SWP_NOOWNERZORDER );
983
984     /* change cliprect coordinates system relative to window bounding rect */
985     OffsetRect(&clipRect, -lprcPosRect->left, -lprcPosRect->top);
986     HRGN clipRgn = CreateRectRgnIndirect(&clipRect);
987     SetWindowRgn(_inplacewnd, clipRgn, FALSE);
988
989     //RedrawWindow(_videownd, &posRect, NULL, RDW_INVALIDATE|RDW_ERASE|RDW_ALLCHILDREN);
990 };
991
992 void VLCPlugin::freezeEvents(BOOL freeze)
993 {
994     vlcConnectionPointContainer->freezeEvents(freeze);
995 };
996
997 void VLCPlugin::firePropChangedEvent(DISPID dispid)
998 {
999     vlcConnectionPointContainer->firePropChangedEvent(dispid);
1000 };
1001
1002 void VLCPlugin::fireOnPlayEvent(void)
1003 {
1004     DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
1005     vlcConnectionPointContainer->fireEvent(DISPID_PlayEvent, &dispparamsNoArgs);
1006 };
1007
1008 void VLCPlugin::fireOnPauseEvent(void)
1009 {
1010     DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
1011     vlcConnectionPointContainer->fireEvent(DISPID_PauseEvent, &dispparamsNoArgs);
1012 };
1013
1014 void VLCPlugin::fireOnStopEvent(void)
1015 {
1016     DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
1017     vlcConnectionPointContainer->fireEvent(DISPID_StopEvent, &dispparamsNoArgs);
1018 };
1019
1020 bool VLCPlugin::playlist_select( int idx, libvlc_exception_t *ex )
1021 {
1022     libvlc_media_t *p_m = NULL;
1023
1024     libvlc_media_list_lock(_p_mlist);
1025
1026     int count = libvlc_media_list_count(_p_mlist,ex);
1027     if( libvlc_exception_raised(ex) )
1028         goto bad_unlock;
1029
1030     if( idx<0||idx>=count )
1031         goto bad_unlock;
1032
1033     _i_midx = idx;
1034
1035     p_m = libvlc_media_list_item_at_index(_p_mlist,_i_midx,ex);
1036     libvlc_media_list_unlock(_p_mlist);
1037
1038     if( libvlc_exception_raised(ex) )
1039         return false;
1040
1041     if( _p_mplayer )
1042     {
1043         libvlc_media_player_release( _p_mplayer );
1044         _p_mplayer = NULL;
1045     }
1046
1047     _p_mplayer = libvlc_media_player_new_from_media(p_m,ex);
1048     if( _p_mplayer )
1049         set_player_window(ex);
1050
1051     libvlc_media_release( p_m );
1052     return !libvlc_exception_raised(ex);
1053
1054 bad_unlock:
1055     libvlc_media_list_unlock(_p_mlist);
1056     return false;
1057 }
1058
1059 void VLCPlugin::set_player_window(libvlc_exception_t *ex)
1060 {
1061     // XXX FIXME no idea if this is correct or not
1062     libvlc_media_player_set_hwnd(_p_mplayer,getInPlaceWindow(),ex);
1063 }
1064
1065 int  VLCPlugin::playlist_add_extended_untrusted(const char *mrl, int optc, const char **optv, libvlc_exception_t *ex)
1066 {
1067     int item = -1;
1068     libvlc_media_t *p_m = libvlc_media_new(_p_libvlc,mrl,ex);
1069     if( libvlc_exception_raised(ex) )
1070         return -1;
1071
1072     for( int i = 0; i < optc; ++i )
1073         libvlc_media_add_option_flag(p_m, optv[i], libvlc_media_option_unique);
1074
1075     libvlc_media_list_lock(_p_mlist);
1076     libvlc_media_list_add_media(_p_mlist,p_m,ex);
1077     if( !libvlc_exception_raised(ex) )
1078         item = libvlc_media_list_count(_p_mlist,ex)-1;
1079     libvlc_media_list_unlock(_p_mlist);
1080     libvlc_media_release(p_m);
1081
1082     return item;
1083 }