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