1 /*****************************************************************************
\r
2 * plugin.cpp: ActiveX control for VLC
\r
3 *****************************************************************************
\r
4 * Copyright (C) 2005 VideoLAN
\r
6 * Authors: Damien Fouilleul <Damien.Fouilleul@laposte.net>
\r
8 * This program is free software; you can redistribute it and/or modify
\r
9 * it under the terms of the GNU General Public License as published by
\r
10 * the Free Software Foundation; either version 2 of the License, or
\r
11 * (at your option) any later version.
\r
13 * This program is distributed in the hope that it will be useful,
\r
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
16 * GNU General Public License for more details.
\r
18 * You should have received a copy of the GNU General Public License
\r
19 * along with this program; if not, write to the Free Software
\r
20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
\r
21 *****************************************************************************/
\r
25 #include "oleobject.h"
\r
26 #include "olecontrol.h"
\r
27 #include "oleinplaceobject.h"
\r
28 #include "oleinplaceactiveobject.h"
\r
29 #include "persistpropbag.h"
\r
30 #include "persiststreaminit.h"
\r
31 #include "persiststorage.h"
\r
32 #include "provideclassinfo.h"
\r
33 #include "connectioncontainer.h"
\r
34 #include "objectsafety.h"
\r
35 #include "vlccontrol.h"
\r
42 using namespace std;
\r
44 ////////////////////////////////////////////////////////////////////////
\r
47 // {E23FE9C6-778E-49d4-B537-38FCDE4887D8}
\r
48 //const GUID CLSID_VLCPlugin =
\r
49 // { 0xe23fe9c6, 0x778e, 0x49d4, { 0xb5, 0x37, 0x38, 0xfc, 0xde, 0x48, 0x87, 0xd8 } };
\r
51 static LRESULT CALLBACK VLCInPlaceClassWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
\r
59 if( GetUpdateRect(hWnd, NULL, FALSE) )
\r
61 BeginPaint(hWnd, &ps);
\r
62 EndPaint(hWnd, &ps);
\r
67 return DefWindowProc(hWnd, uMsg, wParam, lParam);
\r
71 static LRESULT CALLBACK VLCVideoClassWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
\r
72 VLCPlugin *p_instance = reinterpret_cast<VLCPlugin *>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
\r
82 if( GetUpdateRect(hWnd, &pr, FALSE) )
\r
84 BeginPaint(hWnd, &ps);
\r
85 p_instance->onPaint(ps, pr);
\r
86 EndPaint(hWnd, &ps);
\r
91 return DefWindowProc(hWnd, uMsg, wParam, lParam);
\r
95 VLCPluginClass::VLCPluginClass(LONG *p_class_ref, HINSTANCE hInstance) :
\r
96 _p_class_ref(p_class_ref),
\r
97 _hinstance(hInstance)
\r
101 if( ! GetClassInfo(hInstance, getInPlaceWndClassName(), &wClass) )
\r
103 wClass.style = CS_NOCLOSE|CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS;
\r
104 wClass.lpfnWndProc = VLCInPlaceClassWndProc;
\r
105 wClass.cbClsExtra = 0;
\r
106 wClass.cbWndExtra = 0;
\r
107 wClass.hInstance = hInstance;
\r
108 wClass.hIcon = NULL;
\r
109 wClass.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
110 wClass.hbrBackground = NULL;
\r
111 wClass.lpszMenuName = NULL;
\r
112 wClass.lpszClassName = getInPlaceWndClassName();
\r
114 _inplace_wndclass_atom = RegisterClass(&wClass);
\r
118 _inplace_wndclass_atom = 0;
\r
121 if( ! GetClassInfo(hInstance, getVideoWndClassName(), &wClass) )
\r
123 wClass.style = CS_NOCLOSE|CS_HREDRAW|CS_VREDRAW;
\r
124 wClass.lpfnWndProc = VLCVideoClassWndProc;
\r
125 wClass.cbClsExtra = 0;
\r
126 wClass.cbWndExtra = 0;
\r
127 wClass.hInstance = hInstance;
\r
128 wClass.hIcon = NULL;
\r
129 wClass.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
130 wClass.hbrBackground = NULL;
\r
131 wClass.lpszMenuName = NULL;
\r
132 wClass.lpszClassName = getVideoWndClassName();
\r
134 _video_wndclass_atom = RegisterClass(&wClass);
\r
138 _video_wndclass_atom = 0;
\r
141 _inplace_hbitmap = (HBITMAP)LoadImage(getHInstance(), TEXT("INPLACE-PICT"), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR);
\r
146 VLCPluginClass::~VLCPluginClass()
\r
148 if( 0 != _inplace_wndclass_atom )
\r
149 UnregisterClass(MAKEINTATOM(_inplace_wndclass_atom), _hinstance);
\r
151 if( 0 != _video_wndclass_atom )
\r
152 UnregisterClass(MAKEINTATOM(_video_wndclass_atom), _hinstance);
\r
154 if( NULL != _inplace_hbitmap )
\r
155 DeleteObject(_inplace_hbitmap);
\r
158 STDMETHODIMP VLCPluginClass::QueryInterface(REFIID riid, void **ppv)
\r
161 return E_INVALIDARG;
\r
163 if( (IID_IUnknown == riid) || (IID_IClassFactory == riid) )
\r
166 *ppv = reinterpret_cast<LPVOID>(this);
\r
173 return E_NOINTERFACE;
\r
176 STDMETHODIMP_(ULONG) VLCPluginClass::AddRef(void)
\r
178 return InterlockedIncrement(_p_class_ref);
\r
181 STDMETHODIMP_(ULONG) VLCPluginClass::Release(void)
\r
183 ULONG refcount = InterlockedDecrement(_p_class_ref);
\r
184 if( 0 == refcount )
\r
192 STDMETHODIMP VLCPluginClass::CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppv)
\r
199 if( NULL != pUnkOuter )
\r
200 return CLASS_E_NOAGGREGATION;
\r
202 VLCPlugin *plugin = new VLCPlugin(this);
\r
203 if( NULL != plugin )
\r
205 HRESULT hr = plugin->QueryInterface(riid, ppv);
\r
209 return E_OUTOFMEMORY;
\r
212 STDMETHODIMP VLCPluginClass::LockServer(BOOL fLock)
\r
222 ////////////////////////////////////////////////////////////////////////
\r
224 VLCPlugin::VLCPlugin(VLCPluginClass *p_class) :
\r
230 _b_autostart(TRUE),
\r
231 _b_loopmode(FALSE),
\r
232 _b_showdisplay(TRUE),
\r
233 _b_sendevents(TRUE),
\r
238 vlcOleObject = new VLCOleObject(this);
\r
239 vlcOleControl = new VLCOleControl(this);
\r
240 vlcOleInPlaceObject = new VLCOleInPlaceObject(this);
\r
241 vlcOleInPlaceActiveObject = new VLCOleInPlaceActiveObject(this);
\r
242 vlcPersistStorage = new VLCPersistStorage(this);
\r
243 vlcPersistStreamInit = new VLCPersistStreamInit(this);
\r
244 vlcPersistPropertyBag = new VLCPersistPropertyBag(this);
\r
245 vlcProvideClassInfo = new VLCProvideClassInfo(this);
\r
246 vlcConnectionPointContainer = new VLCConnectionPointContainer(this);
\r
247 vlcObjectSafety = new VLCObjectSafety(this);
\r
248 vlcControl = new VLCControl(this);
\r
251 VLCPlugin::~VLCPlugin()
\r
253 vlcOleInPlaceObject->UIDeactivate();
\r
254 vlcOleInPlaceObject->InPlaceDeactivate();
\r
257 delete vlcObjectSafety;
\r
258 delete vlcConnectionPointContainer;
\r
259 delete vlcProvideClassInfo;
\r
260 delete vlcPersistPropertyBag;
\r
261 delete vlcPersistStreamInit;
\r
262 delete vlcPersistStorage;
\r
263 delete vlcOleInPlaceActiveObject;
\r
264 delete vlcOleInPlaceObject;
\r
265 delete vlcOleControl;
\r
266 delete vlcOleObject;
\r
271 _p_class->Release();
\r
274 STDMETHODIMP VLCPlugin::QueryInterface(REFIID riid, void **ppv)
\r
277 return E_INVALIDARG;
\r
279 if( IID_IUnknown == riid )
\r
282 *ppv = reinterpret_cast<LPVOID>(this);
\r
285 else if( IID_IOleObject == riid )
\r
288 *ppv = reinterpret_cast<LPVOID>(vlcOleObject);
\r
291 else if( IID_IOleControl == riid )
\r
294 *ppv = reinterpret_cast<LPVOID>(vlcOleControl);
\r
297 else if( IID_IOleWindow == riid )
\r
300 *ppv = reinterpret_cast<LPVOID>(vlcOleInPlaceObject);
\r
303 else if( IID_IOleInPlaceObject == riid )
\r
306 *ppv = reinterpret_cast<LPVOID>(vlcOleInPlaceObject);
\r
309 else if( IID_IOleInPlaceActiveObject == riid )
\r
312 *ppv = reinterpret_cast<LPVOID>(vlcOleInPlaceActiveObject);
\r
315 else if( IID_IPersist == riid )
\r
318 *ppv = reinterpret_cast<LPVOID>(vlcPersistPropertyBag);
\r
321 else if( IID_IPersistStreamInit == riid )
\r
324 *ppv = reinterpret_cast<LPVOID>(vlcPersistStreamInit);
\r
327 else if( IID_IPersistStorage == riid )
\r
330 *ppv = reinterpret_cast<LPVOID>(vlcPersistStorage);
\r
333 else if( IID_IPersistPropertyBag == riid )
\r
336 *ppv = reinterpret_cast<LPVOID>(vlcPersistPropertyBag);
\r
339 else if( IID_IProvideClassInfo == riid )
\r
342 *ppv = reinterpret_cast<LPVOID>(vlcProvideClassInfo);
\r
345 else if( IID_IProvideClassInfo2 == riid )
\r
348 *ppv = reinterpret_cast<LPVOID>(vlcProvideClassInfo);
\r
351 else if( IID_IConnectionPointContainer == riid )
\r
354 *ppv = reinterpret_cast<LPVOID>(vlcConnectionPointContainer);
\r
357 else if( IID_IObjectSafety == riid )
\r
360 *ppv = reinterpret_cast<LPVOID>(vlcObjectSafety);
\r
363 else if( IID_IDispatch == riid )
\r
366 *ppv = reinterpret_cast<LPVOID>(vlcControl);
\r
369 else if( IID_IVLCControl == riid )
\r
372 *ppv = reinterpret_cast<LPVOID>(vlcControl);
\r
378 return E_NOINTERFACE;
\r
381 STDMETHODIMP_(ULONG) VLCPlugin::AddRef(void)
\r
383 return InterlockedIncrement((LONG *)&_i_ref);
\r
386 STDMETHODIMP_(ULONG) VLCPlugin::Release(void)
\r
388 if( ! InterlockedDecrement((LONG *)&_i_ref) )
\r
396 //////////////////////////////////////
\r
399 ** we use an in-place child window to represent plugin viewport,
\r
400 ** whose size is limited by the clipping rectangle
\r
401 ** all drawing within this window must follow
\r
402 ** cartesian coordinate system represented by _bounds.
\r
405 void VLCPlugin::calcPositionChange(LPRECT lprPosRect, LPCRECT lprcClipRect)
\r
407 _bounds.right = lprPosRect->right-lprPosRect->left;
\r
409 if( lprcClipRect->left <= lprPosRect->left )
\r
411 // left side is not clipped out
\r
414 if( lprcClipRect->right >= lprPosRect->right )
\r
416 // right side is not clipped out, no change
\r
418 else if( lprcClipRect->right >= lprPosRect->left )
\r
420 // right side is clipped out
\r
421 lprPosRect->right = lprcClipRect->right;
\r
425 // outside of clipping rectange, not visible
\r
426 lprPosRect->right = lprPosRect->left;
\r
431 // left side is clipped out
\r
432 _bounds.left = lprPosRect->left-lprcClipRect->left;
\r
433 _bounds.right += _bounds.left;
\r
435 lprPosRect->left = lprcClipRect->left;
\r
436 if( lprcClipRect->right >= lprPosRect->right )
\r
438 // right side is not clipped out
\r
442 // right side is clipped out
\r
443 lprPosRect->right = lprcClipRect->right;
\r
447 _bounds.bottom = lprPosRect->bottom-lprPosRect->top;
\r
449 if( lprcClipRect->top <= lprPosRect->top )
\r
451 // top side is not clipped out
\r
454 if( lprcClipRect->bottom >= lprPosRect->bottom )
\r
456 // bottom side is not clipped out, no change
\r
458 else if( lprcClipRect->bottom >= lprPosRect->top )
\r
460 // bottom side is clipped out
\r
461 lprPosRect->bottom = lprcClipRect->bottom;
\r
465 // outside of clipping rectange, not visible
\r
466 lprPosRect->right = lprPosRect->left;
\r
471 _bounds.top = lprPosRect->top-lprcClipRect->top;
\r
472 _bounds.bottom += _bounds.top;
\r
474 lprPosRect->top = lprcClipRect->top;
\r
475 if( lprcClipRect->bottom >= lprPosRect->bottom )
\r
477 // bottom side is not clipped out
\r
481 // bottom side is clipped out
\r
482 lprPosRect->bottom = lprcClipRect->bottom;
\r
487 HRESULT VLCPlugin::onInitNew(void)
\r
491 char *ppsz_argv[] = { "vlc", "-vv" };
\r
493 DWORD i_type, i_data = MAX_PATH + 1;
\r
494 char p_data[MAX_PATH + 1];
\r
495 if( RegOpenKeyEx( HKEY_LOCAL_MACHINE, "Software\\VideoLAN\\VLC",
\r
496 0, KEY_READ, &h_key ) == ERROR_SUCCESS )
\r
498 if( RegQueryValueEx( h_key, "InstallDir", 0, &i_type,
\r
499 (LPBYTE)p_data, &i_data ) == ERROR_SUCCESS )
\r
501 if( i_type == REG_SZ )
\r
503 strcat( p_data, "\\vlc" );
\r
504 ppsz_argv[0] = p_data;
\r
507 RegCloseKey( h_key );
\r
511 ppsz_argv[0] = "C:\\cygwin\\home\\Damien_Fouilleul\\dev\\videolan\\vlc-trunk\\vlc";
\r
514 _i_vlc = VLC_Create();
\r
516 if( VLC_Init(_i_vlc, sizeof(ppsz_argv)/sizeof(char*), ppsz_argv) )
\r
518 VLC_Destroy(_i_vlc);
\r
524 return E_UNEXPECTED;
\r
527 HRESULT VLCPlugin::onClose(DWORD dwSaveOption)
\r
531 if( isInPlaceActive() )
\r
533 onInPlaceDeactivate();
\r
536 VLC_CleanUp(_i_vlc);
\r
537 VLC_Destroy(_i_vlc);
\r
543 BOOL VLCPlugin::isInPlaceActive(void)
\r
545 return (NULL != _inplacewnd);
\r
548 HRESULT VLCPlugin::onActivateInPlace(LPMSG lpMesg, HWND hwndParent, LPCRECT lprcPosRect, LPCRECT lprcClipRect)
\r
550 RECT posRect = *lprcPosRect;
\r
552 calcPositionChange(&posRect, lprcClipRect);
\r
554 _inplacewnd = CreateWindow(_p_class->getInPlaceWndClassName(),
\r
555 "VLC Plugin In-Place Window",
\r
556 WS_CHILD|WS_CLIPCHILDREN|WS_TABSTOP,
\r
559 posRect.right-posRect.left,
\r
560 posRect.bottom-posRect.top,
\r
563 _p_class->getHInstance(),
\r
567 if( NULL == _inplacewnd )
\r
570 SetWindowLongPtr(_inplacewnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this));
\r
572 _videownd = CreateWindow(_p_class->getVideoWndClassName(),
\r
573 "VLC Plugin Video Window",
\r
574 WS_CHILD|WS_CLIPCHILDREN|WS_VISIBLE,
\r
577 _bounds.right-_bounds.left,
\r
578 _bounds.bottom-_bounds.top,
\r
581 _p_class->getHInstance(),
\r
585 if( NULL == _videownd )
\r
587 DestroyWindow(_inplacewnd);
\r
591 SetWindowLongPtr(_videownd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this));
\r
593 /* horrible cast there */
\r
595 val.i_int = reinterpret_cast<int>(_videownd);
\r
596 VLC_VariableSet(_i_vlc, "drawable", val);
\r
598 setVisible(_b_showdisplay);
\r
600 if( NULL != _psz_src )
\r
602 // add target to playlist
\r
604 int cOptionsCount = 0;
\r
608 cOptions[cOptionsCount++] = "loop";
\r
610 VLC_AddTarget(_i_vlc, _psz_src, (const char **)&cOptions, cOptionsCount, PLAYLIST_APPEND, PLAYLIST_END);
\r
621 HRESULT VLCPlugin::onInPlaceDeactivate(void)
\r
626 DestroyWindow(_videownd);
\r
628 DestroyWindow(_inplacewnd);
\r
629 _inplacewnd = NULL;
\r
634 BOOL VLCPlugin::isVisible(void)
\r
636 return GetWindowLong(_inplacewnd, GWL_STYLE) & WS_VISIBLE;
\r
639 void VLCPlugin::setVisible(BOOL fVisible)
\r
641 ShowWindow(_inplacewnd, fVisible ? SW_SHOW : SW_HIDE);
\r
644 void VLCPlugin::setFocus(BOOL fFocus)
\r
647 SetActiveWindow(_inplacewnd);
\r
650 BOOL VLCPlugin::hasFocus(void)
\r
652 return GetActiveWindow() == _inplacewnd;
\r
655 void VLCPlugin::onPaint(PAINTSTRUCT &ps, RECT &pr)
\r
658 ** if VLC is playing, it may not display any VIDEO content
\r
659 ** hence, draw control logo
\r
661 int width = _bounds.right-_bounds.left;
\r
662 int height = _bounds.bottom-_bounds.top;
\r
664 HBITMAP pict = _p_class->getInPlacePict();
\r
667 HDC hdcPict = CreateCompatibleDC(ps.hdc);
\r
668 if( NULL != hdcPict )
\r
671 if( GetObject(pict, sizeof(BITMAPINFO), &bm) )
\r
673 int dstWidth = bm.bmWidth;
\r
674 if( dstWidth > width-4 )
\r
675 dstWidth = width-4;
\r
677 int dstHeight = bm.bmHeight;
\r
678 if( dstHeight > height-4 )
\r
679 dstHeight = height-4;
\r
681 int dstX = (width-dstWidth)/2;
\r
682 int dstY = (height-dstHeight)/2;
\r
684 SelectObject(hdcPict, pict);
\r
685 StretchBlt(ps.hdc, dstX, dstY, dstWidth, dstHeight,
\r
686 hdcPict, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);
\r
688 ExcludeClipRect(ps.hdc, dstX, dstY, dstWidth+dstX, dstHeight+dstY);
\r
693 FillRect(ps.hdc, &pr, (HBRUSH)GetStockObject(WHITE_BRUSH));
\r
694 SelectObject(ps.hdc, GetStockObject(BLACK_BRUSH));
\r
696 MoveToEx(ps.hdc, 0, 0, NULL);
\r
697 LineTo(ps.hdc, width-1, 0);
\r
698 LineTo(ps.hdc, width-1, height-1);
\r
699 LineTo(ps.hdc, 0, height-1);
\r
700 LineTo(ps.hdc, 0, 0);
\r
703 void VLCPlugin::onPositionChange(LPCRECT lprcPosRect, LPCRECT lprcClipRect)
\r
705 RECT posRect = *lprcPosRect;
\r
707 calcPositionChange(&posRect, lprcClipRect);
\r
710 ** change in-place window geometry to match clipping region
\r
712 MoveWindow(_inplacewnd,
\r
715 posRect.right-posRect.left,
\r
716 posRect.bottom-posRect.top,
\r
720 ** change video window geometry to match object bounds within clipping region
\r
722 MoveWindow(_videownd,
\r
725 _bounds.right-_bounds.left,
\r
726 _bounds.bottom-_bounds.top,
\r
731 updateRect.left = -_bounds.left;
\r
732 updateRect.top = -_bounds.top;
\r
733 updateRect.right = _bounds.right-_bounds.left;
\r
734 updateRect.bottom = _bounds.bottom-_bounds.top;
\r
736 ValidateRect(_videownd, NULL);
\r
737 InvalidateRect(_videownd, &updateRect, FALSE);
\r
738 UpdateWindow(_videownd);
\r
741 void VLCPlugin::fireOnPlayEvent(void)
\r
743 if( _b_sendevents )
\r
745 DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
\r
746 vlcConnectionPointContainer->fireEvent(1, &dispparamsNoArgs);
\r
750 void VLCPlugin::fireOnPauseEvent(void)
\r
752 if( _b_sendevents )
\r
754 DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
\r
755 vlcConnectionPointContainer->fireEvent(2, &dispparamsNoArgs);
\r
759 void VLCPlugin::fireOnStopEvent(void)
\r
761 if( _b_sendevents )
\r
763 DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
\r
764 vlcConnectionPointContainer->fireEvent(3, &dispparamsNoArgs);
\r