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