1 /*****************************************************************************
2 * plugin.cpp: ActiveX control for VLC
3 *****************************************************************************
4 * Copyright (C) 2005 VideoLAN
6 * Authors: Damien Fouilleul <Damien.Fouilleul@laposte.net>
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.
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.
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 *****************************************************************************/
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"
44 ////////////////////////////////////////////////////////////////////////
47 // {E23FE9C6-778E-49d4-B537-38FCDE4887D8}
48 //const GUID CLSID_VLCPlugin =
49 // { 0xe23fe9c6, 0x778e, 0x49d4, { 0xb5, 0x37, 0x38, 0xfc, 0xde, 0x48, 0x87, 0xd8 } };
51 static LRESULT CALLBACK VLCInPlaceClassWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
59 if( GetUpdateRect(hWnd, NULL, FALSE) )
61 BeginPaint(hWnd, &ps);
67 return DefWindowProc(hWnd, uMsg, wParam, lParam);
71 static LRESULT CALLBACK VLCVideoClassWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
72 VLCPlugin *p_instance = reinterpret_cast<VLCPlugin *>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
82 if( GetUpdateRect(hWnd, &pr, FALSE) )
84 BeginPaint(hWnd, &ps);
85 p_instance->onPaint(ps, pr);
91 return DefWindowProc(hWnd, uMsg, wParam, lParam);
95 VLCPluginClass::VLCPluginClass(LONG *p_class_ref, HINSTANCE hInstance) :
96 _p_class_ref(p_class_ref),
101 if( ! GetClassInfo(hInstance, getInPlaceWndClassName(), &wClass) )
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;
109 wClass.hCursor = LoadCursor(NULL, IDC_ARROW);
110 wClass.hbrBackground = NULL;
111 wClass.lpszMenuName = NULL;
112 wClass.lpszClassName = getInPlaceWndClassName();
114 _inplace_wndclass_atom = RegisterClass(&wClass);
118 _inplace_wndclass_atom = 0;
121 if( ! GetClassInfo(hInstance, getVideoWndClassName(), &wClass) )
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;
129 wClass.hCursor = LoadCursor(NULL, IDC_ARROW);
130 wClass.hbrBackground = NULL;
131 wClass.lpszMenuName = NULL;
132 wClass.lpszClassName = getVideoWndClassName();
134 _video_wndclass_atom = RegisterClass(&wClass);
138 _video_wndclass_atom = 0;
141 _inplace_hbitmap = (HBITMAP)LoadImage(getHInstance(), TEXT("INPLACE-PICT"), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR);
146 VLCPluginClass::~VLCPluginClass()
148 if( 0 != _inplace_wndclass_atom )
149 UnregisterClass(MAKEINTATOM(_inplace_wndclass_atom), _hinstance);
151 if( 0 != _video_wndclass_atom )
152 UnregisterClass(MAKEINTATOM(_video_wndclass_atom), _hinstance);
154 if( NULL != _inplace_hbitmap )
155 DeleteObject(_inplace_hbitmap);
158 STDMETHODIMP VLCPluginClass::QueryInterface(REFIID riid, void **ppv)
163 if( (IID_IUnknown == riid) || (IID_IClassFactory == riid) )
166 *ppv = reinterpret_cast<LPVOID>(this);
173 return E_NOINTERFACE;
176 STDMETHODIMP_(ULONG) VLCPluginClass::AddRef(void)
178 return InterlockedIncrement(_p_class_ref);
181 STDMETHODIMP_(ULONG) VLCPluginClass::Release(void)
183 ULONG refcount = InterlockedDecrement(_p_class_ref);
192 STDMETHODIMP VLCPluginClass::CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppv)
199 if( NULL != pUnkOuter )
200 return CLASS_E_NOAGGREGATION;
202 VLCPlugin *plugin = new VLCPlugin(this);
205 HRESULT hr = plugin->QueryInterface(riid, ppv);
209 return E_OUTOFMEMORY;
212 STDMETHODIMP VLCPluginClass::LockServer(BOOL fLock)
222 ////////////////////////////////////////////////////////////////////////
224 VLCPlugin::VLCPlugin(VLCPluginClass *p_class) :
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);
251 VLCPlugin::~VLCPlugin()
253 vlcOleInPlaceObject->UIDeactivate();
254 vlcOleInPlaceObject->InPlaceDeactivate();
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;
274 STDMETHODIMP VLCPlugin::QueryInterface(REFIID riid, void **ppv)
279 if( IID_IUnknown == riid )
282 *ppv = reinterpret_cast<LPVOID>(this);
285 else if( IID_IOleObject == riid )
288 *ppv = reinterpret_cast<LPVOID>(vlcOleObject);
291 else if( IID_IOleControl == riid )
294 *ppv = reinterpret_cast<LPVOID>(vlcOleControl);
297 else if( IID_IOleWindow == riid )
300 *ppv = reinterpret_cast<LPVOID>(vlcOleInPlaceObject);
303 else if( IID_IOleInPlaceObject == riid )
306 *ppv = reinterpret_cast<LPVOID>(vlcOleInPlaceObject);
309 else if( IID_IOleInPlaceActiveObject == riid )
312 *ppv = reinterpret_cast<LPVOID>(vlcOleInPlaceActiveObject);
315 else if( IID_IPersist == riid )
318 *ppv = reinterpret_cast<LPVOID>(vlcPersistPropertyBag);
321 else if( IID_IPersistStreamInit == riid )
324 *ppv = reinterpret_cast<LPVOID>(vlcPersistStreamInit);
327 else if( IID_IPersistStorage == riid )
330 *ppv = reinterpret_cast<LPVOID>(vlcPersistStorage);
333 else if( IID_IPersistPropertyBag == riid )
336 *ppv = reinterpret_cast<LPVOID>(vlcPersistPropertyBag);
339 else if( IID_IProvideClassInfo == riid )
342 *ppv = reinterpret_cast<LPVOID>(vlcProvideClassInfo);
345 else if( IID_IProvideClassInfo2 == riid )
348 *ppv = reinterpret_cast<LPVOID>(vlcProvideClassInfo);
351 else if( IID_IConnectionPointContainer == riid )
354 *ppv = reinterpret_cast<LPVOID>(vlcConnectionPointContainer);
357 else if( IID_IObjectSafety == riid )
360 *ppv = reinterpret_cast<LPVOID>(vlcObjectSafety);
363 else if( IID_IDispatch == riid )
366 *ppv = reinterpret_cast<LPVOID>(vlcControl);
369 else if( IID_IVLCControl == riid )
372 *ppv = reinterpret_cast<LPVOID>(vlcControl);
378 return E_NOINTERFACE;
381 STDMETHODIMP_(ULONG) VLCPlugin::AddRef(void)
383 return InterlockedIncrement((LONG *)&_i_ref);
386 STDMETHODIMP_(ULONG) VLCPlugin::Release(void)
388 if( ! InterlockedDecrement((LONG *)&_i_ref) )
396 //////////////////////////////////////
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.
405 void VLCPlugin::calcPositionChange(LPRECT lprPosRect, LPCRECT lprcClipRect)
407 _bounds.right = lprPosRect->right-lprPosRect->left;
409 if( lprcClipRect->left <= lprPosRect->left )
411 // left side is not clipped out
414 if( lprcClipRect->right >= lprPosRect->right )
416 // right side is not clipped out, no change
418 else if( lprcClipRect->right >= lprPosRect->left )
420 // right side is clipped out
421 lprPosRect->right = lprcClipRect->right;
425 // outside of clipping rectange, not visible
426 lprPosRect->right = lprPosRect->left;
431 // left side is clipped out
432 _bounds.left = lprPosRect->left-lprcClipRect->left;
433 _bounds.right += _bounds.left;
435 lprPosRect->left = lprcClipRect->left;
436 if( lprcClipRect->right >= lprPosRect->right )
438 // right side is not clipped out
442 // right side is clipped out
443 lprPosRect->right = lprcClipRect->right;
447 _bounds.bottom = lprPosRect->bottom-lprPosRect->top;
449 if( lprcClipRect->top <= lprPosRect->top )
451 // top side is not clipped out
454 if( lprcClipRect->bottom >= lprPosRect->bottom )
456 // bottom side is not clipped out, no change
458 else if( lprcClipRect->bottom >= lprPosRect->top )
460 // bottom side is clipped out
461 lprPosRect->bottom = lprcClipRect->bottom;
465 // outside of clipping rectange, not visible
466 lprPosRect->right = lprPosRect->left;
471 _bounds.top = lprPosRect->top-lprcClipRect->top;
472 _bounds.bottom += _bounds.top;
474 lprPosRect->top = lprcClipRect->top;
475 if( lprcClipRect->bottom >= lprPosRect->bottom )
477 // bottom side is not clipped out
481 // bottom side is clipped out
482 lprPosRect->bottom = lprcClipRect->bottom;
489 HRESULT VLCPlugin::onInit(BOOL isNew)
493 char *ppsz_argv[] = { "vlc", "-vv" };
495 DWORD i_type, i_data = MAX_PATH + 1;
496 char p_data[MAX_PATH + 1];
497 if( RegOpenKeyEx( HKEY_LOCAL_MACHINE, "Software\\VideoLAN\\VLC",
498 0, KEY_READ, &h_key ) == ERROR_SUCCESS )
500 if( RegQueryValueEx( h_key, "InstallDir", 0, &i_type,
501 (LPBYTE)p_data, &i_data ) == ERROR_SUCCESS )
503 if( i_type == REG_SZ )
505 strcat( p_data, "\\vlc" );
506 ppsz_argv[0] = p_data;
509 RegCloseKey( h_key );
513 ppsz_argv[0] = "C:\\cygwin\\home\\Damien_Fouilleul\\dev\\videolan\\vlc-trunk\\vlc";
516 _i_vlc = VLC_Create();
518 if( VLC_Init(_i_vlc, sizeof(ppsz_argv)/sizeof(char*), ppsz_argv) )
528 ** object has fully initialized,
529 ** try to activate in place if container is ready
531 LPOLECLIENTSITE pActiveSite;
533 if( SUCCEEDED(vlcOleObject->GetClientSite(&pActiveSite)) && (NULL != pActiveSite) )
535 vlcOleObject->DoVerb(OLEIVERB_INPLACEACTIVATE, NULL, pActiveSite, 0, NULL, NULL);
536 pActiveSite->Release();
544 HRESULT VLCPlugin::onLoad(void)
547 ** object has fully initialized,
548 ** try to activate in place if container is ready
550 LPOLECLIENTSITE pActiveSite;
552 if( SUCCEEDED(vlcOleObject->GetClientSite(&pActiveSite)) && (NULL != pActiveSite) )
554 vlcOleObject->DoVerb(OLEIVERB_INPLACEACTIVATE, NULL, pActiveSite, 0, NULL, NULL);
555 pActiveSite->Release();
560 HRESULT VLCPlugin::onClientSiteChanged(LPOLECLIENTSITE pActiveSite)
562 if( NULL != pActiveSite )
565 ** object is embedded in container
566 ** try to activate in place if it has initialized
570 vlcOleObject->DoVerb(OLEIVERB_INPLACEACTIVATE, NULL, pActiveSite, 0, NULL, NULL);
576 HRESULT VLCPlugin::onClose(DWORD dwSaveOption)
580 if( isInPlaceActive() )
582 onInPlaceDeactivate();
592 BOOL VLCPlugin::isInPlaceActive(void)
594 return (NULL != _inplacewnd);
597 HRESULT VLCPlugin::onActivateInPlace(LPMSG lpMesg, HWND hwndParent, LPCRECT lprcPosRect, LPCRECT lprcClipRect)
599 RECT posRect = *lprcPosRect;
601 calcPositionChange(&posRect, lprcClipRect);
603 _inplacewnd = CreateWindow(_p_class->getInPlaceWndClassName(),
604 "VLC Plugin In-Place Window",
605 WS_CHILD|WS_CLIPCHILDREN|WS_TABSTOP,
608 posRect.right-posRect.left,
609 posRect.bottom-posRect.top,
612 _p_class->getHInstance(),
616 if( NULL == _inplacewnd )
619 SetWindowLongPtr(_inplacewnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this));
621 _videownd = CreateWindow(_p_class->getVideoWndClassName(),
622 "VLC Plugin Video Window",
623 WS_CHILD|WS_CLIPCHILDREN|WS_VISIBLE,
626 _bounds.right-_bounds.left,
627 _bounds.bottom-_bounds.top,
630 _p_class->getHInstance(),
634 if( NULL == _videownd )
636 DestroyWindow(_inplacewnd);
640 SetWindowLongPtr(_videownd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this));
643 ShowWindow(_inplacewnd, SW_SHOWNORMAL);
645 /* horrible cast there */
647 val.i_int = reinterpret_cast<int>(_videownd);
648 VLC_VariableSet(_i_vlc, "drawable", val);
650 if( NULL != _psz_src )
652 // add target to playlist
654 int cOptionsCount = 0;
658 cOptions[cOptionsCount++] = "loop";
660 VLC_AddTarget(_i_vlc, _psz_src, (const char **)&cOptions, cOptionsCount, PLAYLIST_APPEND, PLAYLIST_END);
671 HRESULT VLCPlugin::onInPlaceDeactivate(void)
676 DestroyWindow(_videownd);
678 DestroyWindow(_inplacewnd);
684 void VLCPlugin::setVisible(BOOL fVisible)
686 _b_visible = fVisible;
687 if( isInPlaceActive() )
688 ShowWindow(_inplacewnd, fVisible ? SW_SHOWNORMAL : SW_HIDE);
689 firePropChangedEvent(DISPID_Visible);
692 void VLCPlugin::setFocus(BOOL fFocus)
695 SetActiveWindow(_inplacewnd);
698 BOOL VLCPlugin::hasFocus(void)
700 return GetActiveWindow() == _inplacewnd;
703 void VLCPlugin::onPaint(PAINTSTRUCT &ps, RECT &pr)
706 ** if VLC is playing, it may not display any VIDEO content
707 ** hence, draw control logo
709 int width = _bounds.right-_bounds.left;
710 int height = _bounds.bottom-_bounds.top;
712 HBITMAP pict = _p_class->getInPlacePict();
715 HDC hdcPict = CreateCompatibleDC(ps.hdc);
716 if( NULL != hdcPict )
719 if( GetObject(pict, sizeof(BITMAPINFO), &bm) )
721 int dstWidth = bm.bmWidth;
722 if( dstWidth > width-4 )
725 int dstHeight = bm.bmHeight;
726 if( dstHeight > height-4 )
727 dstHeight = height-4;
729 int dstX = (width-dstWidth)/2;
730 int dstY = (height-dstHeight)/2;
732 SelectObject(hdcPict, pict);
733 StretchBlt(ps.hdc, dstX, dstY, dstWidth, dstHeight,
734 hdcPict, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);
736 ExcludeClipRect(ps.hdc, dstX, dstY, dstWidth+dstX, dstHeight+dstY);
741 FillRect(ps.hdc, &pr, (HBRUSH)GetStockObject(WHITE_BRUSH));
742 SelectObject(ps.hdc, GetStockObject(BLACK_BRUSH));
744 MoveToEx(ps.hdc, 0, 0, NULL);
745 LineTo(ps.hdc, width-1, 0);
746 LineTo(ps.hdc, width-1, height-1);
747 LineTo(ps.hdc, 0, height-1);
748 LineTo(ps.hdc, 0, 0);
751 void VLCPlugin::onPositionChange(LPCRECT lprcPosRect, LPCRECT lprcClipRect)
753 RECT posRect = *lprcPosRect;
755 calcPositionChange(&posRect, lprcClipRect);
758 ** change in-place window geometry to match clipping region
760 MoveWindow(_inplacewnd,
763 posRect.right-posRect.left,
764 posRect.bottom-posRect.top,
768 ** change video window geometry to match object bounds within clipping region
770 MoveWindow(_videownd,
773 _bounds.right-_bounds.left,
774 _bounds.bottom-_bounds.top,
779 updateRect.left = -_bounds.left;
780 updateRect.top = -_bounds.top;
781 updateRect.right = _bounds.right-_bounds.left;
782 updateRect.bottom = _bounds.bottom-_bounds.top;
784 ValidateRect(_videownd, NULL);
785 InvalidateRect(_videownd, &updateRect, FALSE);
786 UpdateWindow(_videownd);
789 void VLCPlugin::firePropChangedEvent(DISPID dispid)
793 vlcConnectionPointContainer->firePropChangedEvent(dispid);
797 void VLCPlugin::fireOnPlayEvent(void)
801 DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
802 vlcConnectionPointContainer->fireEvent(DISPID_PlayEvent, &dispparamsNoArgs);
806 void VLCPlugin::fireOnPauseEvent(void)
810 DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
811 vlcConnectionPointContainer->fireEvent(DISPID_PauseEvent, &dispparamsNoArgs);
815 void VLCPlugin::fireOnStopEvent(void)
819 DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
820 vlcConnectionPointContainer->fireEvent(DISPID_StopEvent, &dispparamsNoArgs);