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