]> git.sesse.net Git - vlc/blob - projects/activex/plugin.cpp
macosx: fixed menubar appearance in fullscreen mode by partially reverting [46c93c9cc...
[vlc] / 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++] = "--no-stats";
479     ppsz_argv[ppsz_argc++] = "--no-media-library";
480     ppsz_argv[ppsz_argc++] = "--ignore-config";
481     ppsz_argv[ppsz_argc++] = "--intf=dummy";
482
483     // loop mode is a configuration option only
484     if( _b_autoloop )
485         ppsz_argv[ppsz_argc++] = "--loop";
486
487     libvlc_exception_t ex;
488     libvlc_exception_init(&ex);
489
490     _p_libvlc = libvlc_new(ppsz_argc, ppsz_argv, &ex);
491     if( libvlc_exception_raised(&ex) )
492         return;
493
494     _p_mlist = libvlc_media_list_new(_p_libvlc, &ex);
495     if( libvlc_exception_raised(&ex) )
496     {
497         libvlc_release(_p_libvlc);
498         return;
499     }
500
501     // initial volume setting
502     libvlc_audio_set_volume(_p_libvlc, _i_volume, NULL);
503     if( _b_mute )
504     {
505         libvlc_audio_set_mute(_p_libvlc, TRUE, NULL);
506     }
507
508     // initial playlist item
509     if( SysStringLen(_bstr_mrl) > 0 )
510     {
511         char *psz_mrl = NULL;
512
513         if( SysStringLen(_bstr_baseurl) > 0 )
514         {
515             /*
516             ** if the MRL a relative URL, we should end up with an absolute URL
517             */
518             LPWSTR abs_url = CombineURL(_bstr_baseurl, _bstr_mrl);
519             if( NULL != abs_url )
520             {
521                 psz_mrl = CStrFromWSTR(CP_UTF8, abs_url, wcslen(abs_url));
522                 CoTaskMemFree(abs_url);
523             }
524             else
525             {
526                 psz_mrl = CStrFromBSTR(CP_UTF8, _bstr_mrl);
527             }
528         }
529         else
530         {
531             /*
532             ** baseURL is empty, assume MRL is absolute
533             */
534             psz_mrl = CStrFromBSTR(CP_UTF8, _bstr_mrl);
535         }
536         if( NULL != psz_mrl )
537         {
538             const char *options[1];
539             int i_options = 0;
540
541             char timeBuffer[32];
542             if( _i_time )
543             {
544                 snprintf(timeBuffer, sizeof(timeBuffer), ":start-time=%d", _i_time);
545                 options[i_options++] = timeBuffer;
546             }
547             // add default target to playlist
548             playlist_add_extended_untrusted(psz_mrl, i_options, options, NULL);
549             CoTaskMemFree(psz_mrl);
550         }
551     }
552 };
553
554 void VLCPlugin::setErrorInfo(REFIID riid, const char *description)
555 {
556     vlcSupportErrorInfo->setErrorInfo( getClassID() == CLSID_VLCPlugin2 ?
557         OLESTR("VideoLAN.VLCPlugin.2") : OLESTR("VideoLAN.VLCPlugin.1"),
558         riid, description );
559 };
560
561 HRESULT VLCPlugin::onAmbientChanged(LPUNKNOWN pContainer, DISPID dispID)
562 {
563     VARIANT v;
564     switch( dispID )
565     {
566         case DISPID_AMBIENT_BACKCOLOR:
567             VariantInit(&v);
568             V_VT(&v) = VT_I4;
569             if( SUCCEEDED(GetObjectProperty(pContainer, dispID, v)) )
570             {
571                 setBackColor(V_I4(&v));
572             }
573             break;
574         case DISPID_AMBIENT_DISPLAYNAME:
575             break;
576         case DISPID_AMBIENT_FONT:
577             break;
578         case DISPID_AMBIENT_FORECOLOR:
579             break;
580         case DISPID_AMBIENT_LOCALEID:
581             break;
582         case DISPID_AMBIENT_MESSAGEREFLECT:
583             break;
584         case DISPID_AMBIENT_SCALEUNITS:
585             break;
586         case DISPID_AMBIENT_TEXTALIGN:
587             break;
588         case DISPID_AMBIENT_USERMODE:
589             VariantInit(&v);
590             V_VT(&v) = VT_BOOL;
591             if( SUCCEEDED(GetObjectProperty(pContainer, dispID, v)) )
592             {
593                 setUserMode(V_BOOL(&v) != VARIANT_FALSE);
594             }
595             break;
596         case DISPID_AMBIENT_UIDEAD:
597             break;
598         case DISPID_AMBIENT_SHOWGRABHANDLES:
599             break;
600         case DISPID_AMBIENT_SHOWHATCHING:
601             break;
602         case DISPID_AMBIENT_DISPLAYASDEFAULT:
603             break;
604         case DISPID_AMBIENT_SUPPORTSMNEMONICS:
605             break;
606         case DISPID_AMBIENT_AUTOCLIP:
607             break;
608         case DISPID_AMBIENT_APPEARANCE:
609             break;
610         case DISPID_AMBIENT_CODEPAGE:
611             VariantInit(&v);
612             V_VT(&v) = VT_I4;
613             if( SUCCEEDED(GetObjectProperty(pContainer, dispID, v)) )
614             {
615                 setCodePage(V_I4(&v));
616             }
617             break;
618         case DISPID_AMBIENT_PALETTE:
619             break;
620         case DISPID_AMBIENT_CHARSET:
621             break;
622         case DISPID_AMBIENT_RIGHTTOLEFT:
623             break;
624         case DISPID_AMBIENT_TOPTOBOTTOM:
625             break;
626         case DISPID_UNKNOWN:
627             /*
628             ** multiple property change, look up the ones we are interested in
629             */
630             VariantInit(&v);
631             V_VT(&v) = VT_BOOL;
632             if( SUCCEEDED(GetObjectProperty(pContainer, DISPID_AMBIENT_USERMODE, v)) )
633             {
634                 setUserMode(V_BOOL(&v) != VARIANT_FALSE);
635             }
636             VariantInit(&v);
637             V_VT(&v) = VT_I4;
638             if( SUCCEEDED(GetObjectProperty(pContainer, DISPID_AMBIENT_CODEPAGE, v)) )
639             {
640                 setCodePage(V_I4(&v));
641             }
642             break;
643     }
644     return S_OK;
645 };
646
647 HRESULT VLCPlugin::onClose(DWORD dwSaveOption)
648 {
649     if( isInPlaceActive() )
650     {
651         onInPlaceDeactivate();
652     }
653     if( isRunning() )
654     {
655         libvlc_instance_t* p_libvlc = _p_libvlc;
656
657         IVLCLog *p_log;
658         if( SUCCEEDED(vlcControl2->get_log(&p_log)) )
659         {
660             // make sure the log is disabled
661             p_log->put_verbosity(-1);
662             p_log->Release();
663         }
664
665         _p_libvlc = NULL;
666         vlcDataObject->onClose();
667
668         if( p_libvlc )
669             libvlc_release(p_libvlc);
670     }
671     return S_OK;
672 };
673
674 BOOL VLCPlugin::isInPlaceActive(void)
675 {
676     return (NULL != _inplacewnd);
677 };
678
679 HRESULT VLCPlugin::onActivateInPlace(LPMSG lpMesg, HWND hwndParent, LPCRECT lprcPosRect, LPCRECT lprcClipRect)
680 {
681     RECT clipRect = *lprcClipRect;
682     libvlc_exception_t ex;
683     libvlc_exception_init(&ex);
684
685     /*
686     ** record keeping of control geometry within container
687     */
688     _posRect = *lprcPosRect;
689
690     /*
691     ** Create a window for in place activated control.
692     ** the window geometry matches the control viewport
693     ** within container so that embedded video is always
694     ** properly displayed.
695     */
696     _inplacewnd = CreateWindow(_p_class->getInPlaceWndClassName(),
697             TEXT("VLC Plugin In-Place Window"),
698             WS_CHILD|WS_CLIPCHILDREN|WS_CLIPSIBLINGS,
699             lprcPosRect->left,
700             lprcPosRect->top,
701             lprcPosRect->right-lprcPosRect->left,
702             lprcPosRect->bottom-lprcPosRect->top,
703             hwndParent,
704             0,
705             _p_class->getHInstance(),
706             NULL
707            );
708
709     if( NULL == _inplacewnd )
710         return E_FAIL;
711
712     SetWindowLongPtr(_inplacewnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this));
713
714     /* change cliprect coordinates system relative to window bounding rect */
715     OffsetRect(&clipRect, -lprcPosRect->left, -lprcPosRect->top);
716
717     HRGN clipRgn = CreateRectRgnIndirect(&clipRect);
718     SetWindowRgn(_inplacewnd, clipRgn, TRUE);
719
720     if( _b_usermode )
721     {
722         /* will run vlc if not done already */
723         libvlc_instance_t* p_libvlc;
724         HRESULT result = getVLC(&p_libvlc);
725         if( FAILED(result) )
726             return result;
727
728         /* set internal video width and height */
729         libvlc_video_set_size(p_libvlc,
730             lprcPosRect->right-lprcPosRect->left,
731             lprcPosRect->bottom-lprcPosRect->top,
732             NULL );
733
734         /* set internal video parent window */
735         libvlc_video_set_parent(p_libvlc,
736             reinterpret_cast<libvlc_drawable_t>(_inplacewnd), NULL);
737
738         if( _b_autoplay && playlist_select(0,NULL) )
739         {
740             libvlc_media_player_play(_p_mplayer,NULL);
741             fireOnPlayEvent();
742         }
743     }
744
745     if( isVisible() )
746         ShowWindow(_inplacewnd, SW_SHOW);
747
748     return S_OK;
749 };
750
751 HRESULT VLCPlugin::onInPlaceDeactivate(void)
752 {
753     if( isPlaying(NULL) )
754     {
755         playlist_stop(NULL);
756         fireOnStopEvent();
757     }
758
759     DestroyWindow(_inplacewnd);
760     _inplacewnd = NULL;
761
762     return S_OK;
763 };
764
765 void VLCPlugin::setVisible(BOOL fVisible)
766 {
767     if( fVisible != _b_visible )
768     {
769         _b_visible = fVisible;
770         if( isInPlaceActive() )
771         {
772             ShowWindow(_inplacewnd, fVisible ? SW_SHOW : SW_HIDE);
773             if( fVisible )
774                 InvalidateRect(_inplacewnd, NULL, TRUE);
775         }
776         setDirty(TRUE);
777         firePropChangedEvent(DISPID_Visible);
778     }
779 };
780
781 void VLCPlugin::setVolume(int volume)
782 {
783     if( volume < 0 )
784         volume = 0;
785     else if( volume > 200 )
786         volume = 200;
787
788     if( volume != _i_volume )
789     {
790         _i_volume = volume;
791         if( isRunning() )
792         {
793             libvlc_audio_set_volume(_p_libvlc, _i_volume, NULL);
794         }
795         setDirty(TRUE);
796     }
797 };
798
799 void VLCPlugin::setBackColor(OLE_COLOR backcolor)
800 {
801     if( _i_backcolor != backcolor )
802     {
803         _i_backcolor = backcolor;
804         if( isInPlaceActive() )
805         {
806
807         }
808         setDirty(TRUE);
809     }
810 };
811
812 void VLCPlugin::setTime(int seconds)
813 {
814     if( seconds < 0 )
815         seconds = 0;
816
817     if( seconds != _i_time )
818     {
819         setStartTime(_i_time);
820         if( NULL != _p_mplayer )
821         {
822             libvlc_media_player_set_time(_p_mplayer, _i_time, NULL);
823         }
824     }
825 };
826
827 void VLCPlugin::setFocus(BOOL fFocus)
828 {
829     if( fFocus )
830         SetActiveWindow(_inplacewnd);
831 };
832
833 BOOL VLCPlugin::hasFocus(void)
834 {
835     return GetActiveWindow() == _inplacewnd;
836 };
837
838 void VLCPlugin::onDraw(DVTARGETDEVICE * ptd, HDC hicTargetDev,
839         HDC hdcDraw, LPCRECTL lprcBounds, LPCRECTL lprcWBounds)
840 {
841     if( isVisible() )
842     {
843         long width = lprcBounds->right-lprcBounds->left;
844         long height = lprcBounds->bottom-lprcBounds->top;
845
846         RECT bounds = { lprcBounds->left, lprcBounds->top, lprcBounds->right, lprcBounds->bottom };
847
848         if( isUserMode() )
849         {
850             /* VLC is in user mode, just draw background color */
851             COLORREF colorref = RGB(0, 0, 0);
852             OleTranslateColor(_i_backcolor, (HPALETTE)GetStockObject(DEFAULT_PALETTE), &colorref);
853             if( colorref != RGB(0, 0, 0) )
854             {
855                 /* custom background */
856                 HBRUSH colorbrush = CreateSolidBrush(colorref);
857                 FillRect(hdcDraw, &bounds, colorbrush);
858                 DeleteObject((HANDLE)colorbrush);
859             }
860             else
861             {
862                 /* black background */
863                 FillRect(hdcDraw, &bounds, (HBRUSH)GetStockObject(BLACK_BRUSH));
864             }
865         }
866         else
867         {
868             /* VLC is in design mode, draw the VLC logo */
869             FillRect(hdcDraw, &bounds, (HBRUSH)GetStockObject(WHITE_BRUSH));
870
871             LPPICTURE pict = getPicture();
872             if( NULL != pict )
873             {
874                 OLE_XSIZE_HIMETRIC picWidth;
875                 OLE_YSIZE_HIMETRIC picHeight;
876
877                 pict->get_Width(&picWidth);
878                 pict->get_Height(&picHeight);
879
880                 SIZEL picSize = { picWidth, picHeight };
881
882                 if( NULL != hicTargetDev )
883                 {
884                     DPFromHimetric(hicTargetDev, (LPPOINT)&picSize, 1);
885                 }
886                 else if( NULL != (hicTargetDev = CreateDevDC(ptd)) )
887                 {
888                     DPFromHimetric(hicTargetDev, (LPPOINT)&picSize, 1);
889                     DeleteDC(hicTargetDev);
890                 }
891
892                 if( picSize.cx > width-4 )
893                     picSize.cx = width-4;
894                 if( picSize.cy > height-4 )
895                     picSize.cy = height-4;
896
897                 LONG dstX = lprcBounds->left+(width-picSize.cx)/2;
898                 LONG dstY = lprcBounds->top+(height-picSize.cy)/2;
899
900                 if( NULL != lprcWBounds )
901                 {
902                     RECT wBounds = { lprcWBounds->left, lprcWBounds->top, lprcWBounds->right, lprcWBounds->bottom };
903                     pict->Render(hdcDraw, dstX, dstY, picSize.cx, picSize.cy,
904                             0L, picHeight, picWidth, -picHeight, &wBounds);
905                 }
906                 else
907                     pict->Render(hdcDraw, dstX, dstY, picSize.cx, picSize.cy,
908                             0L, picHeight, picWidth, -picHeight, NULL);
909
910                 pict->Release();
911             }
912
913             SelectObject(hdcDraw, GetStockObject(BLACK_BRUSH));
914
915             MoveToEx(hdcDraw, bounds.left, bounds.top, NULL);
916             LineTo(hdcDraw, bounds.left+width-1, bounds.top);
917             LineTo(hdcDraw, bounds.left+width-1, bounds.top+height-1);
918             LineTo(hdcDraw, bounds.left, bounds.top+height-1);
919             LineTo(hdcDraw, bounds.left, bounds.top);
920         }
921     }
922 };
923
924 void VLCPlugin::onPaint(HDC hdc, const RECT &bounds, const RECT &clipRect)
925 {
926     if( isVisible() )
927     {
928         /* if VLC is in design mode, draw control logo */
929         HDC hdcDraw = CreateCompatibleDC(hdc);
930         if( NULL != hdcDraw )
931         {
932             SIZEL size = getExtent();
933             DPFromHimetric(hdc, (LPPOINT)&size, 1);
934             RECTL posRect = { 0, 0, size.cx, size.cy };
935
936             int width = bounds.right-bounds.left;
937             int height = bounds.bottom-bounds.top;
938
939             HBITMAP hBitmap = CreateCompatibleBitmap(hdc, width, height);
940             if( NULL != hBitmap )
941             {
942                 HBITMAP oldBmp = (HBITMAP)SelectObject(hdcDraw, hBitmap);
943
944                 if( (size.cx != width) || (size.cy != height) )
945                 {
946                     // needs to scale canvas
947                     SetMapMode(hdcDraw, MM_ANISOTROPIC);
948                     SetWindowExtEx(hdcDraw, size.cx, size.cy, NULL);
949                     SetViewportExtEx(hdcDraw, width, height, NULL);
950                 }
951
952                 onDraw(NULL, hdc, hdcDraw, &posRect, NULL);
953
954                 SetMapMode(hdcDraw, MM_TEXT);
955                 BitBlt(hdc, bounds.left, bounds.top,
956                         width, height,
957                         hdcDraw, 0, 0,
958                         SRCCOPY);
959
960                 SelectObject(hdcDraw, oldBmp);
961                 DeleteObject(hBitmap);
962             }
963             DeleteDC(hdcDraw);
964         }
965     }
966 };
967
968 void VLCPlugin::onPositionChange(LPCRECT lprcPosRect, LPCRECT lprcClipRect)
969 {
970     RECT clipRect = *lprcClipRect;
971
972     //RedrawWindow(GetParent(_inplacewnd), &_posRect, NULL, RDW_INVALIDATE|RDW_ERASE|RDW_ALLCHILDREN);
973
974     /*
975     ** record keeping of control geometry within container
976     */
977     _posRect = *lprcPosRect;
978
979     /*
980     ** change in-place window geometry to match clipping region
981     */
982     SetWindowPos(_inplacewnd, NULL,
983             lprcPosRect->left,
984             lprcPosRect->top,
985             lprcPosRect->right-lprcPosRect->left,
986             lprcPosRect->bottom-lprcPosRect->top,
987             SWP_NOACTIVATE|
988             SWP_NOCOPYBITS|
989             SWP_NOZORDER|
990             SWP_NOOWNERZORDER );
991
992     /* change cliprect coordinates system relative to window bounding rect */
993     OffsetRect(&clipRect, -lprcPosRect->left, -lprcPosRect->top);
994     HRGN clipRgn = CreateRectRgnIndirect(&clipRect);
995     SetWindowRgn(_inplacewnd, clipRgn, FALSE);
996
997     //RedrawWindow(_videownd, &posRect, NULL, RDW_INVALIDATE|RDW_ERASE|RDW_ALLCHILDREN);
998     if( isRunning() )
999     {
1000         libvlc_video_set_size(_p_libvlc,
1001             lprcPosRect->right-lprcPosRect->left,
1002             lprcPosRect->bottom-lprcPosRect->top,
1003             NULL );
1004     }
1005 };
1006
1007 void VLCPlugin::freezeEvents(BOOL freeze)
1008 {
1009     vlcConnectionPointContainer->freezeEvents(freeze);
1010 };
1011
1012 void VLCPlugin::firePropChangedEvent(DISPID dispid)
1013 {
1014     vlcConnectionPointContainer->firePropChangedEvent(dispid);
1015 };
1016
1017 void VLCPlugin::fireOnPlayEvent(void)
1018 {
1019     DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
1020     vlcConnectionPointContainer->fireEvent(DISPID_PlayEvent, &dispparamsNoArgs);
1021 };
1022
1023 void VLCPlugin::fireOnPauseEvent(void)
1024 {
1025     DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
1026     vlcConnectionPointContainer->fireEvent(DISPID_PauseEvent, &dispparamsNoArgs);
1027 };
1028
1029 void VLCPlugin::fireOnStopEvent(void)
1030 {
1031     DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
1032     vlcConnectionPointContainer->fireEvent(DISPID_StopEvent, &dispparamsNoArgs);
1033 };
1034
1035 bool VLCPlugin::playlist_select( int idx, libvlc_exception_t *ex )
1036 {
1037     libvlc_media_t *p_m = NULL;
1038
1039     libvlc_media_list_lock(_p_mlist);
1040
1041     int count = libvlc_media_list_count(_p_mlist,ex);
1042     if( libvlc_exception_raised(ex) )
1043         goto bad_unlock;
1044
1045     if( idx<0||idx>=count )
1046         goto bad_unlock;
1047
1048     _i_midx = idx;
1049
1050     p_m = libvlc_media_list_item_at_index(_p_mlist,_i_midx,ex);
1051     libvlc_media_list_unlock(_p_mlist);
1052
1053     if( libvlc_exception_raised(ex) )
1054         return false;
1055
1056     if( _p_mplayer )
1057     {
1058         libvlc_media_player_release( _p_mplayer );
1059         _p_mplayer = NULL;
1060     }
1061
1062     _p_mplayer = libvlc_media_player_new_from_media(p_m,ex);
1063     if( _p_mplayer )
1064         set_player_window(ex);
1065
1066     libvlc_media_release( p_m );
1067     return !libvlc_exception_raised(ex);
1068
1069 bad_unlock:
1070     libvlc_media_list_unlock(_p_mlist);
1071     return false;
1072 }
1073
1074 void VLCPlugin::set_player_window(libvlc_exception_t *ex)
1075 {
1076     // XXX FIXME no idea if this is correct or not
1077     libvlc_media_player_set_hwnd(_p_mplayer,getInPlaceWindow(),ex);
1078 }
1079
1080 int  VLCPlugin::playlist_add_extended_untrusted(const char *mrl, int optc, const char **optv, libvlc_exception_t *ex)
1081 {
1082     int item = -1;
1083     libvlc_media_t *p_m = libvlc_media_new(_p_libvlc,mrl,ex);
1084     if( libvlc_exception_raised(ex) )
1085         return -1;
1086
1087     for( int i = 0; i < optc; ++i )
1088     {
1089         libvlc_media_add_option_untrusted(p_m, optv[i],ex);
1090         if( libvlc_exception_raised(ex) )
1091         {
1092             libvlc_media_release(p_m);
1093             return -1;
1094         }
1095     }
1096
1097     libvlc_media_list_lock(_p_mlist);
1098     libvlc_media_list_add_media(_p_mlist,p_m,ex);
1099     if( !libvlc_exception_raised(ex) )
1100         item = libvlc_media_list_count(_p_mlist,ex)-1;
1101     libvlc_media_list_unlock(_p_mlist);
1102     libvlc_media_release(p_m);
1103
1104     return item;
1105 }
1106
1107