X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=activex%2Fplugin.cpp;h=cc289b92459643095f3e826a738b704b0e17d1bc;hb=a4d1fdfc024b594a26d1d83386893aa2b6dae8ce;hp=6bd417741199fadb425162b63b804a587c580e50;hpb=1591dec08cacf0168d6008b41671d265264a7a4d;p=vlc diff --git a/activex/plugin.cpp b/activex/plugin.cpp index 6bd4177411..cc289b9245 100644 --- a/activex/plugin.cpp +++ b/activex/plugin.cpp @@ -1,7 +1,7 @@ /***************************************************************************** * plugin.cpp: ActiveX control for VLC ***************************************************************************** - * Copyright (C) 2005 VideoLAN + * Copyright (C) 2006 the VideoLAN team * * Authors: Damien Fouilleul * @@ -17,7 +17,7 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/ #include "plugin.h" @@ -33,42 +33,26 @@ #include "connectioncontainer.h" #include "objectsafety.h" #include "vlccontrol.h" +#include "vlccontrol2.h" +#include "viewobject.h" +#include "dataobject.h" +#include "supporterrorinfo.h" #include "utils.h" #include #include +#include +#include +#include +#include using namespace std; //////////////////////////////////////////////////////////////////////// //class factory -// {E23FE9C6-778E-49d4-B537-38FCDE4887D8} -//const GUID CLSID_VLCPlugin = -// { 0xe23fe9c6, 0x778e, 0x49d4, { 0xb5, 0x37, 0x38, 0xfc, 0xde, 0x48, 0x87, 0xd8 } }; - static LRESULT CALLBACK VLCInPlaceClassWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { - switch( uMsg ) - { - case WM_ERASEBKGND: - return 1L; - - case WM_PAINT: - PAINTSTRUCT ps; - if( GetUpdateRect(hWnd, NULL, FALSE) ) - { - BeginPaint(hWnd, &ps); - EndPaint(hWnd, &ps); - } - return 0L; - - default: - return DefWindowProc(hWnd, uMsg, wParam, lParam); - } -}; - -static LRESULT CALLBACK VLCVideoClassWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { VLCPlugin *p_instance = reinterpret_cast(GetWindowLongPtr(hWnd, GWLP_USERDATA)); switch( uMsg ) @@ -81,8 +65,10 @@ static LRESULT CALLBACK VLCVideoClassWndProc(HWND hWnd, UINT uMsg, WPARAM wParam RECT pr; if( GetUpdateRect(hWnd, &pr, FALSE) ) { + RECT bounds; + GetClientRect(hWnd, &bounds); BeginPaint(hWnd, &ps); - p_instance->onPaint(ps, pr); + p_instance->onPaint(ps.hdc, bounds, pr); EndPaint(hWnd, &ps); } return 0L; @@ -92,15 +78,17 @@ static LRESULT CALLBACK VLCVideoClassWndProc(HWND hWnd, UINT uMsg, WPARAM wParam } }; -VLCPluginClass::VLCPluginClass(LONG *p_class_ref, HINSTANCE hInstance) : +VLCPluginClass::VLCPluginClass(LONG *p_class_ref, HINSTANCE hInstance, REFCLSID rclsid) : _p_class_ref(p_class_ref), - _hinstance(hInstance) + _hinstance(hInstance), + _classid(rclsid), + _inplace_picture(NULL) { WNDCLASS wClass; if( ! GetClassInfo(hInstance, getInPlaceWndClassName(), &wClass) ) { - wClass.style = CS_NOCLOSE|CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS; + wClass.style = CS_NOCLOSE|CS_DBLCLKS; wClass.lpfnWndProc = VLCInPlaceClassWndProc; wClass.cbClsExtra = 0; wClass.cbWndExtra = 0; @@ -118,28 +106,19 @@ VLCPluginClass::VLCPluginClass(LONG *p_class_ref, HINSTANCE hInstance) : _inplace_wndclass_atom = 0; } - if( ! GetClassInfo(hInstance, getVideoWndClassName(), &wClass) ) + HBITMAP hbitmap = (HBITMAP)LoadImage(getHInstance(), TEXT("INPLACE-PICT"), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR); + if( NULL != hbitmap ) { - wClass.style = CS_NOCLOSE|CS_HREDRAW|CS_VREDRAW; - wClass.lpfnWndProc = VLCVideoClassWndProc; - wClass.cbClsExtra = 0; - wClass.cbWndExtra = 0; - wClass.hInstance = hInstance; - wClass.hIcon = NULL; - wClass.hCursor = LoadCursor(NULL, IDC_ARROW); - wClass.hbrBackground = NULL; - wClass.lpszMenuName = NULL; - wClass.lpszClassName = getVideoWndClassName(); - - _video_wndclass_atom = RegisterClass(&wClass); - } - else - { - _video_wndclass_atom = 0; - } + PICTDESC pictDesc; - _inplace_hbitmap = (HBITMAP)LoadImage(getHInstance(), TEXT("INPLACE-PICT"), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR); + pictDesc.cbSizeofstruct = sizeof(PICTDESC); + pictDesc.picType = PICTYPE_BITMAP; + pictDesc.bmp.hbitmap = hbitmap; + pictDesc.bmp.hpal = NULL; + if( FAILED(OleCreatePictureIndirect(&pictDesc, IID_IPicture, TRUE, reinterpret_cast(&_inplace_picture))) ) + _inplace_picture = NULL; + } AddRef(); }; @@ -148,11 +127,8 @@ VLCPluginClass::~VLCPluginClass() if( 0 != _inplace_wndclass_atom ) UnregisterClass(MAKEINTATOM(_inplace_wndclass_atom), _hinstance); - if( 0 != _video_wndclass_atom ) - UnregisterClass(MAKEINTATOM(_video_wndclass_atom), _hinstance); - - if( NULL != _inplace_hbitmap ) - DeleteObject(_inplace_hbitmap); + if( NULL != _inplace_picture ) + _inplace_picture->Release(); }; STDMETHODIMP VLCPluginClass::QueryInterface(REFIID riid, void **ppv) @@ -160,7 +136,8 @@ STDMETHODIMP VLCPluginClass::QueryInterface(REFIID riid, void **ppv) if( NULL == ppv ) return E_INVALIDARG; - if( (IID_IUnknown == riid) || (IID_IClassFactory == riid) ) + if( (IID_IUnknown == riid) + || (IID_IClassFactory == riid) ) { AddRef(); *ppv = reinterpret_cast(this); @@ -189,20 +166,22 @@ STDMETHODIMP_(ULONG) VLCPluginClass::Release(void) return refcount; }; -STDMETHODIMP VLCPluginClass::CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppv) +STDMETHODIMP VLCPluginClass::CreateInstance(LPUNKNOWN pUnkOuter, REFIID riid, void **ppv) { if( NULL == ppv ) return E_POINTER; *ppv = NULL; - if( NULL != pUnkOuter ) + if( (NULL != pUnkOuter) && (IID_IUnknown != riid) ) { return CLASS_E_NOAGGREGATION; + } - VLCPlugin *plugin = new VLCPlugin(this); + VLCPlugin *plugin = new VLCPlugin(this, pUnkOuter); if( NULL != plugin ) { HRESULT hr = plugin->QueryInterface(riid, ppv); + // the following will destroy the object if QueryInterface() failed plugin->Release(); return hr; } @@ -221,21 +200,16 @@ STDMETHODIMP VLCPluginClass::LockServer(BOOL fLock) //////////////////////////////////////////////////////////////////////// -VLCPlugin::VLCPlugin(VLCPluginClass *p_class) : +VLCPlugin::VLCPlugin(VLCPluginClass *p_class, LPUNKNOWN pUnkOuter) : _inplacewnd(NULL), _p_class(p_class), _i_ref(1UL), - _codepage(CP_ACP), - _psz_src(NULL), - _b_autostart(TRUE), - _b_loopmode(FALSE), - _b_visible(TRUE), - _b_sendevents(TRUE), - _i_vlc(0) + _p_libvlc(NULL), + _i_codepage(CP_ACP), + _b_usermode(TRUE) { p_class->AddRef(); - vlcOleObject = new VLCOleObject(this); vlcOleControl = new VLCOleControl(this); vlcOleInPlaceObject = new VLCOleInPlaceObject(this); vlcOleInPlaceActiveObject = new VLCOleInPlaceActiveObject(this); @@ -246,15 +220,30 @@ VLCPlugin::VLCPlugin(VLCPluginClass *p_class) : vlcConnectionPointContainer = new VLCConnectionPointContainer(this); vlcObjectSafety = new VLCObjectSafety(this); vlcControl = new VLCControl(this); + vlcControl2 = new VLCControl2(this); + vlcViewObject = new VLCViewObject(this); + vlcDataObject = new VLCDataObject(this); + vlcOleObject = new VLCOleObject(this); + vlcSupportErrorInfo = new VLCSupportErrorInfo(this); + + // configure controlling IUnknown interface for implemented interfaces + this->pUnkOuter = (NULL != pUnkOuter) ? pUnkOuter : dynamic_cast(this); + + // default picure + _p_pict = p_class->getInPlacePict(); + + // make sure that persistable properties are initialized + onInit(); }; VLCPlugin::~VLCPlugin() { - vlcOleInPlaceObject->UIDeactivate(); - vlcOleInPlaceObject->InPlaceDeactivate(); - + delete vlcSupportErrorInfo; + delete vlcOleObject; + delete vlcDataObject; + delete vlcViewObject; + delete vlcControl2; delete vlcControl; - delete vlcObjectSafety; delete vlcConnectionPointContainer; delete vlcProvideClassInfo; delete vlcPersistPropertyBag; @@ -262,11 +251,13 @@ VLCPlugin::~VLCPlugin() delete vlcPersistStorage; delete vlcOleInPlaceActiveObject; delete vlcOleInPlaceObject; + delete vlcObjectSafety; + delete vlcOleControl; - delete vlcOleObject; + if( _p_pict ) + _p_pict->Release(); - if( _psz_src ) - free(_psz_src); + SysFreeString(_bstr_mrl); _p_class->Release(); }; @@ -277,105 +268,56 @@ STDMETHODIMP VLCPlugin::QueryInterface(REFIID riid, void **ppv) return E_INVALIDARG; if( IID_IUnknown == riid ) - { - AddRef(); *ppv = reinterpret_cast(this); - return NOERROR; - } else if( IID_IOleObject == riid ) - { - AddRef(); *ppv = reinterpret_cast(vlcOleObject); - return NOERROR; - } else if( IID_IOleControl == riid ) - { - AddRef(); *ppv = reinterpret_cast(vlcOleControl); - return NOERROR; - } else if( IID_IOleWindow == riid ) - { - AddRef(); *ppv = reinterpret_cast(vlcOleInPlaceObject); - return NOERROR; - } else if( IID_IOleInPlaceObject == riid ) - { - AddRef(); *ppv = reinterpret_cast(vlcOleInPlaceObject); - return NOERROR; - } else if( IID_IOleInPlaceActiveObject == riid ) - { - AddRef(); *ppv = reinterpret_cast(vlcOleInPlaceActiveObject); - return NOERROR; - } else if( IID_IPersist == riid ) - { - AddRef(); - *ppv = reinterpret_cast(vlcPersistPropertyBag); - return NOERROR; - } + *ppv = reinterpret_cast(vlcPersistStreamInit); else if( IID_IPersistStreamInit == riid ) - { - AddRef(); *ppv = reinterpret_cast(vlcPersistStreamInit); - return NOERROR; - } else if( IID_IPersistStorage == riid ) - { - AddRef(); *ppv = reinterpret_cast(vlcPersistStorage); - return NOERROR; - } else if( IID_IPersistPropertyBag == riid ) - { - AddRef(); *ppv = reinterpret_cast(vlcPersistPropertyBag); - return NOERROR; - } else if( IID_IProvideClassInfo == riid ) - { - AddRef(); *ppv = reinterpret_cast(vlcProvideClassInfo); - return NOERROR; - } else if( IID_IProvideClassInfo2 == riid ) - { - AddRef(); *ppv = reinterpret_cast(vlcProvideClassInfo); - return NOERROR; - } else if( IID_IConnectionPointContainer == riid ) - { - AddRef(); *ppv = reinterpret_cast(vlcConnectionPointContainer); - return NOERROR; - } else if( IID_IObjectSafety == riid ) - { - AddRef(); *ppv = reinterpret_cast(vlcObjectSafety); - return NOERROR; - } else if( IID_IDispatch == riid ) - { - AddRef(); - *ppv = reinterpret_cast(vlcControl); - return NOERROR; - } + *ppv = (CLSID_VLCPlugin2 == getClassID()) ? + reinterpret_cast(vlcControl2) : + reinterpret_cast(vlcControl); else if( IID_IVLCControl == riid ) - { - AddRef(); *ppv = reinterpret_cast(vlcControl); - return NOERROR; + else if( IID_IVLCControl2 == riid ) + *ppv = reinterpret_cast(vlcControl2); + else if( IID_IViewObject == riid ) + *ppv = reinterpret_cast(vlcViewObject); + else if( IID_IViewObject2 == riid ) + *ppv = reinterpret_cast(vlcViewObject); + else if( IID_IDataObject == riid ) + *ppv = reinterpret_cast(vlcDataObject); + else if( IID_ISupportErrorInfo == riid ) + *ppv = reinterpret_cast(vlcSupportErrorInfo); + else + { + *ppv = NULL; + return E_NOINTERFACE; } - - *ppv = NULL; - - return E_NOINTERFACE; + ((LPUNKNOWN)*ppv)->AddRef(); + return NOERROR; }; STDMETHODIMP_(ULONG) VLCPlugin::AddRef(void) @@ -395,102 +337,97 @@ STDMETHODIMP_(ULONG) VLCPlugin::Release(void) ////////////////////////////////////// -/* -** we use an in-place child window to represent plugin viewport, -** whose size is limited by the clipping rectangle -** all drawing within this window must follow -** cartesian coordinate system represented by _bounds. -*/ - -void VLCPlugin::calcPositionChange(LPRECT lprPosRect, LPCRECT lprcClipRect) +HRESULT VLCPlugin::onInit(void) { - _bounds.right = lprPosRect->right-lprPosRect->left; - - if( lprcClipRect->left <= lprPosRect->left ) - { - // left side is not clipped out - _bounds.left = 0; + if( NULL == _p_libvlc ) + { + // initialize persistable properties + _b_autoplay = TRUE; + _b_autoloop = FALSE; + _bstr_baseurl = NULL; + _bstr_mrl = NULL; + _b_visible = TRUE; + _b_mute = FALSE; + _i_volume = 50; + _i_time = 0; + // set default/preferred size (320x240) pixels in HIMETRIC + HDC hDC = CreateDevDC(NULL); + _extent.cx = 320; + _extent.cy = 240; + HimetricFromDP(hDC, (LPPOINT)&_extent, 1); + DeleteDC(hDC); - if( lprcClipRect->right >= lprPosRect->right ) - { - // right side is not clipped out, no change - } - else if( lprcClipRect->right >= lprPosRect->left ) - { - // right side is clipped out - lprPosRect->right = lprcClipRect->right; - } - else - { - // outside of clipping rectange, not visible - lprPosRect->right = lprPosRect->left; - } + return S_OK; } - else - { - // left side is clipped out - _bounds.left = lprPosRect->left-lprcClipRect->left; - _bounds.right += _bounds.left; + return CO_E_ALREADYINITIALIZED; +}; - lprPosRect->left = lprcClipRect->left; - if( lprcClipRect->right >= lprPosRect->right ) - { - // right side is not clipped out - } - else +HRESULT VLCPlugin::onLoad(void) +{ + if( SysStringLen(_bstr_baseurl) == 0 ) + { + /* + ** try to retreive the base URL using the client site moniker, which for Internet Explorer + ** is the URL of the page the plugin is embedded into. + */ + LPOLECLIENTSITE pClientSite; + if( SUCCEEDED(vlcOleObject->GetClientSite(&pClientSite)) && (NULL != pClientSite) ) { - // right side is clipped out - lprPosRect->right = lprcClipRect->right; + IBindCtx *pBC = 0; + if( SUCCEEDED(CreateBindCtx(0, &pBC)) ) + { + LPMONIKER pContMoniker = NULL; + if( SUCCEEDED(pClientSite->GetMoniker(OLEGETMONIKER_ONLYIFTHERE, + OLEWHICHMK_CONTAINER, &pContMoniker)) ) + { + LPOLESTR base_url; + if( SUCCEEDED(pContMoniker->GetDisplayName(pBC, NULL, &base_url)) ) + { + /* + ** check that the moniker name is a URL + */ + if( UrlIsW(base_url, URLIS_URL) ) + { + /* copy base URL */ + _bstr_baseurl = SysAllocString(base_url); + } + CoTaskMemFree(base_url); + } + } + } } } + setDirty(FALSE); + return S_OK; +}; - _bounds.bottom = lprPosRect->bottom-lprPosRect->top; - - if( lprcClipRect->top <= lprPosRect->top ) +HRESULT VLCPlugin::getVLCObject(int* i_vlc) +{ + libvlc_instance_t *p_libvlc; + HRESULT result = getVLC(&p_libvlc); + if( SUCCEEDED(result) ) { - // top side is not clipped out - _bounds.top = 0; - - if( lprcClipRect->bottom >= lprPosRect->bottom ) - { - // bottom side is not clipped out, no change - } - else if( lprcClipRect->bottom >= lprPosRect->top ) - { - // bottom side is clipped out - lprPosRect->bottom = lprcClipRect->bottom; - } - else - { - // outside of clipping rectange, not visible - lprPosRect->right = lprPosRect->left; - } + *i_vlc = libvlc_get_vlc_id(p_libvlc); } else { - _bounds.top = lprPosRect->top-lprcClipRect->top; - _bounds.bottom += _bounds.top; - - lprPosRect->top = lprcClipRect->top; - if( lprcClipRect->bottom >= lprPosRect->bottom ) - { - // bottom side is not clipped out - } - else - { - // bottom side is clipped out - lprPosRect->bottom = lprcClipRect->bottom; - } + *i_vlc = 0; } -}; - -#include + return result; +} -HRESULT VLCPlugin::onInit(BOOL isNew) +HRESULT VLCPlugin::getVLC(libvlc_instance_t** pp_libvlc) { - if( 0 == _i_vlc ) + extern HMODULE DllGetModule(); + + if( ! isRunning() ) { - char *ppsz_argv[] = { "vlc", "-vv" }; + /* + ** default initialization options + */ + char *ppsz_argv[32] = { "vlc" }; + int ppsz_argc = 1; + HKEY h_key; DWORD i_type, i_data = MAX_PATH + 1; char p_data[MAX_PATH + 1]; @@ -502,89 +439,219 @@ HRESULT VLCPlugin::onInit(BOOL isNew) { if( i_type == REG_SZ ) { - strcat( p_data, "\\vlc" ); - ppsz_argv[0] = p_data; + strcat( p_data, "\\plugins" ); + //ppsz_argv[ppsz_argc++] = "--plugin-path"; + //ppsz_argv[ppsz_argc++] = p_data; } } RegCloseKey( h_key ); } -#if 0 - ppsz_argv[0] = "C:\\cygwin\\home\\Damien_Fouilleul\\dev\\videolan\\vlc-trunk\\vlc"; -#endif - - _i_vlc = VLC_Create(); - - if( VLC_Init(_i_vlc, sizeof(ppsz_argv)/sizeof(char*), ppsz_argv) ) + char p_path[MAX_PATH+1]; + DWORD len = GetModuleFileNameA(DllGetModule(), p_path, sizeof(p_path)); + if( len > 0 ) { - VLC_Destroy(_i_vlc); - _i_vlc = 0; - return E_FAIL; + p_path[len] = '\0'; + ppsz_argv[0] = p_path; } - if( isNew ) + // make sure plugin isn't affected with VLC single instance mode + ppsz_argv[ppsz_argc++] = "--no-one-instance"; + + /* common settings */ + ppsz_argv[ppsz_argc++] = "-vv"; + ppsz_argv[ppsz_argc++] = "--no-stats"; + ppsz_argv[ppsz_argc++] = "--no-media-library"; + ppsz_argv[ppsz_argc++] = "--intf"; + ppsz_argv[ppsz_argc++] = "dummy"; + + // loop mode is a configuration option only + if( _b_autoloop ) + ppsz_argv[ppsz_argc++] = "--loop"; + + if( IsDebuggerPresent() ) { /* - ** object has fully initialized, - ** try to activate in place if container is ready + ** VLC default threading mechanism is designed to be as compatible + ** with POSIX as possible. However when debugged on win32, threads + ** lose signals and eventually VLC get stuck during initialization. + ** threading support can be configured to be more debugging friendly + ** but it will be less compatible with POSIX. + ** This is done by initializing with the following options: */ - LPOLECLIENTSITE pActiveSite; + ppsz_argv[ppsz_argc++] = "--fast-mutex"; + ppsz_argv[ppsz_argc++] = "--win9x-cv-method=1"; + } - if( SUCCEEDED(vlcOleObject->GetClientSite(&pActiveSite)) && (NULL != pActiveSite) ) + _p_libvlc = libvlc_new(ppsz_argc, ppsz_argv, NULL); + if( NULL == _p_libvlc ) + { + *pp_libvlc = NULL; + return E_FAIL; + } + + // initial volume setting + libvlc_audio_set_volume(_p_libvlc, _i_volume, NULL); + if( _b_mute ) + { + libvlc_audio_set_mute(_p_libvlc, TRUE, NULL); + } + + // initial playlist item + if( SysStringLen(_bstr_mrl) > 0 ) + { + char *psz_mrl = NULL; + + if( SysStringLen(_bstr_baseurl) > 0 ) + { + DWORD len = INTERNET_MAX_URL_LENGTH; + LPOLESTR abs_url = (LPOLESTR)CoTaskMemAlloc(sizeof(OLECHAR)*len); + if( NULL != abs_url ) + { + /* + ** if the MRL a relative URL, we should end up with an absolute URL + */ + if( SUCCEEDED(UrlCombineW(_bstr_baseurl, _bstr_mrl, abs_url, &len, + URL_ESCAPE_UNSAFE|URL_PLUGGABLE_PROTOCOL)) ) + { + psz_mrl = CStrFromBSTR(CP_UTF8, abs_url); + } + else + { + psz_mrl = CStrFromBSTR(CP_UTF8, _bstr_mrl); + } + CoTaskMemFree(abs_url); + } + } + else { - vlcOleObject->DoVerb(OLEIVERB_INPLACEACTIVATE, NULL, pActiveSite, 0, NULL, NULL); - pActiveSite->Release(); + /* + ** baseURL is empty, assume MRL is absolute + */ + psz_mrl = CStrFromBSTR(CP_UTF8, _bstr_mrl); + } + if( NULL != psz_mrl ) + { + const char *options[1]; + int i_options = 0; + + char timeBuffer[32]; + if( _i_time ) + { + snprintf(timeBuffer, sizeof(timeBuffer), ":start-time=%d", _i_time); + options[i_options++] = timeBuffer; + } + // add default target to playlist + libvlc_playlist_add_extended(_p_libvlc, psz_mrl, NULL, i_options, options, NULL); + CoTaskMemFree(psz_mrl); } } - return S_OK; } - return E_UNEXPECTED; + *pp_libvlc = _p_libvlc; + return S_OK; }; -HRESULT VLCPlugin::onLoad(void) +void VLCPlugin::setErrorInfo(REFIID riid, const char *description) { - /* - ** object has fully initialized, - ** try to activate in place if container is ready - */ - LPOLECLIENTSITE pActiveSite; - - if( SUCCEEDED(vlcOleObject->GetClientSite(&pActiveSite)) && (NULL != pActiveSite) ) - { - vlcOleObject->DoVerb(OLEIVERB_INPLACEACTIVATE, NULL, pActiveSite, 0, NULL, NULL); - pActiveSite->Release(); - } - return S_OK; + vlcSupportErrorInfo->setErrorInfo( getClassID() == CLSID_VLCPlugin2 ? + OLESTR("VideoLAN.VLCPlugin.2") : OLESTR("VideoLAN.VLCPlugin.1"), + riid, description ); }; -HRESULT VLCPlugin::onClientSiteChanged(LPOLECLIENTSITE pActiveSite) +HRESULT VLCPlugin::onAmbientChanged(LPUNKNOWN pContainer, DISPID dispID) { - if( NULL != pActiveSite ) - { - /* - ** object is embedded in container - ** try to activate in place if it has initialized - */ - if( _i_vlc ) - { - vlcOleObject->DoVerb(OLEIVERB_INPLACEACTIVATE, NULL, pActiveSite, 0, NULL, NULL); - } + VARIANT v; + switch( dispID ) + { + case DISPID_AMBIENT_BACKCOLOR: + break; + case DISPID_AMBIENT_DISPLAYNAME: + break; + case DISPID_AMBIENT_FONT: + break; + case DISPID_AMBIENT_FORECOLOR: + break; + case DISPID_AMBIENT_LOCALEID: + break; + case DISPID_AMBIENT_MESSAGEREFLECT: + break; + case DISPID_AMBIENT_SCALEUNITS: + break; + case DISPID_AMBIENT_TEXTALIGN: + break; + case DISPID_AMBIENT_USERMODE: + VariantInit(&v); + V_VT(&v) = VT_BOOL; + if( SUCCEEDED(GetObjectProperty(pContainer, dispID, v)) ) + { + setUserMode(V_BOOL(&v) != VARIANT_FALSE); + } + break; + case DISPID_AMBIENT_UIDEAD: + break; + case DISPID_AMBIENT_SHOWGRABHANDLES: + break; + case DISPID_AMBIENT_SHOWHATCHING: + break; + case DISPID_AMBIENT_DISPLAYASDEFAULT: + break; + case DISPID_AMBIENT_SUPPORTSMNEMONICS: + break; + case DISPID_AMBIENT_AUTOCLIP: + break; + case DISPID_AMBIENT_APPEARANCE: + break; + case DISPID_AMBIENT_CODEPAGE: + VariantInit(&v); + V_VT(&v) = VT_I4; + if( SUCCEEDED(GetObjectProperty(pContainer, dispID, v)) ) + { + setCodePage(V_I4(&v)); + } + break; + case DISPID_AMBIENT_PALETTE: + break; + case DISPID_AMBIENT_CHARSET: + break; + case DISPID_AMBIENT_RIGHTTOLEFT: + break; + case DISPID_AMBIENT_TOPTOBOTTOM: + break; + case DISPID_UNKNOWN: + /* + ** multiple property change, look up the ones we are interested in + */ + VariantInit(&v); + V_VT(&v) = VT_BOOL; + if( SUCCEEDED(GetObjectProperty(pContainer, DISPID_AMBIENT_USERMODE, v)) ) + { + setUserMode(V_BOOL(&v) != VARIANT_FALSE); + } + VariantInit(&v); + V_VT(&v) = VT_I4; + if( SUCCEEDED(GetObjectProperty(pContainer, DISPID_AMBIENT_CODEPAGE, v)) ) + { + setCodePage(V_I4(&v)); + } + break; } return S_OK; }; HRESULT VLCPlugin::onClose(DWORD dwSaveOption) { - if( _i_vlc ) + if( isInPlaceActive() ) { - if( isInPlaceActive() ) - { - onInPlaceDeactivate(); - } + onInPlaceDeactivate(); + } + if( isRunning() ) + { + libvlc_instance_t* p_libvlc = _p_libvlc; + + _p_libvlc = NULL; + vlcDataObject->onClose(); - VLC_CleanUp(_i_vlc); - VLC_Destroy(_i_vlc); - _i_vlc = 0; + libvlc_destroy(p_libvlc, NULL ); } return S_OK; }; @@ -596,17 +663,26 @@ BOOL VLCPlugin::isInPlaceActive(void) HRESULT VLCPlugin::onActivateInPlace(LPMSG lpMesg, HWND hwndParent, LPCRECT lprcPosRect, LPCRECT lprcClipRect) { - RECT posRect = *lprcPosRect; + RECT clipRect = *lprcClipRect; - calcPositionChange(&posRect, lprcClipRect); + /* + ** record keeping of control geometry within container + */ + _posRect = *lprcPosRect; + /* + ** Create a window for in place activated control. + ** the window geometry matches the control viewport + ** within container so that embedded video is always + ** properly displayed. + */ _inplacewnd = CreateWindow(_p_class->getInPlaceWndClassName(), "VLC Plugin In-Place Window", - WS_CHILD|WS_CLIPCHILDREN|WS_TABSTOP, - posRect.left, - posRect.top, - posRect.right-posRect.left, - posRect.bottom-posRect.top, + WS_CHILD|WS_CLIPCHILDREN|WS_CLIPSIBLINGS, + lprcPosRect->left, + lprcPosRect->top, + lprcPosRect->right-lprcPosRect->left, + lprcPosRect->bottom-lprcPosRect->top, hwndParent, 0, _p_class->getHInstance(), @@ -618,63 +694,51 @@ HRESULT VLCPlugin::onActivateInPlace(LPMSG lpMesg, HWND hwndParent, LPCRECT lprc SetWindowLongPtr(_inplacewnd, GWLP_USERDATA, reinterpret_cast(this)); - _videownd = CreateWindow(_p_class->getVideoWndClassName(), - "VLC Plugin Video Window", - WS_CHILD|WS_CLIPCHILDREN|WS_VISIBLE, - _bounds.left, - _bounds.top, - _bounds.right-_bounds.left, - _bounds.bottom-_bounds.top, - _inplacewnd, - 0, - _p_class->getHInstance(), - NULL - ); - - if( NULL == _videownd ) - { - DestroyWindow(_inplacewnd); - return E_FAIL; - } - - SetWindowLongPtr(_videownd, GWLP_USERDATA, reinterpret_cast(this)); + /* change cliprect coordinates system relative to window bounding rect */ + OffsetRect(&clipRect, -lprcPosRect->left, -lprcPosRect->top); - if( getVisible() ) - ShowWindow(_inplacewnd, SW_SHOWNORMAL); + HRGN clipRgn = CreateRectRgnIndirect(&clipRect); + SetWindowRgn(_inplacewnd, clipRgn, TRUE); - /* horrible cast there */ - vlc_value_t val; - val.i_int = reinterpret_cast(_videownd); - VLC_VariableSet(_i_vlc, "drawable", val); - - if( NULL != _psz_src ) + if( _b_usermode ) { - // add target to playlist - char *cOptions[1]; - int cOptionsCount = 0; + /* will run vlc if not done already */ + libvlc_instance_t* p_libvlc; + HRESULT result = getVLC(&p_libvlc); + if( FAILED(result) ) + return result; - if( _b_loopmode ) - { - cOptions[cOptionsCount++] = "loop"; - } - VLC_AddTarget(_i_vlc, _psz_src, (const char **)&cOptions, cOptionsCount, PLAYLIST_APPEND, PLAYLIST_END); + /* set internal video width and height */ + libvlc_video_set_size(p_libvlc, + lprcPosRect->right-lprcPosRect->left, + lprcPosRect->bottom-lprcPosRect->top, + NULL ); - if( _b_autostart ) + /* set internal video parent window */ + libvlc_video_set_parent(p_libvlc, + reinterpret_cast(_inplacewnd), NULL); + + if( _b_autoplay & (libvlc_playlist_items_count(p_libvlc, NULL) > 0) ) { - VLC_Play(_i_vlc); + libvlc_playlist_play(p_libvlc, 0, 0, NULL, NULL); fireOnPlayEvent(); } } + + if( isVisible() ) + ShowWindow(_inplacewnd, SW_SHOW); + return S_OK; }; HRESULT VLCPlugin::onInPlaceDeactivate(void) { - VLC_Stop(_i_vlc); - fireOnStopEvent(); + if( isRunning() ) + { + libvlc_playlist_stop(_p_libvlc, NULL); + fireOnStopEvent(); + } - DestroyWindow(_videownd); - _videownd = NULL; DestroyWindow(_inplacewnd); _inplacewnd = NULL; @@ -683,10 +747,56 @@ HRESULT VLCPlugin::onInPlaceDeactivate(void) void VLCPlugin::setVisible(BOOL fVisible) { - _b_visible = fVisible; - if( isInPlaceActive() ) - ShowWindow(_inplacewnd, fVisible ? SW_SHOWNORMAL : SW_HIDE); - firePropChangedEvent(DISPID_Visible); + if( fVisible != _b_visible ) + { + _b_visible = fVisible; + if( isInPlaceActive() ) + { + ShowWindow(_inplacewnd, fVisible ? SW_SHOW : SW_HIDE); + if( fVisible ) + InvalidateRect(_inplacewnd, NULL, TRUE); + } + setDirty(TRUE); + firePropChangedEvent(DISPID_Visible); + } +}; + +void VLCPlugin::setVolume(int volume) +{ + if( volume < 0 ) + volume = 0; + else if( volume > 200 ) + volume = 200; + + if( volume != _i_volume ) + { + _i_volume = volume; + if( isRunning() ) + { + libvlc_audio_set_volume(_p_libvlc, _i_volume, NULL); + } + setDirty(TRUE); + } +}; + +void VLCPlugin::setTime(int seconds) +{ + if( seconds < 0 ) + seconds = 0; + + if( seconds != _i_time ) + { + setStartTime(_i_time); + if( isRunning() ) + { + libvlc_input_t *p_input = libvlc_playlist_get_input(_p_libvlc, NULL); + if( NULL != p_input ) + { + libvlc_input_set_time(p_input, _i_time, NULL); + libvlc_input_free(p_input); + } + } + } }; void VLCPlugin::setFocus(BOOL fFocus) @@ -700,124 +810,178 @@ BOOL VLCPlugin::hasFocus(void) return GetActiveWindow() == _inplacewnd; }; -void VLCPlugin::onPaint(PAINTSTRUCT &ps, RECT &pr) +void VLCPlugin::onDraw(DVTARGETDEVICE * ptd, HDC hicTargetDev, + HDC hdcDraw, LPCRECTL lprcBounds, LPCRECTL lprcWBounds) { - /* - ** if VLC is playing, it may not display any VIDEO content - ** hence, draw control logo - */ - int width = _bounds.right-_bounds.left; - int height = _bounds.bottom-_bounds.top; - - HBITMAP pict = _p_class->getInPlacePict(); - if( NULL != pict ) + if( isVisible() ) { - HDC hdcPict = CreateCompatibleDC(ps.hdc); - if( NULL != hdcPict ) + long width = lprcBounds->right-lprcBounds->left; + long height = lprcBounds->bottom-lprcBounds->top; + + RECT bounds = { lprcBounds->left, lprcBounds->top, lprcBounds->right, lprcBounds->bottom }; + FillRect(hdcDraw, &bounds, (HBRUSH)GetStockObject(WHITE_BRUSH)); + + LPPICTURE pict = getPicture(); + if( NULL != pict ) { - BITMAP bm; - if( GetObject(pict, sizeof(BITMAPINFO), &bm) ) + OLE_XSIZE_HIMETRIC picWidth; + OLE_YSIZE_HIMETRIC picHeight; + + pict->get_Width(&picWidth); + pict->get_Height(&picHeight); + + SIZEL picSize = { picWidth, picHeight }; + + if( NULL != hicTargetDev ) + { + DPFromHimetric(hicTargetDev, (LPPOINT)&picSize, 1); + } + else if( NULL != (hicTargetDev = CreateDevDC(ptd)) ) + { + DPFromHimetric(hicTargetDev, (LPPOINT)&picSize, 1); + DeleteDC(hicTargetDev); + } + + if( picSize.cx > width-4 ) + picSize.cx = width-4; + if( picSize.cy > height-4 ) + picSize.cy = height-4; + + LONG dstX = lprcBounds->left+(width-picSize.cx)/2; + LONG dstY = lprcBounds->top+(height-picSize.cy)/2; + + if( NULL != lprcWBounds ) { - int dstWidth = bm.bmWidth; - if( dstWidth > width-4 ) - dstWidth = width-4; - - int dstHeight = bm.bmHeight; - if( dstHeight > height-4 ) - dstHeight = height-4; - - int dstX = (width-dstWidth)/2; - int dstY = (height-dstHeight)/2; - - SelectObject(hdcPict, pict); - StretchBlt(ps.hdc, dstX, dstY, dstWidth, dstHeight, - hdcPict, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY); - DeleteDC(hdcPict); - ExcludeClipRect(ps.hdc, dstX, dstY, dstWidth+dstX, dstHeight+dstY); + RECT wBounds = { lprcWBounds->left, lprcWBounds->top, lprcWBounds->right, lprcWBounds->bottom }; + pict->Render(hdcDraw, dstX, dstY, picSize.cx, picSize.cy, + 0L, picHeight, picWidth, -picHeight, &wBounds); } + else + pict->Render(hdcDraw, dstX, dstY, picSize.cx, picSize.cy, + 0L, picHeight, picWidth, -picHeight, NULL); + + pict->Release(); } + + SelectObject(hdcDraw, GetStockObject(BLACK_BRUSH)); + + MoveToEx(hdcDraw, bounds.left, bounds.top, NULL); + LineTo(hdcDraw, bounds.left+width-1, bounds.top); + LineTo(hdcDraw, bounds.left+width-1, bounds.top+height-1); + LineTo(hdcDraw, bounds.left, bounds.top+height-1); + LineTo(hdcDraw, bounds.left, bounds.top); } +}; - FillRect(ps.hdc, &pr, (HBRUSH)GetStockObject(WHITE_BRUSH)); - SelectObject(ps.hdc, GetStockObject(BLACK_BRUSH)); +void VLCPlugin::onPaint(HDC hdc, const RECT &bounds, const RECT &clipRect) +{ + if( isVisible() ) + { + /** if VLC is playing, it may not display any VIDEO content + ** hence, draw control logo*/ + HDC hdcDraw = CreateCompatibleDC(hdc); + if( NULL != hdcDraw ) + { + SIZEL size = getExtent(); + DPFromHimetric(hdc, (LPPOINT)&size, 1); + RECTL posRect = { 0, 0, size.cx, size.cy }; - MoveToEx(ps.hdc, 0, 0, NULL); - LineTo(ps.hdc, width-1, 0); - LineTo(ps.hdc, width-1, height-1); - LineTo(ps.hdc, 0, height-1); - LineTo(ps.hdc, 0, 0); + int width = bounds.right-bounds.left; + int height = bounds.bottom-bounds.top; + + HBITMAP hBitmap = CreateCompatibleBitmap(hdc, width, height); + if( NULL != hBitmap ) + { + HBITMAP oldBmp = (HBITMAP)SelectObject(hdcDraw, hBitmap); + + if( (size.cx != width) || (size.cy != height) ) + { + // needs to scale canvas + SetMapMode(hdcDraw, MM_ANISOTROPIC); + SetWindowExtEx(hdcDraw, size.cx, size.cy, NULL); + SetViewportExtEx(hdcDraw, width, height, NULL); + } + + onDraw(NULL, hdc, hdcDraw, &posRect, NULL); + + SetMapMode(hdcDraw, MM_TEXT); + BitBlt(hdc, bounds.left, bounds.top, + width, height, + hdcDraw, 0, 0, + SRCCOPY); + + SelectObject(hdcDraw, oldBmp); + DeleteObject(hBitmap); + } + DeleteDC(hdcDraw); + } + } }; void VLCPlugin::onPositionChange(LPCRECT lprcPosRect, LPCRECT lprcClipRect) { - RECT posRect = *lprcPosRect; + RECT clipRect = *lprcClipRect; - calcPositionChange(&posRect, lprcClipRect); + //RedrawWindow(GetParent(_inplacewnd), &_posRect, NULL, RDW_INVALIDATE|RDW_ERASE|RDW_ALLCHILDREN); /* - ** change in-place window geometry to match clipping region + ** record keeping of control geometry within container */ - MoveWindow(_inplacewnd, - posRect.left, - posRect.top, - posRect.right-posRect.left, - posRect.bottom-posRect.top, - FALSE); + _posRect = *lprcPosRect; /* - ** change video window geometry to match object bounds within clipping region + ** change in-place window geometry to match clipping region */ - MoveWindow(_videownd, - _bounds.left, - _bounds.top, - _bounds.right-_bounds.left, - _bounds.bottom-_bounds.top, - FALSE); - - RECT updateRect; - - updateRect.left = -_bounds.left; - updateRect.top = -_bounds.top; - updateRect.right = _bounds.right-_bounds.left; - updateRect.bottom = _bounds.bottom-_bounds.top; + SetWindowPos(_inplacewnd, NULL, + lprcPosRect->left, + lprcPosRect->top, + lprcPosRect->right-lprcPosRect->left, + lprcPosRect->bottom-lprcPosRect->top, + SWP_NOACTIVATE| + SWP_NOCOPYBITS| + SWP_NOZORDER| + SWP_NOOWNERZORDER ); + + /* change cliprect coordinates system relative to window bounding rect */ + OffsetRect(&clipRect, -lprcPosRect->left, -lprcPosRect->top); + HRGN clipRgn = CreateRectRgnIndirect(&clipRect); + SetWindowRgn(_inplacewnd, clipRgn, FALSE); + + //RedrawWindow(_videownd, &posRect, NULL, RDW_INVALIDATE|RDW_ERASE|RDW_ALLCHILDREN); + if( isRunning() ) + { + libvlc_video_set_size(_p_libvlc, + lprcPosRect->right-lprcPosRect->left, + lprcPosRect->bottom-lprcPosRect->top, + NULL ); + } +}; - ValidateRect(_videownd, NULL); - InvalidateRect(_videownd, &updateRect, FALSE); - UpdateWindow(_videownd); +void VLCPlugin::freezeEvents(BOOL freeze) +{ + vlcConnectionPointContainer->freezeEvents(freeze); }; void VLCPlugin::firePropChangedEvent(DISPID dispid) { - if( _b_sendevents ) - { - vlcConnectionPointContainer->firePropChangedEvent(dispid); - } + vlcConnectionPointContainer->firePropChangedEvent(dispid); }; void VLCPlugin::fireOnPlayEvent(void) { - if( _b_sendevents ) - { - DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0}; - vlcConnectionPointContainer->fireEvent(DISPID_PlayEvent, &dispparamsNoArgs); - } + DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0}; + vlcConnectionPointContainer->fireEvent(DISPID_PlayEvent, &dispparamsNoArgs); }; void VLCPlugin::fireOnPauseEvent(void) { - if( _b_sendevents ) - { - DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0}; - vlcConnectionPointContainer->fireEvent(DISPID_PauseEvent, &dispparamsNoArgs); - } + DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0}; + vlcConnectionPointContainer->fireEvent(DISPID_PauseEvent, &dispparamsNoArgs); }; void VLCPlugin::fireOnStopEvent(void) { - if( _b_sendevents ) - { - DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0}; - vlcConnectionPointContainer->fireEvent(DISPID_StopEvent, &dispparamsNoArgs); - } + DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0}; + vlcConnectionPointContainer->fireEvent(DISPID_StopEvent, &dispparamsNoArgs); };