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