]> git.sesse.net Git - vlc/blob - activex/plugin.cpp
- previously checked in this file to work only within my debug environment
[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     // set default/preferred size (320x240) pixels in HIMETRIC
255     HDC hDC = CreateDevDC(NULL);
256     _extent.cx = (320*2540L)/GetDeviceCaps(hDC, LOGPIXELSX);
257     _extent.cy = (240*2540L)/GetDeviceCaps(hDC, LOGPIXELSY);
258     DeleteDC(hDC);
259 };
260
261 VLCPlugin::~VLCPlugin()
262 {
263     vlcOleInPlaceObject->UIDeactivate();
264     vlcOleInPlaceObject->InPlaceDeactivate();
265
266     delete vlcViewObject;
267     delete vlcControl;
268     delete vlcObjectSafety;
269     delete vlcConnectionPointContainer;
270     delete vlcProvideClassInfo;
271     delete vlcPersistPropertyBag;
272     delete vlcPersistStreamInit;
273     delete vlcPersistStorage;
274     delete vlcOleInPlaceActiveObject;
275     delete vlcOleInPlaceObject;
276     delete vlcOleControl;
277     delete vlcOleObject;
278
279     if( _psz_src )
280         free(_psz_src);
281
282     _p_class->Release();
283 };
284
285 STDMETHODIMP VLCPlugin::QueryInterface(REFIID riid, void **ppv)
286 {
287     if( NULL == ppv )
288         return E_INVALIDARG;
289
290     if( IID_IUnknown == riid )
291     {
292         AddRef();
293         *ppv = reinterpret_cast<LPVOID>(this);
294         return NOERROR;
295     }
296     else if( IID_IOleObject == riid )
297     {
298         AddRef();
299         *ppv = reinterpret_cast<LPVOID>(vlcOleObject);
300         return NOERROR;
301     }
302     else if( IID_IOleControl == riid )
303     {
304         AddRef();
305         *ppv = reinterpret_cast<LPVOID>(vlcOleControl);
306         return NOERROR;
307     }
308     else if( IID_IOleWindow == riid )
309     {
310         AddRef();
311         *ppv = reinterpret_cast<LPVOID>(vlcOleInPlaceObject);
312         return NOERROR;
313     }
314     else if( IID_IOleInPlaceObject == riid )
315     {
316         AddRef();
317         *ppv = reinterpret_cast<LPVOID>(vlcOleInPlaceObject);
318         return NOERROR;
319     }
320     else if( IID_IOleInPlaceActiveObject == riid )
321     {
322         AddRef();
323         *ppv = reinterpret_cast<LPVOID>(vlcOleInPlaceActiveObject);
324         return NOERROR;
325     }
326     else if( IID_IPersist == riid )
327     {
328         AddRef();
329         *ppv = reinterpret_cast<LPVOID>(vlcPersistPropertyBag);
330         return NOERROR;
331     }
332     else if( IID_IPersistStreamInit == riid )
333     {
334         AddRef();
335         *ppv = reinterpret_cast<LPVOID>(vlcPersistStreamInit);
336         return NOERROR;
337     }
338     else if( IID_IPersistStorage == riid )
339     {
340         AddRef();
341         *ppv = reinterpret_cast<LPVOID>(vlcPersistStorage);
342         return NOERROR;
343     }
344     else if( IID_IPersistPropertyBag == riid )
345     {
346         AddRef();
347         *ppv = reinterpret_cast<LPVOID>(vlcPersistPropertyBag);
348         return NOERROR;
349     }
350     else if( IID_IProvideClassInfo == riid )
351     {
352         AddRef();
353         *ppv = reinterpret_cast<LPVOID>(vlcProvideClassInfo);
354         return NOERROR;
355     }
356     else if( IID_IProvideClassInfo2 == riid )
357     {
358         AddRef();
359         *ppv = reinterpret_cast<LPVOID>(vlcProvideClassInfo);
360         return NOERROR;
361     }
362     else if( IID_IConnectionPointContainer == riid )
363     {
364         AddRef();
365         *ppv = reinterpret_cast<LPVOID>(vlcConnectionPointContainer);
366         return NOERROR;
367     }
368     else if( IID_IObjectSafety == riid )
369     {
370         AddRef();
371         *ppv = reinterpret_cast<LPVOID>(vlcObjectSafety);
372         return NOERROR;
373     }
374     else if( IID_IDispatch == riid )
375     {
376         AddRef();
377         *ppv = reinterpret_cast<LPVOID>(vlcControl);
378         return NOERROR;
379     }
380     else if( IID_IVLCControl == riid )
381     {
382         AddRef();
383         *ppv = reinterpret_cast<LPVOID>(vlcControl);
384         return NOERROR;
385     }
386     else if( IID_IViewObject == riid )
387     {
388         AddRef();
389         *ppv = reinterpret_cast<LPVOID>(vlcViewObject);
390         return NOERROR;
391     }
392     else if( IID_IViewObject2 == riid )
393     {
394         AddRef();
395         *ppv = reinterpret_cast<LPVOID>(vlcViewObject);
396         return NOERROR;
397     }
398
399     *ppv = NULL;
400
401     return E_NOINTERFACE;
402 };
403
404 STDMETHODIMP_(ULONG) VLCPlugin::AddRef(void)
405 {
406     return InterlockedIncrement((LONG *)&_i_ref);
407 };
408
409 STDMETHODIMP_(ULONG) VLCPlugin::Release(void)
410 {
411     if( ! InterlockedDecrement((LONG *)&_i_ref) )
412     {
413         delete this;
414         return 0;
415     }
416     return _i_ref;
417 };
418
419 //////////////////////////////////////
420
421 /*
422 ** we use a window to represent plugin viewport,
423 ** whose geometry is limited by the clipping rectangle
424 ** all drawing within this window must follow must
425 ** follow coordinates system described in lprPosRect
426 */
427
428 static void getViewportCoords(LPRECT lprPosRect, LPRECT lprClipRect)
429 {
430     RECT bounds;
431     bounds.right  = lprPosRect->right-lprPosRect->left;
432
433     if( lprClipRect->left <= lprPosRect->left )
434     {
435         // left side is not clipped out
436         bounds.left = 0;
437
438         if( lprClipRect->right >= lprPosRect->right )
439         {
440             // right side is not clipped out, no change
441         }
442         else if( lprClipRect->right >= lprPosRect->left )
443         {
444             // right side is clipped out
445             lprPosRect->right = lprClipRect->right;
446         }
447         else
448         {
449             // outside of clipping rectange, not visible
450             lprPosRect->right = lprPosRect->left;
451         }
452     }
453     else
454     {
455         // left side is clipped out
456         bounds.left = lprPosRect->left-lprClipRect->left;
457         bounds.right += bounds.left;
458
459         lprPosRect->left = lprClipRect->left;
460         if( lprClipRect->right >= lprPosRect->right )
461         {
462             // right side is not clipped out
463         }
464         else
465         {
466             // right side is clipped out
467             lprPosRect->right = lprClipRect->right;
468         }
469     }
470
471     bounds.bottom = lprPosRect->bottom-lprPosRect->top;
472
473     if( lprClipRect->top <= lprPosRect->top )
474     {
475         // top side is not clipped out
476         bounds.top = 0;
477
478         if( lprClipRect->bottom >= lprPosRect->bottom )
479         {
480             // bottom side is not clipped out, no change
481         }
482         else if( lprClipRect->bottom >= lprPosRect->top )
483         {
484             // bottom side is clipped out
485             lprPosRect->bottom = lprClipRect->bottom;
486         }
487         else
488         {
489             // outside of clipping rectange, not visible
490             lprPosRect->right = lprPosRect->left;
491         }
492     }
493     else
494     {
495         bounds.top = lprPosRect->top-lprClipRect->top;
496         bounds.bottom += bounds.top;
497
498         lprPosRect->top = lprClipRect->top;
499         if( lprClipRect->bottom >= lprPosRect->bottom )
500         {
501             // bottom side is not clipped out
502         }
503         else
504         {
505             // bottom side is clipped out
506             lprPosRect->bottom = lprClipRect->bottom;
507         }
508     }
509     *lprClipRect = *lprPosRect;
510     *lprPosRect  = bounds;
511 };
512
513 HRESULT VLCPlugin::onInit(BOOL isNew)
514 {
515     if( 0 == _i_vlc )
516     {
517 #ifdef ACTIVEX_DEBUG
518         char *ppsz_argv[] = { "vlc", "-vvv", "--fast-mutex", "--win9x-cv-method=1" };
519 #else
520         char *ppsz_argv[] = { "vlc", "-vv" };
521 #endif
522         HKEY h_key;
523         DWORD i_type, i_data = MAX_PATH + 1;
524         char p_data[MAX_PATH + 1];
525         if( RegOpenKeyEx( HKEY_LOCAL_MACHINE, "Software\\VideoLAN\\VLC",
526                           0, KEY_READ, &h_key ) == ERROR_SUCCESS )
527         {
528              if( RegQueryValueEx( h_key, "InstallDir", 0, &i_type,
529                                   (LPBYTE)p_data, &i_data ) == ERROR_SUCCESS )
530              {
531                  if( i_type == REG_SZ )
532                  {
533                      strcat( p_data, "\\vlc" );
534                      ppsz_argv[0] = p_data;
535                  }
536              }
537              RegCloseKey( h_key );
538         }
539
540 #if 0
541         ppsz_argv[0] = "C:\\cygwin\\home\\Damien_Fouilleul\\dev\\videolan\\vlc-trunk\\vlc";
542 #endif
543
544         _i_vlc = VLC_Create();
545
546         if( VLC_Init(_i_vlc, sizeof(ppsz_argv)/sizeof(char*), ppsz_argv) )
547         {
548             VLC_Destroy(_i_vlc);
549             _i_vlc = 0;
550             return E_FAIL;
551         }
552
553         if( isNew )
554         {
555             /*
556             ** object has fully initialized,
557             ** try to activate in place if container is ready
558             */
559             LPOLECLIENTSITE pActiveSite;
560
561             if( SUCCEEDED(vlcOleObject->GetClientSite(&pActiveSite)) && (NULL != pActiveSite) )
562             {
563                 vlcOleObject->DoVerb(OLEIVERB_INPLACEACTIVATE, NULL, pActiveSite, 0, NULL, NULL);
564                 pActiveSite->Release();
565             }
566         }
567         return S_OK;
568     }
569     return E_UNEXPECTED;
570 };
571
572 HRESULT VLCPlugin::onLoad(void)
573 {
574     /*
575     ** object has fully initialized,
576     ** try to activate in place if container is ready
577     */
578     LPOLECLIENTSITE pActiveSite;
579
580     if( SUCCEEDED(vlcOleObject->GetClientSite(&pActiveSite)) && (NULL != pActiveSite) )
581     {
582         vlcOleObject->DoVerb(OLEIVERB_INPLACEACTIVATE, NULL, pActiveSite, 0, NULL, NULL);
583         pActiveSite->Release();
584     }
585     return S_OK;
586 };
587
588 HRESULT VLCPlugin::onClientSiteChanged(LPOLECLIENTSITE pActiveSite)
589 {
590     if( NULL != pActiveSite )
591     {
592         /*
593         ** object is embedded in container 
594         ** try to activate in place if it has initialized
595         */
596         if( _i_vlc )
597         {
598             vlcOleObject->DoVerb(OLEIVERB_INPLACEACTIVATE, NULL, pActiveSite, 0, NULL, NULL);
599         }
600     }
601     return S_OK;
602 };
603
604 HRESULT VLCPlugin::onClose(DWORD dwSaveOption)
605 {
606     if( _i_vlc )
607     {
608         if( isInPlaceActive() )
609         {
610             onInPlaceDeactivate();
611         }
612
613         VLC_CleanUp(_i_vlc);
614         VLC_Destroy(_i_vlc);
615         _i_vlc = 0;
616     }
617     return S_OK;
618 };
619
620 BOOL VLCPlugin::isInPlaceActive(void)
621 {
622     return (NULL != _inplacewnd);
623 };
624
625 HRESULT VLCPlugin::onActivateInPlace(LPMSG lpMesg, HWND hwndParent, LPCRECT lprcPosRect, LPCRECT lprcClipRect)
626 {
627     RECT posRect = *lprcPosRect;
628     RECT clipRect = *lprcClipRect;
629
630     /*
631     ** record keeping of control geometry within container
632     */ 
633     _posRect = posRect;
634
635     /*
636     ** convert posRect & clipRect to match control viewport coordinates
637     */
638     getViewportCoords(&posRect, &clipRect);
639
640     /*
641     ** Create a window for in place activated control.
642     ** the window geometry represents the control viewport
643     ** so that embedded video is always properly clipped.
644     */
645     _inplacewnd = CreateWindow(_p_class->getInPlaceWndClassName(),
646             "VLC Plugin In-Place Window",
647             WS_CHILD|WS_CLIPCHILDREN|WS_TABSTOP,
648             clipRect.left,
649             clipRect.top,
650             clipRect.right-clipRect.left,
651             clipRect.bottom-clipRect.top,
652             hwndParent,
653             0,
654             _p_class->getHInstance(),
655             NULL
656            );
657
658     if( NULL == _inplacewnd )
659         return E_FAIL;
660
661     SetWindowLongPtr(_inplacewnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this));
662
663     /*
664     ** VLC embedded video geometry automatically matches parent window.
665     ** hence create a child window so that video position and size
666     ** is always correct relative to the viewport bounds
667     */
668     _videownd = CreateWindow(_p_class->getVideoWndClassName(),
669             "VLC Plugin Video Window",
670             WS_CHILD|WS_CLIPCHILDREN|WS_VISIBLE,
671             posRect.left,
672             posRect.top,
673             posRect.right-posRect.left,
674             posRect.bottom-posRect.top,
675             _inplacewnd,
676             0,
677             _p_class->getHInstance(),
678             NULL
679            );
680
681     if( NULL == _videownd )
682     {
683         DestroyWindow(_inplacewnd);
684         return E_FAIL;
685     }
686
687     SetWindowLongPtr(_videownd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this));
688
689     if( getVisible() )
690         ShowWindow(_inplacewnd, SW_SHOWNORMAL);
691
692     /* horrible cast there */
693     vlc_value_t val;
694     val.i_int = reinterpret_cast<int>(_videownd);
695     VLC_VariableSet(_i_vlc, "drawable", val);
696
697     if( NULL != _psz_src )
698     {
699         // add target to playlist
700         char *cOptions[1];
701         int  cOptionsCount = 0;
702
703         if( _b_loopmode )
704         {
705             cOptions[cOptionsCount++] = "loop";
706         }
707         VLC_AddTarget(_i_vlc, _psz_src, (const char **)&cOptions, cOptionsCount, PLAYLIST_APPEND, PLAYLIST_END);
708
709         if( _b_autostart )
710         {
711             VLC_Play(_i_vlc);
712             fireOnPlayEvent();
713         }
714     }
715     return S_OK;
716 };
717
718 HRESULT VLCPlugin::onInPlaceDeactivate(void)
719 {
720     VLC_Stop(_i_vlc);
721     fireOnStopEvent();
722
723     DestroyWindow(_videownd);
724     _videownd = NULL;
725     DestroyWindow(_inplacewnd);
726     _inplacewnd = NULL;
727  
728     return S_OK;
729 };
730
731 void VLCPlugin::setVisible(BOOL fVisible)
732 {
733     _b_visible = fVisible;
734     if( isInPlaceActive() )
735         ShowWindow(_inplacewnd, fVisible ? SW_SHOWNORMAL : SW_HIDE);
736     firePropChangedEvent(DISPID_Visible);
737 };
738
739 void VLCPlugin::setFocus(BOOL fFocus)
740 {
741     if( fFocus )
742         SetActiveWindow(_inplacewnd);
743 };
744
745 BOOL VLCPlugin::hasFocus(void)
746 {
747     return GetActiveWindow() == _inplacewnd;
748 };
749
750 void VLCPlugin::onPaint(HDC hdc, const RECT &bounds, const RECT &pr)
751 {
752     /*
753     ** if VLC is playing, it may not display any VIDEO content 
754     ** hence, draw control logo
755     */ 
756     int width = bounds.right-bounds.left;
757     int height = bounds.bottom-bounds.top;
758
759     HBITMAP pict = _p_class->getInPlacePict();
760     if( NULL != pict )
761     {
762         HDC hdcPict = CreateCompatibleDC(hdc);
763         if( NULL != hdcPict )
764         {
765             BITMAP bm;
766             if( GetObject(pict, sizeof(BITMAPINFO), &bm) )
767             {
768                 int dstWidth = bm.bmWidth;
769                 if( dstWidth > width-4 )
770                     dstWidth = width-4;
771
772                 int dstHeight = bm.bmHeight;
773                 if( dstHeight > height-4 )
774                     dstHeight = height-4;
775
776                 int dstX = bounds.left+(width-dstWidth)/2;
777                 int dstY = bounds.top+(height-dstHeight)/2;
778
779                 SelectObject(hdcPict, pict);
780                 StretchBlt(hdc, dstX, dstY, dstWidth, dstHeight,
781                         hdcPict, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);
782                 DeleteDC(hdcPict);
783                 ExcludeClipRect(hdc, dstX, dstY, dstWidth+dstX, dstHeight+dstY);
784             }
785         }
786     }
787
788     FillRect(hdc, &pr, (HBRUSH)GetStockObject(WHITE_BRUSH));
789     SelectObject(hdc, GetStockObject(BLACK_BRUSH));
790
791     MoveToEx(hdc, bounds.left, bounds.top, NULL);
792     LineTo(hdc, bounds.left+width-1, bounds.top);
793     LineTo(hdc, bounds.left+width-1, bounds.top+height-1);
794     LineTo(hdc, bounds.left, bounds.top+height-1);
795     LineTo(hdc, bounds.left, bounds.top);
796 };
797
798 void VLCPlugin::onPositionChange(LPCRECT lprcPosRect, LPCRECT lprcClipRect)
799 {
800     RECT clipRect = *lprcClipRect;
801     RECT posRect  = *lprcPosRect;
802
803     /*
804     ** record keeping of control geometry within container
805     */ 
806     _posRect = posRect;
807
808     /*
809     ** convert posRect & clipRect to match control viewport coordinates
810     */
811     getViewportCoords(&posRect, &clipRect);
812
813     /*
814     ** change in-place window geometry to match clipping region
815     */
816     MoveWindow(_inplacewnd,
817             clipRect.left,
818             clipRect.top,
819             clipRect.right-clipRect.left,
820             clipRect.bottom-clipRect.top,
821             FALSE);
822
823     /*
824     ** change video window geometry to match object bounds within clipping region
825     */
826     MoveWindow(_videownd,
827             posRect.left,
828             posRect.top,
829             posRect.right-posRect.left,
830             posRect.bottom-posRect.top,
831             FALSE);
832
833
834     /*
835     ** force a full refresh of control content
836     */
837     RECT updateRect;
838     updateRect.left = -posRect.left;
839     updateRect.top = -posRect.top;
840     updateRect.right = posRect.right-posRect.left;
841     updateRect.bottom = posRect.bottom-posRect.top;
842
843     ValidateRect(_videownd, NULL);
844     InvalidateRect(_videownd, &updateRect, FALSE);
845     UpdateWindow(_videownd);
846 };
847
848 void VLCPlugin::firePropChangedEvent(DISPID dispid)
849 {
850     if( _b_sendevents )
851     {
852         vlcConnectionPointContainer->firePropChangedEvent(dispid); 
853     }
854 };
855
856 void VLCPlugin::fireOnPlayEvent(void)
857 {
858     if( _b_sendevents )
859     {
860         DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
861         vlcConnectionPointContainer->fireEvent(DISPID_PlayEvent, &dispparamsNoArgs); 
862     }
863 };
864
865 void VLCPlugin::fireOnPauseEvent(void)
866 {
867     if( _b_sendevents )
868     {
869         DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
870         vlcConnectionPointContainer->fireEvent(DISPID_PauseEvent, &dispparamsNoArgs); 
871     }
872 };
873
874 void VLCPlugin::fireOnStopEvent(void)
875 {
876     if( _b_sendevents )
877     {
878         DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
879         vlcConnectionPointContainer->fireEvent(DISPID_StopEvent, &dispparamsNoArgs); 
880     }
881 };
882