]> git.sesse.net Git - vlc/blob - activex/plugin.cpp
- all: intitial offscreen drawing support (mostly for printing). Unfortunately, video...
[vlc] / activex / plugin.cpp
1 /*****************************************************************************
2  * plugin.cpp: ActiveX control for VLC
3  *****************************************************************************
4  * Copyright (C) 2005 VideoLAN
5  *
6  * Authors: Damien Fouilleul <Damien.Fouilleul@laposte.net>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
21  *****************************************************************************/
22
23 #include "plugin.h"
24
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 "viewobject.h"
37
38 #include "utils.h"
39
40 #include <string.h>
41 #include <winreg.h>
42
43 using namespace std;
44
45 ////////////////////////////////////////////////////////////////////////
46 //class factory
47
48 // {E23FE9C6-778E-49d4-B537-38FCDE4887D8}
49 //const GUID CLSID_VLCPlugin = 
50 //    { 0xe23fe9c6, 0x778e, 0x49d4, { 0xb5, 0x37, 0x38, 0xfc, 0xde, 0x48, 0x87, 0xd8 } };
51
52 static LRESULT CALLBACK VLCInPlaceClassWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
53     switch( uMsg )
54     {
55         case WM_ERASEBKGND:
56             return 1L;
57
58         case WM_PAINT:
59             PAINTSTRUCT ps;
60             if( GetUpdateRect(hWnd, NULL, FALSE) )
61             {
62                 BeginPaint(hWnd, &ps);
63                 EndPaint(hWnd, &ps);
64             }
65             return 0L;
66
67         default:
68             return DefWindowProc(hWnd, uMsg, wParam, lParam);
69     }
70 };
71
72 static LRESULT CALLBACK VLCVideoClassWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
73     VLCPlugin *p_instance = reinterpret_cast<VLCPlugin *>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
74
75     switch( uMsg )
76     {
77         case WM_ERASEBKGND:
78             return 1L;
79
80         case WM_PAINT:
81             PAINTSTRUCT ps;
82             RECT pr;
83             if( GetUpdateRect(hWnd, &pr, FALSE) )
84             {
85                 RECT bounds;
86                 GetClientRect(hWnd, &bounds);
87                 BeginPaint(hWnd, &ps);
88                 p_instance->onPaint(ps.hdc, bounds, pr);
89                 EndPaint(hWnd, &ps);
90             }
91             return 0L;
92
93         default:
94             return DefWindowProc(hWnd, uMsg, wParam, lParam);
95     }
96 };
97
98 VLCPluginClass::VLCPluginClass(LONG *p_class_ref, HINSTANCE hInstance) :
99     _p_class_ref(p_class_ref),
100     _hinstance(hInstance)
101 {
102     WNDCLASS wClass;
103
104     if( ! GetClassInfo(hInstance, getInPlaceWndClassName(), &wClass) )
105     {
106         wClass.style          = CS_NOCLOSE|CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS;
107         wClass.lpfnWndProc    = VLCInPlaceClassWndProc;
108         wClass.cbClsExtra     = 0;
109         wClass.cbWndExtra     = 0;
110         wClass.hInstance      = hInstance;
111         wClass.hIcon          = NULL;
112         wClass.hCursor        = LoadCursor(NULL, IDC_ARROW);
113         wClass.hbrBackground  = NULL;
114         wClass.lpszMenuName   = NULL;
115         wClass.lpszClassName  = getInPlaceWndClassName();
116        
117         _inplace_wndclass_atom = RegisterClass(&wClass);
118     }
119     else
120     {
121         _inplace_wndclass_atom = 0;
122     }
123
124     if( ! GetClassInfo(hInstance, getVideoWndClassName(), &wClass) )
125     {
126         wClass.style          = CS_NOCLOSE|CS_HREDRAW|CS_VREDRAW;
127         wClass.lpfnWndProc    = VLCVideoClassWndProc;
128         wClass.cbClsExtra     = 0;
129         wClass.cbWndExtra     = 0;
130         wClass.hInstance      = hInstance;
131         wClass.hIcon          = NULL;
132         wClass.hCursor        = LoadCursor(NULL, IDC_ARROW);
133         wClass.hbrBackground  = NULL;
134         wClass.lpszMenuName   = NULL;
135         wClass.lpszClassName  = getVideoWndClassName();
136        
137         _video_wndclass_atom = RegisterClass(&wClass);
138     }
139     else
140     {
141         _video_wndclass_atom = 0;
142     }
143
144     _inplace_hbitmap = (HBITMAP)LoadImage(getHInstance(), TEXT("INPLACE-PICT"), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR);
145
146     AddRef();
147 };
148
149 VLCPluginClass::~VLCPluginClass()
150 {
151     if( 0 != _inplace_wndclass_atom )
152         UnregisterClass(MAKEINTATOM(_inplace_wndclass_atom), _hinstance);
153
154     if( 0 != _video_wndclass_atom )
155         UnregisterClass(MAKEINTATOM(_video_wndclass_atom), _hinstance);
156
157     if( NULL != _inplace_hbitmap )
158         DeleteObject(_inplace_hbitmap);
159 };
160
161 STDMETHODIMP VLCPluginClass::QueryInterface(REFIID riid, void **ppv)
162 {
163     if( NULL == ppv )
164         return E_INVALIDARG;
165
166     if( (IID_IUnknown == riid) || (IID_IClassFactory == riid) )
167     {
168         AddRef();
169         *ppv = reinterpret_cast<LPVOID>(this);
170
171         return NOERROR;
172     }
173
174     *ppv = NULL;
175
176     return E_NOINTERFACE;
177 };
178
179 STDMETHODIMP_(ULONG) VLCPluginClass::AddRef(void)
180 {
181     return InterlockedIncrement(_p_class_ref);
182 };
183
184 STDMETHODIMP_(ULONG) VLCPluginClass::Release(void)
185 {
186     ULONG refcount = InterlockedDecrement(_p_class_ref);
187     if( 0 == refcount )
188     {
189         delete this;
190         return 0;
191     }
192     return refcount;
193 };
194
195 STDMETHODIMP VLCPluginClass::CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppv)
196 {
197     if( NULL == ppv )
198         return E_POINTER;
199
200     *ppv = NULL;
201
202     if( NULL != pUnkOuter )
203         return CLASS_E_NOAGGREGATION;
204
205     VLCPlugin *plugin = new VLCPlugin(this);
206     if( NULL != plugin )
207     {
208         HRESULT hr = plugin->QueryInterface(riid, ppv);
209         plugin->Release();
210         return hr;
211     }
212     return E_OUTOFMEMORY;
213 };
214
215 STDMETHODIMP VLCPluginClass::LockServer(BOOL fLock)
216 {
217     if( fLock )
218         AddRef();
219     else 
220         Release();
221
222     return S_OK;
223 };
224
225 ////////////////////////////////////////////////////////////////////////
226
227 VLCPlugin::VLCPlugin(VLCPluginClass *p_class) :
228     _inplacewnd(NULL),
229     _p_class(p_class),
230     _i_ref(1UL),
231     _codepage(CP_ACP),
232     _psz_src(NULL),
233     _b_autostart(TRUE),
234     _b_loopmode(FALSE),
235     _b_visible(TRUE),
236     _b_sendevents(TRUE),
237     _i_vlc(0)
238 {
239     p_class->AddRef();
240
241     vlcOleObject = new VLCOleObject(this);
242     vlcOleControl = new VLCOleControl(this);
243     vlcOleInPlaceObject = new VLCOleInPlaceObject(this);
244     vlcOleInPlaceActiveObject = new VLCOleInPlaceActiveObject(this);
245     vlcPersistStorage = new VLCPersistStorage(this);
246     vlcPersistStreamInit = new VLCPersistStreamInit(this);
247     vlcPersistPropertyBag = new VLCPersistPropertyBag(this);
248     vlcProvideClassInfo = new VLCProvideClassInfo(this);
249     vlcConnectionPointContainer = new VLCConnectionPointContainer(this);
250     vlcObjectSafety = new VLCObjectSafety(this);
251     vlcControl = new VLCControl(this);
252     vlcViewObject = new VLCViewObject(this);
253 };
254
255 VLCPlugin::~VLCPlugin()
256 {
257     vlcOleInPlaceObject->UIDeactivate();
258     vlcOleInPlaceObject->InPlaceDeactivate();
259
260     delete vlcViewObject;
261     delete vlcControl;
262     delete vlcObjectSafety;
263     delete vlcConnectionPointContainer;
264     delete vlcProvideClassInfo;
265     delete vlcPersistPropertyBag;
266     delete vlcPersistStreamInit;
267     delete vlcPersistStorage;
268     delete vlcOleInPlaceActiveObject;
269     delete vlcOleInPlaceObject;
270     delete vlcOleControl;
271     delete vlcOleObject;
272
273     if( _psz_src )
274         free(_psz_src);
275
276     _p_class->Release();
277 };
278
279 STDMETHODIMP VLCPlugin::QueryInterface(REFIID riid, void **ppv)
280 {
281     if( NULL == ppv )
282         return E_INVALIDARG;
283
284     if( IID_IUnknown == riid )
285     {
286         AddRef();
287         *ppv = reinterpret_cast<LPVOID>(this);
288         return NOERROR;
289     }
290     else if( IID_IOleObject == riid )
291     {
292         AddRef();
293         *ppv = reinterpret_cast<LPVOID>(vlcOleObject);
294         return NOERROR;
295     }
296     else if( IID_IOleControl == riid )
297     {
298         AddRef();
299         *ppv = reinterpret_cast<LPVOID>(vlcOleControl);
300         return NOERROR;
301     }
302     else if( IID_IOleWindow == riid )
303     {
304         AddRef();
305         *ppv = reinterpret_cast<LPVOID>(vlcOleInPlaceObject);
306         return NOERROR;
307     }
308     else if( IID_IOleInPlaceObject == riid )
309     {
310         AddRef();
311         *ppv = reinterpret_cast<LPVOID>(vlcOleInPlaceObject);
312         return NOERROR;
313     }
314     else if( IID_IOleInPlaceActiveObject == riid )
315     {
316         AddRef();
317         *ppv = reinterpret_cast<LPVOID>(vlcOleInPlaceActiveObject);
318         return NOERROR;
319     }
320     else if( IID_IPersist == riid )
321     {
322         AddRef();
323         *ppv = reinterpret_cast<LPVOID>(vlcPersistPropertyBag);
324         return NOERROR;
325     }
326     else if( IID_IPersistStreamInit == riid )
327     {
328         AddRef();
329         *ppv = reinterpret_cast<LPVOID>(vlcPersistStreamInit);
330         return NOERROR;
331     }
332     else if( IID_IPersistStorage == riid )
333     {
334         AddRef();
335         *ppv = reinterpret_cast<LPVOID>(vlcPersistStorage);
336         return NOERROR;
337     }
338     else if( IID_IPersistPropertyBag == riid )
339     {
340         AddRef();
341         *ppv = reinterpret_cast<LPVOID>(vlcPersistPropertyBag);
342         return NOERROR;
343     }
344     else if( IID_IProvideClassInfo == riid )
345     {
346         AddRef();
347         *ppv = reinterpret_cast<LPVOID>(vlcProvideClassInfo);
348         return NOERROR;
349     }
350     else if( IID_IProvideClassInfo2 == riid )
351     {
352         AddRef();
353         *ppv = reinterpret_cast<LPVOID>(vlcProvideClassInfo);
354         return NOERROR;
355     }
356     else if( IID_IConnectionPointContainer == riid )
357     {
358         AddRef();
359         *ppv = reinterpret_cast<LPVOID>(vlcConnectionPointContainer);
360         return NOERROR;
361     }
362     else if( IID_IObjectSafety == riid )
363     {
364         AddRef();
365         *ppv = reinterpret_cast<LPVOID>(vlcObjectSafety);
366         return NOERROR;
367     }
368     else if( IID_IDispatch == riid )
369     {
370         AddRef();
371         *ppv = reinterpret_cast<LPVOID>(vlcControl);
372         return NOERROR;
373     }
374     else if( IID_IVLCControl == riid )
375     {
376         AddRef();
377         *ppv = reinterpret_cast<LPVOID>(vlcControl);
378         return NOERROR;
379     }
380     else if( IID_IViewObject == riid )
381     {
382         AddRef();
383         *ppv = reinterpret_cast<LPVOID>(vlcViewObject);
384         return NOERROR;
385     }
386
387     *ppv = NULL;
388
389     return E_NOINTERFACE;
390 };
391
392 STDMETHODIMP_(ULONG) VLCPlugin::AddRef(void)
393 {
394     return InterlockedIncrement((LONG *)&_i_ref);
395 };
396
397 STDMETHODIMP_(ULONG) VLCPlugin::Release(void)
398 {
399     if( ! InterlockedDecrement((LONG *)&_i_ref) )
400     {
401         delete this;
402         return 0;
403     }
404     return _i_ref;
405 };
406
407 //////////////////////////////////////
408
409 /*
410 ** we use an in-place child window to represent plugin viewport,
411 ** whose size is limited by the clipping rectangle
412 ** all drawing within this window must follow 
413 ** cartesian coordinate system represented by _bounds.
414 */
415
416 void VLCPlugin::calcPositionChange(LPRECT lprPosRect, LPCRECT lprcClipRect)
417 {
418     _bounds.right  = lprPosRect->right-lprPosRect->left;
419
420     if( lprcClipRect->left <= lprPosRect->left )
421     {
422         // left side is not clipped out
423         _bounds.left = 0;
424
425         if( lprcClipRect->right >= lprPosRect->right )
426         {
427             // right side is not clipped out, no change
428         }
429         else if( lprcClipRect->right >= lprPosRect->left )
430         {
431             // right side is clipped out
432             lprPosRect->right = lprcClipRect->right;
433         }
434         else
435         {
436             // outside of clipping rectange, not visible
437             lprPosRect->right = lprPosRect->left;
438         }
439     }
440     else
441     {
442         // left side is clipped out
443         _bounds.left = lprPosRect->left-lprcClipRect->left;
444         _bounds.right += _bounds.left;
445
446         lprPosRect->left = lprcClipRect->left;
447         if( lprcClipRect->right >= lprPosRect->right )
448         {
449             // right side is not clipped out
450         }
451         else
452         {
453             // right side is clipped out
454             lprPosRect->right = lprcClipRect->right;
455         }
456     }
457
458     _bounds.bottom = lprPosRect->bottom-lprPosRect->top;
459
460     if( lprcClipRect->top <= lprPosRect->top )
461     {
462         // top side is not clipped out
463         _bounds.top = 0;
464
465         if( lprcClipRect->bottom >= lprPosRect->bottom )
466         {
467             // bottom side is not clipped out, no change
468         }
469         else if( lprcClipRect->bottom >= lprPosRect->top )
470         {
471             // bottom side is clipped out
472             lprPosRect->bottom = lprcClipRect->bottom;
473         }
474         else
475         {
476             // outside of clipping rectange, not visible
477             lprPosRect->right = lprPosRect->left;
478         }
479     }
480     else
481     {
482         _bounds.top = lprPosRect->top-lprcClipRect->top;
483         _bounds.bottom += _bounds.top;
484
485         lprPosRect->top = lprcClipRect->top;
486         if( lprcClipRect->bottom >= lprPosRect->bottom )
487         {
488             // bottom side is not clipped out
489         }
490         else
491         {
492             // bottom side is clipped out
493             lprPosRect->bottom = lprcClipRect->bottom;
494         }
495     }
496 };
497
498 HRESULT VLCPlugin::onInit(BOOL isNew)
499 {
500     if( 0 == _i_vlc )
501     {
502 #ifdef ACTIVEX_DEBUG
503         char *ppsz_argv[] = { "vlc", "-vvv", "--fast-mutex", "--win9x-cv-method=1" };
504 #else
505         char *ppsz_argv[] = { "vlc", "-vv" };
506 #endif
507         HKEY h_key;
508         DWORD i_type, i_data = MAX_PATH + 1;
509         char p_data[MAX_PATH + 1];
510         if( RegOpenKeyEx( HKEY_LOCAL_MACHINE, "Software\\VideoLAN\\VLC",
511                           0, KEY_READ, &h_key ) == ERROR_SUCCESS )
512         {
513              if( RegQueryValueEx( h_key, "InstallDir", 0, &i_type,
514                                   (LPBYTE)p_data, &i_data ) == ERROR_SUCCESS )
515              {
516                  if( i_type == REG_SZ )
517                  {
518                      strcat( p_data, "\\vlc" );
519                      ppsz_argv[0] = p_data;
520                  }
521              }
522              RegCloseKey( h_key );
523         }
524
525 #if 0
526         ppsz_argv[0] = "C:\\cygwin\\home\\Damien_Fouilleul\\dev\\videolan\\vlc-trunk\\vlc";
527 #endif
528
529         _i_vlc = VLC_Create();
530
531         if( VLC_Init(_i_vlc, sizeof(ppsz_argv)/sizeof(char*), ppsz_argv) )
532         {
533             VLC_Destroy(_i_vlc);
534             _i_vlc = 0;
535             return E_FAIL;
536         }
537
538         if( isNew )
539         {
540             /*
541             ** object has fully initialized,
542             ** try to activate in place if container is ready
543             */
544             LPOLECLIENTSITE pActiveSite;
545
546             if( SUCCEEDED(vlcOleObject->GetClientSite(&pActiveSite)) && (NULL != pActiveSite) )
547             {
548                 vlcOleObject->DoVerb(OLEIVERB_INPLACEACTIVATE, NULL, pActiveSite, 0, NULL, NULL);
549                 pActiveSite->Release();
550             }
551         }
552         return S_OK;
553     }
554     return E_UNEXPECTED;
555 };
556
557 HRESULT VLCPlugin::onLoad(void)
558 {
559     /*
560     ** object has fully initialized,
561     ** try to activate in place if container is ready
562     */
563     LPOLECLIENTSITE pActiveSite;
564
565     if( SUCCEEDED(vlcOleObject->GetClientSite(&pActiveSite)) && (NULL != pActiveSite) )
566     {
567         vlcOleObject->DoVerb(OLEIVERB_INPLACEACTIVATE, NULL, pActiveSite, 0, NULL, NULL);
568         pActiveSite->Release();
569     }
570     return S_OK;
571 };
572
573 HRESULT VLCPlugin::onClientSiteChanged(LPOLECLIENTSITE pActiveSite)
574 {
575     if( NULL != pActiveSite )
576     {
577         /*
578         ** object is embedded in container 
579         ** try to activate in place if it has initialized
580         */
581         if( _i_vlc )
582         {
583             vlcOleObject->DoVerb(OLEIVERB_INPLACEACTIVATE, NULL, pActiveSite, 0, NULL, NULL);
584         }
585     }
586     return S_OK;
587 };
588
589 HRESULT VLCPlugin::onClose(DWORD dwSaveOption)
590 {
591     if( _i_vlc )
592     {
593         if( isInPlaceActive() )
594         {
595             onInPlaceDeactivate();
596         }
597
598         VLC_CleanUp(_i_vlc);
599         VLC_Destroy(_i_vlc);
600         _i_vlc = 0;
601     }
602     return S_OK;
603 };
604
605 BOOL VLCPlugin::isInPlaceActive(void)
606 {
607     return (NULL != _inplacewnd);
608 };
609
610 HRESULT VLCPlugin::onActivateInPlace(LPMSG lpMesg, HWND hwndParent, LPCRECT lprcPosRect, LPCRECT lprcClipRect)
611 {
612     RECT posRect = *lprcPosRect;
613
614     calcPositionChange(&posRect, lprcClipRect);
615
616     _inplacewnd = CreateWindow(_p_class->getInPlaceWndClassName(),
617             "VLC Plugin In-Place Window",
618             WS_CHILD|WS_CLIPCHILDREN|WS_TABSTOP,
619             posRect.left,
620             posRect.top,
621             posRect.right-posRect.left,
622             posRect.bottom-posRect.top,
623             hwndParent,
624             0,
625             _p_class->getHInstance(),
626             NULL
627            );
628
629     if( NULL == _inplacewnd )
630         return E_FAIL;
631
632     SetWindowLongPtr(_inplacewnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this));
633
634     _videownd = CreateWindow(_p_class->getVideoWndClassName(),
635             "VLC Plugin Video Window",
636             WS_CHILD|WS_CLIPCHILDREN|WS_VISIBLE,
637             _bounds.left,
638             _bounds.top,
639             _bounds.right-_bounds.left,
640             _bounds.bottom-_bounds.top,
641             _inplacewnd,
642             0,
643             _p_class->getHInstance(),
644             NULL
645            );
646
647     if( NULL == _videownd )
648     {
649         DestroyWindow(_inplacewnd);
650         return E_FAIL;
651     }
652
653     SetWindowLongPtr(_videownd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this));
654
655     if( getVisible() )
656         ShowWindow(_inplacewnd, SW_SHOWNORMAL);
657
658     /* horrible cast there */
659     vlc_value_t val;
660     val.i_int = reinterpret_cast<int>(_videownd);
661     VLC_VariableSet(_i_vlc, "drawable", val);
662
663     if( NULL != _psz_src )
664     {
665         // add target to playlist
666         char *cOptions[1];
667         int  cOptionsCount = 0;
668
669         if( _b_loopmode )
670         {
671             cOptions[cOptionsCount++] = "loop";
672         }
673         VLC_AddTarget(_i_vlc, _psz_src, (const char **)&cOptions, cOptionsCount, PLAYLIST_APPEND, PLAYLIST_END);
674
675         if( _b_autostart )
676         {
677             VLC_Play(_i_vlc);
678             fireOnPlayEvent();
679         }
680     }
681     return S_OK;
682 };
683
684 HRESULT VLCPlugin::onInPlaceDeactivate(void)
685 {
686     VLC_Stop(_i_vlc);
687     fireOnStopEvent();
688
689     DestroyWindow(_videownd);
690     _videownd = NULL;
691     DestroyWindow(_inplacewnd);
692     _inplacewnd = NULL;
693  
694     return S_OK;
695 };
696
697 void VLCPlugin::setVisible(BOOL fVisible)
698 {
699     _b_visible = fVisible;
700     if( isInPlaceActive() )
701         ShowWindow(_inplacewnd, fVisible ? SW_SHOWNORMAL : SW_HIDE);
702     firePropChangedEvent(DISPID_Visible);
703 };
704
705 void VLCPlugin::setFocus(BOOL fFocus)
706 {
707     if( fFocus )
708         SetActiveWindow(_inplacewnd);
709 };
710
711 BOOL VLCPlugin::hasFocus(void)
712 {
713     return GetActiveWindow() == _inplacewnd;
714 };
715
716 void VLCPlugin::onPaint(HDC hdc, const RECT &bounds, const RECT &pr)
717 {
718     /*
719     ** if VLC is playing, it may not display any VIDEO content 
720     ** hence, draw control logo
721     */ 
722     int width = bounds.right-bounds.left;
723     int height = bounds.bottom-bounds.top;
724
725     HBITMAP pict = _p_class->getInPlacePict();
726     if( NULL != pict )
727     {
728         HDC hdcPict = CreateCompatibleDC(hdc);
729         if( NULL != hdcPict )
730         {
731             BITMAP bm;
732             if( GetObject(pict, sizeof(BITMAPINFO), &bm) )
733             {
734                 int dstWidth = bm.bmWidth;
735                 if( dstWidth > width-4 )
736                     dstWidth = width-4;
737
738                 int dstHeight = bm.bmHeight;
739                 if( dstHeight > height-4 )
740                     dstHeight = height-4;
741
742                 int dstX = bounds.left+(width-dstWidth)/2;
743                 int dstY = bounds.top+(height-dstHeight)/2;
744
745                 SelectObject(hdcPict, pict);
746                 StretchBlt(hdc, dstX, dstY, dstWidth, dstHeight,
747                         hdcPict, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);
748                 DeleteDC(hdcPict);
749                 ExcludeClipRect(hdc, dstX, dstY, dstWidth+dstX, dstHeight+dstY);
750             }
751         }
752     }
753
754     FillRect(hdc, &pr, (HBRUSH)GetStockObject(WHITE_BRUSH));
755     SelectObject(hdc, GetStockObject(BLACK_BRUSH));
756
757     MoveToEx(hdc, bounds.left, bounds.top, NULL);
758     LineTo(hdc, bounds.left+width-1, bounds.top);
759     LineTo(hdc, bounds.left+width-1, bounds.top+height-1);
760     LineTo(hdc, bounds.left, bounds.top+height-1);
761     LineTo(hdc, bounds.left, bounds.top);
762 };
763
764 void VLCPlugin::onPositionChange(LPCRECT lprcPosRect, LPCRECT lprcClipRect)
765 {
766     RECT posRect = *lprcPosRect;
767
768     calcPositionChange(&posRect, lprcClipRect);
769
770     /*
771     ** change in-place window geometry to match clipping region
772     */
773     MoveWindow(_inplacewnd,
774             posRect.left,
775             posRect.top,
776             posRect.right-posRect.left,
777             posRect.bottom-posRect.top,
778             FALSE);
779
780     /*
781     ** change video window geometry to match object bounds within clipping region
782     */
783     MoveWindow(_videownd,
784             _bounds.left,
785             _bounds.top,
786             _bounds.right-_bounds.left,
787             _bounds.bottom-_bounds.top,
788             FALSE);
789
790     RECT updateRect;
791
792     updateRect.left = -_bounds.left;
793     updateRect.top = -_bounds.top;
794     updateRect.right = _bounds.right-_bounds.left;
795     updateRect.bottom = _bounds.bottom-_bounds.top;
796
797     ValidateRect(_videownd, NULL);
798     InvalidateRect(_videownd, &updateRect, FALSE);
799     UpdateWindow(_videownd);
800 };
801
802 void VLCPlugin::firePropChangedEvent(DISPID dispid)
803 {
804     if( _b_sendevents )
805     {
806         vlcConnectionPointContainer->firePropChangedEvent(dispid); 
807     }
808 };
809
810 void VLCPlugin::fireOnPlayEvent(void)
811 {
812     if( _b_sendevents )
813     {
814         DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
815         vlcConnectionPointContainer->fireEvent(DISPID_PlayEvent, &dispparamsNoArgs); 
816     }
817 };
818
819 void VLCPlugin::fireOnPauseEvent(void)
820 {
821     if( _b_sendevents )
822     {
823         DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
824         vlcConnectionPointContainer->fireEvent(DISPID_PauseEvent, &dispparamsNoArgs); 
825     }
826 };
827
828 void VLCPlugin::fireOnStopEvent(void)
829 {
830     if( _b_sendevents )
831     {
832         DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
833         vlcConnectionPointContainer->fireEvent(DISPID_StopEvent, &dispparamsNoArgs); 
834     }
835 };
836